WIP of the rewrite of blend/projection to follow BSF's math approach.

This commit is contained in:
Areloch 2019-02-22 08:12:03 -06:00
parent c1bf59bf07
commit 2903aaeea0
2 changed files with 127 additions and 107 deletions

View file

@ -655,7 +655,15 @@ void RenderProbeMgr::render( SceneRenderState *state )
for (U32 i = 0; i < mEffectiveProbeCount; i++)
{
contribColors[i] = Point4F(RandomGen.randF(0, 1), RandomGen.randF(0, 1), RandomGen.randF(0, 1),1);
//we're going to cheat here a little for consistent debugging behavior. The first 3 probes will always have R G and then B for their colors, every other will be random
if (i == 0)
contribColors[i] = Point4F(1, 0, 0, 1);
else if (i == 1)
contribColors[i] = Point4F(0, 1, 0, 1);
else if (i == 2)
contribColors[i] = Point4F(0, 0, 1, 1);
else
contribColors[i] = Point4F(RandomGen.randF(0, 1), RandomGen.randF(0, 1), RandomGen.randF(0, 1),1);
}
mProbeArrayEffect->setShaderConst("$probeContribColors", contribColors);

View file

@ -33,11 +33,25 @@ uniform float4 probeConfigData[MAX_PROBES]; //r,g,b/mode,radius,atten
uniform float4 probeContribColors[MAX_PROBES];
#endif
struct ProbeData
{
float3 wsPosition;
float radius;
float3 boxExtents;
float attenuation;
float4x4 worldToLocal;
uint cubemapIdx;
uint type; //box = 0, sphere = 1
float contribution;
float pad;
};
// Box Projected IBL Lighting
// Based on: http://www.gamedev.net/topic/568829-box-projected-cubemap-environment-mapping/
// and https://seblagarde.wordpress.com/2012/09/29/image-based-lighting-approaches-and-parallax-corrected-cubemap/
float3 boxProject(float3 wsPosition, float3 wsEyeRay, float3 reflectDir, float3 boxWSPos, float3 boxMin, float3 boxMax)
/*float3 boxProject(float3 wsPosition, float3 wsEyeRay, float3 reflectDir, float3 boxWSPos, float3 boxMin, float3 boxMax)
{
float3 positionLS = mul(worldToObjArray[id], float4(wsEyeRay, 1.0)).xyz;
//float3 rayLS = mul(worldToObjArray[id], float4(wsEyeRay, 1.0)).xyz;
//float3 reflCameraLS = mul(worldToObjArray[id], float4(reflectDir), 1.0)).xyz;
@ -51,18 +65,54 @@ float3 boxProject(float3 wsPosition, float3 wsEyeRay, float3 reflectDir, float3
float3 posonbox = offset + nrdir * dist;
return posonbox - boxWSPos;
}
}*/
float3 iblBoxDiffuse( Surface surface, int id)
float3 defineSphereSpaceInfluence(Surface surface, ProbeData probe, float3 wsEyeRay, out float contribution)
{
float3 cubeN = boxProject(surface.P, surface.V, surface.R, inRefPosArray[id].xyz, bbMinArray[id].xyz, bbMaxArray[id].xyz);
return TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR,cubeN,id,surface.roughness*cubeMips).xyz;
contribution = 0;
return float3(0, 0, 0);
}
float3 iblBoxSpecular(Surface surface, TORQUE_SAMPLER2D(brdfTexture), int id)
float3 defineBoxSpaceInfluence(Surface surface, ProbeData probe, float3 wsEyeRay, out float contribution)
{
float3 lsPos = mul(probe.worldToLocal, float4(surface.P, 1.0)).xyz;
float3 lsDir = mul(probe.worldToLocal, float4(wsEyeRay, 0)).xyz;
float3 lsInvDir = float3(1 / lsDir.x, 1 / lsDir.y, 1 / lsDir.z);
float3 intersectsMax = lsInvDir - lsPos * lsInvDir;
float3 intersectsMin = -lsInvDir - lsPos * lsInvDir;
float3 positiveIntersections = max(intersectsMax, intersectsMin);
float intersectDist = min(positiveIntersections.x, min(positiveIntersections.y, positiveIntersections.z));
float3 wsIntersectPosition = surface.P + intersectDist * wsEyeRay;
float3 lookupDir = wsIntersectPosition - probe.wsPosition;
float3 reducedExtents = probe.boxExtents - float3(probe.attenuation, probe.attenuation, probe.attenuation);
float distToBox = length(max(max(-reducedExtents - (lsPos * probe.boxExtents), 0), (lsPos * probe.boxExtents) - reducedExtents));
float normalizedDistance = distToBox / 50; //50 is a random BS number. was probe.attenuation
float t = saturate(3.3333 - 3.3333 * normalizedDistance);
contribution = t * t * (3.0 - 2.0 * t);
return lookupDir;
}
float4 iblBoxDiffuse( Surface surface, ProbeData probe, float3 dir)
{
float lod = surface.roughness*cubeMips;
float3 color = TORQUE_TEXCUBEARRAYLOD(irradianceCubemapAR, dir, probe.cubemapIdx, lod).xyz;
return float4(color * probe.contribution, ceil(probe.contribution));
}
float4 iblBoxSpecular(Surface surface, ProbeData probe, float3 dir)
{
// BRDF
float2 brdf = TORQUE_TEX2DLOD(brdfTexture, float4(surface.roughness, surface.NdotV,0.0,0.0)).xy;
float2 brdf = TORQUE_TEX2DLOD(BRDFTexture, float4(surface.roughness, surface.NdotV,0.0,0.0)).xy;
// Radiance (Specular)
#if DEBUGVIZ_SPECCUBEMAP == 0
@ -71,27 +121,9 @@ float3 iblBoxSpecular(Surface surface, TORQUE_SAMPLER2D(brdfTexture), int id)
float lod = 0;
#endif
float3 cubeR = boxProject(surface.P, surface.V, surface.R, inRefPosArray[id].xyz, bbMinArray[id].xyz, bbMaxArray[id].xyz);
float3 color = TORQUE_TEXCUBEARRAYLOD(cubeMapAR, dir, probe.cubemapIdx, lod).xyz * (brdf.x + brdf.y);
float3 radiance = TORQUE_TEXCUBEARRAYLOD(cubeMapAR,cubeR,id,lod).xyz * (brdf.x + brdf.y);
return radiance;
}
float defineBoxSpaceInfluence(Surface surface, int id)
{
float3 surfPosLS = mul( worldToObjArray[id], float4(surface.P,1.0)).xyz;
float3 boxMinLS = inProbePosArray[id].xyz-(float3(1,1,1)*probeConfigData[id].g);
float3 boxMaxLS = inProbePosArray[id].xyz+(float3(1,1,1)*probeConfigData[id].g);
float boxOuterRange = length(boxMaxLS - boxMinLS);
float boxInnerRange = boxOuterRange / probeConfigData[id].b;
float3 localDir = float3(abs(surfPosLS.x), abs(surfPosLS.y), abs(surfPosLS.z));
localDir = (localDir - boxInnerRange) / (boxOuterRange - boxInnerRange);
return max(localDir.x, max(localDir.y, localDir.z)) * -1;
return float4(color * probe.contribution, 1);
}
float4 main( PFXVertToPix IN ) : SV_TARGET
@ -111,67 +143,65 @@ float4 main( PFXVertToPix IN ) : SV_TARGET
int i = 0;
float blendVal[MAX_PROBES];
float blendFactor[MAX_PROBES];
float blendSum = 0;
float blendFacSum = 0;
float invBlendSum = 0;
float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
for (i = 0; i < numProbes; i++)
{
if (probeConfigData[i].r)
{
float3 L = inProbePosArray[i].xyz - surface.P;
blendVal[i] = 1.0 - length(L) / probeConfigData[i].g;
}
else
{
blendVal[i] = defineBoxSpaceInfluence(surface, i);
}
blendVal[i] = saturate(blendVal[i]);
blendSum += blendVal[i];
invBlendSum += (1.0f - blendVal[i]);
}
//energy conservation
float3 kD = 1.0.xxx - F;
kD *= 1.0 - surface.metalness;
// Weight0 = normalized NDF, inverted to have 1 at center, 0 at boundary.
// And as we invert, we need to divide by Num-1 to stay normalized (else sum is > 1).
// respect constraint B.
// Weight1 = normalized inverted NDF, so we have 1 at center, 0 at boundary
// and respect constraint A.
float4 irradiance = float4(0, 0, 0, 0);
float4 specular = float4(0, 0, 0, 0);
for (i = 0; i < numProbes; i++)
{
if (numProbes>1)
{
blendFactor[i] = ((1.0f -blendVal[i] / blendSum)) / (numProbes - 1);
blendFactor[i] *= ((1.0f -blendVal[i]) / invBlendSum);
blendFacSum += blendFactor[i];
}
else
{
blendFactor[i] = blendVal[i];
blendFacSum = blendVal[i];
}
}
float contributingProbeCount = 1;
// Normalize blendVal
#if DEBUGVIZ_ATTENUATION == 0 //this can likely be removed when we fix the above normalization behavior
if (blendFacSum == 0.0f) // Possible with custom weight
{
blendFacSum = 1.0f;
}
float contribSum = 0;
#if DEBUGVIZ_CONTRIB == 1
float contribVal[MAX_PROBES];
#endif
float invBlendSumWeighted = 1.0f / blendFacSum;
//Process prooooobes
for (i = 0; i < numProbes; ++i)
{
blendFactor[i] *= invBlendSumWeighted;
ProbeData probe;
probe.wsPosition = inProbePosArray[i].xyz;
probe.radius = probeConfigData[i].g;
probe.boxExtents = length(bbMaxArray[i].xyz - bbMinArray[i].xyz);
probe.attenuation = probeConfigData[i].b;
probe.worldToLocal = worldToObjArray[i];
probe.cubemapIdx = i;
probe.type = probeConfigData[i].r;
probe.contribution = 0;
if (probe.type == 0) //box
{
float3 reflDir = defineBoxSpaceInfluence(surface, probe, IN.wsEyeRay, probe.contribution);
float4 irr = iblBoxDiffuse(surface, probe, reflDir);
float3 spec = iblBoxSpecular(surface, probe, reflDir).rgb * F;
irradiance += irr;
specular += float4(spec,1);
contributingProbeCount += irr.a; //if we have any contribution to this pixel, our a should be at a 1, which we'll ultimately utilize to average the total
contribSum += probe.contribution;
#if DEBUGVIZ_CONTRIB == 1
contribVal[i] = probe.contribution;
#endif
}
}
//return float4(blendFactor[0], blendFactor[0], blendFactor[0], 1);
//Average these bad boys out
//irradiance /= contributingProbeCount;
//specular /= contributingProbeCount;
#if DEBUGVIZ_ATTENUATION == 1
return float4(blendFacSum, blendFacSum, blendFacSum, 1);
return float4(contribSum, contribSum, contribSum, 1);
#endif
#if DEBUGVIZ_CONTRIB == 1
@ -179,10 +209,10 @@ float4 main( PFXVertToPix IN ) : SV_TARGET
float3 finalContribColor = float3(0, 0, 0);
for (i = 0; i < numProbes; ++i)
{
if (blendFactor[i] == 0)
if (contribVal[i] == 0)
continue;
finalContribColor += blendFactor[i] * probeContribColors[i].rgb;
finalContribColor += contribVal[i] * probeContribColors[i].rgb;
}
return float4(finalContribColor, 1);
@ -190,44 +220,26 @@ float4 main( PFXVertToPix IN ) : SV_TARGET
#if DEBUGVIZ_SPECCUBEMAP == 0 && DEBUGVIZ_DIFFCUBEMAP == 0
float3 irradiance = float3(0,0,0);
float3 specular = float3(0,0,0);
float3 F = FresnelSchlickRoughness(surface.NdotV, surface.f0, surface.roughness);
//energy conservation
float3 kD = 1.0.xxx - F;
kD *= 1.0 - surface.metalness;
for (i = 0; i < numProbes; ++i)
/*for (i = 0; i < numProbes; ++i)
{
if (blendFactor[i] == 0)
if (blendVal[i] == 0)
continue;
irradiance += blendFactor[i]*iblBoxDiffuse(surface, i);
irradiance += blendVal[i]*iblBoxDiffuse(surface, i);
specular += blendFactor[i]*F*iblBoxSpecular(surface, TORQUE_SAMPLER2D_MAKEARG(BRDFTexture),i);
}
specular += blendVal[i]*F*iblBoxSpecular(surface, TORQUE_SAMPLER2D_MAKEARG(BRDFTexture),i);
}*/
//final diffuse color
float3 diffuse = kD * irradiance * surface.baseColor.rgb;
float4 finalColor = float4(diffuse + specular * surface.ao, blendFacSum);
float3 diffuse = kD * irradiance.rgb * surface.baseColor.rgb;
float4 finalColor = float4(diffuse + specular.rgb * surface.ao, contribSum);
return finalColor;
return finalColor;
#elif DEBUGVIZ_SPECCUBEMAP == 1 && DEBUGVIZ_DIFFCUBEMAP == 0
float3 cubeColor = float3(0, 0, 0);
for (i = 0; i < numProbes; ++i)
{
cubeColor += blendFactor[i] * iblBoxSpecular(surface, TORQUE_SAMPLER2D_MAKEARG(BRDFTexture), i);
}
return float4(cubeColor,1);
return float4(specular.rgb, 1);
#elif DEBUGVIZ_DIFFCUBEMAP == 1
float3 cubeColor = float3(0, 0, 0);
for (i = 0; i < numProbes; ++i)
{
cubeColor += blendFactor[i] * iblBoxDiffuse(surface, i);
}
return float4(cubeColor, 1);
return float4(irradiance.rgb, 1);
#endif
}