|
@@ -88,9 +88,121 @@ void compute4Lights( float3 wsView,
|
|
out float4 outDiffuse,
|
|
out float4 outDiffuse,
|
|
out float4 outSpecular )
|
|
out float4 outSpecular )
|
|
{
|
|
{
|
|
-
|
|
|
|
- outDiffuse = float4(0,0,0,0);
|
|
|
|
- outSpecular = float4(0,0,0,0);
|
|
|
|
|
|
+ // NOTE: The light positions and spotlight directions
|
|
|
|
+ // are stored in SoA order, so inLightPos[0] is the
|
|
|
|
+ // x coord for all 4 lights... inLightPos[1] is y... etc.
|
|
|
|
+ //
|
|
|
|
+ // This is the key to fully utilizing the vector units and
|
|
|
|
+ // saving a huge amount of instructions.
|
|
|
|
+ //
|
|
|
|
+ // For example this change saved more than 10 instructions
|
|
|
|
+ // over a simple for loop for each light.
|
|
|
|
+
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ float4 lightVectors[3];
|
|
|
|
+ for ( i = 0; i < 3; i++ )
|
|
|
|
+ lightVectors[i] = wsPosition[i] - inLightPos[i];
|
|
|
|
+
|
|
|
|
+ float4 squareDists = 0;
|
|
|
|
+ for ( i = 0; i < 3; i++ )
|
|
|
|
+ squareDists += lightVectors[i] * lightVectors[i];
|
|
|
|
+
|
|
|
|
+ // Accumulate the dot product between the light
|
|
|
|
+ // vector and the normal.
|
|
|
|
+ //
|
|
|
|
+ // The normal is negated because it faces away from
|
|
|
|
+ // the surface and the light faces towards the
|
|
|
|
+ // surface... this keeps us from needing to flip
|
|
|
|
+ // the light vector direction which complicates
|
|
|
|
+ // the spot light calculations.
|
|
|
|
+ //
|
|
|
|
+ // We normalize the result a little later.
|
|
|
|
+ //
|
|
|
|
+ float4 nDotL = 0;
|
|
|
|
+ for ( i = 0; i < 3; i++ )
|
|
|
|
+ nDotL += lightVectors[i] * -wsNormal[i];
|
|
|
|
+
|
|
|
|
+ float4 rDotL = 0;
|
|
|
|
+ #ifndef TORQUE_BL_NOSPECULAR
|
|
|
|
+
|
|
|
|
+ // We're using the Phong specular reflection model
|
|
|
|
+ // here where traditionally Torque has used Blinn-Phong
|
|
|
|
+ // which has proven to be more accurate to real materials.
|
|
|
|
+ //
|
|
|
|
+ // We do so because its cheaper as do not need to
|
|
|
|
+ // calculate the half angle for all 4 lights.
|
|
|
|
+ //
|
|
|
|
+ // Advanced Lighting still uses Blinn-Phong, but the
|
|
|
|
+ // specular reconstruction it does looks fairly similar
|
|
|
|
+ // to this.
|
|
|
|
+ //
|
|
|
|
+ float3 R = reflect( wsView, -wsNormal );
|
|
|
|
+
|
|
|
|
+ for ( i = 0; i < 3; i++ )
|
|
|
|
+ rDotL += lightVectors[i] * R[i];
|
|
|
|
+
|
|
|
|
+ #endif
|
|
|
|
+
|
|
|
|
+ // Normalize the dots.
|
|
|
|
+ //
|
|
|
|
+ // Notice we're using the half type here to get a
|
|
|
|
+ // much faster sqrt via the rsq_pp instruction at
|
|
|
|
+ // the loss of some precision.
|
|
|
|
+ //
|
|
|
|
+ // Unless we have some extremely large point lights
|
|
|
|
+ // i don't believe the precision loss will matter.
|
|
|
|
+ //
|
|
|
|
+ half4 correction = (half4)rsqrt( squareDists );
|
|
|
|
+ nDotL = saturate( nDotL * correction );
|
|
|
|
+ rDotL = clamp( rDotL * correction, 0.00001, 1.0 );
|
|
|
|
+
|
|
|
|
+ // First calculate a simple point light linear
|
|
|
|
+ // attenuation factor.
|
|
|
|
+ //
|
|
|
|
+ // If this is a directional light the inverse
|
|
|
|
+ // radius should be greater than the distance
|
|
|
|
+ // causing the attenuation to have no affect.
|
|
|
|
+ //
|
|
|
|
+ float4 atten = saturate( 1.0 - ( squareDists * inLightInvRadiusSq ) );
|
|
|
|
+
|
|
|
|
+ #ifndef TORQUE_BL_NOSPOTLIGHT
|
|
|
|
+
|
|
|
|
+ // The spotlight attenuation factor. This is really
|
|
|
|
+ // fast for what it does... 6 instructions for 4 spots.
|
|
|
|
+
|
|
|
|
+ float4 spotAtten = 0;
|
|
|
|
+ for ( i = 0; i < 3; i++ )
|
|
|
|
+ spotAtten += lightVectors[i] * inLightSpotDir[i];
|
|
|
|
+
|
|
|
|
+ float4 cosAngle = ( spotAtten * correction ) - inLightSpotAngle;
|
|
|
|
+ atten *= saturate( cosAngle * inLightSpotFalloff );
|
|
|
|
+
|
|
|
|
+ #endif
|
|
|
|
+
|
|
|
|
+ // Finally apply the shadow masking on the attenuation.
|
|
|
|
+ atten *= shadowMask;
|
|
|
|
+
|
|
|
|
+ // Get the final light intensity.
|
|
|
|
+ float4 intensity = nDotL * atten;
|
|
|
|
+
|
|
|
|
+ // Combine the light colors for output.
|
|
|
|
+ outDiffuse = 0;
|
|
|
|
+ for ( i = 0; i < 4; i++ )
|
|
|
|
+ outDiffuse += intensity[i] * inLightColor[i];
|
|
|
|
+
|
|
|
|
+ // Output the specular power.
|
|
|
|
+ float4 specularIntensity = pow( rDotL, float4(1,1,1,1) ) * atten;
|
|
|
|
+
|
|
|
|
+ // Apply the per-light specular attenuation.
|
|
|
|
+ float4 specular = float4(0,0,0,1);
|
|
|
|
+ for ( i = 0; i < 4; i++ )
|
|
|
|
+ specular += float4( inLightColor[i].rgb * inLightColor[i].a * specularIntensity[i], 1 );
|
|
|
|
+
|
|
|
|
+ // Add the final specular intensity values together
|
|
|
|
+ // using a single dot product operation then get the
|
|
|
|
+ // final specular lighting color.
|
|
|
|
+ outSpecular = float4(1,1,1,1) * specular;
|
|
}
|
|
}
|
|
|
|
|
|
struct Surface
|
|
struct Surface
|
|
@@ -159,7 +271,7 @@ inline Surface createForwardSurface(float4 baseColor, float3 normal, float4 pbrP
|
|
surface.V = normalize(wsEyePos - surface.P);
|
|
surface.V = normalize(wsEyePos - surface.P);
|
|
surface.baseColor = baseColor;
|
|
surface.baseColor = baseColor;
|
|
const float minRoughness=1e-4;
|
|
const float minRoughness=1e-4;
|
|
- surface.roughness = clamp(1.0 - pbrProperties.b, minRoughness, 1); //t3d uses smoothness, so we convert to roughness.
|
|
|
|
|
|
+ surface.roughness = clamp(1.0 - pbrProperties.b, minRoughness, 1.0); //t3d uses smoothness, so we convert to roughness.
|
|
surface.roughness_brdf = surface.roughness * surface.roughness;
|
|
surface.roughness_brdf = surface.roughness * surface.roughness;
|
|
surface.metalness = pbrProperties.a;
|
|
surface.metalness = pbrProperties.a;
|
|
surface.ao = pbrProperties.g;
|
|
surface.ao = pbrProperties.g;
|
|
@@ -302,13 +414,13 @@ float3 boxProject(float3 wsPosition, float3 wsReflectVec, float4x4 worldToObj, f
|
|
}
|
|
}
|
|
|
|
|
|
float4 computeForwardProbes(Surface surface,
|
|
float4 computeForwardProbes(Surface surface,
|
|
- float cubeMips, float numProbes, float4x4 worldToObjArray[MAX_FORWARD_PROBES], float4 probeConfigData[MAX_FORWARD_PROBES],
|
|
|
|
|
|
+ float cubeMips, int numProbes, float4x4 worldToObjArray[MAX_FORWARD_PROBES], float4 probeConfigData[MAX_FORWARD_PROBES],
|
|
float4 inProbePosArray[MAX_FORWARD_PROBES], float4 bbMinArray[MAX_FORWARD_PROBES], float4 bbMaxArray[MAX_FORWARD_PROBES], float4 inRefPosArray[MAX_FORWARD_PROBES],
|
|
float4 inProbePosArray[MAX_FORWARD_PROBES], float4 bbMinArray[MAX_FORWARD_PROBES], float4 bbMaxArray[MAX_FORWARD_PROBES], float4 inRefPosArray[MAX_FORWARD_PROBES],
|
|
- float hasSkylight, TORQUE_SAMPLER2D(BRDFTexture),
|
|
|
|
- TORQUE_SAMPLERCUBE(skylightIrradMap), TORQUE_SAMPLERCUBE(skylightSpecularMap),
|
|
|
|
- TORQUE_SAMPLERCUBEARRAY(irradianceCubemapAR), TORQUE_SAMPLERCUBEARRAY(specularCubemapAR))
|
|
|
|
|
|
+ float skylightCubemapIdx, TORQUE_SAMPLER2D(BRDFTexture),
|
|
|
|
+ TORQUE_SAMPLERCUBEARRAY(irradianceCubemapAR), TORQUE_SAMPLERCUBEARRAY(specularCubemapAR))
|
|
{
|
|
{
|
|
- int i = 0;
|
|
|
|
|
|
+ int i = 0;
|
|
|
|
+ float alpha = 1;
|
|
float blendFactor[MAX_FORWARD_PROBES];
|
|
float blendFactor[MAX_FORWARD_PROBES];
|
|
float blendSum = 0;
|
|
float blendSum = 0;
|
|
float blendFacSum = 0;
|
|
float blendFacSum = 0;
|
|
@@ -332,6 +444,8 @@ float4 computeForwardProbes(Surface surface,
|
|
if (contribution[i] > 0.0)
|
|
if (contribution[i] > 0.0)
|
|
probehits++;
|
|
probehits++;
|
|
}
|
|
}
|
|
|
|
+ else
|
|
|
|
+ continue;
|
|
|
|
|
|
contribution[i] = max(contribution[i], 0);
|
|
contribution[i] = max(contribution[i], 0);
|
|
|
|
|
|
@@ -360,8 +474,43 @@ float4 computeForwardProbes(Surface surface,
|
|
{
|
|
{
|
|
blendFactor[i] *= invBlendSumWeighted;
|
|
blendFactor[i] *= invBlendSumWeighted;
|
|
contribution[i] *= blendFactor[i];
|
|
contribution[i] *= blendFactor[i];
|
|
|
|
+ alpha -= contribution[i];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+ else
|
|
|
|
+ alpha -= blendSum;
|
|
|
|
+
|
|
|
|
+#if DEBUGVIZ_ATTENUATION == 1
|
|
|
|
+ float contribAlpha = 1;
|
|
|
|
+ for (i = 0; i < numProbes; ++i)
|
|
|
|
+ {
|
|
|
|
+ contribAlpha -= contribution[i];
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return float4(1 - contribAlpha, 1 - contribAlpha, 1 - contribAlpha, 1);
|
|
|
|
+#endif
|
|
|
|
+
|
|
|
|
+#if DEBUGVIZ_CONTRIB == 1
|
|
|
|
+ float3 probeContribColors[4];
|
|
|
|
+ probeContribColors[0] = float3(1,0,0);
|
|
|
|
+ probeContribColors[1] = float3(0,1,0);
|
|
|
|
+ probeContribColors[2] = float3(0,0,1);
|
|
|
|
+ probeContribColors[3] = float3(1,1,0);
|
|
|
|
+
|
|
|
|
+ float3 finalContribColor = float3(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 += float3(0.3, 0.3, 0.3) * contribAlpha;
|
|
|
|
+
|
|
|
|
+ return float4(finalContribColor, 1);
|
|
|
|
+#endif
|
|
|
|
|
|
float3 irradiance = float3(0, 0, 0);
|
|
float3 irradiance = float3(0, 0, 0);
|
|
float3 specular = float3(0, 0, 0);
|
|
float3 specular = float3(0, 0, 0);
|
|
@@ -369,7 +518,6 @@ float4 computeForwardProbes(Surface surface,
|
|
// Radiance (Specular)
|
|
// Radiance (Specular)
|
|
float lod = surface.roughness*cubeMips;
|
|
float lod = surface.roughness*cubeMips;
|
|
|
|
|
|
- float alpha = 1;
|
|
|
|
for (i = 0; i < numProbes; ++i)
|
|
for (i = 0; i < numProbes; ++i)
|
|
{
|
|
{
|
|
float contrib = contribution[i];
|
|
float contrib = contribution[i];
|
|
@@ -384,10 +532,10 @@ float4 computeForwardProbes(Surface surface,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- if (hasSkylight && alpha > 0.001)
|
|
|
|
|
|
+ if(skylightCubemapIdx != -1 && alpha >= 0.001)
|
|
{
|
|
{
|
|
- irradiance += TORQUE_TEXCUBELOD(skylightIrradMap, float4(surface.R, 0)).xyz;
|
|
|
|
- specular = TORQUE_TEXCUBELOD(skylightSpecularMap, float4(surface.R, lod)).xyz;
|
|
|
|
|
|
+ irradiance += TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, surface.R, skylightCubemapIdx, 0).xyz * alpha;
|
|
|
|
+ specular += TORQUE_TEXCUBEARRAYLOD(specularCubemapAR, surface.R, skylightCubemapIdx, lod).xyz * alpha;
|
|
}
|
|
}
|
|
|
|
|
|
float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
|
|
float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
|
|
@@ -403,7 +551,7 @@ float4 computeForwardProbes(Surface surface,
|
|
|
|
|
|
//final diffuse color
|
|
//final diffuse color
|
|
float3 diffuse = kD * irradiance * surface.baseColor.rgb;
|
|
float3 diffuse = kD * irradiance * surface.baseColor.rgb;
|
|
- float4 finalColor = float4(diffuse + specular, 1);
|
|
|
|
-//finalColor.rgb += abs(surface.N);
|
|
|
|
|
|
+ float4 finalColor = float4(diffuse + specular * surface.ao, 1.0);
|
|
|
|
+
|
|
return finalColor;
|
|
return finalColor;
|
|
}
|
|
}
|