jMonkeyEngine / jmonkeyengine

A complete 3-D game development suite written in Java.
http://jmonkeyengine.org
BSD 3-Clause "New" or "Revised" License
3.84k stars 1.13k forks source link

Shader compile error when checking for hardware skinning support on model with PBR material def. #1340

Closed rvandoosselaer closed 4 years ago

rvandoosselaer commented 4 years ago

Get a NB_PROBES is not defined error in the shader.

Environment:

2020-04-01 10:39:56,603 INFO  [main] com.jme3.system.JmeDesktopSystem (JmeDesktopSystem.java:345) - Running on jMonkeyEngine 3.3.0-stable
 * Branch: HEAD
 * Git Hash: 391e0dc
 * Build Date: 2020-03-30
2020-04-01 10:39:56,863 INFO  [jME3 Main] com.jme3.system.lwjgl.LwjglContext (LwjglContext.java:100) - LWJGL 2.9.3 context running on thread jME3 Main
 * Graphics Adapter: null
 * Driver Version: null
 * Scaling Factor: 1
2020-04-01 10:39:56,879 INFO  [jME3 Main] com.jme3.renderer.opengl.GLRenderer (GLRenderer.java:538) - OpenGL Renderer Information
 * Vendor: ATI Technologies Inc.
 * Renderer: AMD Radeon Pro Vega 20 OpenGL Engine
 * OpenGL Version: 4.1 ATI-2.11.20
 * GLSL Version: 4.10
 * Profile: Core

Stacktrace:

