|
@@ -22,23 +22,24 @@
|
|
|
|
|
|
#include "./torque.glsl"
|
|
|
#include "./brdf.glsl"
|
|
|
+#include "./shaderModelAutoGen.glsl"
|
|
|
+
|
|
|
#ifndef TORQUE_SHADERGEN
|
|
|
#line 26
|
|
|
// These are the uniforms used by most lighting shaders.
|
|
|
|
|
|
-uniform vec4 inLightPos[3];
|
|
|
-uniform vec4 inLightInvRadiusSq;
|
|
|
+uniform vec4 inLightPos[4];
|
|
|
+uniform vec4 inLightConfigData[4];
|
|
|
uniform vec4 inLightColor[4];
|
|
|
|
|
|
#ifndef TORQUE_BL_NOSPOTLIGHT
|
|
|
- uniform vec4 inLightSpotDir[3];
|
|
|
+ uniform vec4 inLightSpotDir[4];
|
|
|
uniform vec4 inLightSpotAngle;
|
|
|
uniform vec4 inLightSpotFalloff;
|
|
|
#endif
|
|
|
|
|
|
uniform vec4 ambient;
|
|
|
-#define ambientCameraFactor 0.3
|
|
|
-uniform float smoothness;
|
|
|
+uniform float roughness;
|
|
|
uniform float metalness;
|
|
|
uniform vec4 albedo;
|
|
|
|
|
@@ -73,48 +74,53 @@ struct Surface
|
|
|
vec3 V; // world space view vector
|
|
|
vec4 baseColor; // base color [0 -> 1] (rgba)
|
|
|
float metalness; // metalness [0:dielectric -> 1:metal]
|
|
|
- float roughness; // roughness: [0:smooth -> 1:rough] (linear)
|
|
|
- float roughness_brdf; // roughness remapped from linear to BRDF
|
|
|
+ float roughness; // material roughness: [0:smooth -> 1:rough]
|
|
|
+ float linearRoughness; // linear roughness (roughness^2)
|
|
|
+ float linearRoughnessSq; // (linearRoughness^2)
|
|
|
float depth; // depth: [0:near -> 1:far] (linear)
|
|
|
float ao; // ambient occlusion [0 -> 1]
|
|
|
float matFlag; // material flag - use getFlag to retreive
|
|
|
|
|
|
float NdotV; // cos(angle between normal and view vector)
|
|
|
vec3 f0; // fresnel value (rgb)
|
|
|
- float f90;
|
|
|
vec3 albedo; // diffuse light absorbtion value (rgb)
|
|
|
vec3 R; // reflection vector
|
|
|
vec3 F; // fresnel term computed from f0, N and V
|
|
|
+ float f90;
|
|
|
+
|
|
|
};
|
|
|
|
|
|
void updateSurface(inout Surface surface)
|
|
|
{
|
|
|
surface.NdotV = abs(dot(surface.N, surface.V)) + 1e-5f; // avoid artifact
|
|
|
|
|
|
- surface.albedo = surface.baseColor.rgb * (1.0 - surface.metalness);
|
|
|
- surface.f0 = lerp(vec3(0.04f), surface.baseColor.rgb, surface.metalness);
|
|
|
+ surface.linearRoughness = surface.roughness * surface.roughness;
|
|
|
+ surface.linearRoughnessSq = surface.linearRoughness * surface.linearRoughness;
|
|
|
+
|
|
|
+ surface.albedo = surface.baseColor.rgb * (1.0f - surface.metalness);
|
|
|
+ surface.f0 = mix(0.04f, surface.baseColor.rgb, surface.metalness);
|
|
|
+
|
|
|
surface.R = -reflect(surface.V, surface.N);
|
|
|
surface.f90 = saturate(50.0 * dot(surface.f0, vec3(0.33,0.33,0.33)));
|
|
|
surface.F = F_Schlick(surface.f0, surface.f90, surface.NdotV);
|
|
|
}
|
|
|
|
|
|
-Surface createSurface(vec4 normDepth, sampler2D colorBuffer, sampler2D matInfoBuffer, in vec2 uv, in vec3 wsEyePos, in vec3 wsEyeRay, in mat4 invView)
|
|
|
+Surface createSurface(vec4 gbuffer0, sampler2D gbufferTex1, sampler2D gbufferTex2, in vec2 uv, in vec3 wsEyePos, in vec3 wsEyeRay, in mat4 invView)
|
|
|
{
|
|
|
Surface surface;// = Surface();
|
|
|
|
|
|
- vec4 gbuffer1 = texture(colorBuffer, uv);
|
|
|
- vec4 gbuffer2 = texture(matInfoBuffer, uv);
|
|
|
- surface.depth = normDepth.a;
|
|
|
+ vec4 gbuffer1 = texture(gbufferTex1, uv);
|
|
|
+ vec4 gbuffer2 = texture(gbufferTex2, uv);
|
|
|
+ surface.depth = gbuffer0.a;
|
|
|
surface.P = wsEyePos + wsEyeRay * surface.depth;
|
|
|
- surface.N = tMul(invView, vec4(normDepth.xyz,0)).xyz;
|
|
|
+ surface.N = tMul(invView, vec4(gbuffer0.xyz,0)).xyz;
|
|
|
surface.V = normalize(wsEyePos - surface.P);
|
|
|
surface.baseColor = gbuffer1;
|
|
|
- const float minRoughness=1e-4;
|
|
|
- surface.roughness = 1.0 - (gbuffer2.b*0.8+0.1999); //t3d uses smoothness, so we convert to roughness.
|
|
|
- surface.roughness_brdf = surface.roughness * surface.roughness;
|
|
|
+ surface.roughness = clamp(gbuffer2.b, 0.01f, 1.0f);
|
|
|
surface.metalness = gbuffer2.a;
|
|
|
surface.ao = gbuffer2.g;
|
|
|
surface.matFlag = gbuffer2.r;
|
|
|
+
|
|
|
updateSurface(surface);
|
|
|
return surface;
|
|
|
}
|
|
@@ -128,9 +134,7 @@ Surface createForwardSurface(vec4 baseColor, vec3 normal, vec4 pbrProperties, in
|
|
|
surface.N = normal;
|
|
|
surface.V = normalize(wsEyePos - surface.P);
|
|
|
surface.baseColor = baseColor;
|
|
|
- const float minRoughness=1e-4;
|
|
|
- surface.roughness = 1.0 - (pbrProperties.b*0.8+0.1999); //t3d uses smoothness, so we convert to roughness.
|
|
|
- surface.roughness_brdf = surface.roughness * surface.roughness;
|
|
|
+ surface.roughness = clamp(pbrProperties.b, 0.01f, 1.0f);
|
|
|
surface.metalness = pbrProperties.a;
|
|
|
surface.ao = pbrProperties.g;
|
|
|
surface.matFlag = pbrProperties.r;
|
|
@@ -166,16 +170,15 @@ vec3 BRDF_GetDebugSpecular(in Surface surface, in SurfaceToLight surfaceToLight)
|
|
|
{
|
|
|
//GGX specular
|
|
|
vec3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
|
|
|
- float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness);
|
|
|
- float D = D_GGX(surfaceToLight.NdotH, surface.roughness);
|
|
|
- vec3 Fr = D * F * Vis;
|
|
|
- return Fr*M_1OVER_PI_F;
|
|
|
+ float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.linearRoughnessSq);
|
|
|
+ float D = D_GGX(surfaceToLight.NdotH, surface.linearRoughnessSq);
|
|
|
+ vec3 Fr = D * F * Vis * M_1OVER_PI_F;
|
|
|
+ return Fr;
|
|
|
}
|
|
|
|
|
|
vec3 BRDF_GetDebugDiffuse(in Surface surface, in SurfaceToLight surfaceToLight)
|
|
|
{
|
|
|
- vec3 Fd = surface.albedo.rgb;
|
|
|
- return Fd*M_1OVER_PI_F;
|
|
|
+ return surface.albedo.rgb * M_1OVER_PI_F;
|
|
|
}
|
|
|
|
|
|
//attenuations functions from "moving frostbite to pbr paper"
|
|
@@ -206,15 +209,15 @@ float getDistanceAtt( vec3 unormalizedLightVector , float invSqrAttRadius )
|
|
|
vec3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
|
|
|
{
|
|
|
//lambert diffuse
|
|
|
- vec3 Fd = surface.albedo.rgb;
|
|
|
+ vec3 Fd = surface.albedo.rgb * M_1OVER_PI_F;
|
|
|
|
|
|
//GGX specular
|
|
|
vec3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
|
|
|
- float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.roughness);
|
|
|
- float D = D_GGX(surfaceToLight.NdotH, surface.roughness);
|
|
|
+ float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.linearRoughnessSq);
|
|
|
+ float D = D_GGX(surfaceToLight.NdotH, surface.linearRoughnessSq);
|
|
|
vec3 Fr = D * F * Vis;
|
|
|
|
|
|
- return (Fd + Fr) * M_1OVER_PI_F;
|
|
|
+ return Fd + Fr;
|
|
|
}
|
|
|
|
|
|
vec3 getDirectionalLight(Surface surface, SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float shadow)
|
|
@@ -235,6 +238,11 @@ float computeSpecOcclusion( float NdotV , float AO , float roughness )
|
|
|
return saturate (pow( abs(NdotV + AO) , exp2 ( -16.0f * roughness - 1.0f )) - 1.0f + AO );
|
|
|
}
|
|
|
|
|
|
+float roughnessToMipLevel(float roughness, float numMips)
|
|
|
+{
|
|
|
+ return roughness * numMips;
|
|
|
+}
|
|
|
+
|
|
|
vec4 compute4Lights( Surface surface,
|
|
|
vec4 shadowMask,
|
|
|
vec4 inLightPos[4],
|
|
@@ -340,7 +348,7 @@ vec3 boxProject(vec3 wsPosition, vec3 wsReflectVec, mat4 worldToObj, vec3 refBox
|
|
|
}
|
|
|
|
|
|
vec4 computeForwardProbes(Surface surface,
|
|
|
- float cubeMips, float numProbes, mat4x4 worldToObjArray[MAX_FORWARD_PROBES], vec4 probeConfigData[MAX_FORWARD_PROBES],
|
|
|
+ float cubeMips, int numProbes, mat4x4 worldToObjArray[MAX_FORWARD_PROBES], vec4 probeConfigData[MAX_FORWARD_PROBES],
|
|
|
vec4 inProbePosArray[MAX_FORWARD_PROBES], vec4 refBoxMinArray[MAX_FORWARD_PROBES], vec4 refBoxMaxArray[MAX_FORWARD_PROBES], vec4 inRefPosArray[MAX_FORWARD_PROBES],
|
|
|
float skylightCubemapIdx, sampler2D BRDFTexture,
|
|
|
samplerCubeArray irradianceCubemapAR, samplerCubeArray specularCubemapAR)
|
|
@@ -401,11 +409,43 @@ vec4 computeForwardProbes(Surface surface,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+#if DEBUGVIZ_ATTENUATION == 1
|
|
|
+ float contribAlpha = 1;
|
|
|
+ for (i = 0; i < numProbes; ++i)
|
|
|
+ {
|
|
|
+ contribAlpha -= contribution[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ return vec4(1 - contribAlpha, 1 - contribAlpha, 1 - contribAlpha, 1);
|
|
|
+#endif
|
|
|
+
|
|
|
+#if DEBUGVIZ_CONTRIB == 1
|
|
|
+ vec3 probeContribColors[4];
|
|
|
+ probeContribColors[0] = vec3(1,0,0);
|
|
|
+ probeContribColors[1] = vec3(0,1,0);
|
|
|
+ probeContribColors[2] = vec3(0,0,1);
|
|
|
+ probeContribColors[3] = vec3(1,1,0);
|
|
|
+
|
|
|
+ vec3 finalContribColor = vec3(0, 0, 0);
|
|
|
+ float contribAlpha = 1;
|
|
|
+ for (i = 0; i < numProbes; ++i)
|
|
|
+ {
|
|
|
+ finalContribColor += contribution[i] *probeContribColors[i].rgb;
|
|
|
+ contribAlpha -= contribution[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ //Skylight coloration for anything not covered by probes above
|
|
|
+ if(skylightCubemapIdx != -1)
|
|
|
+ finalContribColor += vec3(0.3, 0.3, 0.3) * contribAlpha;
|
|
|
+
|
|
|
+ return vec4(finalContribColor, 1);
|
|
|
+#endif
|
|
|
+
|
|
|
vec3 irradiance = vec3(0, 0, 0);
|
|
|
vec3 specular = vec3(0, 0, 0);
|
|
|
|
|
|
// Radiance (Specular)
|
|
|
- float lod = surface.roughness*cubeMips;
|
|
|
+ float lod = roughnessToMipLevel(surface.roughness, cubeMips);
|
|
|
|
|
|
for (i = 0; i < numProbes; ++i)
|
|
|
{
|
|
@@ -428,17 +468,182 @@ vec4 computeForwardProbes(Surface surface,
|
|
|
}
|
|
|
|
|
|
//energy conservation
|
|
|
- vec3 kD = 1.0f - surface.F;
|
|
|
+ vec3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
|
|
|
+ vec3 kD = 1.0f - F;
|
|
|
kD *= 1.0f - surface.metalness;
|
|
|
|
|
|
float dfgNdotV = max( surface.NdotV , 0.0009765625f ); //0.5f/512.0f (512 is size of dfg/brdf lookup tex)
|
|
|
- vec2 envBRDF = textureLod(BRDFTexture, vec2(dfgNdotV, surface.roughness),0).rg;
|
|
|
- specular *= surface.F * envBRDF.x + surface.f90 * envBRDF.y;
|
|
|
+ vec2 envBRDF = texture(BRDFTexture, vec4(dfgNdotV, surface.roughness,0,0)).rg;
|
|
|
+ specular *= F * envBRDF.x + surface.f90 * envBRDF.y;
|
|
|
irradiance *= kD * surface.baseColor.rgb;
|
|
|
|
|
|
//AO
|
|
|
irradiance *= surface.ao;
|
|
|
specular *= computeSpecOcclusion(surface.NdotV, surface.ao, surface.roughness);
|
|
|
|
|
|
- return vec4(irradiance + specular, 0);//alpha writes disabled
|
|
|
+ //http://marmosetco.tumblr.com/post/81245981087
|
|
|
+ float horizonOcclusion = 1.3;
|
|
|
+ float horizon = saturate( 1 + horizonOcclusion * dot(surface.R, surface.N));
|
|
|
+ horizon *= horizon;
|
|
|
+
|
|
|
+ return vec4((irradiance + specular) * horizon, 0);//alpha writes disabled
|
|
|
}
|
|
|
+
|
|
|
+vec4 debugVizForwardProbes(Surface surface,
|
|
|
+ float cubeMips, int numProbes, mat4 worldToObjArray[MAX_FORWARD_PROBES], vec4 probeConfigData[MAX_FORWARD_PROBES],
|
|
|
+ vec4 inProbePosArray[MAX_FORWARD_PROBES], vec4 refBoxMinArray[MAX_FORWARD_PROBES], vec4 refBoxMaxArray[MAX_FORWARD_PROBES], vec4 inRefPosArray[MAX_FORWARD_PROBES],
|
|
|
+ float skylightCubemapIdx, sampler2D(BRDFTexture),
|
|
|
+ samplerCubeArray irradianceCubemapAR, samplerCubeArray specularCubemapAR, int showAtten, int showContrib, int showSpec, int showDiff)
|
|
|
+{
|
|
|
+ int i = 0;
|
|
|
+ float alpha = 1;
|
|
|
+ float blendFactor[MAX_FORWARD_PROBES];
|
|
|
+ float blendSum = 0;
|
|
|
+ float blendFacSum = 0;
|
|
|
+ float invBlendSum = 0;
|
|
|
+ float probehits = 0;
|
|
|
+ //Set up our struct data
|
|
|
+ float contribution[MAX_FORWARD_PROBES];
|
|
|
+ for (i = 0; i < numProbes; ++i)
|
|
|
+ {
|
|
|
+ contribution[i] = 0;
|
|
|
+
|
|
|
+ if (probeConfigData[i].r == 0) //box
|
|
|
+ {
|
|
|
+ contribution[i] = defineBoxSpaceInfluence(surface.P, worldToObjArray[i], probeConfigData[i].b);
|
|
|
+ if (contribution[i] > 0.0)
|
|
|
+ probehits++;
|
|
|
+ }
|
|
|
+ else if (probeConfigData[i].r == 1) //sphere
|
|
|
+ {
|
|
|
+ contribution[i] = defineSphereSpaceInfluence(surface.P, inProbePosArray[i].xyz, probeConfigData[i].g);
|
|
|
+ if (contribution[i] > 0.0)
|
|
|
+ probehits++;
|
|
|
+ }
|
|
|
+
|
|
|
+ contribution[i] = max(contribution[i], 0);
|
|
|
+
|
|
|
+ blendSum += contribution[i];
|
|
|
+ invBlendSum += (1.0f - contribution[i]);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (probehits > 1.0)
|
|
|
+ {
|
|
|
+ for (i = 0; i < numProbes; i++)
|
|
|
+ {
|
|
|
+ blendFactor[i] = ((contribution[i] / blendSum)) / probehits;
|
|
|
+ blendFactor[i] *= ((contribution[i]) / invBlendSum);
|
|
|
+ blendFactor[i] = saturate(blendFactor[i]);
|
|
|
+ blendFacSum += blendFactor[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ // Normalize blendVal
|
|
|
+ if (blendFacSum == 0.0f) // Possible with custom weight
|
|
|
+ {
|
|
|
+ blendFacSum = 1.0f;
|
|
|
+ }
|
|
|
+
|
|
|
+ float invBlendSumWeighted = 1.0f / blendFacSum;
|
|
|
+ for (i = 0; i < numProbes; ++i)
|
|
|
+ {
|
|
|
+ blendFactor[i] *= invBlendSumWeighted;
|
|
|
+ contribution[i] *= blendFactor[i];
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(showAtten == 1)
|
|
|
+ {
|
|
|
+ float contribAlpha = 1;
|
|
|
+ for (i = 0; i < numProbes; ++i)
|
|
|
+ {
|
|
|
+ contribAlpha -= contribution[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ return vec4(1 - contribAlpha, 1 - contribAlpha, 1 - contribAlpha, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(showContrib == 1)
|
|
|
+ {
|
|
|
+ vec3 probeContribColors[4];
|
|
|
+ probeContribColors[0] = vec3(1,0,0);
|
|
|
+ probeContribColors[1] = vec3(0,1,0);
|
|
|
+ probeContribColors[2] = vec3(0,0,1);
|
|
|
+ probeContribColors[3] = vec3(1,1,0);
|
|
|
+
|
|
|
+ vec3 finalContribColor = vec3(0, 0, 0);
|
|
|
+ float contribAlpha = 1;
|
|
|
+ for (i = 0; i < numProbes; ++i)
|
|
|
+ {
|
|
|
+ finalContribColor += contribution[i] *probeContribColors[i].rgb;
|
|
|
+ contribAlpha -= contribution[i];
|
|
|
+ }
|
|
|
+
|
|
|
+ //Skylight coloration for anything not covered by probes above
|
|
|
+ if(skylightCubemapIdx != -1)
|
|
|
+ finalContribColor += vec3(0.3, 0.3, 0.3) * contribAlpha;
|
|
|
+
|
|
|
+ return vec4(finalContribColor, 1);
|
|
|
+ }
|
|
|
+
|
|
|
+ vec3 irradiance = vec3(0, 0, 0);
|
|
|
+ vec3 specular = vec3(0, 0, 0);
|
|
|
+
|
|
|
+ // Radiance (Specular)
|
|
|
+ float lod = roughnessToMipLevel(surface.roughness, cubeMips);
|
|
|
+
|
|
|
+ if(showSpec == 1)
|
|
|
+ {
|
|
|
+ lod = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ for (i = 0; i < numProbes; ++i)
|
|
|
+ {
|
|
|
+ float contrib = contribution[i];
|
|
|
+ if (contrib > 0.0f)
|
|
|
+ {
|
|
|
+ int cubemapIdx = probeConfigData[i].a;
|
|
|
+ vec3 dir = boxProject(surface.P, surface.R, worldToObjArray[i], refBoxMinArray[i].xyz, refBoxMaxArray[i].xyz, inRefPosArray[i].xyz);
|
|
|
+
|
|
|
+ irradiance += textureLod(irradianceCubemapAR, dir, cubemapIdx, 0).xyz * contrib;
|
|
|
+ specular += textureLod(specularCubemapAR, dir, cubemapIdx, lod).xyz * contrib;
|
|
|
+ alpha -= contrib;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if(skylightCubemapIdx != -1 && alpha >= 0.001)
|
|
|
+ {
|
|
|
+ irradiance = mix(irradiance,textureLod(irradianceCubemapAR, surface.R, skylightCubemapIdx, 0).xyz,alpha);
|
|
|
+ specular = mix(specular,textureLod(specularCubemapAR, surface.R, skylightCubemapIdx, lod).xyz,alpha);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(showSpec == 1)
|
|
|
+ {
|
|
|
+ return vec4(specular, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ if(showDiff == 1)
|
|
|
+ {
|
|
|
+ return vec4(irradiance, 0);
|
|
|
+ }
|
|
|
+
|
|
|
+ //energy conservation
|
|
|
+ vec3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
|
|
|
+ vec3 kD = 1.0f - F;
|
|
|
+ kD *= 1.0f - surface.metalness;
|
|
|
+
|
|
|
+ float dfgNdotV = max( surface.NdotV , 0.0009765625f ); //0.5f/512.0f (512 is size of dfg/brdf lookup tex)
|
|
|
+ vec2 envBRDF = textureLod(BRDFTexture, vec2(dfgNdotV, surface.roughness),0).rg;
|
|
|
+ specular *= F * envBRDF.x + surface.f90 * envBRDF.y;
|
|
|
+ irradiance *= kD * surface.baseColor.rgb;
|
|
|
+
|
|
|
+ //AO
|
|
|
+ irradiance *= surface.ao;
|
|
|
+ specular *= computeSpecOcclusion(surface.NdotV, surface.ao, surface.roughness);
|
|
|
+
|
|
|
+ //http://marmosetco.tumblr.com/post/81245981087
|
|
|
+ float horizonOcclusion = 1.3;
|
|
|
+ float horizon = saturate( 1 + horizonOcclusion * dot(surface.R, surface.N));
|
|
|
+ horizon *= horizon;
|
|
|
+
|
|
|
+ return vec4((irradiance + specular) * horizon, 0);//alpha writes disabled
|
|
|
+}
|