Bug in shader with Webgl in Three.js on Mac

Hi!

This is a bugreport in the Freeciv 3D version which uses a custom Webgl shader to render the terrain.

Some users on Mac are reporting a bug that the terrain shader-material is always black, when the shader for the terrain mesh should render the terrain in the correct terrain colour depending on the map tile terrain.
This bug never occur on Chrome on Windows.

https://www.freecivx.net

Shader source code:

Any help is welcome!

Correct rendering looks like this:

From ChatGPT

The issue described—a black terrain shader on Mac while rendering correctly on Chrome on Windows—suggests a potential compatibility problem with the shader code or texture usage. Here’s a checklist to diagnose and fix the issue:

Likely Causes and Fixes:

Precision Issues on Mac:
Macs often have stricter precision requirements in WebGL. Your shader uses highp precision, but some variables or operations might default to lower precision, causing rendering issues.
Fix: Explicitly set precision for all variables, especially vec3 and vec4. For example:
precision mediump float;

Texture Binding and Sampling:
Ensure all sampler2D uniforms (maptiles, borders, etc.) are correctly bound and initialized on the Mac platform.
Fix: Confirm that texture binding follows WebGL conventions and that textures have correct dimensions, formats, and filtering options.

vColor.r Condition:
The condition if (vColor.r == 0.0) renders the fragment black. This might be the default value for vColor on Mac due to uninitialized vertex attributes or differing defaults.
Fix: Ensure vColor is initialized correctly in the vertex shader. Add a fallback color in case vColor is uninitialized:
if (vColor.r == 0.0) {
gl_FragColor.rgb = vec3(0.3, 0.3, 0.3);
return;
}

Texture Coordinate Handling:
The calculations for vUv, dx, and dy may produce invalid or out-of-range texture coordinates on Mac due to rounding differences.
Fix: Clamp texture coordinates explicitly:
vec2 clampedUv = clamp(vUv, 0.0, 1.0);

Shader Compilation Warnings:
Macs may tolerate fewer GLSL warnings or implicit conversions compared to Windows.
Fix: Check the browser console for shader compilation errors or warnings and address them.

Driver or WebGL Implementation:
WebGL implementations differ slightly across platforms. Some functions may behave differently or be unsupported on Mac.
Fix: Ensure your WebGL context is created with compatible settings and test the shader on a known good WebGL implementation (like ANGLE).

Debugging Tips:

Log Shader Variables: Add debug outputs to log intermediate values, especially vColor, terrain_type, and terrain_color.
Simplify the Shader: Temporarily disable complex conditions or textures to isolate the issue.
Fallback Shader: Create a simpler shader for Macs as a fallback if the issue persists.
Example Debugging Output:
Insert temporary debug outputs:
gl_FragColor = vec4(vColor.rgb, 1.0); // Output vColor to check initialization

Testing:

Run the shader in WebGL Inspector or browser developer tools to analyze uniform values and texture bindings.
Test with reduced precision or fewer textures to identify platform-specific limits.
Let me know if you’d like further assistance debugging or simplifying the shader!

I see that the shader works correctly for map tiles which are under the water, those blue tiles. The water is a plane with MeshPhysicalMaterial.

Maybe mixing MeshPhysicalMaterial and this custom shader is the problem.

1 Like

Oooh good detective work!

MeshPhysicalMaterial does a re-render of the scene, to use as a source for the refraction… So this sounds like that secondary render is succeeding when the first pass isn’t. PhysicalMaterial also does a lot of work… So you’re right, it’s totally possible that it’s interacting strangely with the rest of the pipeline.

Those suggestions from GPT are interesting as well.

This specific suggestion stood out to me:

vColor.r Condition:
1 Like