2020-04-01 10:40:03,000 WARN  [jME3 Main] com.jme3.renderer.opengl.GLRenderer (GLRenderer.java:1473) - Bad compile of:
1   #version 150 core
2   #define SRGB 1
3   #define FRAGMENT_SHADER 1
4   #define BASECOLORMAP 1
5   #define EMISSIVE 1
6   #define NUM_BONES 30
7   #define NORMAL_TYPE -1.0
8   #define SINGLE_PASS_LIGHTING 1
9   #define NB_LIGHTS 3
10  #extension GL_ARB_shader_texture_lod : enable
11  // -- begin import Common/ShaderLib/GLSLCompat.glsllib --
12  #if defined GL_ES
13  #  define hfloat highp float
14  #  define hvec2  highp vec2
15  #  define hvec3  highp vec3
16  #  define hvec4  highp vec4
17  #  define lfloat lowp float
18  #  define lvec2 lowp vec2
19  #  define lvec3 lowp vec3
20  #  define lvec4 lowp vec4
21  #else
22  #  define hfloat float
23  #  define hvec2  vec2
24  #  define hvec3  vec3
25  #  define hvec4  vec4
26  #  define lfloat float
27  #  define lvec2  vec2
28  #  define lvec3  vec3
29  #  define lvec4  vec4
30  #endif
31  
32  #if __VERSION__ >= 130
33  #  ifdef GL_ES
34  out highp vec4 outFragColor;
35  #  else
36  out vec4 outFragColor;
37  #endif
38  #  define texture1D texture
39  #  define texture2D texture
40  #  define texture3D texture
41  #  define textureCube texture
42  #  define texture2DLod textureLod
43  #  define textureCubeLod textureLod
44  #  define texture2DArray texture
45  #  if defined VERTEX_SHADER
46  #    define varying out
47  #    define attribute in
48  #  elif defined FRAGMENT_SHADER
49  #    define varying in
50  #    define gl_FragColor outFragColor
51  #  endif
52  #else
53  #  define isnan(val) !(val<0.0||val>0.0||val==0.0)
54  #endif
55  
56  
57  // -- end import Common/ShaderLib/GLSLCompat.glsllib --
58  // -- begin import Common/ShaderLib/PBR.glsllib --
59  #ifndef PI
60      #define PI 3.14159265358979323846264
61  #endif
62  
63  //Specular fresnel computation
64  vec3 F_Shlick(float vh, vec3 F0){
65      float fresnelFact = pow(2.0, (-5.55473*vh - 6.98316) * vh);
66      return mix(F0, vec3(1.0, 1.0, 1.0), fresnelFact);
67  }
68  
69  vec3 sphericalHarmonics( const in vec3 normal, const vec3 sph[9] ){
70      float x = normal.x;
71      float y = normal.y;
72      float z = normal.z;
73  
74      vec3 result = (
75          sph[0] +
76  
77          sph[1] * y +
78          sph[2] * z +
79          sph[3] * x +
80  
81          sph[4] * y * x +
82          sph[5] * y * z +
83          sph[6] * (3.0 * z * z - 1.0) +
84          sph[7] * (z * x) +
85          sph[8] * (x*x - y*y)
86      );
87  
88      return max(result, vec3(0.0));
89  }
90  
91  
92  float PBR_ComputeDirectLight(vec3 normal, vec3 lightDir, vec3 viewDir,
93                              vec3 lightColor, vec3 fZero, float roughness, float ndotv,
94                              out vec3 outDiffuse, out vec3 outSpecular){
95      // Compute halfway vector.
96      vec3 halfVec = normalize(lightDir + viewDir);
97  
98      // Compute ndotl, ndoth,  vdoth terms which are needed later.
99      float ndotl = max( dot(normal,   lightDir), 0.0);
100     float ndoth = max( dot(normal,   halfVec),  0.0);       
101     float hdotv = max( dot(viewDir,  halfVec),  0.0);
102 
103     // Compute diffuse using energy-conserving Lambert.
104     // Alternatively, use Oren-Nayar for really rough 
105     // materials or if you have lots of processing power ...
106     outDiffuse = vec3(ndotl) * lightColor;
107 
108     //cook-torrence, microfacet BRDF : http://blog.selfshadow.com/publications/s2013-shading-course/karis/s2013_pbs_epic_notes_v2.pdf
109    
110     float alpha = roughness * roughness;
111 
112     //D, GGX normaal Distribution function     
113     float alpha2 = alpha * alpha;
114     float sum  = ((ndoth * ndoth) * (alpha2 - 1.0) + 1.0);
115     float denom = PI * sum * sum;
116     float D = alpha2 / denom;  
117 
118     // Compute Fresnel function via Schlick's approximation.
119     vec3 fresnel = F_Shlick(hdotv, fZero);
120     
121     //G Shchlick GGX Gometry shadowing term,  k = alpha/2
122     float k = alpha * 0.5;
123 
124  /*   
125     //classic Schlick ggx
126     float G_V = ndotv / (ndotv * (1.0 - k) + k);
127     float G_L = ndotl / (ndotl * (1.0 - k) + k);
128     float G = ( G_V * G_L );
129     
130     float specular =(D* fresnel * G) /(4 * ndotv);
131    */
132  
133     // UE4 way to optimise shlick GGX Gometry shadowing term
134     //http://graphicrants.blogspot.co.uk/2013/08/specular-brdf-reference.html
135     float G_V = ndotv + sqrt( (ndotv - ndotv * k) * ndotv + k );
136     float G_L = ndotl + sqrt( (ndotl - ndotl * k) * ndotl + k );    
137     // the max here is to avoid division by 0 that may cause some small glitches.
138     float G = 1.0/max( G_V * G_L ,0.01); 
139 
140     float specular = D * G * ndotl;
141  
142     outSpecular = vec3(specular) * fresnel * lightColor;
143     return hdotv;
144 }
145 
146 vec3 integrateBRDFApprox( const in vec3 specular, float roughness, float NoV ){
147     const vec4 c0 = vec4( -1, -0.0275, -0.572, 0.022 );
148     const vec4 c1 = vec4( 1, 0.0425, 1.04, -0.04 );
149     vec4 r = roughness * c0 + c1;
150     float a004 = min( r.x * r.x, exp2( -9.28 * NoV ) ) * r.x + r.y;
151     vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
152     return specular * AB.x + AB.y;
153 }
154 
155 // from Sebastien Lagarde https://seblagarde.files.wordpress.com/2015/07/course_notes_moving_frostbite_to_pbr_v32.pdf page 69
156 vec3 getSpecularDominantDir(const in vec3 N, const in vec3 R, const in float realRoughness){
157     vec3 dominant;
158 
159     float smoothness = 1.0 - realRoughness;
160     float lerpFactor = smoothness * (sqrt(smoothness) + realRoughness);
161     // The result is not normalized as we fetch in a cubemap
162     dominant = mix(N, R, lerpFactor);
163 
164     return dominant;
165 }
166 
167 vec3 ApproximateSpecularIBL(samplerCube envMap,sampler2D integrateBRDF, vec3 SpecularColor , float Roughness, float ndotv, vec3 refVec, float nbMipMaps){
168     float Lod = sqrt( Roughness ) * (nbMipMaps - 1.0);
169     vec3 PrefilteredColor =  textureCubeLod(envMap, refVec.xyz,Lod).rgb;
170     vec2 EnvBRDF = texture2D(integrateBRDF,vec2(Roughness, ndotv)).rg;
171     return PrefilteredColor * ( SpecularColor * EnvBRDF.x+ EnvBRDF.y );    
172 }
173 
174 vec3 ApproximateSpecularIBLPolynomial(samplerCube envMap, vec3 SpecularColor , float Roughness, float ndotv, vec3 refVec, float nbMipMaps){
175     float Lod = sqrt( Roughness ) * (nbMipMaps - 1.0);
176     vec3 PrefilteredColor =  textureCubeLod(envMap, refVec.xyz, Lod).rgb;
177     return PrefilteredColor * integrateBRDFApprox(SpecularColor, Roughness, ndotv);
178 }
179 
180 
181 float renderProbe(vec3 viewDir, vec3 worldPos, vec3 normal, vec3 norm, float Roughness, vec4 diffuseColor, vec4 specularColor, float ndotv, vec3 ao, mat4 lightProbeData,vec3 shCoeffs[9],samplerCube prefEnvMap, inout vec3 color ){
182 
183     // lightProbeData is a mat4 with this layout
184     //   3x3 rot mat|
185     //      0  1  2 |  3
186     // 0 | ax bx cx | px | )
187     // 1 | ay by cy | py | probe position
188     // 2 | az bz cz | pz | )
189     // --|----------|
190     // 3 | sx sy sz   sp | -> 1/probe radius + nbMipMaps
191     //    --scale--
192     // parallax fix for spherical / obb bounds and probe blending from
193     // from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
194     vec3 rv = reflect(-viewDir, normal);
195     vec4 probePos = lightProbeData[3];
196     float invRadius = fract( probePos.w);
197     float nbMipMaps = probePos.w - invRadius;
198     vec3 direction = worldPos - probePos.xyz;
199     float ndf = 0.0;
200 
201     if(lightProbeData[0][3] != 0.0){
202         // oriented box probe
203         mat3 wToLocalRot = mat3(lightProbeData);
204         wToLocalRot = inverse(wToLocalRot);
205         vec3 scale = vec3(lightProbeData[0][3], lightProbeData[1][3], lightProbeData[2][3]);
206         #if NB_PROBES >= 2
207             // probe blending
208             // compute fragment position in probe local space
209             vec3 localPos = wToLocalRot * worldPos;
210             localPos -= probePos.xyz;
211             // compute normalized distance field
212             vec3 localDir = abs(localPos);
213             localDir /= scale;
214             ndf = max(max(localDir.x, localDir.y), localDir.z);
215         #endif
216         // parallax fix
217         vec3 rayLs = wToLocalRot * rv;
218         rayLs /= scale;
219 
220         vec3 positionLs = worldPos - probePos.xyz;
221         positionLs = wToLocalRot * positionLs;
222         positionLs /= scale;
223 
224         vec3 unit = vec3(1.0);
225         vec3 firstPlaneIntersect = (unit - positionLs) / rayLs;
226         vec3 secondPlaneIntersect = (-unit - positionLs) / rayLs;
227         vec3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect);
228         float distance = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z);
229 
230         vec3 intersectPositionWs = worldPos + rv * distance;
231         rv = intersectPositionWs - probePos.xyz;
232 
233     } else {
234         // spherical probe
235         // paralax fix
236         rv = invRadius * direction + rv;
237 
238         #if NB_PROBES >= 2
239             // probe blending
240             float dist = sqrt(dot(direction, direction));
241             ndf = dist * invRadius;
242         #endif
243     }
244 
245     vec3 indirectDiffuse = vec3(0.0);
246     vec3 indirectSpecular = vec3(0.0);
247     indirectDiffuse = sphericalHarmonics(normal.xyz, shCoeffs) * diffuseColor.rgb;
248     vec3 dominantR = getSpecularDominantDir( normal, rv.xyz, Roughness * Roughness );
249     indirectSpecular = ApproximateSpecularIBLPolynomial(prefEnvMap, specularColor.rgb, Roughness, ndotv, dominantR, nbMipMaps);
250 
251     #ifdef HORIZON_FADE
252         //horizon fade from http://marmosetco.tumblr.com/post/81245981087
253         float horiz = dot(rv, norm);
254         float horizFadePower = 1.0 - Roughness;
255         horiz = clamp( 1.0 + horizFadePower * horiz, 0.0, 1.0 );
256         horiz *= horiz;
257         indirectSpecular *= vec3(horiz);
258     #endif
259 
260     vec3 indirectLighting = (indirectDiffuse + indirectSpecular) * ao;
261 
262     color = indirectLighting * step( 0.0, probePos.w);
263     return ndf;
264 }
265 
266 
267 
268 
269 
270 // -- end import Common/ShaderLib/PBR.glsllib --
271 // -- begin import Common/ShaderLib/Parallax.glsllib --
272 #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP))) && !defined(VERTEX_LIGHTING)    
273     vec2 steepParallaxOffset(sampler2D parallaxMap, vec3 vViewDir,vec2 texCoord,float parallaxScale){
274         vec2 vParallaxDirection = normalize(  vViewDir.xy );
275 
276         // The length of this vector determines the furthest amount of displacement: (Ati's comment)
277         float fLength         = length( vViewDir );
278         float fParallaxLength = sqrt( fLength * fLength - vViewDir.z * vViewDir.z ) / vViewDir.z; 
279 
280         // Compute the actual reverse parallax displacement vector: (Ati's comment)
281         vec2 vParallaxOffsetTS = vParallaxDirection * fParallaxLength;
282 
283         // Need to scale the amount of displacement to account for different height ranges
284         // in height maps. This is controlled by an artist-editable parameter: (Ati's comment)              
285         parallaxScale *=0.3;
286         vParallaxOffsetTS *= parallaxScale;
287 
288        vec3 eyeDir = normalize(vViewDir).xyz;   
289 
290         float nMinSamples = 6.0;
291         float nMaxSamples = 1000.0 * parallaxScale;   
292         float nNumSamples = mix( nMinSamples, nMaxSamples, 1.0 - eyeDir.z );   //In reference shader: int nNumSamples = (int)(lerp( nMinSamples, nMaxSamples, dot( eyeDirWS, N ) ));
293         float fStepSize = 1.0 / nNumSamples;   
294         float fCurrHeight = 0.0;
295         float fPrevHeight = 1.0;
296         float fNextHeight = 0.0;
297         float nStepIndex = 0.0;
298         vec2 vTexOffsetPerStep = fStepSize * vParallaxOffsetTS;
299         vec2 vTexCurrentOffset = texCoord;
300         float  fCurrentBound     = 1.0;
301         float  fParallaxAmount   = 0.0;   
302 
303         while ( nStepIndex < nNumSamples && fCurrHeight <= fCurrentBound ) {
304             vTexCurrentOffset -= vTexOffsetPerStep;
305             fPrevHeight = fCurrHeight;
306             
307            
308            #ifdef NORMALMAP_PARALLAX
309                //parallax map is stored in the alpha channel of the normal map         
310                fCurrHeight = texture2D( parallaxMap, vTexCurrentOffset).a; 
311            #else
312                //parallax map is a texture
313                fCurrHeight = texture2D( parallaxMap, vTexCurrentOffset).r;                
314            #endif
315            
316             fCurrentBound -= fStepSize;
317             nStepIndex+=1.0;
318         } 
319         vec2 pt1 = vec2( fCurrentBound, fCurrHeight );
320         vec2 pt2 = vec2( fCurrentBound + fStepSize, fPrevHeight );
321 
322         float fDelta2 = pt2.x - pt2.y;
323         float fDelta1 = pt1.x - pt1.y;
324 
325         float fDenominator = fDelta2 - fDelta1;
326 
327         fParallaxAmount = (pt1.x * fDelta2 - pt2.x * fDelta1 ) / fDenominator;
328 
329         vec2 vParallaxOffset = vParallaxOffsetTS * (1.0 - fParallaxAmount );
330        return texCoord - vParallaxOffset;  
331     }
332 
333     vec2 classicParallaxOffset(sampler2D parallaxMap, vec3 vViewDir,vec2 texCoord,float parallaxScale){ 
334        float h;
335        #ifdef NORMALMAP_PARALLAX
336                //parallax map is stored in the alpha channel of the normal map         
337                h = texture2D(parallaxMap, texCoord).a;               
338        #else
339                //parallax map is a texture
340                h = texture2D(parallaxMap, texCoord).r;
341        #endif
342        float heightScale = parallaxScale;
343        float heightBias = heightScale* -0.6;
344        vec3 normView = normalize(vViewDir);       
345        h = (h * heightScale + heightBias) * normView.z;
346        return texCoord + (h * normView.xy);
347     }
348 #endif
349 // -- end import Common/ShaderLib/Parallax.glsllib --
350 // -- begin import Common/ShaderLib/Lighting.glsllib --
351 /*Common function for light calculations*/
352 
353 
354 /*
355 * Computes light direction 
356 * lightType should be 0.0,1.0,2.0, repectively for Directional, point and spot lights.
357 * Outputs the light direction and the light half vector. 
358 */
359 void lightComputeDir(in vec3 worldPos, in float lightType, in vec4 position, out vec4 lightDir, out vec3 lightVec){
360     float posLight = step(0.5, lightType);    
361     vec3 tempVec = position.xyz * sign(posLight - 0.5) - (worldPos * posLight);
362     lightVec = tempVec;          
363     float dist = length(tempVec);
364 #ifdef SRGB
365     lightDir.w = (1.0 - position.w * dist) / (1.0 + position.w * dist * dist);
366     lightDir.w = clamp(lightDir.w, 1.0 - posLight, 1.0);
367 #else
368     lightDir.w = clamp(1.0 - position.w * dist * posLight, 0.0, 1.0);
369 #endif
370     lightDir.xyz = tempVec / vec3(dist);
371 }
372 
373 /*
374 * Computes the spot falloff for a spotlight
375 */
376 float computeSpotFalloff(in vec4 lightDirection, in vec3 lightVector){
377     vec3 L=normalize(lightVector);
378     vec3 spotdir = normalize(lightDirection.xyz);
379     float curAngleCos = dot(-L, spotdir);    
380     float innerAngleCos = floor(lightDirection.w) * 0.001;
381     float outerAngleCos = fract(lightDirection.w);
382     float innerMinusOuter = innerAngleCos - outerAngleCos;
383     float falloff = clamp((curAngleCos - outerAngleCos) / innerMinusOuter, step(lightDirection.w, 0.001), 1.0);
384 
385 #ifdef SRGB
386     // Use quadratic falloff (notice the ^4)
387     return pow(clamp((curAngleCos - outerAngleCos) / innerMinusOuter, 0.0, 1.0), 4.0);
388 #else
389     // Use linear falloff
390     return falloff;
391 #endif
392 }
393 
394 // -- end import Common/ShaderLib/Lighting.glsllib --
395 
396 varying vec2 texCoord;
397 #ifdef SEPARATE_TEXCOORD
398   varying vec2 texCoord2;
399 #endif
400 
401 varying vec4 Color;
402 
403 uniform vec4 g_LightData[NB_LIGHTS];
404 uniform vec3 g_CameraPosition;
405 uniform vec4 g_AmbientLightColor;
406 
407 uniform float m_Roughness;
408 uniform float m_Metallic;
409 
410 varying vec3 wPosition;    
411 
412 
413 #if NB_PROBES >= 1
414   uniform samplerCube g_PrefEnvMap;
415   uniform vec3 g_ShCoeffs[9];
416   uniform mat4 g_LightProbeData;
417 #endif
418 #if NB_PROBES >= 2
419   uniform samplerCube g_PrefEnvMap2;
420   uniform vec3 g_ShCoeffs2[9];
421   uniform mat4 g_LightProbeData2;
422 #endif
423 #if NB_PROBES == 3
424   uniform samplerCube g_PrefEnvMap3;
425   uniform vec3 g_ShCoeffs3[9];
426   uniform mat4 g_LightProbeData3;
427 #endif
428 
429 #ifdef BASECOLORMAP
430   uniform sampler2D m_BaseColorMap;
431 #endif
432 
433 #ifdef USE_PACKED_MR
434   uniform sampler2D m_MetallicRoughnessMap;
435 #else
436     #ifdef METALLICMAP
437       uniform sampler2D m_MetallicMap;
438     #endif
439     #ifdef ROUGHNESSMAP
440       uniform sampler2D m_RoughnessMap;
441     #endif
442 #endif
443 
444 #ifdef EMISSIVE
445   uniform vec4 m_Emissive;
446 #endif
447 #ifdef EMISSIVEMAP
448   uniform sampler2D m_EmissiveMap;
449 #endif
450 #if defined(EMISSIVE) || defined(EMISSIVEMAP)
451     uniform float m_EmissivePower;
452     uniform float m_EmissiveIntensity;
453 #endif 
454 
455 #ifdef SPECGLOSSPIPELINE
456 
457   uniform vec4 m_Specular;
458   uniform float m_Glossiness;
459   #ifdef USE_PACKED_SG
460     uniform sampler2D m_SpecularGlossinessMap;
461   #else
462     uniform sampler2D m_SpecularMap;
463     uniform sampler2D m_GlossinessMap;
464   #endif
465 #endif
466 
467 #ifdef PARALLAXMAP
468   uniform sampler2D m_ParallaxMap;  
469 #endif
470 #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
471     uniform float m_ParallaxHeight;
472 #endif
473 
474 #ifdef LIGHTMAP
475   uniform sampler2D m_LightMap;
476 #endif
477   
478 #if defined(NORMALMAP) || defined(PARALLAXMAP)
479   uniform sampler2D m_NormalMap;   
480   varying vec4 wTangent;
481 #endif
482 varying vec3 wNormal;
483 
484 #ifdef DISCARD_ALPHA
485   uniform float m_AlphaDiscardThreshold;
486 #endif
487 
488 void main(){
489     vec2 newTexCoord;
490     vec3 viewDir = normalize(g_CameraPosition - wPosition);
491 
492     vec3 norm = normalize(wNormal);
493     #if defined(NORMALMAP) || defined(PARALLAXMAP)
494         vec3 tan = normalize(wTangent.xyz);
495         mat3 tbnMat = mat3(tan, wTangent.w * cross( (norm), (tan)), norm);
496     #endif
497 
498     #if (defined(PARALLAXMAP) || (defined(NORMALMAP_PARALLAX) && defined(NORMALMAP)))
499        vec3 vViewDir =  viewDir * tbnMat;  
500        #ifdef STEEP_PARALLAX
501            #ifdef NORMALMAP_PARALLAX
502                //parallax map is stored in the alpha channel of the normal map         
503                newTexCoord = steepParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);
504            #else
505                //parallax map is a texture
506                newTexCoord = steepParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight);         
507            #endif
508        #else
509            #ifdef NORMALMAP_PARALLAX
510                //parallax map is stored in the alpha channel of the normal map         
511                newTexCoord = classicParallaxOffset(m_NormalMap, vViewDir, texCoord, m_ParallaxHeight);
512            #else
513                //parallax map is a texture
514                newTexCoord = classicParallaxOffset(m_ParallaxMap, vViewDir, texCoord, m_ParallaxHeight);
515            #endif
516        #endif
517     #else
518        newTexCoord = texCoord;    
519     #endif
520     
521     #ifdef BASECOLORMAP
522         vec4 albedo = texture2D(m_BaseColorMap, newTexCoord) * Color;
523     #else
524         vec4 albedo = Color;
525     #endif
526 
527     #ifdef USE_PACKED_MR
528         vec2 rm = texture2D(m_MetallicRoughnessMap, newTexCoord).gb;
529         float Roughness = rm.x * max(m_Roughness, 1e-4);
530         float Metallic = rm.y * max(m_Metallic, 0.0);
531     #else
532         #ifdef ROUGHNESSMAP
533             float Roughness = texture2D(m_RoughnessMap, newTexCoord).r * max(m_Roughness, 1e-4);
534         #else
535             float Roughness =  max(m_Roughness, 1e-4);
536         #endif
537         #ifdef METALLICMAP
538             float Metallic = texture2D(m_MetallicMap, newTexCoord).r * max(m_Metallic, 0.0);
539         #else
540             float Metallic =  max(m_Metallic, 0.0);
541         #endif
542     #endif
543  
544     float alpha = albedo.a;
545 
546     #ifdef DISCARD_ALPHA
547         if(alpha < m_AlphaDiscardThreshold){
548             discard;
549         }
550     #endif
551  
552     // ***********************
553     // Read from textures
554     // ***********************
555     #if defined(NORMALMAP)
556       vec4 normalHeight = texture2D(m_NormalMap, newTexCoord);
557       //Note the -2.0 and -1.0. We invert the green channel of the normal map, 
558       //as it's complient with normal maps generated with blender.
559       //see http://hub.jmonkeyengine.org/forum/topic/parallax-mapping-fundamental-bug/#post-256898
560       //for more explanation.
561       vec3 normal = normalize((normalHeight.xyz * vec3(2.0, NORMAL_TYPE * 2.0, 2.0) - vec3(1.0, NORMAL_TYPE * 1.0, 1.0)));
562       normal = normalize(tbnMat * normal);
563       //normal = normalize(normal * inverse(tbnMat));
564     #else
565       vec3 normal = norm;
566     #endif
567 
568     #ifdef SPECGLOSSPIPELINE
569 
570         #ifdef USE_PACKED_SG
571             vec4 specularColor = texture2D(m_SpecularGlossinessMap, newTexCoord);
572             float glossiness = specularColor.a * m_Glossiness;
573             specularColor *= m_Specular;
574         #else
575             #ifdef SPECULARMAP
576                 vec4 specularColor = texture2D(m_SpecularMap, newTexCoord);
577             #else
578                 vec4 specularColor = vec4(1.0);
579             #endif
580             #ifdef GLOSSINESSMAP
581                 float glossiness = texture2D(m_GlossinessMap, newTexCoord).r * m_Glossiness;
582             #else
583                 float glossiness = m_Glossiness;
584             #endif
585             specularColor *= m_Specular;
586         #endif
587         vec4 diffuseColor = albedo;// * (1.0 - max(max(specularColor.r, specularColor.g), specularColor.b));
588         Roughness = 1.0 - glossiness;
589         vec3 fZero = specularColor.xyz;
590     #else
591         float specular = 0.5;
592         float nonMetalSpec = 0.08 * specular;
593         vec4 specularColor = (nonMetalSpec - nonMetalSpec * Metallic) + albedo * Metallic;
594         vec4 diffuseColor = albedo - albedo * Metallic;
595         vec3 fZero = vec3(specular);
596     #endif
597 
598     gl_FragColor.rgb = vec3(0.0);
599     vec3 ao = vec3(1.0);
600 
601     #ifdef LIGHTMAP
602        vec3 lightMapColor;
603        #ifdef SEPARATE_TEXCOORD
604           lightMapColor = texture2D(m_LightMap, texCoord2).rgb;
605        #else
606           lightMapColor = texture2D(m_LightMap, texCoord).rgb;
607        #endif
608        #ifdef AO_MAP
609          lightMapColor.gb = lightMapColor.rr;
610          ao = lightMapColor;
611        #else
612          gl_FragColor.rgb += diffuseColor.rgb * lightMapColor;
613        #endif
614        specularColor.rgb *= lightMapColor;
615     #endif
616 
617 
618     float ndotv = max( dot( normal, viewDir ),0.0);
619     for( int i = 0;i < NB_LIGHTS; i+=3){
620         vec4 lightColor = g_LightData[i];
621         vec4 lightData1 = g_LightData[i+1];                
622         vec4 lightDir;
623         vec3 lightVec;            
624         lightComputeDir(wPosition, lightColor.w, lightData1, lightDir, lightVec);
625 
626         float fallOff = 1.0;
627         #if __VERSION__ >= 110
628             // allow use of control flow
629         if(lightColor.w > 1.0){
630         #endif
631             fallOff =  computeSpotFalloff(g_LightData[i+2], lightVec);
632         #if __VERSION__ >= 110
633         }
634         #endif
635         //point light attenuation
636         fallOff *= lightDir.w;
637 
638         lightDir.xyz = normalize(lightDir.xyz);            
639         vec3 directDiffuse;
640         vec3 directSpecular;
641         
642         float hdotv = PBR_ComputeDirectLight(normal, lightDir.xyz, viewDir,
643                             lightColor.rgb, fZero, Roughness, ndotv,
644                             directDiffuse,  directSpecular);
645 
646         vec3 directLighting = diffuseColor.rgb *directDiffuse + directSpecular;
647         
648         gl_FragColor.rgb += directLighting * fallOff;
649     }
650 
651     #if NB_PROBES >= 1
652         vec3 color1 = vec3(0.0);
653         vec3 color2 = vec3(0.0);
654         vec3 color3 = vec3(0.0);
655         float weight1 = 1.0;
656         float weight2 = 0.0;
657         float weight3 = 0.0;
658 
659         float ndf = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData, g_ShCoeffs, g_PrefEnvMap, color1);
660         #if NB_PROBES >= 2
661             float ndf2 = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData2, g_ShCoeffs2, g_PrefEnvMap2, color2);
662         #endif
663         #if NB_PROBES == 3
664             float ndf3 = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData3, g_ShCoeffs3, g_PrefEnvMap3, color3);
665         #endif
666 
667         #if NB_PROBES >= 2
668             float invNdf =  max(1.0 - ndf,0.0);
669             float invNdf2 =  max(1.0 - ndf2,0.0);
670             float sumNdf = ndf + ndf2;
671             float sumInvNdf = invNdf + invNdf2;
672             #if NB_PROBES == 3
673                 float invNdf3 = max(1.0 - ndf3,0.0);
674                 sumNdf += ndf3;
675                 sumInvNdf += invNdf3;
676                 weight3 =  ((1.0 - (ndf3 / sumNdf)) / (NB_PROBES - 1)) *  (invNdf3 / sumInvNdf);
677             #endif
678 
679             weight1 = ((1.0 - (ndf / sumNdf)) / (NB_PROBES - 1)) *  (invNdf / sumInvNdf);
680             weight2 = ((1.0 - (ndf2 / sumNdf)) / (NB_PROBES - 1)) *  (invNdf2 / sumInvNdf);
681 
682             float weightSum = weight1 + weight2 + weight3;
683 
684             weight1 /= weightSum;
685             weight2 /= weightSum;
686             weight3 /= weightSum;
687         #endif
688 
689         #ifdef USE_AMBIENT_LIGHT
690             color1.rgb *= g_AmbientLightColor.rgb;
691             color2.rgb *= g_AmbientLightColor.rgb;
692             color3.rgb *= g_AmbientLightColor.rgb;
693         #endif
694         gl_FragColor.rgb += color1 * clamp(weight1,0.0,1.0) + color2 * clamp(weight2,0.0,1.0) + color3 * clamp(weight3,0.0,1.0);
695 
696     #endif
697 
698     #if defined(EMISSIVE) || defined (EMISSIVEMAP)
699         #ifdef EMISSIVEMAP
700             vec4 emissive = texture2D(m_EmissiveMap, newTexCoord);
701         #else
702             vec4 emissive = m_Emissive;
703         #endif
704         gl_FragColor += emissive * pow(emissive.a, m_EmissivePower) * m_EmissiveIntensity;
705     #endif
706     gl_FragColor.a = alpha;
707    
708 }

