I’v been trying to get headless-gl to work with three.js, running some gists provided by @bsergean in a discussion about the topic in issue #7085, but with no success so far. Some examples will give an error with an undefined WebGL context such as this:
ubuntu@ubuntu:~/dev/08be90a2f21205062ccc$ xvfb-run -s "-ac -screen 0 1280x1024x24" npm start
> offscreen-sample@1.0.0 start /home/ubuntu/dev/08be90a2f21205062ccc
> coffee offscreen_sample.coffee
parsed ! undefined undefined
undefined
THREE.WebGLRenderer 95
THREE.WebGLRenderer: _canvas.addEventListener is not a function
events.js:183
throw er; // Unhandled 'error' event
^
TypeError: Cannot read property 'getShaderPrecisionFormat' of undefined
at getMaxPrecision (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/three/build/three.js:14830:13)
at new WebGLCapabilities (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/three/build/three.js:14859:22)
at initGLContext (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/three/build/three.js:21926:19)
at new WebGLRenderer (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/three/build/three.js:21976:3)
at render (/home/ubuntu/dev/08be90a2f21205062ccc/offscreen_sample.coffee:35:16)
at exports.PNG.<anonymous> (/home/ubuntu/dev/08be90a2f21205062ccc/offscreen_sample.coffee:136:5)
at emitOne (events.js:116:13)
at exports.PNG.emit (events.js:211:7)
at exports.PNG.<anonymous> (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/pngjs/lib/png.js:37:10)
at emitOne (events.js:116:13)
at module.exports.emit (events.js:211:7)
at module.exports.ParserAsync._complete (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/pngjs/lib/parser-async.js:153:8)
at emitOne (events.js:116:13)
at module.exports.emit (events.js:211:7)
at module.exports.complete (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/pngjs/lib/filter-parse-async.js:19:12)
at module.exports.Filter._reverseFilterLine (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/pngjs/lib/filter-parse.js:169:10)
at module.exports.ChunkStream._processRead (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/pngjs/lib/chunkstream.js:174:13)
at module.exports.ChunkStream._process (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/pngjs/lib/chunkstream.js:193:14)
at module.exports.ChunkStream.write (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/pngjs/lib/chunkstream.js:61:8)
at Inflate.<anonymous> (/home/ubuntu/dev/08be90a2f21205062ccc/node_modules/pngjs/lib/parser-async.js:94:9)
at emitOne (events.js:116:13)
at Inflate.emit (events.js:211:7)
at addChunk (_stream_readable.js:263:12)
at readableAddChunk (_stream_readable.js:250:11)
at Inflate.Readable.push (_stream_readable.js:208:10)
at Inflate.Transform.push (_stream_transform.js:147:32)
at Zlib.callback (zlib.js:474:14)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! offscreen-sample@1.0.0 start: `coffee offscreen_sample.coffee`
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the offscreen-sample@1.0.0 start script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.
npm ERR! A complete log of this run can be found in:
npm ERR! /home/ubuntu/.npm/_logs/2018-08-30T06_39_19_283Z-debug.log
while others such as this example will return and error when creating a shader such as the following:
ubuntu@ubuntu:~/dev/0d79ce3c7384cf6d1bb6$ xvfb-run -s "-ac -screen 0 1280x1024x24" node_modules/.bin/coffee cmd_antialias.coffee -i test_aliased.png -o out.png
THREE.WebGLRenderer 72
THREE.WebGLRenderer: OES_texture_float extension not supported.
THREE.WebGLRenderer: OES_texture_float_linear extension not supported.
THREE.WebGLRenderer: OES_texture_half_float extension not supported.
THREE.WebGLRenderer: OES_texture_half_float_linear extension not supported.
THREE.WebGLRenderer: OES_standard_derivatives extension not supported.
THREE.WebGLRenderer: ANGLE_instanced_arrays extension not supported.
THREE.WebGLRenderer: OES_element_index_uint extension not supported.
THREE.WebGLRenderer: EXT_texture_filter_anisotropic extension not supported.
THREE.WebGLShader: Shader couldn't compile.
THREE.WebGLShader: gl.getShaderInfoLog() vertex 0:2(1): error: syntax error, unexpected NEW_IDENTIFIER
1: precision highp float;
2: precision highp int;
3: #define SHADER_NAME ShaderMaterial
4: #define VERTEX_TEXTURES
5: #define GAMMA_FACTOR 2
6: #define MAX_DIR_LIGHTS 0
7: #define MAX_POINT_LIGHTS 0
8: #define MAX_SPOT_LIGHTS 0
9: #define MAX_HEMI_LIGHTS 0
10: #define MAX_SHADOWS 0
11: #define MAX_BONES 1019
12: uniform mat4 modelMatrix;
13: uniform mat4 modelViewMatrix;
14: uniform mat4 projectionMatrix;
15: uniform mat4 viewMatrix;
16: uniform mat3 normalMatrix;
17: uniform vec3 cameraPosition;
18: attribute vec3 position;
19: attribute vec3 normal;
20: attribute vec2 uv;
21: #ifdef USE_COLOR
22: attribute vec3 color;
23: #endif
24: #ifdef USE_MORPHTARGETS
25: attribute vec3 morphTarget0;
26: attribute vec3 morphTarget1;
27: attribute vec3 morphTarget2;
28: attribute vec3 morphTarget3;
29: #ifdef USE_MORPHNORMALS
30: attribute vec3 morphNormal0;
31: attribute vec3 morphNormal1;
32: attribute vec3 morphNormal2;
33: attribute vec3 morphNormal3;
34: #else
35: attribute vec3 morphTarget4;
36: attribute vec3 morphTarget5;
37: attribute vec3 morphTarget6;
38: attribute vec3 morphTarget7;
39: #endif
40: #endif
41: #ifdef USE_SKINNING
42: attribute vec4 skinIndex;
43: attribute vec4 skinWeight;
44: #endif
45:
46: varying vec2 vUv;
47:
48: void main() {
49: vUv = uv;
50: gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );
51: }
52:
THREE.WebGLShader: Shader couldn't compile.
THREE.WebGLShader: gl.getShaderInfoLog() fragment 0:2(1): error: syntax error, unexpected NEW_IDENTIFIER
1: precision highp float;
2: precision highp int;
3: #define SHADER_NAME ShaderMaterial
4: #define MAX_DIR_LIGHTS 0
5: #define MAX_POINT_LIGHTS 0
6: #define MAX_SPOT_LIGHTS 0
7: #define MAX_HEMI_LIGHTS 0
8: #define MAX_SHADOWS 0
9: #define GAMMA_FACTOR 2
10: uniform mat4 viewMatrix;
11: uniform vec3 cameraPosition;
12:
13:
14: //
15: // Assembled (de-glslify'ed) from https://github.com/mattdesl/glsl-fxaa
16: //
17:
18: #ifndef FXAA_REDUCE_MIN
19: #define FXAA_REDUCE_MIN (1.0/ 128.0)
20: #endif
21: #ifndef FXAA_REDUCE_MUL
22: #define FXAA_REDUCE_MUL (1.0 / 8.0)
23: #endif
24: #ifndef FXAA_SPAN_MAX
25: #define FXAA_SPAN_MAX 8.0
26: #endif
27:
28: // optimized version for mobile, where dependent
29: // texture reads can be a bottleneck
30: vec4 fxaa(sampler2D tex, vec2 fragCoord, vec2 resolution,
31: vec2 v_rgbNW, vec2 v_rgbNE,
32: vec2 v_rgbSW, vec2 v_rgbSE,
33: vec2 v_rgbM) {
34: vec4 color;
35: vec2 inverseVP = vec2(1.0 / resolution.x, 1.0 / resolution.y);
36: vec3 rgbNW = texture2D(tex, v_rgbNW).xyz;
37: vec3 rgbNE = texture2D(tex, v_rgbNE).xyz;
38: vec3 rgbSW = texture2D(tex, v_rgbSW).xyz;
39: vec3 rgbSE = texture2D(tex, v_rgbSE).xyz;
40: vec4 texColor = texture2D(tex, v_rgbM);
41: vec3 rgbM = texColor.xyz;
42: vec3 luma = vec3(0.299, 0.587, 0.114);
43: float lumaNW = dot(rgbNW, luma);
44: float lumaNE = dot(rgbNE, luma);
45: float lumaSW = dot(rgbSW, luma);
46: float lumaSE = dot(rgbSE, luma);
47: float lumaM = dot(rgbM, luma);
48: float lumaMin = min(lumaM, min(min(lumaNW, lumaNE), min(lumaSW, lumaSE)));
49: float lumaMax = max(lumaM, max(max(lumaNW, lumaNE), max(lumaSW, lumaSE)));
50:
51: vec2 dir;
52: dir.x = -((lumaNW + lumaNE) - (lumaSW + lumaSE));
53: dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE));
54:
55: float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) *
56: (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN);
57:
58: float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce);
59: dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX),
60: max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX),
61: dir * rcpDirMin)) * inverseVP;
62:
63: vec3 rgbA = 0.5 * (
64: texture2D(tex, fragCoord * inverseVP + dir * (1.0 / 3.0 - 0.5)).xyz +
65: texture2D(tex, fragCoord * inverseVP + dir * (2.0 / 3.0 - 0.5)).xyz);
66: vec3 rgbB = rgbA * 0.5 + 0.25 * (
67: texture2D(tex, fragCoord * inverseVP + dir * -0.5).xyz +
68: texture2D(tex, fragCoord * inverseVP + dir * 0.5).xyz);
69:
70: float lumaB = dot(rgbB, luma);
71: if ((lumaB < lumaMin) || (lumaB > lumaMax))
72: color = vec4(rgbA, texColor.a);
73: else
74: color = vec4(rgbB, texColor.a);
75: return color;
76: }
77:
78: void texcoords(vec2 fragCoord, vec2 resolution,
79: out vec2 v_rgbNW, out vec2 v_rgbNE,
80: out vec2 v_rgbSW, out vec2 v_rgbSE,
81: out vec2 v_rgbM) {
82: vec2 inverseVP = 1.0 / resolution.xy;
83: v_rgbNW = (fragCoord + vec2(-1.0, -1.0)) * inverseVP;
84: v_rgbNE = (fragCoord + vec2(1.0, -1.0)) * inverseVP;
85: v_rgbSW = (fragCoord + vec2(-1.0, 1.0)) * inverseVP;
86: v_rgbSE = (fragCoord + vec2(1.0, 1.0)) * inverseVP;
87: v_rgbM = vec2(fragCoord * inverseVP);
88: }
89:
90: vec4 apply(sampler2D tex, vec2 fragCoord, vec2 resolution) {
91: vec2 v_rgbNW;
92: vec2 v_rgbNE;
93: vec2 v_rgbSW;
94: vec2 v_rgbSE;
95: vec2 v_rgbM;
96:
97: // compute the texture coords
98: texcoords(fragCoord, resolution,
99: v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
100:
101: // compute FXAA
102: return fxaa(tex, fragCoord, resolution,
103: v_rgbNW, v_rgbNE, v_rgbSW, v_rgbSE, v_rgbM);
104: }
105:
106: uniform vec2 resolution;
107: uniform sampler2D dataTexture;
108: varying vec2 vUv;
109:
110: void main() {
111: vec2 fragCoord = vUv * resolution;
112: gl_FragColor = apply(dataTexture, fragCoord, resolution);
113: }
114:
THREE.WebGLProgram: shader error: 1286 gl.VALIDATE_STATUS false gl.getProgramInfoLog 0:2(1): error: syntax error, unexpected NEW_IDENTIFIER
0:2(1): error: syntax error, unexpected NEW_IDENTIFIER
Image written: out.png
Has anyone been able to render a THREE scene server-side?