浏览代码

Implement box-to-sphere-map distance attenuation

/main
Evgenii Golubev 8 年前
当前提交
db1a3661
共有 2 个文件被更改,包括 55 次插入32 次删除
  1. 18
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl
  2. 69
      Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl

18
Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl


float3 unL = positionWS - lightData.positionWS;
// Pick the axis along which to dilate the attenuation sphere into an ellipsoid.
float3 axis = (halfWidth >= halfHeight) ? lightData.right : lightData.up;
// Rotate the light direction into the light space.
float3x3 lightToWorld = float3x3(lightData.right, lightData.up, lightData.forward);
unL = mul(unL, transpose(lightToWorld));
// We define the ellipsoid s.t. r1 = r2 = r, r3 = (r + |w - h| / 2).
// TODO: This could be precomputed.
float radius = rsqrt(lightData.invSqrAttenuationRadius);
float invAspectRatio = radius / (radius + abs(halfWidth - halfHeight));
// The attenuation volume is a box of size [2 * r + w, 2 * r + h, 2 * r].
// TODO: this could be precomputed.
float radius = rsqrt(lightData.invSqrAttenuationRadius);
float3 invHalfDiag = float3(rcp(radius + halfWidth),
rcp(radius + halfHeight),
rcp(radius));
float intensity = GetEllipsoidalDistanceAttenuation(unL, lightData.invSqrAttenuationRadius,
axis, invAspectRatio);
float intensity = GetBoxToSphereMapDistanceAttenuation(unL, invHalfDiag);
// Terminate if the shaded point is too far away.
if (intensity == 0.0) return;

69
Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl


// Light direction is oriented backward (-Z). i.e in shader code, light direction is -lightData.forward
//-----------------------------------------------------------------------------
// Various helper
//-----------------------------------------------------------------------------
// Performs the mapping of the vector 'v' centered within the cube of dimensions [-1, 1]^3
// to a vector centered within the sphere of radius 1.
// The function expects 'v' to be within the cube (possibly unexpected results otherwise).
// Ref: http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
float3 MapCubeToSphere(float3 v)
{
float3 v2 = v * v;
float2 vr3 = v2.xy * rcp(3.0);
return v * sqrt((float3)1.0 - 0.5 * v2.yzx - 0.5 * v2.zxy + vr3.yxx * v2.zzy);
}
// Computes the squared magnitude of the vector computed by MapCubeToSphere().
float ComputeCubeToSphereMapSqMagnitude(float3 v)
{
float3 v2 = v * v;
// Note: dot(v, v) is often computed before this function is called,
// so the compiler should optimize and use the precomputed result here.
return dot(v, v) - v2.x * v2.y - v2.y * v2.z - v2.z * v2.x + v2.x * v2.y * v2.z;
}
//-----------------------------------------------------------------------------
// Attenuation functions
//-----------------------------------------------------------------------------

}
// Applies SmoothDistanceAttenuation() after stretching the attenuation sphere of the
// given radius into an ellipsoid with the specified aspect ratio and the longest axis.
// given radius into an ellipsoid with the specified (positive) aspect ratio and the longest axis.
// Both the ellipsoid (e.i. 'axis') and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the ellipsoid.
float GetEllipsoidalDistanceAttenuation(float3 unL, float invSqrAttenuationRadius,
float3 axis, float invAspectRatio)
{

return SmoothDistanceAttenuation(dot(unL, unL), invSqrAttenuationRadius);
}
// Applies SmoothDistanceAttenuation() after performing the box to sphere mapping.
// If the length of the diagonal of the box is 'd', invHalfDiag = rcp(0.5 * d).
// Both the box (e.i. 'invHalfDiag') and 'unL' should be in the same coordinate system.
// 'unL' should be computed from the center of the box.
float GetBoxToSphereMapDistanceAttenuation(float3 unL, float3 invHalfDiag)
{
// As our algorithm only works with the [-1, 1]^2 cube,
// we rescale the light vector to compensate.
unL *= invHalfDiag;
// Our algorithm expects the input vector to be within the cube.
if (dot(unL, unL) > 1.0) return 0.0;
// Compute the light attenuation.
float sqDist = ComputeCubeToSphereMapSqMagnitude(unL);
return SmoothDistanceAttenuation(sqDist, 1.0);
}
//-----------------------------------------------------------------------------
// IES Helper
//-----------------------------------------------------------------------------

tangentY = float3(b, 1.0f - N.y * N.y * a, -N.y);
}
*/
//-----------------------------------------------------------------------------
// various helper
//-----------------------------------------------------------------------------
// Performs the mapping of the vector 'v' located within the cube of dimensions [-r, r]^3
// to a vector within the sphere of radius 'r', where r = sqrt(r2).
// Modified version of http://mathproofs.blogspot.com/2005/07/mapping-cube-to-sphere.html
float3 MapCubeToSphere(float3 v, float r2)
{
float3 v2 = v * v;
float2 vr3 = v2.xy * rcp(3.0 * r2);
return v * sqrt((float3)r2 - 0.5 * v2.yzx - 0.5 * v2.zxy + vr3.yxx * v2.zzy);
}
// Computes the squared magnitude of the vector computed by MapCubeToSphere().
float ComputeCubeToSphereMapSqMagnitude(float3 v, float r2)
{
float3 v2 = v * v;
// Note: dot(v, v) is often computed before this function is called,
// so the compiler should optimize and use the precomputed result here.
return r2 * dot(v, v) - v2.x * v2.y - v2.y * v2.z - v2.z * v2.x + v2.x * v2.y * v2.z * rcp(r2);
}
#endif // UNITY_COMMON_LIGHTING_INCLUDED
正在加载...
取消
保存