2020-04-01 10:40:03,002 WARN  [jME3 Main] com.jme3.anim.SkinningControl (SkinningControl.java:178) - Could not enable HW skinning due to shader compile error:
com.jme3.renderer.RendererException: compile error in: ShaderSource[name=Common/MatDefs/Light/PBRLighting.frag, defines, type=Fragment, language=GLSL150]
WARNING: 0:10: extension 'GL_ARB_shader_texture_lod' is not supported
ERROR: 0:206: '' : syntax error: incorrect preprocessor directive
ERROR: 0:206: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:238: '' : syntax error: incorrect preprocessor directive
ERROR: 0:238: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:413: '' : syntax error: incorrect preprocessor directive
ERROR: 0:413: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:418: '' : syntax error: incorrect preprocessor directive
ERROR: 0:418: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:423: '' : syntax error: incorrect preprocessor directive
ERROR: 0:423: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:651: '' : syntax error: incorrect preprocessor directive
ERROR: 0:651: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:660: '' : syntax error: incorrect preprocessor directive
ERROR: 0:660: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:663: '' : syntax error: incorrect preprocessor directive
ERROR: 0:663: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:667: '' : syntax error: incorrect preprocessor directive
ERROR: 0:667: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
ERROR: 0:672: '' : syntax error: incorrect preprocessor directive
ERROR: 0:672: '' : syntax error: unexpected tokens following #if preprocessor directive - expected a newline
stephengold commented 4 years ago

