浏览代码

Add the initial implementation of LTC line lights

/main
Evgenii Golubev 8 年前
当前提交
ca4fef9f
共有 2 个文件被更改,包括 91 次插入40 次删除
  1. 73
      Assets/ScriptableRenderLoop/HDRenderLoop/Material/Lit/Lit.hlsl
  2. 58
      Assets/ScriptableRenderLoop/ShaderLibrary/AreaLighting.hlsl

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


TEXTURE2D(_LtcDisneyDiffuseMatrix); // RGBA
TEXTURE2D(_LtcMultiGGXFresnelDisneyDiffuse); // RGB, A unused
static const float3x3 _identity3x3 = {1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0};
//-----------------------------------------------------------------------------
// Helper functions/variable specific to this material

float len = lightData.size.x;
float3 T = lightData.right;
// TODO: This could be precomputed.
// Translate both points s.t. the shaded point is at the origin of the coordinate system.
// Translate the endpoints s.t. the shaded point is at the origin of the coordinate system.
P1 -= positionWS;
P2 -= positionWS;

basis[1] = normalize(cross(bsdfData.normalWS, basis[0]));
basis[2] = bsdfData.normalWS;
// Rotate both endpoints into the local coordinate system (left-handed).
// Rotate the endpoints into the local coordinate system (left-handed).
// Terminate the algorithm if both points are below the horizon.
if (P1.z <= 0.0 && P2.z <= 0.0) return;
// Compute the binormal.
float3 B = normalize(cross(P2 - P1, P1));
if (P2.z <= 0.0)
float ltcValue;
// Evaluate the diffuse part.
// Convention: 'P2' is above the horizon.
swap(P1, P2);
}
#ifdef DIFFUSE_LAMBERT_BRDF
ltcValue = LTCEvaluate(P1, P2, B, _identity3x3);
#else
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformDisneyDiffuse);
#endif
// Recompute the tangent in the local coordinate system.
T = normalize(P2 - P1);
if (ltcValue == 0.0)
{
// The light is below the horizon.
return;
}
// Clip the part of the light below the horizon.
if (P1.z <= 0.0)
{
// P = P1 + t * T; P.z == 0.
float t = -P1.z / T.z;
P1 = float3(P1.xy + t * T.xy, 0.0);
#ifndef DIFFUSE_LAMBERT_BRDF
ltcValue *= preLightData.ltcDisneyDiffuseMagnitude;
#endif
// Set the length of the visible part of the light.
len -= t;
ltcValue *= lightData.diffuseScale;
diffuseLighting = bsdfData.diffuseColor * lightData.color * ltcValue;
// Compute the normal direction to the line, s.t. it is the shortest vector between the shaded
// point and the line, pointing away from the shaded point. Can be viewed as a point on the line.
float proj = dot(P1, T);
float3 P0 = P1 - proj * T;
// Evaluate the specular part.
{
float3 fresnelTerm = bsdfData.fresnel0 * preLightData.ltcGGXFresnelMagnitudeDiff
+ (float3)preLightData.ltcGGXFresnelMagnitude;
// Compute the parameterization: distances from 'P1' and 'P2' to 'P0'.
float l1 = proj;
float l2 = l1 + len;
// Integrate the clamped cosine over the line segment.
float irradiance = LineIrradiance(l1, l2, P0, T);
// Only Lambertian for now. TODO: Disney Diffuse and GGX.
diffuseLighting = (lightData.diffuseScale * irradiance * INV_PI) * bsdfData.diffuseColor * lightData.color;
ltcValue = LTCEvaluate(P1, P2, B, preLightData.ltcXformGGX);
ltcValue *= lightData.specularScale;
specularLighting = fresnelTerm * lightData.color * ltcValue;
}
}
//-----------------------------------------------------------------------------

// Evaluate the diffuse part.
{
#ifdef DIFFUSE_LAMBERT_BRDF
static const float3x3 identity3x3 = {1.0, 0.0, 0.0,
0.0, 1.0, 0.0,
0.0, 0.0, 1.0};
identity3x3);
_identity3x3);
#else
ltcValue = LTCEvaluate(L, V, bsdfData.normalWS, preLightData.NdotV, lightData.twoSided,
preLightData.ltcXformDisneyDiffuse);

58
Assets/ScriptableRenderLoop/ShaderLibrary/AreaLighting.hlsl


return twoSided ? abs(sum) : max(sum, 0.0);
}
float LTCEvaluate(float4x3 L, float3 V, float3 N, float NdotV, bool twoSided, float3x3 minV)
// For polygonal lights.
float LTCEvaluate(float4x3 L, float3 V, float3 N, float NdotV, bool twoSided, float3x3 invM)
{
// Construct local orthonormal basis around N, aligned with N
// TODO: it could be stored in PreLightData. All LTC lights compute it more than once!

basis[2] = N;
// rotate area light in local basis
minV = mul(transpose(basis), minV);
L = mul(L, minV);
invM = mul(transpose(basis), invM);
L = mul(L, invM);
// Polygon radiance in transformed configuration - specular
return PolygonRadiance(L, twoSided);

float intWt = LineFwt(tLDDL2, l2) - LineFwt(tLDDL1, l1);
float intP0 = LineFpo(tLDDL2, l2rcpD, rcp(d)) - LineFpo(tLDDL1, l1rcpD, rcp(d));
return intP0 * normal.z + intWt * tangent.z;
}
// For line lights.
float LTCEvaluate(float3 P1, float3 P2, float3 B, float3x3 invM)
{
// Inverse-transform the endpoints and the binormal.
P1 = mul(P1, invM);
P2 = mul(P2, invM);
B = mul(B, invM);
// Terminate the algorithm if both points are below the horizon.
if (P1.z <= 0.0 && P2.z <= 0.0) return 0.0;
if (P2.z <= 0.0)
{
// Convention: 'P2' is above the horizon.
swap(P1, P2);
}
// Recompute the length and the tangent in the new coordinate system.
float len = length(P2 - P1);
float3 T = normalize(P2 - P1);
// Clip the part of the light below the horizon.
if (P1.z <= 0.0)
{
// P = P1 + t * T; P.z == 0.
float t = -P1.z / T.z;
P1 = float3(P1.xy + t * T.xy, 0.0);
// Set the length of the visible part of the light.
len -= t;
}
// Compute the normal direction to the line, s.t. it is the shortest vector
// between the shaded point and the line, pointing away from the shaded point.
// Can be interpreted as a point on the line, since the shaded point is at the origin.
float proj = dot(P1, T);
float3 P0 = P1 - proj * T;
// Compute the parameterization: distances from 'P1' and 'P2' to 'P0'.
float l1 = proj;
float l2 = l1 + len;
// Integrate the clamped cosine over the line segment.
float irradiance = LineIrradiance(l1, l2, P0, T);
// Compute the width factor. We take the absolute value because the points may be swapped.
float width = abs(dot(B, normalize(cross(T, P1))));
return INV_PI * width * irradiance;
}
#endif // UNITY_AREA_LIGHTING_INCLUDED
正在加载...
取消
保存