Three.js: Examples: Problem with webgl_shaders_ocean

Created on 1 Oct 2017  ·  24Comments  ·  Source: mrdoob/three.js

Description of the problem

I've discovered today that the current dev version of webgl_shaders_ocean does not work with Firefox 55.0.2 and Ubuntu 16.04 LTS. The water does not appear and i see some error messages in the browser console.

0:102(109): error: sampler arrays indexed with non-constant expressions are forbidden in GLSL 1.30 and later

And

Integer overflow trying to construct a fake vertex attrib 0 array for a draw-operation with -1 vertices. Try reducing the number of vertices.
Drawing without vertex attrib 0 array enabled forces the browser to do expensive emulation work when running on desktop OpenGL platforms, for example on Mac. It is preferable to always draw with vertex attrib 0 array enabled, by using bindAttribLocation to bind some always-used attribute to location 0.

The problem does not occur with Chromium. Besides, the live version of webgl_shaders_ocean works. So this error probably exists since the latest changes of THREE.Water, see #12167. If i revert the PR, the error does not appear.

/ping @Astrak

Three.js version
  • [X] Dev
  • [ ] r87
  • [ ] ...
Browser
  • [] All of them
  • [ ] Chrome
  • [X] Firefox
  • [ ] Internet Explorer
OS
  • [] All of them
  • [ ] Windows
  • [ ] macOS
  • [X] Linux
  • [ ] Android
  • [ ] iOS
Hardware Requirements (graphics card, VR Device, ...)
Bug

Most helpful comment

This bug is now fixed via #13140. Yay! 🎉 🙌

All 24 comments

I've just run the example in the current dev branch on Debian 9.1 with FF 52.4 and FF 58.0, this did not happen.

The geometries did not change much in the PR, the fragment shader just includes the needed chunks to call getShadowMask().

Does the error message log what is at 0:102(109) ?

Unfortunately not. The logged fragment shader gets cut off after line 27 :unamused:

If i remove the shader chunks in the fragment shader (THREE.Water) and the call of getShadowMask(), the error disappears.

Unfortunately not. The logged fragment shader gets cut off after line 27 😒

apologies for the question, but is there a _[...]_ at the end of the shader log where it gets cut off?

@moraxy Thanks for that advice! When i click on _[...]_, i can see the whole program.
Here is the entire fragment shader:

