diff --git a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag index 283db1fd6..716d3ff7a 100644 --- a/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag +++ b/jme3-core/src/main/resources/Common/MatDefs/Light/PBRLighting.frag @@ -94,91 +94,6 @@ varying vec3 wNormal; uniform float m_AlphaDiscardThreshold; #endif -float renderProbe(vec3 viewDir, vec3 normal, vec3 norm, float Roughness, vec4 diffuseColor, vec4 specularColor, float ndotv, vec3 ao, mat4 lightProbeData,vec3 shCoeffs[9],samplerCube prefEnvMap, inout vec3 color ){ - - // lightProbeData is a mat4 with this layout - // 3x3 rot mat| - // 0 1 2 | 3 - // 0 | ax bx cx | px | ) - // 1 | ay by cy | py | probe position - // 2 | az bz cz | pz | ) - // --|----------| - // 3 | sx sy sz sp | -> 1/probe radius + nbMipMaps - // --scale-- - // parallax fix for spherical / obb bounds and probe blending from - // from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ - vec3 rv = reflect(-viewDir, normal); - vec4 probePos = lightProbeData[3]; - float invRadius = fract( probePos.w); - float nbMipMaps = probePos.w - invRadius; - vec3 direction = wPosition - probePos.xyz; - float ndf = 0.0; - - if(lightProbeData[0][3] != 0.0){ - // oriented box probe - mat3 wToLocalRot = mat3(lightProbeData); - wToLocalRot = inverse(wToLocalRot); - vec3 scale = vec3(lightProbeData[0][3], lightProbeData[1][3], lightProbeData[2][3]); - #if NB_PROBES >= 2 - // probe blending - // compute fragment position in probe local space - vec3 localPos = wToLocalRot * wPosition; - localPos -= probePos.xyz; - // compute normalized distance field - vec3 localDir = abs(localPos); - localDir /= scale; - ndf = max(max(localDir.x, localDir.y), localDir.z); - #endif - // parallax fix - vec3 rayLs = wToLocalRot * rv; - rayLs /= scale; - - vec3 positionLs = wPosition - probePos.xyz; - positionLs = wToLocalRot * positionLs; - positionLs /= scale; - - vec3 unit = vec3(1.0); - vec3 firstPlaneIntersect = (unit - positionLs) / rayLs; - vec3 secondPlaneIntersect = (-unit - positionLs) / rayLs; - vec3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect); - float distance = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z); - - vec3 intersectPositionWs = wPosition + rv * distance; - rv = intersectPositionWs - probePos.xyz; - - } else { - // spherical probe - // paralax fix - rv = invRadius * direction + rv; - - #if NB_PROBES >= 2 - // probe blending - float dist = sqrt(dot(direction, direction)); - ndf = dist * invRadius; - #endif - } - - vec3 indirectDiffuse = vec3(0.0); - vec3 indirectSpecular = vec3(0.0); - indirectDiffuse = sphericalHarmonics(normal.xyz, shCoeffs) * diffuseColor.rgb; - vec3 dominantR = getSpecularDominantDir( normal, rv.xyz, Roughness * Roughness ); - indirectSpecular = ApproximateSpecularIBLPolynomial(prefEnvMap, specularColor.rgb, Roughness, ndotv, dominantR, nbMipMaps); - - #ifdef HORIZON_FADE - //horizon fade from http://marmosetco.tumblr.com/post/81245981087 - float horiz = dot(rv, norm); - float horizFadePower = 1.0 - Roughness; - horiz = clamp( 1.0 + horizFadePower * horiz, 0.0, 1.0 ); - horiz *= horiz; - indirectSpecular *= vec3(horiz); - #endif - - vec3 indirectLighting = (indirectDiffuse + indirectSpecular) * ao; - - color = indirectLighting * step( 0.0, probePos.w); - return ndf; -} - void main(){ vec2 newTexCoord; vec3 viewDir = normalize(g_CameraPosition - wPosition); @@ -350,12 +265,12 @@ void main(){ float weight2 = 0.0; float weight3 = 0.0; - float ndf = renderProbe(viewDir, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData, g_ShCoeffs, g_PrefEnvMap, color1); + float ndf = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData, g_ShCoeffs, g_PrefEnvMap, color1); #if NB_PROBES >= 2 - float ndf2 = renderProbe(viewDir, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData2, g_ShCoeffs2, g_PrefEnvMap2, color2); + float ndf2 = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData2, g_ShCoeffs2, g_PrefEnvMap2, color2); #endif #if NB_PROBES == 3 - float ndf3 = renderProbe(viewDir, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData3, g_ShCoeffs3, g_PrefEnvMap3, color3); + float ndf3 = renderProbe(viewDir, wPosition, normal, norm, Roughness, diffuseColor, specularColor, ndotv, ao, g_LightProbeData3, g_ShCoeffs3, g_PrefEnvMap3, color3); #endif #if NB_PROBES >= 2 diff --git a/jme3-core/src/main/resources/Common/ShaderLib/PBR.glsllib b/jme3-core/src/main/resources/Common/ShaderLib/PBR.glsllib index 81d56dc95..ee4edac8e 100644 --- a/jme3-core/src/main/resources/Common/ShaderLib/PBR.glsllib +++ b/jme3-core/src/main/resources/Common/ShaderLib/PBR.glsllib @@ -121,6 +121,92 @@ vec3 ApproximateSpecularIBLPolynomial(samplerCube envMap, vec3 SpecularColor , f } +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 ){ + + // lightProbeData is a mat4 with this layout + // 3x3 rot mat| + // 0 1 2 | 3 + // 0 | ax bx cx | px | ) + // 1 | ay by cy | py | probe position + // 2 | az bz cz | pz | ) + // --|----------| + // 3 | sx sy sz sp | -> 1/probe radius + nbMipMaps + // --scale-- + // parallax fix for spherical / obb bounds and probe blending from + // from https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/ + vec3 rv = reflect(-viewDir, normal); + vec4 probePos = lightProbeData[3]; + float invRadius = fract( probePos.w); + float nbMipMaps = probePos.w - invRadius; + vec3 direction = worldPos - probePos.xyz; + float ndf = 0.0; + + if(lightProbeData[0][3] != 0.0){ + // oriented box probe + mat3 wToLocalRot = mat3(lightProbeData); + wToLocalRot = inverse(wToLocalRot); + vec3 scale = vec3(lightProbeData[0][3], lightProbeData[1][3], lightProbeData[2][3]); + #if NB_PROBES >= 2 + // probe blending + // compute fragment position in probe local space + vec3 localPos = wToLocalRot * worldPos; + localPos -= probePos.xyz; + // compute normalized distance field + vec3 localDir = abs(localPos); + localDir /= scale; + ndf = max(max(localDir.x, localDir.y), localDir.z); + #endif + // parallax fix + vec3 rayLs = wToLocalRot * rv; + rayLs /= scale; + + vec3 positionLs = worldPos - probePos.xyz; + positionLs = wToLocalRot * positionLs; + positionLs /= scale; + + vec3 unit = vec3(1.0); + vec3 firstPlaneIntersect = (unit - positionLs) / rayLs; + vec3 secondPlaneIntersect = (-unit - positionLs) / rayLs; + vec3 furthestPlane = max(firstPlaneIntersect, secondPlaneIntersect); + float distance = min(min(furthestPlane.x, furthestPlane.y), furthestPlane.z); + + vec3 intersectPositionWs = worldPos + rv * distance; + rv = intersectPositionWs - probePos.xyz; + + } else { + // spherical probe + // paralax fix + rv = invRadius * direction + rv; + + #if NB_PROBES >= 2 + // probe blending + float dist = sqrt(dot(direction, direction)); + ndf = dist * invRadius; + #endif + } + + vec3 indirectDiffuse = vec3(0.0); + vec3 indirectSpecular = vec3(0.0); + indirectDiffuse = sphericalHarmonics(normal.xyz, shCoeffs) * diffuseColor.rgb; + vec3 dominantR = getSpecularDominantDir( normal, rv.xyz, Roughness * Roughness ); + indirectSpecular = ApproximateSpecularIBLPolynomial(prefEnvMap, specularColor.rgb, Roughness, ndotv, dominantR, nbMipMaps); + + #ifdef HORIZON_FADE + //horizon fade from http://marmosetco.tumblr.com/post/81245981087 + float horiz = dot(rv, norm); + float horizFadePower = 1.0 - Roughness; + horiz = clamp( 1.0 + horizFadePower * horiz, 0.0, 1.0 ); + horiz *= horiz; + indirectSpecular *= vec3(horiz); + #endif + + vec3 indirectLighting = (indirectDiffuse + indirectSpecular) * ao; + + color = indirectLighting * step( 0.0, probePos.w); + return ndf; +} + +