WebGL output:

Expected output (all features ON):

Expected output

Features

Problem description

8 people or so tested my Billiard game. About 50% got perfect graphics. Some people got normal graphics, but no shadows were rendered. One person got no output at all except for the background color. So I set up this test program to narrow down the reason for the errors. The person without graphics also got nothing in this test program, unless vertex normals were disabled. Sometimes, they got the following result, after toggling some options: Groken geometry I have no clue, how this is even possible. AFAICT, all related code parts should affect colors only.

Excerpt: Code parts, that were toggled off

Since unchecking VERTEX_NORMALS above was enough to "fix" the graphics, the error should be somewhere in these sections:

Camera vertex shader

// SHADER CAMERA {...} #if VERTEX_NORMALS attribute vec3 aVertexNormal; #endif {...} #if VERTEX_NORMALS uniform mat4 uNormalMatrix; #endif {...} #if VERTEX_NORMALS varying vec3 vVertexNormal; #endif {...} #if VERTEX_NORMALS vVertexNormal = vec3( uNormalMatrix * vec4( aVertexNormal, 1.0 ) ); #endif

Camera fragment shader

{...} #if VERTEX_NORMALS uniform vec4 uLightPosition; uniform vec4 uLightAmbient; uniform vec4 uLightDiffuse; uniform vec4 uLightSpecular; uniform vec4 uMaterialAmbient; uniform vec4 uMaterialDiffuse; uniform vec4 uMaterialSpecular; uniform float uMaterialShininess; #endif {...} #if VERTEX_NORMALS varying vec3 vVertexNormal; #endif {...} #if VERTEX_NORMALS vec3 normal = normalize( vVertexNormal ); vec3 light = normalize( uLightPosition.xyz - ((uLightPosition.w == 0.0) ? vec3(0,0,0) : vVertexPosition.xyz) ); vec3 view = normalize( -vVertexPosition ); vec3 halfv = normalize( light + view ); vec3 highlight = uLightAmbient.rgb * uMaterialAmbient.rgb; float dotNL = max( dot( normal, light ), 0.0 ); highlight += uLightDiffuse.rgb * uMaterialDiffuse.rgb * dotNL; #if TEXTURE_COORDS highlight *= texel_color.rgb; #endif float dotNH = max( dot( normal, halfv ), 0.0 ); highlight += pow( dotNH, uMaterialShininess ) * uLightSpecular.rgb * uMaterialSpecular.rgb; vec4 highlight_color = vec4( highlight * 1.0, uMaterialDiffuse.a ); #else vec4 highlight_color = vec4( 0, 0, 0, 0 ); #endif {...}

Control program ("renderer")

// BUFFERS {...} if (SETTINGS.SHADER.OPTIONS.VERTEX_NORMALS) { normal_buffer = gl.createBuffer(); gl.bindBuffer( gl.ARRAY_BUFFER, normal_buffer ); gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( data.normals ), gl.STATIC_DRAW ); } {...} if (SETTINGS.SHADER.OPTIONS.VERTEX_NORMALS) { gl.bindBuffer( gl.ARRAY_BUFFER, entity.buffers.normal ); gl.vertexAttribPointer( camera_aloc.vertexNormal, 3, // num_components gl.FLOAT, // type false, // normalize 0, // stride 0, // offset ); gl.enableVertexAttribArray( camera_aloc.vertexNormal ); let normal_matrix = VMath.identity_mat4(); for (let i = 0; i < 3; ++i) { VMath.mat4_rotate( normal_matrix, normal_matrix, AXES[i], self.camera.rotation[i], ); } self.light.rotation = [ 0*self.camera.rotation[0], 0*self.camera.rotation[1], 0*self.camera.rotation[2], ]; for (let i = 0; i < 3; ++i) { VMath.mat4_rotate( normal_matrix, normal_matrix, AXES[i], self.light.rotation[i], ); } if (entity.rotation) { for (let i = 0; i < 3; ++i) { VMath.mat4_rotate( normal_matrix, normal_matrix, AXES[i], entity.rotation[i], ); } } gl.uniformMatrix4fv( camera_uloc.normalMatrix, false, normal_matrix, ); } {...} // entities_scene The full test program is embedded in the source of this very document. Thanks a lot for taking a look at this :)