浏览代码

Add support for box lights (unoptimized, WIP)

/Yibing-Project-2
Evgenii Golubev 7 年前
当前提交
ae685427
共有 3 个文件被更改,包括 96 次插入28 次删除
  1. 28
      ScriptableRenderPipeline/Core/ShaderLibrary/GeometricTools.hlsl
  2. 8
      ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightEvaluation.hlsl
  3. 88
      ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/Resources/VolumetricLighting.compute

28
ScriptableRenderPipeline/Core/ShaderLibrary/GeometricTools.hlsl


// Can support cones with an elliptic base: pre-scale 'coneAxisX' and 'coneAxisY' by (h/r_x) and (h/r_y).
// Returns parametric distances 'tEntr' and 'tExit' along the ray,
// subject to constraints 'tMin' and 'tMax'.
bool ConeRayIntersect(float3 rayOrigin, float3 rayDirection,
bool IntersectRayCone(float3 rayOrigin, float3 rayDirection,
inout float tEntr, inout float tExit)
out float tEntr, out float tExit)
{
// Inverse transform the ray into a coordinate system with the cone at the origin facing along the Z axis.
float3x3 rotMat = float3x3(coneAxisX, coneAxisY, coneDirection);

if (tEntr == tExit) { hit = false; }
return hit;
}
// This implementation does not attempt to explicitly handle NaNs.
// Ref: https://tavianator.com/fast-branchless-raybounding-box-intersections-part-2-nans/
bool IntersectRayAABB(float3 rayOrigin, float3 rayDirection,
float3 boxPt0, float3 boxPt1,
float tMin, float tMax,
out float tEntr, out float tExit)
{
float3 rayDirInv = rcp(rayDirection); // Could be precomputed
tEntr = tMin;
tExit = tMax;
for (int i = 0; i < 3; ++i)
{
float t0 = boxPt0[i] * rayDirInv[i] - (rayOrigin[i] * rayDirInv[i]);
float t1 = boxPt1[i] * rayDirInv[i] - (rayOrigin[i] * rayDirInv[i]);
tEntr = max(tEntr, min(t0, t1)); // Farthest entry
tExit = min(tExit, max(t0, t1)); // Nearest exit
}
return tEntr < tExit;
}
//-----------------------------------------------------------------------------

8
ScriptableRenderPipeline/HDRenderPipeline/Lighting/LightEvaluation.hlsl


#endif
}
// Note: no fog attenuation along shadow rays for directional lights.
// Note: no volumetric attenuation along shadow rays for directional/box lights.
attenuation *= shadow;
[branch] if (lightData.cookieIndex >= 0)

}
#ifdef VOLUMETRIC_LIGHTING_ENABLED
shadow *= TransmittanceHomogeneousMedium(_GlobalFog_Extinction, dist);
// Note: no volumetric attenuation along shadow rays for directional/box lights.
[flatten] if (lightData.lightType != GPULIGHTTYPE_PROJECTOR_BOX)
{
shadow *= TransmittanceHomogeneousMedium(_GlobalFog_Extinction, dist);
}
#endif
attenuation *= shadow;

88
ScriptableRenderPipeline/HDRenderPipeline/Lighting/Volumetrics/Resources/VolumetricLighting.compute