THREE.WebGLShader: Shader couldn't compile.
THREE.WebGLShader: gl.getShaderInfoLog() fragment 0:2(12): warning: extension `GL_ARB_gpu_shader5' unsupported in fragment shader
0:102(109): error: sampler arrays indexed with non-constant expressions are forbidden in GLSL 1.30 and later
1: precision highp float;
2: precision highp int;
3: #define SHADER_NAME ShaderMaterial
4: #define GAMMA_FACTOR 2
5: #define USE_FOG
6: #define FOG_EXP2
7: #define NUM_CLIPPING_PLANES 0
8: #define UNION_CLIPPING_PLANES 0
9: #define USE_SHADOWMAP
10: #define SHADOWMAP_TYPE_PCF
11: uniform mat4 viewMatrix;
12: uniform vec3 cameraPosition;
13: #define TONE_MAPPING
14: #define saturate(a) clamp( a, 0.0, 1.0 )
15: uniform float toneMappingExposure;
16: uniform float toneMappingWhitePoint;
17: vec3 LinearToneMapping( vec3 color ) {
18:     return toneMappingExposure * color;
19: }
20: vec3 ReinhardToneMapping( vec3 color ) {
21:     color *= toneMappingExposure;
22:     return saturate( color / ( vec3( 1.0 ) + color ) );
23: }
24: #define Uncharted2Helper( x ) max( ( ( x * ( 0.15 * x + 0.10 * 0.50 ) + 0.20 * 0.02 ) / ( x * ( 0.15 * x + 0.50 ) + 0.20 * 0.30 ) ) - 0.02 / 0.30, vec3( 0.0 ) )
25: vec3 Uncharted2ToneMapping( vec3 color ) {
26:     color *= toneMappingExposure;
27:     return saturate( Uncharted2Helper( color ) / Uncharted2Helper( vec3( toneMappingWhitePoint ) ) );
28: }
29: vec3 OptimizedCineonToneMapping( vec3 color ) {
30:     color *= toneMappingExposure;
31:     color = max( vec3( 0.0 ), color - 0.004 );
32:     return pow( ( color * ( 6.2 * color + 0.5 ) ) / ( color * ( 6.2 * color + 1.7 ) + 0.06 ), vec3( 2.2 ) );
33: }
34: 
35: vec3 toneMapping( vec3 color ) { return LinearToneMapping( color ); }
36: 
37: vec4 LinearToLinear( in vec4 value ) {
38:     return value;
39: }
40: vec4 GammaToLinear( in vec4 value, in float gammaFactor ) {
41:     return vec4( pow( value.xyz, vec3( gammaFactor ) ), value.w );
42: }
43: vec4 LinearToGamma( in vec4 value, in float gammaFactor ) {
44:     return vec4( pow( value.xyz, vec3( 1.0 / gammaFactor ) ), value.w );
45: }
46: vec4 sRGBToLinear( in vec4 value ) {
47:     return vec4( mix( pow( value.rgb * 0.9478672986 + vec3( 0.0521327014 ), vec3( 2.4 ) ), value.rgb * 0.0773993808, vec3( lessThanEqual( value.rgb, vec3( 0.04045 ) ) ) ), value.w );
48: }
49: vec4 LinearTosRGB( in vec4 value ) {
50:     return vec4( mix( pow( value.rgb, vec3( 0.41666 ) ) * 1.055 - vec3( 0.055 ), value.rgb * 12.92, vec3( lessThanEqual( value.rgb, vec3( 0.0031308 ) ) ) ), value.w );
51: }
52: vec4 RGBEToLinear( in vec4 value ) {
53:     return vec4( value.rgb * exp2( value.a * 255.0 - 128.0 ), 1.0 );
54: }
55: vec4 LinearToRGBE( in vec4 value ) {
56:     float maxComponent = max( max( value.r, value.g ), value.b );
57:     float fExp = clamp( ceil( log2( maxComponent ) ), -128.0, 127.0 );
58:     return vec4( value.rgb / exp2( fExp ), ( fExp + 128.0 ) / 255.0 );
59: }
60: vec4 RGBMToLinear( in vec4 value, in float maxRange ) {
61:     return vec4( value.xyz * value.w * maxRange, 1.0 );
62: }
63: vec4 LinearToRGBM( in vec4 value, in float maxRange ) {
64:     float maxRGB = max( value.x, max( value.g, value.b ) );
65:     float M      = clamp( maxRGB / maxRange, 0.0, 1.0 );
66:     M            = ceil( M * 255.0 ) / 255.0;
67:     return vec4( value.rgb / ( M * maxRange ), M );
68: }
69: vec4 RGBDToLinear( in vec4 value, in float maxRange ) {
70:     return vec4( value.rgb * ( ( maxRange / 255.0 ) / value.a ), 1.0 );
71: }
72: vec4 LinearToRGBD( in vec4 value, in float maxRange ) {
73:     float maxRGB = max( value.x, max( value.g, value.b ) );
74:     float D      = max( maxRange / maxRGB, 1.0 );
75:     D            = min( floor( D ) / 255.0, 1.0 );
76:     return vec4( value.rgb * ( D * ( 255.0 / maxRange ) ), D );
77: }
78: const mat3 cLogLuvM = mat3( 0.2209, 0.3390, 0.4184, 0.1138, 0.6780, 0.7319, 0.0102, 0.1130, 0.2969 );
79: vec4 LinearToLogLuv( in vec4 value )  {
80:     vec3 Xp_Y_XYZp = value.rgb * cLogLuvM;
81:     Xp_Y_XYZp = max(Xp_Y_XYZp, vec3(1e-6, 1e-6, 1e-6));
82:     vec4 vResult;
83:     vResult.xy = Xp_Y_XYZp.xy / Xp_Y_XYZp.z;
84:     float Le = 2.0 * log2(Xp_Y_XYZp.y) + 127.0;
85:     vResult.w = fract(Le);
86:     vResult.z = (Le - (floor(vResult.w*255.0))/255.0)/255.0;
87:     return vResult;
88: }
89: const mat3 cLogLuvInverseM = mat3( 6.0014, -2.7008, -1.7996, -1.3320, 3.1029, -5.7721, 0.3008, -1.0882, 5.6268 );
90: vec4 LogLuvToLinear( in vec4 value ) {
91:     float Le = value.z * 255.0 + value.w;
92:     vec3 Xp_Y_XYZp;
93:     Xp_Y_XYZp.y = exp2((Le - 127.0) / 2.0);
94:     Xp_Y_XYZp.z = Xp_Y_XYZp.y / value.y;
95:     Xp_Y_XYZp.x = value.x * Xp_Y_XYZp.z;
96:     vec3 vRGB = Xp_Y_XYZp.rgb * cLogLuvInverseM;
97:     return vec4( max(vRGB, 0.0), 1.0 );
98: }
99: 
100: vec4 mapTexelToLinear( vec4 value ) { return LinearToLinear( value ); }
101: vec4 envMapTexelToLinear( vec4 value ) { return LinearToLinear( value ); }
102: vec4 emissiveMapTexelToLinear( vec4 value ) { return LinearToLinear( value ); }
103: vec4 linearToOutputTexel( vec4 value ) { return LinearToLinear( value ); }
104: 
105: uniform sampler2D mirrorSampler;
106: uniform float alpha;
107: uniform float time;
108: uniform float size;
109: uniform float distortionScale;
110: uniform sampler2D normalSampler;
111: uniform vec3 sunColor;
112: uniform vec3 sunDirection;
113: uniform vec3 eye;
114: uniform vec3 waterColor;
115: varying vec4 mirrorCoord;
116: varying vec4 worldPosition;
117: vec4 getNoise( vec2 uv ) {
118:    vec2 uv0 = ( uv / 103.0 ) + vec2(time / 17.0, time / 29.0);
119:    vec2 uv1 = uv / 107.0-vec2( time / -19.0, time / 31.0 );
120:    vec2 uv2 = uv / vec2( 8907.0, 9803.0 ) + vec2( time / 101.0, time / 97.0 );
121:    vec2 uv3 = uv / vec2( 1091.0, 1027.0 ) - vec2( time / 109.0, time / -113.0 );
122:    vec4 noise = texture2D( normalSampler, uv0 ) +
123:        texture2D( normalSampler, uv1 ) +
124:        texture2D( normalSampler, uv2 ) +
125:        texture2D( normalSampler, uv3 );
126:    return noise * 0.5 - 1.0;
127: }
128: void sunLight( const vec3 surfaceNormal, const vec3 eyeDirection, float shiny, float spec, float diffuse, inout vec3 diffuseColor, inout vec3 specularColor ) {
129:    vec3 reflection = normalize( reflect( -sunDirection, surfaceNormal ) );
130:    float direction = max( 0.0, dot( eyeDirection, reflection ) );
131:    specularColor += pow( direction, shiny ) * sunColor * spec;
132:    diffuseColor += max( dot( sunDirection, surfaceNormal ), 0.0 ) * sunColor * diffuse;
133: }
134: #define PI 3.14159265359
135: #define PI2 6.28318530718
136: #define PI_HALF 1.5707963267949
137: #define RECIPROCAL_PI 0.31830988618
138: #define RECIPROCAL_PI2 0.15915494
139: #define LOG2 1.442695
140: #define EPSILON 1e-6
141: #define saturate(a) clamp( a, 0.0, 1.0 )
142: #define whiteCompliment(a) ( 1.0 - saturate( a ) )
143: float pow2( const in float x ) { return x*x; }
144: float pow3( const in float x ) { return x*x*x; }
145: float pow4( const in float x ) { float x2 = x*x; return x2*x2; }
146: float average( const in vec3 color ) { return dot( color, vec3( 0.3333 ) ); }
147: highp float rand( const in vec2 uv ) {
148:    const highp float a = 12.9898, b = 78.233, c = 43758.5453;
149:    highp float dt = dot( uv.xy, vec2( a,b ) ), sn = mod( dt, PI );
150:    return fract(sin(sn) * c);
151: }
152: struct IncidentLight {
153:    vec3 color;
154:    vec3 direction;
155:    bool visible;
156: };
157: struct ReflectedLight {
158:    vec3 directDiffuse;
159:    vec3 directSpecular;
160:    vec3 indirectDiffuse;
161:    vec3 indirectSpecular;
162: };
163: struct GeometricContext {
164:    vec3 position;
165:    vec3 normal;
166:    vec3 viewDir;
167: };
168: vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
169:    return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
170: }
171: vec3 inverseTransformDirection( in vec3 dir, in mat4 matrix ) {
172:    return normalize( ( vec4( dir, 0.0 ) * matrix ).xyz );
173: }
174: vec3 projectOnPlane(in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {
175:    float distance = dot( planeNormal, point - pointOnPlane );
176:    return - distance * planeNormal + point;
177: }
178: float sideOfPlane( in vec3 point, in vec3 pointOnPlane, in vec3 planeNormal ) {
179:    return sign( dot( point - pointOnPlane, planeNormal ) );
180: }
181: vec3 linePlaneIntersect( in vec3 pointOnLine, in vec3 lineDirection, in vec3 pointOnPlane, in vec3 planeNormal ) {
182:    return lineDirection * ( dot( planeNormal, pointOnPlane - pointOnLine ) / dot( planeNormal, lineDirection ) ) + pointOnLine;
183: }
184: mat3 transposeMat3( const in mat3 m ) {
185:    mat3 tmp;
186:    tmp[ 0 ] = vec3( m[ 0 ].x, m[ 1 ].x, m[ 2 ].x );
187:    tmp[ 1 ] = vec3( m[ 0 ].y, m[ 1 ].y, m[ 2 ].y );
188:    tmp[ 2 ] = vec3( m[ 0 ].z, m[ 1 ].z, m[ 2 ].z );
189:    return tmp;
190: }
191: float linearToRelativeLuminance( const in vec3 color ) {
192:    vec3 weights = vec3( 0.2126, 0.7152, 0.0722 );
193:    return dot( weights, color.rgb );
194: }
195: 
196: vec3 packNormalToRGB( const in vec3 normal ) {
197:    return normalize( normal ) * 0.5 + 0.5;
198: }
199: vec3 unpackRGBToNormal( const in vec3 rgb ) {
200:    return 2.0 * rgb.xyz - 1.0;
201: }
202: const float PackUpscale = 256. / 255.;const float UnpackDownscale = 255. / 256.;
203: const vec3 PackFactors = vec3( 256. * 256. * 256., 256. * 256.,  256. );
204: const vec4 UnpackFactors = UnpackDownscale / vec4( PackFactors, 1. );
205: const float ShiftRight8 = 1. / 256.;
206: vec4 packDepthToRGBA( const in float v ) {
207:    vec4 r = vec4( fract( v * PackFactors ), v );
208:    r.yzw -= r.xyz * ShiftRight8;   return r * PackUpscale;
209: }
210: float unpackRGBAToDepth( const in vec4 v ) {
211:    return dot( v, UnpackFactors );
212: }
213: float viewZToOrthographicDepth( const in float viewZ, const in float near, const in float far ) {
214:    return ( viewZ + near ) / ( near - far );
215: }
216: float orthographicDepthToViewZ( const in float linearClipZ, const in float near, const in float far ) {
217:    return linearClipZ * ( near - far ) - near;
218: }
219: float viewZToPerspectiveDepth( const in float viewZ, const in float near, const in float far ) {
220:    return (( near + viewZ ) * far ) / (( far - near ) * viewZ );
221: }
222: float perspectiveDepthToViewZ( const in float invClipZ, const in float near, const in float far ) {
223:    return ( near * far ) / ( ( far - near ) * invClipZ - far );
224: }
225: 
226: float punctualLightIntensityToIrradianceFactor( const in float lightDistance, const in float cutoffDistance, const in float decayExponent ) {
227:    if( decayExponent > 0.0 ) {
228: #if defined ( PHYSICALLY_CORRECT_LIGHTS )
229:        float distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );
230:        float maxDistanceCutoffFactor = pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );
231:        return distanceFalloff * maxDistanceCutoffFactor;
232: #else
233:        return pow( saturate( -lightDistance / cutoffDistance + 1.0 ), decayExponent );
234: #endif
235:    }
236:    return 1.0;
237: }
238: vec3 BRDF_Diffuse_Lambert( const in vec3 diffuseColor ) {
239:    return RECIPROCAL_PI * diffuseColor;
240: }
241: vec3 F_Schlick( const in vec3 specularColor, const in float dotLH ) {
242:    float fresnel = exp2( ( -5.55473 * dotLH - 6.98316 ) * dotLH );
243:    return ( 1.0 - specularColor ) * fresnel + specularColor;
244: }
245: float G_GGX_Smith( const in float alpha, const in float dotNL, const in float dotNV ) {
246:    float a2 = pow2( alpha );
247:    float gl = dotNL + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );
248:    float gv = dotNV + sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );
249:    return 1.0 / ( gl * gv );
250: }
251: float G_GGX_SmithCorrelated( const in float alpha, const in float dotNL, const in float dotNV ) {
252:    float a2 = pow2( alpha );
253:    float gv = dotNL * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNV ) );
254:    float gl = dotNV * sqrt( a2 + ( 1.0 - a2 ) * pow2( dotNL ) );
255:    return 0.5 / max( gv + gl, EPSILON );
256: }
257: float D_GGX( const in float alpha, const in float dotNH ) {
258:    float a2 = pow2( alpha );
259:    float denom = pow2( dotNH ) * ( a2 - 1.0 ) + 1.0;
260:    return RECIPROCAL_PI * a2 / pow2( denom );
261: }
262: vec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {
263:    float alpha = pow2( roughness );
264:    vec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );
265:    float dotNL = saturate( dot( geometry.normal, incidentLight.direction ) );
266:    float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );
267:    float dotNH = saturate( dot( geometry.normal, halfDir ) );
268:    float dotLH = saturate( dot( incidentLight.direction, halfDir ) );
269:    vec3 F = F_Schlick( specularColor, dotLH );
270:    float G = G_GGX_SmithCorrelated( alpha, dotNL, dotNV );
271:    float D = D_GGX( alpha, dotNH );
272:    return F * ( G * D );
273: }
274: vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {
275:    const float LUT_SIZE  = 64.0;
276:    const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;
277:    const float LUT_BIAS  = 0.5 / LUT_SIZE;
278:    float theta = acos( dot( N, V ) );
279:    vec2 uv = vec2(
280:        sqrt( saturate( roughness ) ),
281:        saturate( theta / ( 0.5 * PI ) ) );
282:    uv = uv * LUT_SCALE + LUT_BIAS;
283:    return uv;
284: }
285: float LTC_ClippedSphereFormFactor( const in vec3 f ) {
286:    float l = length( f );
287:    return max( ( l * l + f.z ) / ( l + 1.0 ), 0.0 );
288: }
289: vec3 LTC_EdgeVectorFormFactor( const in vec3 v1, const in vec3 v2 ) {
290:    float x = dot( v1, v2 );
291:    float y = abs( x );
292:    float a = 0.86267 + (0.49788 + 0.01436 * y ) * y;
293:    float b = 3.45068 + (4.18814 + y) * y;
294:    float v = a / b;
295:    float theta_sintheta = (x > 0.0) ? v : 0.5 * inversesqrt( 1.0 - x * x ) - v;
296:    return cross( v1, v2 ) * theta_sintheta;
297: }
298: vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in mat3 mInv, const in vec3 rectCoords[ 4 ] ) {
299:    vec3 v1 = rectCoords[ 1 ] - rectCoords[ 0 ];
300:    vec3 v2 = rectCoords[ 3 ] - rectCoords[ 0 ];
301:    vec3 lightNormal = cross( v1, v2 );
302:    if( dot( lightNormal, P - rectCoords[ 0 ] ) < 0.0 ) return vec3( 0.0 );
303:    vec3 T1, T2;
304:    T1 = normalize( V - N * dot( V, N ) );
305:    T2 = - cross( N, T1 );
306:    mat3 mat = mInv * transposeMat3( mat3( T1, T2, N ) );
307:    vec3 coords[ 4 ];
308:    coords[ 0 ] = mat * ( rectCoords[ 0 ] - P );
309:    coords[ 1 ] = mat * ( rectCoords[ 1 ] - P );
310:    coords[ 2 ] = mat * ( rectCoords[ 2 ] - P );
311:    coords[ 3 ] = mat * ( rectCoords[ 3 ] - P );
312:    coords[ 0 ] = normalize( coords[ 0 ] );
313:    coords[ 1 ] = normalize( coords[ 1 ] );
314:    coords[ 2 ] = normalize( coords[ 2 ] );
315:    coords[ 3 ] = normalize( coords[ 3 ] );
316:    vec3 vectorFormFactor = vec3( 0.0 );
317:    vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 0 ], coords[ 1 ] );
318:    vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 1 ], coords[ 2 ] );
319:    vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 2 ], coords[ 3 ] );
320:    vectorFormFactor += LTC_EdgeVectorFormFactor( coords[ 3 ], coords[ 0 ] );
321:    vec3 result = vec3( LTC_ClippedSphereFormFactor( vectorFormFactor ) );
322:    return result;
323: }
324: vec3 BRDF_Specular_GGX_Environment( const in GeometricContext geometry, const in vec3 specularColor, const in float roughness ) {
325:    float dotNV = saturate( dot( geometry.normal, geometry.viewDir ) );
326:    const vec4 c0 = vec4( - 1, - 0.0275, - 0.572, 0.022 );
327:    const vec4 c1 = vec4( 1, 0.0425, 1.04, - 0.04 );
328:    vec4 r = roughness * c0 + c1;
329:    float a004 = min( r.x * r.x, exp2( - 9.28 * dotNV ) ) * r.x + r.y;
330:    vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
331:    return specularColor * AB.x + AB.y;
332: }
333: float G_BlinnPhong_Implicit( ) {
334:    return 0.25;
335: }
336: float D_BlinnPhong( const in float shininess, const in float dotNH ) {
337:    return RECIPROCAL_PI * ( shininess * 0.5 + 1.0 ) * pow( dotNH, shininess );
338: }
339: vec3 BRDF_Specular_BlinnPhong( const in IncidentLight incidentLight, const in GeometricContext geometry, const in vec3 specularColor, const in float shininess ) {
340:    vec3 halfDir = normalize( incidentLight.direction + geometry.viewDir );
341:    float dotNH = saturate( dot( geometry.normal, halfDir ) );
342:    float dotLH = saturate( dot( incidentLight.direction, halfDir ) );
343:    vec3 F = F_Schlick( specularColor, dotLH );
344:    float G = G_BlinnPhong_Implicit( );
345:    float D = D_BlinnPhong( shininess, dotNH );
346:    return F * ( G * D );
347: }
348: float GGXRoughnessToBlinnExponent( const in float ggxRoughness ) {
349:    return ( 2.0 / pow2( ggxRoughness + 0.0001 ) - 2.0 );
350: }
351: float BlinnExponentToGGXRoughness( const in float blinnExponent ) {
352:    return sqrt( 2.0 / ( blinnExponent + 2.0 ) );
353: }
354: 
355: #ifdef USE_FOG
356:    uniform vec3 fogColor;
357:    varying float fogDepth;
358:    #ifdef FOG_EXP2
359:        uniform float fogDensity;
360:    #else
361:        uniform float fogNear;
362:        uniform float fogFar;
363:    #endif
364: #endif
365: 
366: uniform vec3 ambientLightColor;
367: vec3 getAmbientLightIrradiance( const in vec3 ambientLightColor ) {
368:    vec3 irradiance = ambientLightColor;
369:    #ifndef PHYSICALLY_CORRECT_LIGHTS
370:        irradiance *= PI;
371:    #endif
372:    return irradiance;
373: }
374: #if 1 > 0
375:    struct DirectionalLight {
376:        vec3 direction;
377:        vec3 color;
378:        int shadow;
379:        float shadowBias;
380:        float shadowRadius;
381:        vec2 shadowMapSize;
382:    };
383:    uniform DirectionalLight directionalLights[ 1 ];
384:    void getDirectionalDirectLightIrradiance( const in DirectionalLight directionalLight, const in GeometricContext geometry, out IncidentLight directLight ) {
385:        directLight.color = directionalLight.color;
386:        directLight.direction = directionalLight.direction;
387:        directLight.visible = true;
388:    }
389: #endif
390: #if 0 > 0
391:    struct PointLight {
392:        vec3 position;
393:        vec3 color;
394:        float distance;
395:        float decay;
396:        int shadow;
397:        float shadowBias;
398:        float shadowRadius;
399:        vec2 shadowMapSize;
400:        float shadowCameraNear;
401:        float shadowCameraFar;
402:    };
403:    uniform PointLight pointLights[ 0 ];
404:    void getPointDirectLightIrradiance( const in PointLight pointLight, const in GeometricContext geometry, out IncidentLight directLight ) {
405:        vec3 lVector = pointLight.position - geometry.position;
406:        directLight.direction = normalize( lVector );
407:        float lightDistance = length( lVector );
408:        directLight.color = pointLight.color;
409:        directLight.color *= punctualLightIntensityToIrradianceFactor( lightDistance, pointLight.distance, pointLight.decay );
410:        directLight.visible = ( directLight.color != vec3( 0.0 ) );
411:    }
412: #endif
413: #if 0 > 0
414:    struct SpotLight {
415:        vec3 position;
416:        vec3 direction;
417:        vec3 color;
418:        float distance;
419:        float decay;
420:        float coneCos;
421:        float penumbraCos;
422:        int shadow;
423:        float shadowBias;
424:        float shadowRadius;
425:        vec2 shadowMapSize;
426:    };
427:    uniform SpotLight spotLights[ 0 ];
428:    void getSpotDirectLightIrradiance( const in SpotLight spotLight, const in GeometricContext geometry, out IncidentLight directLight  ) {
429:        vec3 lVector = spotLight.position - geometry.position;
430:        directLight.direction = normalize( lVector );
431:        float lightDistance = length( lVector );
432:        float angleCos = dot( directLight.direction, spotLight.direction );
433:        if ( angleCos > spotLight.coneCos ) {
434:            float spotEffect = smoothstep( spotLight.coneCos, spotLight.penumbraCos, angleCos );
435:            directLight.color = spotLight.color;
436:            directLight.color *= spotEffect * punctualLightIntensityToIrradianceFactor( lightDistance, spotLight.distance, spotLight.decay );
437:            directLight.visible = true;
438:        } else {
439:            directLight.color = vec3( 0.0 );
440:            directLight.visible = false;
441:        }
442:    }
443: #endif
444: #if 0 > 0
445:    struct RectAreaLight {
446:        vec3 color;
447:        vec3 position;
448:        vec3 halfWidth;
449:        vec3 halfHeight;
450:    };
451:    uniform sampler2D ltcMat;   uniform sampler2D ltcMag;
452:    uniform RectAreaLight rectAreaLights[ 0 ];
453: #endif
454: #if 0 > 0
455:    struct HemisphereLight {
456:        vec3 direction;
457:        vec3 skyColor;
458:        vec3 groundColor;
459:    };
460:    uniform HemisphereLight hemisphereLights[ 0 ];
461:    vec3 getHemisphereLightIrradiance( const in HemisphereLight hemiLight, const in GeometricContext geometry ) {
462:        float dotNL = dot( geometry.normal, hemiLight.direction );
463:        float hemiDiffuseWeight = 0.5 * dotNL + 0.5;
464:        vec3 irradiance = mix( hemiLight.groundColor, hemiLight.skyColor, hemiDiffuseWeight );
465:        #ifndef PHYSICALLY_CORRECT_LIGHTS
466:            irradiance *= PI;
467:        #endif
468:        return irradiance;
469:    }
470: #endif
471: #if defined( USE_ENVMAP ) && defined( PHYSICAL )
472:    vec3 getLightProbeIndirectIrradiance( const in GeometricContext geometry, const in int maxMIPLevel ) {
473:        vec3 worldNormal = inverseTransformDirection( geometry.normal, viewMatrix );
474:        #ifdef ENVMAP_TYPE_CUBE
475:            vec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );
476:            #ifdef TEXTURE_LOD_EXT
477:                vec4 envMapColor = textureCubeLodEXT( envMap, queryVec, float( maxMIPLevel ) );
478:            #else
479:                vec4 envMapColor = textureCube( envMap, queryVec, float( maxMIPLevel ) );
480:            #endif
481:            envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;
482:        #elif defined( ENVMAP_TYPE_CUBE_UV )
483:            vec3 queryVec = vec3( flipEnvMap * worldNormal.x, worldNormal.yz );
484:            vec4 envMapColor = textureCubeUV( queryVec, 1.0 );
485:        #else
486:            vec4 envMapColor = vec4( 0.0 );
487:        #endif
488:        return PI * envMapColor.rgb * envMapIntensity;
489:    }
490:    float getSpecularMIPLevel( const in float blinnShininessExponent, const in int maxMIPLevel ) {
491:        float maxMIPLevelScalar = float( maxMIPLevel );
492:        float desiredMIPLevel = maxMIPLevelScalar + 0.79248 - 0.5 * log2( pow2( blinnShininessExponent ) + 1.0 );
493:        return clamp( desiredMIPLevel, 0.0, maxMIPLevelScalar );
494:    }
495:    vec3 getLightProbeIndirectRadiance( const in GeometricContext geometry, const in float blinnShininessExponent, const in int maxMIPLevel ) {
496:        #ifdef ENVMAP_MODE_REFLECTION
497:            vec3 reflectVec = reflect( -geometry.viewDir, geometry.normal );
498:        #else
499:            vec3 reflectVec = refract( -geometry.viewDir, geometry.normal, refractionRatio );
500:        #endif
501:        reflectVec = inverseTransformDirection( reflectVec, viewMatrix );
502:        float specularMIPLevel = getSpecularMIPLevel( blinnShininessExponent, maxMIPLevel );
503:        #ifdef ENVMAP_TYPE_CUBE
504:            vec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );
505:            #ifdef TEXTURE_LOD_EXT
506:                vec4 envMapColor = textureCubeLodEXT( envMap, queryReflectVec, specularMIPLevel );
507:            #else
508:                vec4 envMapColor = textureCube( envMap, queryReflectVec, specularMIPLevel );
509:            #endif
510:            envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;
511:        #elif defined( ENVMAP_TYPE_CUBE_UV )
512:            vec3 queryReflectVec = vec3( flipEnvMap * reflectVec.x, reflectVec.yz );
513:            vec4 envMapColor = textureCubeUV(queryReflectVec, BlinnExponentToGGXRoughness(blinnShininessExponent));
514:        #elif defined( ENVMAP_TYPE_EQUIREC )
515:            vec2 sampleUV;
516:            sampleUV.y = asin( clamp( reflectVec.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5;
517:            sampleUV.x = atan( reflectVec.z, reflectVec.x ) * RECIPROCAL_PI2 + 0.5;
518:            #ifdef TEXTURE_LOD_EXT
519:                vec4 envMapColor = texture2DLodEXT( envMap, sampleUV, specularMIPLevel );
520:            #else
521:                vec4 envMapColor = texture2D( envMap, sampleUV, specularMIPLevel );
522:            #endif
523:            envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;
524:        #elif defined( ENVMAP_TYPE_SPHERE )
525:            vec3 reflectView = normalize( ( viewMatrix * vec4( reflectVec, 0.0 ) ).xyz + vec3( 0.0,0.0,1.0 ) );
526:            #ifdef TEXTURE_LOD_EXT
527:                vec4 envMapColor = texture2DLodEXT( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );
528:            #else
529:                vec4 envMapColor = texture2D( envMap, reflectView.xy * 0.5 + 0.5, specularMIPLevel );
530:            #endif
531:            envMapColor.rgb = envMapTexelToLinear( envMapColor ).rgb;
532:        #endif
533:        return envMapColor.rgb * envMapIntensity;
534:    }
535: #endif
536: 
537: #ifdef USE_SHADOWMAP
538:    #if 1 > 0
539:        uniform sampler2D directionalShadowMap[ 1 ];
540:        varying vec4 vDirectionalShadowCoord[ 1 ];
541:    #endif
542:    #if 0 > 0
543:        uniform sampler2D spotShadowMap[ 0 ];
544:        varying vec4 vSpotShadowCoord[ 0 ];
545:    #endif
546:    #if 0 > 0
547:        uniform sampler2D pointShadowMap[ 0 ];
548:        varying vec4 vPointShadowCoord[ 0 ];
549:    #endif
550:    float texture2DCompare( sampler2D depths, vec2 uv, float compare ) {
551:        return step( compare, unpackRGBAToDepth( texture2D( depths, uv ) ) );
552:    }
553:    float texture2DShadowLerp( sampler2D depths, vec2 size, vec2 uv, float compare ) {
554:        const vec2 offset = vec2( 0.0, 1.0 );
555:        vec2 texelSize = vec2( 1.0 ) / size;
556:        vec2 centroidUV = floor( uv * size + 0.5 ) / size;
557:        float lb = texture2DCompare( depths, centroidUV + texelSize * offset.xx, compare );
558:        float lt = texture2DCompare( depths, centroidUV + texelSize * offset.xy, compare );
559:        float rb = texture2DCompare( depths, centroidUV + texelSize * offset.yx, compare );
560:        float rt = texture2DCompare( depths, centroidUV + texelSize * offset.yy, compare );
561:        vec2 f = fract( uv * size + 0.5 );
562:        float a = mix( lb, lt, f.y );
563:        float b = mix( rb, rt, f.y );
564:        float c = mix( a, b, f.x );
565:        return c;
566:    }
567:    float getShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord ) {
568:        float shadow = 1.0;
569:        shadowCoord.xyz /= shadowCoord.w;
570:        shadowCoord.z += shadowBias;
571:        bvec4 inFrustumVec = bvec4 ( shadowCoord.x >= 0.0, shadowCoord.x <= 1.0, shadowCoord.y >= 0.0, shadowCoord.y <= 1.0 );
572:        bool inFrustum = all( inFrustumVec );
573:        bvec2 frustumTestVec = bvec2( inFrustum, shadowCoord.z <= 1.0 );
574:        bool frustumTest = all( frustumTestVec );
575:        if ( frustumTest ) {
576:        #if defined( SHADOWMAP_TYPE_PCF )
577:            vec2 texelSize = vec2( 1.0 ) / shadowMapSize;
578:            float dx0 = - texelSize.x * shadowRadius;
579:            float dy0 = - texelSize.y * shadowRadius;
580:            float dx1 = + texelSize.x * shadowRadius;
581:            float dy1 = + texelSize.y * shadowRadius;
582:            shadow = (
583:                texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +
584:                texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +
585:                texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +
586:                texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +
587:                texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z ) +
588:                texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +
589:                texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +
590:                texture2DCompare( shadowMap, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +
591:                texture2DCompare( shadowMap, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )
592:            ) * ( 1.0 / 9.0 );
593:        #elif defined( SHADOWMAP_TYPE_PCF_SOFT )
594:            vec2 texelSize = vec2( 1.0 ) / shadowMapSize;
595:            float dx0 = - texelSize.x * shadowRadius;
596:            float dy0 = - texelSize.y * shadowRadius;
597:            float dx1 = + texelSize.x * shadowRadius;
598:            float dy1 = + texelSize.y * shadowRadius;
599:            shadow = (
600:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy0 ), shadowCoord.z ) +
601:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy0 ), shadowCoord.z ) +
602:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy0 ), shadowCoord.z ) +
603:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, 0.0 ), shadowCoord.z ) +
604:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy, shadowCoord.z ) +
605:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, 0.0 ), shadowCoord.z ) +
606:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx0, dy1 ), shadowCoord.z ) +
607:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( 0.0, dy1 ), shadowCoord.z ) +
608:                texture2DShadowLerp( shadowMap, shadowMapSize, shadowCoord.xy + vec2( dx1, dy1 ), shadowCoord.z )
609:            ) * ( 1.0 / 9.0 );
610:        #else
611:            shadow = texture2DCompare( shadowMap, shadowCoord.xy, shadowCoord.z );
612:        #endif
613:        }
614:        return shadow;
615:    }
616:    vec2 cubeToUV( vec3 v, float texelSizeY ) {
617:        vec3 absV = abs( v );
618:        float scaleToCube = 1.0 / max( absV.x, max( absV.y, absV.z ) );
619:        absV *= scaleToCube;
620:        v *= scaleToCube * ( 1.0 - 2.0 * texelSizeY );
621:        vec2 planar = v.xy;
622:        float almostATexel = 1.5 * texelSizeY;
623:        float almostOne = 1.0 - almostATexel;
624:        if ( absV.z >= almostOne ) {
625:            if ( v.z > 0.0 )
626:                planar.x = 4.0 - v.x;
627:        } else if ( absV.x >= almostOne ) {
628:            float signX = sign( v.x );
629:            planar.x = v.z * signX + 2.0 * signX;
630:        } else if ( absV.y >= almostOne ) {
631:            float signY = sign( v.y );
632:            planar.x = v.x + 2.0 * signY + 2.0;
633:            planar.y = v.z * signY - 2.0;
634:        }
635:        return vec2( 0.125, 0.25 ) * planar + vec2( 0.375, 0.75 );
636:    }
637:    float getPointShadow( sampler2D shadowMap, vec2 shadowMapSize, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {
638:        vec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );
639:        vec3 lightToPosition = shadowCoord.xyz;
640:        float dp = ( length( lightToPosition ) - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );       dp += shadowBias;
641:        vec3 bd3D = normalize( lightToPosition );
642:        #if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT )
643:            vec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;
644:            return (
645:                texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +
646:                texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +
647:                texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +
648:                texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +
649:                texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +
650:                texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +
651:                texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +
652:                texture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +
653:                texture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )
654:            ) * ( 1.0 / 9.0 );
655:        #else
656:            return texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );
657:        #endif
658:    }
659: #endif
660: 
661: float getShadowMask() {
662:    float shadow = 1.0;
663:    #ifdef USE_SHADOWMAP
664:    #if 1 > 0
665:    DirectionalLight directionalLight;
666:    for ( int i = 0; i < 1; i ++ ) {
667:        directionalLight = directionalLights[ i ];
668:        shadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;
669:    }
670:    #endif
671:    #if 0 > 0
672:    SpotLight spotLight;
673:    for ( int i = 0; i < 0; i ++ ) {
674:        spotLight = spotLights[ i ];
675:        shadow *= bool( spotLight.shadow ) ? getShadow( spotShadowMap[ i ], spotLight.shadowMapSize, spotLight.shadowBias, spotLight.shadowRadius, vSpotShadowCoord[ i ] ) : 1.0;
676:    }
677:    #endif
678:    #if 0 > 0
679:    PointLight pointLight;
680:    for ( int i = 0; i < 0; i ++ ) {
681:        pointLight = pointLights[ i ];
682:        shadow *= bool( pointLight.shadow ) ? getPointShadow( pointShadowMap[ i ], pointLight.shadowMapSize, pointLight.shadowBias, pointLight.shadowRadius, vPointShadowCoord[ i ], pointLight.shadowCameraNear, pointLight.shadowCameraFar ) : 1.0;
683:    }
684:    #endif
685:    #endif
686:    return shadow;
687: }
688: 
689: void main() {
690:    vec4 noise = getNoise( worldPosition.xz * size );
691:    vec3 surfaceNormal = normalize( noise.xzy * vec3( 1.5, 1.0, 1.5 ) );
692:    vec3 diffuseLight = vec3(0.0);
693:    vec3 specularLight = vec3(0.0);
694:    vec3 worldToEye = eye-worldPosition.xyz;
695:    vec3 eyeDirection = normalize( worldToEye );
696:    sunLight( surfaceNormal, eyeDirection, 100.0, 2.0, 0.5, diffuseLight, specularLight );
697:    float distance = length(worldToEye);
698:    vec2 distortion = surfaceNormal.xz * ( 0.001 + 1.0 / distance ) * distortionScale;
699:    vec3 reflectionSample = vec3( texture2D( mirrorSampler, mirrorCoord.xy / mirrorCoord.z + distortion ) );
700:    float theta = max( dot( eyeDirection, surfaceNormal ), 0.0 );
701:    float rf0 = 0.3;
702:    float reflectance = rf0 + ( 1.0 - rf0 ) * pow( ( 1.0 - theta ), 5.0 );
703:    vec3 scatter = max( 0.0, dot( surfaceNormal, eyeDirection ) ) * waterColor;
704:    vec3 albedo = mix( ( sunColor * diffuseLight * 0.3 + scatter ) * getShadowMask(), ( vec3( 0.1 ) + reflectionSample * 0.9 + reflectionSample * specularLight ), reflectance);
705:    vec3 outgoingLight = albedo;
706:    gl_FragColor = vec4( outgoingLight, alpha );
707: #if defined( TONE_MAPPING )
708:   gl_FragColor.rgb = toneMapping( gl_FragColor.rgb );
709: #endif
710: 
711: #ifdef USE_FOG
712:    #ifdef FOG_EXP2
713:        float fogFactor = whiteCompliment( exp2( - fogDensity * fogDensity * fogDepth * fogDepth * LOG2 ) );
714:    #else
715:        float fogFactor = smoothstep( fogNear, fogFar, fogDepth );
716:    #endif
717:    gl_FragColor.rgb = mix( gl_FragColor.rgb, fogColor, fogFactor );
718: #endif
719: 
720: }

The only sampler that gets indexed with a non-constant expression seems to be directionalShadowMap in line 668? No idea why it refers to 0:102(109).

668: shadow *= bool( directionalLight.shadow ) ? getShadow( directionalShadowMap[ i ], directionalLight.shadowMapSize, directionalLight.shadowBias, directionalLight.shadowRadius, vDirectionalShadowCoord[ i ] ) : 1.0;

Other shadow map examples work. It has to do something with the THREE.Water specific fragment shader...

Same conclusion. It also reports a warning for an en extension at line 2 that is not visible, so it may be referring to a different code that what is logged ?

Same issue as in https://github.com/mrdoob/three.js/issues/6115 by the way

As @moraxy stated and the issue suggests, it may be linked to shadows since the only sampler array with a non-const expression is there : what if you remove water.receiveShadow = true in the example ?

I'm digging that shader in case I have any idea in the meanwhile...

what if you remove water.receiveShadow = true in the example ?

That solves the problem.

@Mugen87 does the shadows in the spline editor example work for you ? (I copied the chunks of the ShadowMaterial to get the shadows in the water shader)

Yep, webgl_geometry_spline_editor works.

Why does the same shadowmask_pars_fragment chunk output two different getShadowMask functions in these two examples ? In the water shader it has for loops with this non-constant uses in samplers arrays, in the ShadowMaterial program of the spline editor example it doesn't : getShadowMask

Loop unrolling? There should be a flag or directive or something to force enable/disable it per loop

Does the renderer achieves the loop unrolling internally with this chunk in built-in materials (it is used in Shadow and Lambert materials) and not with ShaderMaterial ?

How do we deal with this ?

Good question. I remember there was a feature request of a user who asked for an example that shows, how to apply lighting + shadows on a custom shader material (unfortunately, i can't find the issue right now). But we would run into the same error when implementing this.

I'm not sure how to solve this problem. Let's wait how @mrdoob and @WestLangley evaluate the issue.

As a user myself this is a big question, because in GPGPU cases we can use huge for loops with the ShaderMaterial, while on another hand we should be able to use this kind of chunk if we want to design special materials with the ShaderMaterial.

Both keeping and removing this condition seems to cause issues somewhere. @moraxy has mentionned using a flag, which would then look like the only exit door... ? But this is a special policy to introduce then.

This is also the general problem of customizing shaders I guess, with all the SO questions and issues going on... I love onBeforeCompile but creating the water shader by using it on a ShadowMaterial... this could look tricky... and would not solve the other related questions.

I let you solve this :innocent:

I guess we could try adding a unrollLoops property to ShaderMaterial?

if ( material.isShaderMaterial === undefined || material.unrollLoops === true ) {

Sounds good!

@Astrak

What's this shader inspector you posted the screenshot of?

@pailhead That's WebGL Inspector, available as an extension for Chrome and Firefox.

This bug is now fixed via #13140. Yay! 🎉 🙌

Was this page helpful?
0 / 5 - 0 ratings