It looks like NB_PROBES is supposed to be defined here.

That constructor is invoked by J3MLoader in the case that the lightmode of a technique is SinglePassAndImageBased. Can you identify (or share) the J3M that your application used? And perhaps provide an SSCCE?

rvandoosselaer commented 4 years ago

Hi Stephen, I was also able to debug it to this point. It gets indeed set, but there is somewhere a renderpass before where it is not available. I can only reproduce this issue on OSX.

The model is using the default PBRLighting definition, and I double checked, even manually set the technique to this value.

When I do a check in the shader for the variable and set it to a default value of 0 when it is not defined (#ifndef) it works fine. I’ll make a PR for it tomorrow.

Edit: I suspect it has something todo with the (hardware) armature/skinning. When using the same model without an armature I don’t have the issue.

rvandoosselaer commented 4 years ago

I created a PR to fix the issue and added a small test case as requested. When running the test case after the #ifndef the shader compilation error is gone.

If needed I can remove the test case as I don't think it's really 'helpful' as it only loads and displays a model.

pspeed42 commented 4 years ago

The thing that concerns me is how is the value set on other platforms and why is it not set on Macs. 99% sure that other platforms would also error out if the value wasn't set... which makes me think that the error isn't in the shader but in the apparatus that calls it.

rvandoosselaer commented 4 years ago

The value do get set, but not ‘soon enough’. There is a renderpass where it is not available yet and the error is thrown. I tested this by setting the fragColor in the shader when NB_PROBES >= 1 in the provided test case, and this was executed. Maybe it’s because of the strict OpenGL core profile that Mac uses? The PR will not break any existing behavior at least.

But your concern is certainly correct. How do you propose we should proceed with this?

pspeed42 commented 4 years ago

What I worry about is that this fix is only hiding a different problem. If NB_PROBES was missing on Windows, I think we'd still get that error... so it must be set somehow. That would mean that whatever code is supposed to set it isn't working on a Mac. And so I wonder what else is missing.

rvandoosselaer commented 4 years ago

I think I'm getting closer:

SinglePassAndImageBasedLightingLogic:77

@Override
public Shader makeCurrent(AssetManager assetManager, RenderManager renderManager,
    EnumSet<Caps> rendererCaps, LightList lights, DefineList defines) {
    defines.set(nbLightsDefineId, renderManager.getSinglePassLightBatchSize() * 3);
    defines.set(singlePassLightingDefineId, true);

    //TODO here we have a problem, this is called once before render, so the define will be set for all passes (in case we have more than NB_LIGHTS lights)
    //Though the second pass should not render IBL as it is taken care of on first pass like ambient light in phong lighting.
    //We cannot change the define between passes and the old technique, and for some reason the code fails on mac (renders nothing).
    if(lights != null) {
        lightProbes.clear();
        extractIndirectLights(lights, false);
        defines.set(nbProbesDefineId, lightProbes.size());
        defines.set(useAmbientLightDefineId, useAmbientLight);
    }

    return super.makeCurrent(assetManager, renderManager, rendererCaps, lights, defines);
}

The define is only set when the Lightlist is not empty.

When I step through the application, the fist time this method is called, the lightlist is empty, that's why the define is not set, and it isn't added to the shader.

pspeed42 commented 4 years ago

I wonder why light list is set on windows and linux.

MeFisto94 commented 4 years ago

Can you try to use the GL Debug Mode (AppSettings#setGraphicsDebug(true)), so we can see if some GL operation fails before that?

Note that on 3.2 Core Profile PBR works in our CI, so it depends on the setup of your scene. Maybe you can help contributing to https://github.com/MeFisto94/jme3-testing which is then visible at https://github.com/MeFisto94/test-spotbugs-integration on the testing branch (which we will integrate into the engine at some point)

rvandoosselaer commented 4 years ago

@MeFisto94 : I added the #setGraphicsDebug() boolean , but I don't get an error prior to the shader compilation error. I would very much like to help and contribute to your repo. I'll have a look at it in the coming days.

@pspeed42 : I narrowed it down: the method is called with the lights set to null in the the #preload method of the Material.

https://github.com/jMonkeyEngine/jmonkeyengine/blob/4c8e400a83352b12a7ac5d5316c5bbdd06caffa8/jme3-core/src/main/java/com/jme3/material/Material.java#L905

full method: https://github.com/jMonkeyEngine/jmonkeyengine/blob/4c8e400a83352b12a7ac5d5316c5bbdd06caffa8/jme3-core/src/main/java/com/jme3/material/Material.java#L891-L908

The preload scene is called when checking for hardware skinning in the SkinningControl class: https://github.com/jMonkeyEngine/jmonkeyengine/blob/4c8e400a83352b12a7ac5d5316c5bbdd06caffa8/jme3-core/src/main/java/com/jme3/anim/SkinningControl.java#L165-L181

This is called in the #controlRender method of the control: https://github.com/jMonkeyEngine/jmonkeyengine/blob/4c8e400a83352b12a7ac5d5316c5bbdd06caffa8/jme3-core/src/main/java/com/jme3/anim/SkinningControl.java#L283

This seems like a general issue, I don't get why it hasn't come up sooner?

What would be the best fix given this information? Keeping the check in the shader, or setting the define in the SinglePassAndImageBasedLightingLogic class, regardless of whether the lights param is set.

pspeed42 commented 4 years ago

If NB_PROBES wasn't defined on Windows or Linux then it would fail to compile there, too. So, fact: on Linux and Windows, NB_PROBES is set or it's running a different shader.

So on a Mac, either the list is not being set when it is on other platforms or a different fragment shader is being used than on Windows or Linux.

Hiding the error with a #ifndef isn't really going to fix the actual problem. Probably someone on Linux or Windows needs to figure out what is being run in the cases you identify... because something different is being run on Macs.

rvandoosselaer commented 4 years ago

I see if I can get my hands on a Unix machine to test. Looking at the code I find it hard to believe this error is only related to the Mac OS. As the list is passed as null, if it is Mac, Unix, or Windows.

Thanks for your insights and help investigating this issue.

pspeed42 commented 4 years ago

Ok, I see what the issue is.

It's true that even on Windows/Linux, referencing NB_PROBES will fail... if it's used as an actual reference like: float test = NB_PROBES;

However, at least on Windows (and I assume Linux), the preprocessor directives are more lenient.

if NB_PROBES >= 2

...will succeed on my Windows box even if NB_PROBES is undefined. The #ifdef is assumed in this case... unless you are Apple.

So I'm ok with the #ifndef approach to make overly sensitive Macs happy... and at least now I know why it only fails there.

stephengold commented 4 years ago

Fixed in v3.3 branch at 9a84e72 .