for (uint i = 0; i < _DirectionalLightCount; ++i)
{
// Fetch the light.
DirectionalLightData lightData = _DirectionalLightDatas[i];
float3 L = -lightData.forward; // Lights point backwards in Unity
DirectionalLightData light = _DirectionalLightDatas[i];
float3 L = -light.forward; // Lights point backwards in Unity
EvaluateLight_Directional(context, posInput, lightData, unused, 0, L,
EvaluateLight_Directional(context, posInput, light, unused, 0, L,
color, attenuation);
// Note: the 'weight' accounts for transmittance from 't0' to 't'.

if (lightCount > 0)
{
LightData lightData = FetchLight(lightStart, 0);
LightData light = FetchLight(lightStart, 0);
while (i <= last && lightData.lightType != GPULIGHTTYPE_PROJECTOR_BOX)
while (i <= last && light.lightType != GPULIGHTTYPE_PROJECTOR_BOX)
{
float tEntr = tMin;
float tExit = tMax;

// Perform ray-cone intersection for pyramid and spot lights.
if (lightData.lightType != GPULIGHTTYPE_POINT)
if (light.lightType != GPULIGHTTYPE_POINT)
// 'lightData.right' and 'lightData.up' vectors are pre-scaled on the CPU
// s.t. if you were to place them at the distance of 1 directly in front
// of the light, they would give you the "footprint" of the light.
float3 coneAxisX = lightData.right;
float3 coneAxisY = lightData.up;
float lenMul = 1;
if (lightData.lightType == GPULIGHTTYPE_PROJECTOR_PYRAMID)
if (light.lightType == GPULIGHTTYPE_PROJECTOR_PYRAMID)
// 'light.right' and 'light.up' vectors are pre-scaled on the CPU
// s.t. if you were to place them at the distance of 1 directly in front
// of the light, they would give you the "footprint" of the light.
// TODO: pre-scale this on the CPU.
coneAxisX *= rsqrt(2);
coneAxisY *= rsqrt(2);
lenMul = rsqrt(2);
sampleLight = ConeRayIntersect(ray.originWS, ray.directionWS,
lightData.positionWS, lightData.forward,
float3 coneAxisX = lenMul * light.right;
float3 coneAxisY = lenMul * light.up;
sampleLight = IntersectRayCone(ray.originWS, ray.directionWS,
light.positionWS, light.forward,
coneAxisX, coneAxisY,
tMin, tMax, tEntr, tExit);
}

float t, distSq, rcpPdf;
ImportanceSamplePunctualLight(rndVal, lightData.positionWS,
ImportanceSamplePunctualLight(rndVal, light.positionWS,
float3 lightToSample = posInput.positionWS - lightData.positionWS;
float3 lightToSample = posInput.positionWS - light.positionWS;
EvaluateLight_Punctual(context, posInput, lightData, unused, 0, L, dist, distSq,
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, dist, distSq,
color, attenuation);
float intensity = attenuation * rcpPdf;

sampleRadiance += color * intensity;
}
lightData = FetchLight(lightStart, min(++i, last));
light = FetchLight(lightStart, min(++i, last));
while (i <= last)
while (i <= last) // GPULIGHTTYPE_PROJECTOR_BOX
lightData = FetchLight(lightStart, min(++i, last));
lightData.lightType = GPULIGHTTYPE_PROJECTOR_BOX;
light = FetchLight(lightStart, min(++i, last));
light.lightType = GPULIGHTTYPE_PROJECTOR_BOX;
// Convert the box light from OBB to AABB.
// TODO: precompute all of this.
float invHalfWidth = rsqrt(dot(light.right, light.right));
float invHalfHeight = rsqrt(dot(light.right, light.right));
float depth = rsqrt(light.invSqrAttenuationRadius);
float3x3 rotMat = float3x3(light.right * invHalfWidth, light.up * invHalfHeight, light.forward); // Normalize
float3 o = mul(rotMat, ray.originWS - light.positionWS);
float3 d = mul(rotMat, ray.directionWS);
float3 boxPt0 = float3(-invHalfWidth, -invHalfHeight, 0);
float3 boxPt1 = float3( invHalfWidth, invHalfHeight, depth);
float tEntr, tExit;
if (IntersectRayAABB(o, d, boxPt0, boxPt1, tMin, tMax, tEntr, tExit))
{
float tOffset, weight;
ImportanceSampleHomogeneousMedium(rndVal, extinction, tExit - tEntr, tOffset, weight);
float t = tEntr + tOffset;
posInput.positionWS = GetPointAtDistance(ray, t);
float3 L = -light.forward;
float3 color; float attenuation;
EvaluateLight_Punctual(context, posInput, light, unused, 0, L, 1, 1,
color, attenuation);
// Note: the 'weight' accounts for transmittance from 'tEntr' to 't'.
float intensity = attenuation * weight;
// Compute transmittance from 't0' to 'tEntr'.
intensity *= TransmittanceHomogeneousMedium(extinction, tEntr - t0);
// Compute the amount of in-scattered radiance.
sampleRadiance += intensity * color;
}
}
}
}

正在加载...
取消
保存