mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-19 20:24:49 +00:00
specular review
cleanup of various calcs
This commit is contained in:
parent
903c987d53
commit
42710ec6f0
|
|
@ -36,41 +36,76 @@
|
|||
// Charles de Rousiers - Electronic Arts Frostbite
|
||||
// SIGGRAPH 2014
|
||||
|
||||
float3 F_Schlick(float3 f0, float f90, float u)
|
||||
float3 F_Schlick(float3 F0, float cosTheta)
|
||||
{
|
||||
return f0 + (f90 - f0) * pow(1.f - u, 5.f);
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
float3 FresnelSchlickRoughness(float cosTheta, float3 F0, float roughness)
|
||||
{
|
||||
float3 ret = float3(0.0, 0.0, 0.0);
|
||||
float powTheta = pow(1.0 - cosTheta, 5.0);
|
||||
float invRough = float(1.0 - roughness);
|
||||
// Compute the Fresnel-Schlick term for the given cosine of the angle
|
||||
float powTheta = pow(1.0 - cosTheta, 5.0);
|
||||
|
||||
// Adjust the reflectance based on roughness: The roughness scales the contrast of the Fresnel term.
|
||||
float3 fresnel = F0 + (float3(1.0, 1.0, 1.0) - F0) * powTheta;
|
||||
|
||||
// Modulate the fresnel term by roughness, reducing the effect at higher roughness
|
||||
fresnel *= (1.0 - roughness); // Adjust based on roughness
|
||||
|
||||
ret.x = F0.x + (max(invRough, F0.x) - F0.x) * powTheta;
|
||||
ret.y = F0.y + (max(invRough, F0.y) - F0.y) * powTheta;
|
||||
ret.z = F0.z + (max(invRough, F0.z) - F0.z) * powTheta;
|
||||
|
||||
return ret;
|
||||
return fresnel;
|
||||
}
|
||||
|
||||
float V_SmithGGXCorrelated(float NdotL, float NdotV, float alphaRoughnessSq)
|
||||
{
|
||||
float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
|
||||
float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
|
||||
|
||||
float GGX = GGXV + GGXL;
|
||||
if (GGX > 0.0f)
|
||||
{
|
||||
return 0.5f / GGX;
|
||||
}
|
||||
return 0.f;
|
||||
float GeometrySchlickGGX(float NdotV, float roughness) {
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
return NdotV / (NdotV * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
float D_GGX(float NdotH, float alphaRoughnessSq)
|
||||
float V_SmithGGXCorrelated(float NdotL, float NdotV, float roughness) {
|
||||
float r = roughness * roughness;
|
||||
float ggx1 = NdotV / (NdotV * (1.0 - r) + r);
|
||||
float ggx2 = NdotL / (NdotL * (1.0 - r) + r);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
float D_GGX(float NdotH, float roughnessSq)
|
||||
{
|
||||
float f = (NdotH * alphaRoughnessSq - NdotH) * NdotH + 1;
|
||||
return alphaRoughnessSq / (M_PI_F * f * f);
|
||||
float f = (NdotH * NdotH * (roughnessSq - 1.0) + 1.0);
|
||||
return roughnessSq / (M_PI_F * f * f);
|
||||
}
|
||||
|
||||
// The Cook-Torrance BRDF for specular reflection
|
||||
float3 CookTorrance(float3 normal, float3 viewDir, float roughness, float3 F)
|
||||
{
|
||||
float3 H = normalize(viewDir + reflect(-viewDir, normal));
|
||||
float NdotH = max(dot(normal, H), 0.0001);
|
||||
float VdotH = max(dot(viewDir, H), 0.0001);
|
||||
float NdotV = clamp( dot(normal, viewDir), 0.0009765625f,0.9990234375f);
|
||||
float NdotL = NdotH; // Approximate light angle
|
||||
|
||||
// Normal Distribution Function (GGX)
|
||||
float D = D_GGX(NdotH, roughness);
|
||||
|
||||
// Geometry Term (Smith GGX)
|
||||
float G = V_SmithGGXCorrelated(NdotL, NdotV, roughness);
|
||||
|
||||
// Final BRDF (Rebalanced Energy)
|
||||
return (F * D * G) / max(4.0 * NdotV * NdotL, 0.0001);
|
||||
}
|
||||
|
||||
|
||||
float3 OrenNayarDiffuse(float3 albedo, float3 N, float3 V, float3 L, float roughnessSq) {
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
|
||||
float alpha2 = roughnessSq * roughnessSq;
|
||||
float A = 1.0 + (alpha2 / (alpha2 + 0.33));
|
||||
float B = 0.45 * (alpha2 / (alpha2 + 0.09));
|
||||
|
||||
float alpha = max(NdotL, NdotV);
|
||||
float beta = min(NdotL, NdotV);
|
||||
|
||||
return albedo * (A + B * max(0.0, dot(V - N * NdotV, L - N * NdotL)) * alpha * beta) * M_1OVER_PI_F;
|
||||
}
|
||||
|
||||
float3 Fr_DisneyDiffuse(float3 F0, float NdotV, float NdotL, float LdotH, float linearRoughness)
|
||||
|
|
@ -78,8 +113,8 @@ float3 Fr_DisneyDiffuse(float3 F0, float NdotV, float NdotL, float LdotH, float
|
|||
float energyBias = lerp (0 , 0.5 , linearRoughness );
|
||||
float energyFactor = lerp (1.0 , 1.0 / 1.51 , linearRoughness );
|
||||
float fd90 = energyBias + 2.0 * LdotH * LdotH * linearRoughness ;
|
||||
float3 lightScatter = F_Schlick( F0 , fd90 , NdotL );
|
||||
float3 viewScatter = F_Schlick(F0 , fd90 , NdotV );
|
||||
float3 lightScatter = F_Schlick( F0 , fd90 );
|
||||
float3 viewScatter = F_Schlick(F0 , fd90);
|
||||
|
||||
return lightScatter * viewScatter * energyFactor ;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,52 +30,86 @@
|
|||
// Charles de Rousiers - Electronic Arts Frostbite
|
||||
// SIGGRAPH 2014
|
||||
|
||||
vec3 F_Schlick(vec3 f0, float f90, float u)
|
||||
vec3 F_Schlick(vec3 F0, float cosTheta)
|
||||
{
|
||||
return f0 + (f90 - f0) * pow(1.f - u, 5.f);
|
||||
return F0 + (1.0 - F0) * pow(1.0 - cosTheta, 5.0);
|
||||
}
|
||||
|
||||
vec3 FresnelSchlickRoughness(float cosTheta, vec3 F0, float roughness)
|
||||
{
|
||||
vec3 ret = vec3(0.0, 0.0, 0.0);
|
||||
float powTheta = pow(1.0 - cosTheta, 5.0);
|
||||
float invRough = float(1.0 - roughness);
|
||||
// Compute the Fresnel-Schlick term for the given cosine of the angle
|
||||
float powTheta = pow(1.0 - cosTheta, 5.0);
|
||||
|
||||
// Adjust the reflectance based on roughness: The roughness scales the contrast of the Fresnel term.
|
||||
vec3 fresnel = F0 + (vec3(1.0, 1.0, 1.0) - F0) * powTheta;
|
||||
|
||||
// Modulate the fresnel term by roughness, reducing the effect at higher roughness
|
||||
fresnel *= (1.0 - roughness); // Adjust based on roughness
|
||||
|
||||
ret.x = F0.x + (max(invRough, F0.x) - F0.x) * powTheta;
|
||||
ret.y = F0.y + (max(invRough, F0.y) - F0.y) * powTheta;
|
||||
ret.z = F0.z + (max(invRough, F0.z) - F0.z) * powTheta;
|
||||
|
||||
return ret;
|
||||
return fresnel;
|
||||
}
|
||||
|
||||
float V_SmithGGXCorrelated(float NdotL, float NdotV, float alphaRoughnessSq)
|
||||
{
|
||||
float GGXV = NdotL * sqrt(NdotV * NdotV * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
|
||||
float GGXL = NdotV * sqrt(NdotL * NdotL * (1.0 - alphaRoughnessSq) + alphaRoughnessSq);
|
||||
|
||||
float GGX = GGXV + GGXL;
|
||||
if (GGX > 0.0f)
|
||||
{
|
||||
return 0.5f / GGX;
|
||||
}
|
||||
return 0.f;
|
||||
float GeometrySchlickGGX(float NdotV, float roughness) {
|
||||
float r = (roughness + 1.0);
|
||||
float k = (r * r) / 8.0;
|
||||
return NdotV / (NdotV * (1.0 - k) + k);
|
||||
}
|
||||
|
||||
float D_GGX(float NdotH, float alphaRoughnessSq)
|
||||
float V_SmithGGXCorrelated(float NdotL, float NdotV, float roughness) {
|
||||
float r = roughness * roughness;
|
||||
float ggx1 = NdotV / (NdotV * (1.0 - r) + r);
|
||||
float ggx2 = NdotL / (NdotL * (1.0 - r) + r);
|
||||
return ggx1 * ggx2;
|
||||
}
|
||||
|
||||
float D_GGX(float NdotH, float roughnessSq)
|
||||
{
|
||||
float f = (NdotH * alphaRoughnessSq - NdotH) * NdotH + 1;
|
||||
return alphaRoughnessSq / (M_PI_F * f * f);
|
||||
float f = (NdotH * NdotH * (roughnessSq - 1.0) + 1.0);
|
||||
return roughnessSq / (M_PI_F * f * f);
|
||||
}
|
||||
|
||||
// The Cook-Torrance BRDF for specular reflection
|
||||
vec3 CookTorrance(vec3 normal, vec3 viewDir, float roughness, vec3 F)
|
||||
{
|
||||
vec3 H = normalize(viewDir + reflect(-viewDir, normal));
|
||||
float NdotH = max(dot(normal, H), 0.0001);
|
||||
float VdotH = max(dot(viewDir, H), 0.0001);
|
||||
float NdotV = clamp( dot(normal, viewDir), 0.0009765625f,0.9990234375f);
|
||||
float NdotL = NdotH; // Approximate light angle
|
||||
|
||||
// Normal Distribution Function (GGX)
|
||||
float D = D_GGX(NdotH, roughness);
|
||||
|
||||
// Geometry Term (Smith GGX)
|
||||
float G = V_SmithGGXCorrelated(NdotL, NdotV, roughness);
|
||||
|
||||
// Final BRDF (Rebalanced Energy)
|
||||
return (F * D * G) / max(4.0 * NdotV * NdotL, 0.0001);
|
||||
}
|
||||
|
||||
|
||||
vec3 OrenNayarDiffuse(vec3 albedo, vec3 N, vec3 V, vec3 L, float roughnessSq) {
|
||||
float NdotL = max(dot(N, L), 0.0);
|
||||
float NdotV = max(dot(N, V), 0.0);
|
||||
|
||||
float alpha2 = roughnessSq * roughnessSq;
|
||||
float A = 1.0 + (alpha2 / (alpha2 + 0.33));
|
||||
float B = 0.45 * (alpha2 / (alpha2 + 0.09));
|
||||
|
||||
float alpha = max(NdotL, NdotV);
|
||||
float beta = min(NdotL, NdotV);
|
||||
|
||||
return albedo * (A + B * max(0.0, dot(V - N * NdotV, L - N * NdotL)) * alpha * beta) * M_1OVER_PI_F;
|
||||
}
|
||||
|
||||
vec3 Fr_DisneyDiffuse(vec3 F0, float NdotV, float NdotL, float LdotH, float linearRoughness)
|
||||
{
|
||||
float energyBias = lerp(0 , 0.5 , linearRoughness );
|
||||
float energyFactor = lerp(1.0 , 1.0 / 1.51 , linearRoughness );
|
||||
float energyBias = lerp (0 , 0.5 , linearRoughness );
|
||||
float energyFactor = lerp (1.0 , 1.0 / 1.51 , linearRoughness );
|
||||
float fd90 = energyBias + 2.0 * LdotH * LdotH * linearRoughness ;
|
||||
vec3 lightScatter = F_Schlick( F0 , fd90 , NdotL );
|
||||
vec3 viewScatter = F_Schlick(F0 , fd90 , NdotV );
|
||||
vec3 lightScatter = F_Schlick( F0 , fd90 );
|
||||
vec3 viewScatter = F_Schlick(F0 , fd90);
|
||||
|
||||
return lightScatter * viewScatter * energyFactor ;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -114,12 +114,12 @@ void updateSurface(inout Surface surface)
|
|||
surface.linearRoughness = surface.roughness * surface.roughness;
|
||||
surface.linearRoughnessSq = surface.linearRoughness * surface.linearRoughness;
|
||||
|
||||
surface.albedo = surface.baseColor.rgb * (1.0f - surface.metalness);
|
||||
surface.albedo = max(toLinear(surface.baseColor.rgb),0.04f);
|
||||
surface.f0 = mix(vec3(0.04f,0.04f,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.F = F_Schlick(surface.f0, surface.NdotV);
|
||||
}
|
||||
|
||||
Surface createSurface(vec4 gbuffer0, sampler2D gbufferTex1, sampler2D gbufferTex2, in vec2 uv, in vec3 wsEyePos, in vec3 wsEyeRay, in mat4 invView)
|
||||
|
|
@ -186,7 +186,7 @@ SurfaceToLight createSurfaceToLight(in Surface surface, in vec3 L)
|
|||
vec3 BRDF_GetDebugSpecular(in Surface surface, in SurfaceToLight surfaceToLight)
|
||||
{
|
||||
//GGX specular
|
||||
vec3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
|
||||
vec3 F = F_Schlick(surface.f0, surface.NdotV);
|
||||
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;
|
||||
|
|
@ -225,19 +225,31 @@ float getDistanceAtt( vec3 unormalizedLightVector , float invSqrAttRadius )
|
|||
|
||||
vec3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
|
||||
{
|
||||
//diffuse term
|
||||
vec3 Fd = surface.baseColor.rgb * M_1OVER_PI_F * surface.ao;
|
||||
// Compute Fresnel term
|
||||
vec3 F = F_Schlick(surface.f0, surfaceToLight.HdotV);
|
||||
|
||||
//GGX specular
|
||||
vec3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
|
||||
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.linearRoughnessSq);
|
||||
float D = D_GGX(surfaceToLight.NdotH, surface.linearRoughnessSq);
|
||||
vec3 Fr = D * F * Vis;
|
||||
// GGX Normal Distribution Function
|
||||
float D = D_GGX(surfaceToLight.NdotH, surface.linearRoughness);
|
||||
|
||||
// Smith GGX Geometry Function
|
||||
float G = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.linearRoughness);
|
||||
|
||||
// Specular BRDF
|
||||
vec3 numerator = D * G * F;
|
||||
float denominator = 4.0 * max(surface.NdotV, 0.0) * max(surfaceToLight.NdotL, 0.0) + 0.0001;
|
||||
vec3 specularBRDF = numerator / denominator;
|
||||
|
||||
vec3 diffuseBRDF = surface.baseColor.rgb * M_1OVER_PI_F * surface.ao;
|
||||
|
||||
// Final output combining all terms
|
||||
vec3 kS = F; // Specular reflectance
|
||||
vec3 kD = (1.0 - kS) * (1.0 - surface.metalness); // Diffuse reflectance
|
||||
vec3 returnBRDF = kD * (diffuseBRDF) + specularBRDF;
|
||||
|
||||
if(isCapturing == 1)
|
||||
return mix(Fd + Fr, surface.baseColor.rgb, surface.metalness);
|
||||
return lerp(returnBRDF ,surface.albedo.rgb,surface.metalness);
|
||||
else
|
||||
return Fd + Fr;
|
||||
return returnBRDF;
|
||||
}
|
||||
|
||||
vec3 getDirectionalLight(Surface surface, SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float shadow)
|
||||
|
|
@ -246,8 +258,13 @@ vec3 getDirectionalLight(Surface surface, SurfaceToLight surfaceToLight, vec3 li
|
|||
if(isCapturing != 1)
|
||||
lightfloor = 0.0;
|
||||
|
||||
vec3 factor = lightColor * max(surfaceToLight.NdotL * shadow * lightIntensity, lightfloor);
|
||||
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
|
||||
// Calculate both specular and diffuse lighting in one BRDF evaluation
|
||||
vec3 directLighting = evaluateStandardBRDF(surface, surfaceToLight);
|
||||
|
||||
// Direct Diffuse Light Contribution (using Lambertian diffuse in BRDF)
|
||||
vec3 diffuseLight = directLighting * (lightColor * max(surfaceToLight.NdotL * shadow * lightIntensity, lightfloor));
|
||||
|
||||
return diffuseLight;
|
||||
}
|
||||
|
||||
vec3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float radius, float shadow)
|
||||
|
|
@ -257,8 +274,14 @@ vec3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, vec3 light
|
|||
lightfloor = 0.0;
|
||||
|
||||
float attenuation = getDistanceAtt(surfaceToLight.Lu, radius);
|
||||
vec3 factor = lightColor * max(surfaceToLight.NdotL * shadow * lightIntensity * attenuation, lightfloor);
|
||||
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
|
||||
|
||||
// Calculate both specular and diffuse lighting in one BRDF evaluation
|
||||
vec3 directLighting = evaluateStandardBRDF(surface, surfaceToLight);
|
||||
|
||||
// Direct Diffuse Light Contribution (using Lambertian diffuse in BRDF)
|
||||
vec3 diffuseLight = directLighting * lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, lightfloor);
|
||||
|
||||
return diffuseLight;
|
||||
}
|
||||
|
||||
vec3 getSpotlight(Surface surface, SurfaceToLight surfaceToLight, vec3 lightColor, float lightIntensity, float radius, vec3 lightDir, vec2 lightSpotParams, float shadow)
|
||||
|
|
@ -270,18 +293,32 @@ vec3 getSpotlight(Surface surface, SurfaceToLight surfaceToLight, vec3 lightColo
|
|||
float attenuation = 1.0f;
|
||||
attenuation *= getDistanceAtt(surfaceToLight.Lu, radius);
|
||||
attenuation *= getSpotAngleAtt(-surfaceToLight.L, lightDir, lightSpotParams.xy);
|
||||
vec3 factor = lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, lightfloor);
|
||||
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
|
||||
|
||||
// Calculate both specular and diffuse lighting in one BRDF evaluation
|
||||
vec3 directLighting = evaluateStandardBRDF(surface, surfaceToLight);
|
||||
|
||||
// Direct Diffuse Light Contribution (using Lambertian diffuse in BRDF)
|
||||
vec3 diffuseLight = directLighting * lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, lightfloor);
|
||||
|
||||
return diffuseLight;
|
||||
}
|
||||
|
||||
float computeSpecOcclusion( float NdotV , float AO , float roughness )
|
||||
{
|
||||
return saturate (pow( abs(NdotV + AO) , exp2 ( -16.0f * roughness - 1.0f )) - 1.0f + AO );
|
||||
// Compute the geometry term using Smith's GGX for occlusion
|
||||
float r = roughness * roughness; // Roughness squared
|
||||
float ggx = (NdotV) / (NdotV * (1.0 - r) + r); // Smith GGX Geometry Function for occlusion
|
||||
|
||||
// Optionally modify by AO (ambient occlusion) and roughness
|
||||
float specOcclusion = pow(ggx + AO, 2.0);
|
||||
|
||||
// Return the final occlusion factor (clamped between 0 and 1)
|
||||
return saturate(specOcclusion);
|
||||
}
|
||||
|
||||
float roughnessToMipLevel(float roughness, float numMips)
|
||||
{
|
||||
return pow(abs(roughness),0.25) * numMips;
|
||||
return saturate((roughness * numMips) - (pow(roughness, 6.0) * (numMips * 0.125)));
|
||||
}
|
||||
|
||||
vec4 compute4Lights( Surface surface,
|
||||
|
|
@ -541,33 +578,24 @@ vec4 computeForwardProbes(Surface surface,
|
|||
|
||||
if(skylightCubemapIdx != -1 && alpha >= 0.001)
|
||||
{
|
||||
irradiance = mix(irradiance,textureLod(irradianceCubemapAR, vec4(surface.R, skylightCubemapIdx), 0).xyz, alpha);
|
||||
irradiance = mix(irradiance,textureLod(irradianceCubemapAR, vec4(surface.N, skylightCubemapIdx), 0).xyz, alpha);
|
||||
specular = mix(specular,textureLod(specularCubemapAR, vec4(surface.R, skylightCubemapIdx), lod).xyz, alpha);
|
||||
}
|
||||
|
||||
//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(surface.NdotV, surface.roughness),0).rg;
|
||||
specular *= F * envBRDF.x + surface.f90 * envBRDF.y;
|
||||
irradiance *= kD * surface.baseColor.rgb;
|
||||
vec3 diffuse = irradiance * surface.baseColor.rgb * (1.0 - surface.metalness);
|
||||
|
||||
//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;
|
||||
|
||||
vec3 specularCol = specular * (F_Schlick(surface.f0, surface.NdotV) * envBRDF.x + envBRDF.y);
|
||||
specularCol *= surface.metalness + (1.0 - surface.roughness);
|
||||
// Final color output after environment lighting
|
||||
vec3 finalColor = diffuse + specularCol;
|
||||
finalColor *= surface.ao;
|
||||
if(isCapturing == 1)
|
||||
return vec4(mix((irradiance + specular* horizon),surface.baseColor.rgb,surface.metalness),0);
|
||||
return vec4(lerp((finalColor), surface.baseColor.rgb,surface.metalness),0);
|
||||
else
|
||||
return vec4((irradiance + specular* horizon) , 0);//alpha writes disabled
|
||||
{
|
||||
return vec4(finalColor, 0);
|
||||
}
|
||||
}
|
||||
|
||||
vec4 debugVizForwardProbes(Surface surface,
|
||||
|
|
@ -693,7 +721,7 @@ vec4 debugVizForwardProbes(Surface surface,
|
|||
|
||||
if(skylightCubemapIdx != -1 && alpha >= 0.001)
|
||||
{
|
||||
irradiance = mix(irradiance,textureLod(irradianceCubemapAR, vec4(surface.R, skylightCubemapIdx), 0).xyz,alpha);
|
||||
irradiance = mix(irradiance,textureLod(irradianceCubemapAR, vec4(surface.N, skylightCubemapIdx), 0).xyz,alpha);
|
||||
specular = mix(specular,textureLod(specularCubemapAR, vec4(surface.R, skylightCubemapIdx), lod).xyz,alpha);
|
||||
}
|
||||
|
||||
|
|
@ -707,23 +735,18 @@ vec4 debugVizForwardProbes(Surface surface,
|
|||
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;
|
||||
|
||||
vec2 envBRDF = textureLod(BRDFTexture, vec2(surface.NdotV, surface.roughness),0).rg;
|
||||
specular *= F * envBRDF.x + surface.f90 * envBRDF.y;
|
||||
irradiance *= kD * surface.baseColor.rgb;
|
||||
vec3 diffuse = irradiance * surface.baseColor.rgb * (1.0 - surface.metalness);
|
||||
|
||||
//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
|
||||
vec3 specularCol = specular * (F_Schlick(surface.f0, surface.NdotV) * envBRDF.x + envBRDF.y);
|
||||
specularCol *= surface.metalness + (1.0 - surface.roughness);
|
||||
// Final color output after environment lighting
|
||||
vec3 finalColor = diffuse + specularCol;
|
||||
finalColor *= surface.ao;
|
||||
if(isCapturing == 1)
|
||||
return vec4(lerp((finalColor), surface.baseColor.rgb,surface.metalness),0);
|
||||
else
|
||||
{
|
||||
return vec4(finalColor, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,12 +113,12 @@ struct Surface
|
|||
linearRoughness = roughness * roughness;
|
||||
linearRoughnessSq = linearRoughness * linearRoughness;
|
||||
|
||||
albedo = baseColor.rgb * (1.0f - metalness);
|
||||
f0 = lerp(0.04f, baseColor.rgb, metalness);
|
||||
albedo = max(toLinear(baseColor.rgb),0.04f);
|
||||
f0 = lerp(0.04f, albedo.rgb, metalness);
|
||||
|
||||
R = -reflect(V, N);
|
||||
f90 = saturate(50.0f * dot(f0, 0.33f));
|
||||
F = F_Schlick(f0, f90, NdotV);
|
||||
F = F_Schlick(f0, NdotV);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
@ -187,7 +187,7 @@ inline SurfaceToLight createSurfaceToLight(in Surface surface, in float3 L)
|
|||
float3 BRDF_GetDebugSpecular(in Surface surface, in SurfaceToLight surfaceToLight)
|
||||
{
|
||||
//GGX specular
|
||||
float3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
|
||||
float3 F = F_Schlick(surface.f0, surface.NdotV);
|
||||
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.linearRoughnessSq);
|
||||
float D = D_GGX(surfaceToLight.NdotH, surface.linearRoughnessSq);
|
||||
float3 Fr = D * F * Vis * M_1OVER_PI_F;
|
||||
|
|
@ -226,19 +226,31 @@ float getDistanceAtt( float3 unormalizedLightVector , float invSqrAttRadius )
|
|||
|
||||
float3 evaluateStandardBRDF(Surface surface, SurfaceToLight surfaceToLight)
|
||||
{
|
||||
//diffuse term
|
||||
float3 Fd = surface.baseColor.rgb * M_1OVER_PI_F * surface.ao;
|
||||
// Compute Fresnel term
|
||||
float3 F = F_Schlick(surface.f0, surfaceToLight.HdotV);
|
||||
|
||||
//GGX specular
|
||||
float3 F = F_Schlick(surface.f0, surface.f90, surfaceToLight.HdotV);
|
||||
float Vis = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.linearRoughnessSq);
|
||||
float D = D_GGX(surfaceToLight.NdotH, surface.linearRoughnessSq);
|
||||
float3 Fr = D * F * Vis;
|
||||
// GGX Normal Distribution Function
|
||||
float D = D_GGX(surfaceToLight.NdotH, surface.linearRoughness);
|
||||
|
||||
// Smith GGX Geometry Function
|
||||
float G = V_SmithGGXCorrelated(surface.NdotV, surfaceToLight.NdotL, surface.linearRoughness);
|
||||
|
||||
// Specular BRDF
|
||||
float3 numerator = D * G * F;
|
||||
float denominator = 4.0 * max(surface.NdotV, 0.0) * max(surfaceToLight.NdotL, 0.0) + 0.0001;
|
||||
float3 specularBRDF = numerator / denominator;
|
||||
|
||||
float3 diffuseBRDF = surface.baseColor.rgb * M_1OVER_PI_F * surface.ao;
|
||||
|
||||
// Final output combining all terms
|
||||
float3 kS = F; // Specular reflectance
|
||||
float3 kD = (1.0 - kS) * (1.0 - surface.metalness); // Diffuse reflectance
|
||||
float3 returnBRDF = kD * (diffuseBRDF) + specularBRDF;
|
||||
|
||||
if(isCapturing == 1)
|
||||
return lerp(Fd + Fr,surface.baseColor.rgb,surface.metalness);
|
||||
return lerp(returnBRDF ,surface.albedo.rgb,surface.metalness);
|
||||
else
|
||||
return Fd + Fr;
|
||||
return returnBRDF;
|
||||
}
|
||||
|
||||
float3 getDirectionalLight(Surface surface, SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float shadow)
|
||||
|
|
@ -247,8 +259,13 @@ float3 getDirectionalLight(Surface surface, SurfaceToLight surfaceToLight, float
|
|||
if(isCapturing != 1)
|
||||
lightfloor = 0.0;
|
||||
|
||||
float3 factor = lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity, lightfloor) ;
|
||||
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
|
||||
// Calculate both specular and diffuse lighting in one BRDF evaluation
|
||||
float3 directLighting = evaluateStandardBRDF(surface, surfaceToLight);
|
||||
|
||||
// Direct Diffuse Light Contribution (using Lambertian diffuse in BRDF)
|
||||
float3 diffuseLight = directLighting * (lightColor * max(surfaceToLight.NdotL * shadow * lightIntensity, lightfloor));
|
||||
|
||||
return diffuseLight;
|
||||
}
|
||||
|
||||
float3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float radius, float shadow)
|
||||
|
|
@ -258,8 +275,14 @@ float3 getPunctualLight(Surface surface, SurfaceToLight surfaceToLight, float3 l
|
|||
lightfloor = 0.0;
|
||||
|
||||
float attenuation = getDistanceAtt(surfaceToLight.Lu, radius);
|
||||
float3 factor = lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, lightfloor) ;
|
||||
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
|
||||
|
||||
// Calculate both specular and diffuse lighting in one BRDF evaluation
|
||||
float3 directLighting = evaluateStandardBRDF(surface, surfaceToLight);
|
||||
|
||||
// Direct Diffuse Light Contribution (using Lambertian diffuse in BRDF)
|
||||
float3 diffuseLight = directLighting * lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, lightfloor);
|
||||
|
||||
return diffuseLight;
|
||||
}
|
||||
|
||||
float3 getSpotlight(Surface surface, SurfaceToLight surfaceToLight, float3 lightColor, float lightIntensity, float radius, float3 lightDir, float2 lightSpotParams, float shadow)
|
||||
|
|
@ -271,18 +294,32 @@ float3 getSpotlight(Surface surface, SurfaceToLight surfaceToLight, float3 light
|
|||
float attenuation = 1.0f;
|
||||
attenuation *= getDistanceAtt(surfaceToLight.Lu, radius);
|
||||
attenuation *= getSpotAngleAtt(-surfaceToLight.L, lightDir, lightSpotParams.xy);
|
||||
float3 factor = lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, lightfloor) ;
|
||||
return evaluateStandardBRDF(surface,surfaceToLight) * factor;
|
||||
|
||||
// Calculate both specular and diffuse lighting in one BRDF evaluation
|
||||
float3 directLighting = evaluateStandardBRDF(surface, surfaceToLight);
|
||||
|
||||
// Direct Diffuse Light Contribution (using Lambertian diffuse in BRDF)
|
||||
float3 diffuseLight = directLighting * lightColor * max(surfaceToLight.NdotL* shadow * lightIntensity * attenuation, lightfloor);
|
||||
|
||||
return diffuseLight;
|
||||
}
|
||||
|
||||
float computeSpecOcclusion( float NdotV , float AO , float roughness )
|
||||
{
|
||||
return saturate (pow( abs(NdotV + AO) , exp2 ( -16.0f * roughness - 1.0f )) - 1.0f + AO );
|
||||
// Compute the geometry term using Smith's GGX for occlusion
|
||||
float r = roughness * roughness; // Roughness squared
|
||||
float ggx = (NdotV) / (NdotV * (1.0 - r) + r); // Smith GGX Geometry Function for occlusion
|
||||
|
||||
// Optionally modify by AO (ambient occlusion) and roughness
|
||||
float specOcclusion = pow(ggx + AO, 2.0);
|
||||
|
||||
// Return the final occlusion factor (clamped between 0 and 1)
|
||||
return saturate(specOcclusion);
|
||||
}
|
||||
|
||||
float roughnessToMipLevel(float roughness, float numMips)
|
||||
{
|
||||
return pow(abs(roughness),0.25) * numMips;
|
||||
return saturate((roughness * numMips) - (pow(roughness, 6.0) * (numMips * 0.125)));
|
||||
}
|
||||
|
||||
float4 compute4Lights( Surface surface,
|
||||
|
|
@ -547,33 +584,24 @@ float4 computeForwardProbes(Surface surface,
|
|||
|
||||
if(skylightCubemapIdx != -1 && alpha >= 0.001)
|
||||
{
|
||||
irradiance = lerp(irradiance,TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, surface.R, skylightCubemapIdx, 0).xyz,alpha);
|
||||
irradiance = lerp(irradiance,TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, surface.N, skylightCubemapIdx, 0).xyz,alpha);
|
||||
specular = lerp(specular,TORQUE_TEXCUBEARRAYLOD(specularCubemapAR, surface.R, skylightCubemapIdx, lod).xyz,alpha);
|
||||
}
|
||||
|
||||
//energy conservation
|
||||
float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
|
||||
float3 kD = 1.0f - F;
|
||||
kD *= 1.0f - surface.metalness;
|
||||
float2 envBRDF = TORQUE_TEX2D(BRDFTexture, float2(surface.NdotV, surface.roughness)).rg;
|
||||
float3 diffuse = irradiance * surface.baseColor.rgb * (1.0 - surface.metalness);
|
||||
|
||||
//float dfgNdotV = max( surface.NdotV , 0.0009765625f ); //0.5f/512.0f (512 is size of dfg/brdf lookup tex)
|
||||
float2 envBRDF = TORQUE_TEX2DLOD(BRDFTexture, float4(surface.NdotV, 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);
|
||||
|
||||
//http://marmosetco.tumblr.com/post/81245981087
|
||||
float horizonOcclusion = 1.3;
|
||||
float horizon = saturate( 1 + horizonOcclusion * dot(surface.R, surface.N));
|
||||
horizon *= horizon;
|
||||
|
||||
float3 specularCol = specular * (F_Schlick(surface.f0, surface.NdotV) * envBRDF.x + envBRDF.y);
|
||||
specularCol *= surface.metalness + (1.0 - surface.roughness);
|
||||
// Final color output after environment lighting
|
||||
float3 finalColor = diffuse + specularCol;
|
||||
finalColor *= surface.ao;
|
||||
if(isCapturing == 1)
|
||||
return float4(lerp((irradiance + specular* horizon),surface.baseColor.rgb,surface.metalness),0);
|
||||
return float4(lerp((finalColor), surface.baseColor.rgb,surface.metalness),0);
|
||||
else
|
||||
return float4((irradiance + specular* horizon) , 0);//alpha writes disabled
|
||||
{
|
||||
return float4(finalColor, 0);
|
||||
}
|
||||
}
|
||||
|
||||
float4 debugVizForwardProbes(Surface surface,
|
||||
|
|
@ -713,23 +741,18 @@ float4 debugVizForwardProbes(Surface surface,
|
|||
return float4(irradiance, 0);
|
||||
}
|
||||
|
||||
//energy conservation
|
||||
float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
|
||||
float3 kD = 1.0f - F;
|
||||
kD *= 1.0f - surface.metalness;
|
||||
float2 envBRDF = TORQUE_TEX2D(BRDFTexture, float2(surface.NdotV, surface.roughness)).rg;
|
||||
float3 diffuse = irradiance * surface.baseColor.rgb * (1.0 - surface.metalness);
|
||||
|
||||
float2 envBRDF = TORQUE_TEX2DLOD(BRDFTexture, float4(surface.NdotV, 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);
|
||||
|
||||
//http://marmosetco.tumblr.com/post/81245981087
|
||||
float horizonOcclusion = 1.3;
|
||||
float horizon = saturate( 1 + horizonOcclusion * dot(surface.R, surface.N));
|
||||
horizon *= horizon;
|
||||
|
||||
return float4((irradiance + specular* horizon) , 0);//alpha writes disabled
|
||||
float3 specularCol = specular * (F_Schlick(surface.f0, surface.NdotV) * envBRDF.x + envBRDF.y);
|
||||
specularCol *= surface.metalness + (1.0 - surface.roughness);
|
||||
// Final color output after environment lighting
|
||||
float3 finalColor = diffuse + specularCol;
|
||||
finalColor *= surface.ao;
|
||||
if(isCapturing == 1)
|
||||
return float4(lerp((finalColor), surface.baseColor.rgb,surface.metalness),0);
|
||||
else
|
||||
{
|
||||
return float4(finalColor, 0);
|
||||
}
|
||||
}
|
||||
|
|
@ -204,27 +204,18 @@ void main()
|
|||
return;
|
||||
#endif
|
||||
|
||||
|
||||
//energy conservation
|
||||
vec3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
|
||||
vec3 kD = 1.0f - F;
|
||||
kD *= 1.0f - surface.metalness;
|
||||
|
||||
vec2 envBRDF = textureLod(BRDFTexture, vec2(surface.NdotV, surface.roughness),0).rg;
|
||||
specular *= F * envBRDF.x + surface.f90 * envBRDF.y;
|
||||
irradiance *= kD * surface.baseColor.rgb;
|
||||
vec3 diffuse = irradiance * surface.baseColor.rgb * (1.0 - surface.metalness);
|
||||
|
||||
//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;
|
||||
|
||||
vec3 specularCol = specular * (F_Schlick(surface.f0, surface.NdotV) * envBRDF.x + envBRDF.y);
|
||||
specularCol *= surface.metalness + (1.0 - surface.roughness);
|
||||
// Final color output after environment lighting
|
||||
vec3 finalColor = diffuse + specularCol;
|
||||
finalColor *= surface.ao;
|
||||
if(isCapturing == 1)
|
||||
OUT_col = vec4(mix((irradiance + specular* horizon),surface.baseColor.rgb, surface.metalness),0);
|
||||
OUT_col = vec4(lerp((finalColor), surface.baseColor.rgb,surface.metalness),0);
|
||||
else
|
||||
OUT_col = vec4((irradiance + specular* horizon)*ambientColor, 0);//alpha writes disabled
|
||||
{
|
||||
OUT_col = vec4(finalColor*ambientColor, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,13 +159,14 @@ float4 main(PFXVertToPix IN) : SV_TARGET
|
|||
dampen(surface, TORQUE_SAMPLER2D_MAKEARG(WetnessTexture), accumTime, wetAmmout*dampness);
|
||||
|
||||
// Radiance (Specular)
|
||||
#if DEBUGVIZ_SPECCUBEMAP == 0
|
||||
float lod = roughnessToMipLevel(surface.roughness, cubeMips);
|
||||
#elif DEBUGVIZ_SPECCUBEMAP == 1
|
||||
float lod = 0;
|
||||
#endif
|
||||
#if DEBUGVIZ_SPECCUBEMAP == 0
|
||||
lod = roughnessToMipLevel(surface.roughness, cubeMips);
|
||||
#elif DEBUGVIZ_SPECCUBEMAP == 1
|
||||
lod = 0;
|
||||
#endif
|
||||
|
||||
#if SKYLIGHT_ONLY == 0
|
||||
#if SKYLIGHT_ONLY == 0
|
||||
for (i = 0; i < numProbes; i++)
|
||||
{
|
||||
float contrib = contribution[i];
|
||||
|
|
@ -181,7 +182,7 @@ float4 main(PFXVertToPix IN) : SV_TARGET
|
|||
#endif
|
||||
if(skylightCubemapIdx != -1 && alpha >= 0.001)
|
||||
{
|
||||
irradiance = lerp(irradiance,TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, surface.R, skylightCubemapIdx, 0).xyz,alpha);
|
||||
irradiance = lerp(irradiance,TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, surface.N, skylightCubemapIdx, 0).xyz,alpha);
|
||||
specular = lerp(specular,TORQUE_TEXCUBEARRAYLOD(specularCubemapAR, surface.R, skylightCubemapIdx, lod).xyz,alpha);
|
||||
}
|
||||
|
||||
|
|
@ -189,27 +190,20 @@ float4 main(PFXVertToPix IN) : SV_TARGET
|
|||
return float4(specular, 1);
|
||||
#elif DEBUGVIZ_DIFFCUBEMAP == 1
|
||||
return float4(irradiance, 1);
|
||||
#endif
|
||||
//energy conservation
|
||||
float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
|
||||
float3 kD = 1.0f - F;
|
||||
kD *= 1.0f - surface.metalness;
|
||||
#endif
|
||||
|
||||
float2 envBRDF = TORQUE_TEX2DLOD(BRDFTexture, float4(surface.NdotV, surface.roughness,0,0)).rg;
|
||||
specular *= F * envBRDF.x + surface.f90 * envBRDF.y;
|
||||
irradiance *= kD * surface.baseColor.rgb;
|
||||
float2 envBRDF = TORQUE_TEX2D(BRDFTexture, float2(surface.NdotV, surface.roughness)).rg;
|
||||
float3 diffuse = irradiance * surface.baseColor.rgb * (1.0 - surface.metalness);
|
||||
|
||||
//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;
|
||||
|
||||
float3 specularCol = specular * (F_Schlick(surface.f0, surface.NdotV) * envBRDF.x + envBRDF.y);
|
||||
specularCol *= surface.metalness + (1.0 - surface.roughness);
|
||||
// Final color output after environment lighting
|
||||
float3 finalColor = diffuse + specularCol;
|
||||
finalColor *= surface.ao;
|
||||
if(isCapturing == 1)
|
||||
return float4(lerp((irradiance + specular* horizon), surface.baseColor.rgb,surface.metalness),0);
|
||||
return float4(lerp((finalColor), surface.baseColor.rgb,surface.metalness),0);
|
||||
else
|
||||
return float4((irradiance + specular* horizon)*ambientColor, 0);//alpha writes disabled
|
||||
{
|
||||
return float4((finalColor*ambientColor), 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue