Skip to content

Commit a433ed1

Browse files
Merge pull request #18 from EvgeniiG/master
Implement LTC linear light shading for GGX and Disney Diffuse
2 parents aa8db43 + 69f926f commit a433ed1

File tree

17 files changed

+1327
-221
lines changed

17 files changed

+1327
-221
lines changed

Assets/ScriptableRenderLoop/HDRenderLoop/Lighting/SinglePass/SinglePassLoop.hlsl

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,16 @@ void LightLoop( float3 V, float3 positionWS, PreLightData prelightData, BSDFData
4141
{
4242
float3 localDiffuseLighting, localSpecularLighting;
4343

44-
EvaluateBSDF_Area(context, V, positionWS, prelightData, _AreaLightList[i], bsdfData,
45-
localDiffuseLighting, localSpecularLighting);
44+
if (_AreaLightList[i].lightType == GPULIGHTTYPE_LINE)
45+
{
46+
EvaluateBSDF_Line(context, V, positionWS, prelightData, _AreaLightList[i], bsdfData,
47+
localDiffuseLighting, localSpecularLighting);
48+
}
49+
else
50+
{
51+
EvaluateBSDF_Area(context, V, positionWS, prelightData, _AreaLightList[i], bsdfData,
52+
localDiffuseLighting, localSpecularLighting);
53+
}
4654

4755
diffuseLighting += localDiffuseLighting;
4856
specularLighting += localSpecularLighting;

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

Lines changed: 197 additions & 198 deletions
Large diffs are not rendered by default.

Assets/ScriptableRenderLoop/ShaderLibrary/AreaLighting.hlsl

Lines changed: 76 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -163,48 +163,104 @@ float PolygonRadiance(float4x3 L, bool twoSided)
163163
return twoSided ? abs(sum) : max(sum, 0.0);
164164
}
165165

166-
float LTCEvaluate(float4x3 L, float3 V, float3 N, float NdotV, bool twoSided, float3x3 minV)
166+
// For polygonal lights.
167+
float LTCEvaluate(float4x3 L, float3 V, float3 N, float NdotV, bool twoSided, float3x3 invM)
167168
{
168169
// Construct local orthonormal basis around N, aligned with N
169170
// TODO: it could be stored in PreLightData. All LTC lights compute it more than once!
171+
// Also consider using 'bsdfData.tangentWS', 'bsdfData.bitangentWS', 'bsdfData.normalWS'.
170172
float3x3 basis;
171173
basis[0] = normalize(V - N * NdotV);
172174
basis[1] = normalize(cross(N, basis[0]));
173175
basis[2] = N;
174176

175177
// rotate area light in local basis
176-
minV = mul(transpose(basis), minV);
177-
L = mul(L, minV);
178+
invM = mul(transpose(basis), invM);
179+
L = mul(L, invM);
178180

179181
// Polygon radiance in transformed configuration - specular
180182
return PolygonRadiance(L, twoSided);
181183
}
182184

183-
float LineFpo(float rcpD, float rcpDL, float l)
185+
float LineFpo(float tLDDL, float lrcpD, float rcpD)
184186
{
185-
// Compute: l / d / (d * d + l * l) + 1.0 / (d * d) * atan(l / d).
186-
return l * rcpDL + rcpD * rcpD * atan(l * rcpD);
187+
// Compute: ((l / d) / (d * d + l * l)) + (1.0 / (d * d)) * atan(l / d).
188+
return tLDDL + sq(rcpD) * atan(lrcpD);
187189
}
188190

189-
float LineFwt(float sqL, float rcpDL)
191+
float LineFwt(float tLDDL, float l)
190192
{
191-
// Compute: l * l / d / (d * d + l * l).
192-
return sqL * rcpDL;
193+
// Compute: l * ((l / d) / (d * d + l * l)).
194+
return l * tLDDL;
193195
}
194196

195197
// Computes the integral of the clamped cosine over the line segment.
196-
// 'dist' is the shortest distance to the line. 'l1' and 'l2' define the integration interval.
197-
float LineIrradiance(float l1, float l2, float dist, float pointZ, float tangentZ)
198+
// 'l1' and 'l2' define the integration interval.
199+
// 'tangent' is the line's tangent direction.
200+
// 'normal' is the direction orthogonal to the tangent. It is the shortest vector between
201+
// the shaded point and the line, pointing away from the shaded point.
202+
float LineIrradiance(float l1, float l2, float3 normal, float3 tangent)
198203
{
199-
float sqD = dist * dist;
200-
float sqL1 = l1 * l1;
201-
float sqL2 = l2 * l2;
202-
float rcpD = rcp(dist);
203-
float rcpDL1 = rcpD * rcp(sqD + sqL1);
204-
float rcpDL2 = rcpD * rcp(sqD + sqL2);
205-
float intP0 = LineFpo(rcpD, rcpDL2, l2) - LineFpo(rcpD, rcpDL1, l1);
206-
float intWt = LineFwt(sqL2, rcpDL2) - LineFwt(sqL1, rcpDL1);
207-
return intP0 * pointZ + intWt * tangentZ;
204+
float d = length(normal);
205+
float l1rcpD = l1 * rcp(d);
206+
float l2rcpD = l2 * rcp(d);
207+
float tLDDL1 = l1rcpD * rcp(sq(d) + sq(l1));
208+
float tLDDL2 = l2rcpD * rcp(sq(d) + sq(l2));
209+
float intWt = LineFwt(tLDDL2, l2) - LineFwt(tLDDL1, l1);
210+
float intP0 = LineFpo(tLDDL2, l2rcpD, rcp(d)) - LineFpo(tLDDL1, l1rcpD, rcp(d));
211+
return intP0 * normal.z + intWt * tangent.z;
212+
}
213+
214+
// For line lights.
215+
float LTCEvaluate(float3 P1, float3 P2, float3 B, float3x3 invM)
216+
{
217+
// Inverse-transform the endpoints and the binormal.
218+
P1 = mul(P1, invM);
219+
P2 = mul(P2, invM);
220+
B = mul(B, invM);
221+
222+
// Terminate the algorithm if both points are below the horizon.
223+
if (P1.z <= 0.0 && P2.z <= 0.0) return 0.0;
224+
225+
if (P2.z <= 0.0)
226+
{
227+
// Convention: 'P2' is above the horizon.
228+
swap(P1, P2);
229+
}
230+
231+
// Recompute the length and the tangent in the new coordinate system.
232+
float len = length(P2 - P1);
233+
float3 T = normalize(P2 - P1);
234+
235+
// Clip the part of the light below the horizon.
236+
if (P1.z <= 0.0)
237+
{
238+
// P = P1 + t * T; P.z == 0.
239+
float t = -P1.z / T.z;
240+
P1 = float3(P1.xy + t * T.xy, 0.0);
241+
242+
// Set the length of the visible part of the light.
243+
len -= t;
244+
}
245+
246+
// Compute the normal direction to the line, s.t. it is the shortest vector
247+
// between the shaded point and the line, pointing away from the shaded point.
248+
// Can be interpreted as a point on the line, since the shaded point is at the origin.
249+
float proj = dot(P1, T);
250+
float3 P0 = P1 - proj * T;
251+
252+
// Compute the parameterization: distances from 'P1' and 'P2' to 'P0'.
253+
float l1 = proj;
254+
float l2 = l1 + len;
255+
256+
// Integrate the clamped cosine over the line segment.
257+
float irradiance = LineIrradiance(l1, l2, P0, T);
258+
259+
// Compute the width factor. We take the absolute value because the points may be swapped.
260+
float width = abs(dot(B, normalize(cross(T, P1))));
261+
262+
// Guard against numerical precision issues.
263+
return max(INV_PI * width * irradiance, 0.0);
208264
}
209265

210266
#endif // UNITY_AREA_LIGHTING_INCLUDED

Assets/ScriptableRenderLoop/ShaderLibrary/Common.hlsl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,6 +128,11 @@ float4 Max3(float4 a, float4 b, float4 c)
128128
}
129129
#endif // INTRINSIC_MINMAX3
130130

131+
float sq(float x)
132+
{
133+
return x * x;
134+
}
135+
131136
void swap(inout float a, inout float b)
132137
{
133138
float t = a; a = b; b = t;
@@ -211,7 +216,8 @@ void GetCubeFaceID(float3 dir, out int faceIndex)
211216
#define HALF_PI 1.57079632679
212217
#define INV_HALF_PI 0.636619772367
213218

214-
#define FLT_EPSILON 1.192092896e-07f // smallest such that 1.0 + FLT_EPSILON != 1.0
219+
#define FLT_EPSILON 1.192092896e-07 // Smallest positive number, such that 1.0 + FLT_EPSILON != 1.0
220+
#define FLT_MAX 3.402823466e+38 // Maximum representable floating-point number
215221

216222
#define MERGE_NAME(X, Y) X##Y
217223

Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,23 @@ float GetAngleAttenuation(float3 L, float3 lightDir, float lightAngleScale, floa
5959
return attenuation;
6060
}
6161

62+
// Applies SmoothDistanceAttenuation() after stretching the fade-out sphere of the given radius
63+
// into an ellipsoid with the specified aspect ratio and the longest axis.
64+
float GetEllipsoidalDistanceAttenuation(float3 unL, float invSqrAttenuationRadius,
65+
float3 axis, float invAspectRatio)
66+
{
67+
// Project the unnormalized light vector onto the expansion axis.
68+
float projL = dot(unL, axis);
69+
70+
// We want 'unL' to shrink along 'axis' by the aspect ratio. Therefore, we compute
71+
// the difference between the length of the original projection and the shrunk one.
72+
// It is equivalent to the expansion of the fade-out sphere into an ellipsoid.
73+
float scale = projL - projL * invAspectRatio;
74+
unL -= scale * axis;
75+
76+
return SmoothDistanceAttenuation(dot(unL, unL), invSqrAttenuationRadius);
77+
}
78+
6279
//-----------------------------------------------------------------------------
6380
// IES Helper
6481
//-----------------------------------------------------------------------------
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
%YAML 1.1
2+
%TAG !u! tag:unity3d.com,2011:
3+
--- !u!21 &2100000
4+
Material:
5+
serializedVersion: 6
6+
m_ObjectHideFlags: 0
7+
m_PrefabParentObject: {fileID: 0}
8+
m_PrefabInternal: {fileID: 0}
9+
m_Name: GGX_D_a00_s00
10+
m_Shader: {fileID: 4800000, guid: 6e4ae4064600d784cac1e41a9e6f2e59, type: 3}
11+
m_ShaderKeywords: _ALPHACUTOFFENABLE_OFF _DETAIL_MAP_WITH_NORMAL _DISTORTIONDEPTHTEST_OFF
12+
_DISTORTIONONLY_OFF _EMISSION _NORMALMAP_TANGENT_SPACE
13+
m_LightmapFlags: 1
14+
m_CustomRenderQueue: -1
15+
stringTagMap: {}
16+
m_SavedProperties:
17+
serializedVersion: 3
18+
m_TexEnvs:
19+
- _AmbientOcclusionMap:
20+
m_Texture: {fileID: 0}
21+
m_Scale: {x: 1, y: 1}
22+
m_Offset: {x: 0, y: 0}
23+
- _AnisotropyMap:
24+
m_Texture: {fileID: 0}
25+
m_Scale: {x: 1, y: 1}
26+
m_Offset: {x: 0, y: 0}
27+
- _BaseColorMap:
28+
m_Texture: {fileID: 0}
29+
m_Scale: {x: 1, y: 1}
30+
m_Offset: {x: 0, y: 0}
31+
- _BumpMap:
32+
m_Texture: {fileID: 0}
33+
m_Scale: {x: 1, y: 1}
34+
m_Offset: {x: 0, y: 0}
35+
- _DetailAlbedoMap:
36+
m_Texture: {fileID: 0}
37+
m_Scale: {x: 1, y: 1}
38+
m_Offset: {x: 0, y: 0}
39+
- _DetailMap:
40+
m_Texture: {fileID: 0}
41+
m_Scale: {x: 1, y: 1}
42+
m_Offset: {x: 0, y: 0}
43+
- _DetailMask:
44+
m_Texture: {fileID: 0}
45+
m_Scale: {x: 1, y: 1}
46+
m_Offset: {x: 0, y: 0}
47+
- _DetailNormalMap:
48+
m_Texture: {fileID: 0}
49+
m_Scale: {x: 1, y: 1}
50+
m_Offset: {x: 0, y: 0}
51+
- _DiffuseLightingMap:
52+
m_Texture: {fileID: 0}
53+
m_Scale: {x: 1, y: 1}
54+
m_Offset: {x: 0, y: 0}
55+
- _EmissionMap:
56+
m_Texture: {fileID: 0}
57+
m_Scale: {x: 1, y: 1}
58+
m_Offset: {x: 0, y: 0}
59+
- _EmissiveColorMap:
60+
m_Texture: {fileID: 0}
61+
m_Scale: {x: 1, y: 1}
62+
m_Offset: {x: 0, y: 0}
63+
- _HeightMap:
64+
m_Texture: {fileID: 0}
65+
m_Scale: {x: 1, y: 1}
66+
m_Offset: {x: 0, y: 0}
67+
- _MainTex:
68+
m_Texture: {fileID: 0}
69+
m_Scale: {x: 1, y: 1}
70+
m_Offset: {x: 0, y: 0}
71+
- _MaskMap:
72+
m_Texture: {fileID: 0}
73+
m_Scale: {x: 1, y: 1}
74+
m_Offset: {x: 0, y: 0}
75+
- _MetallicGlossMap:
76+
m_Texture: {fileID: 0}
77+
m_Scale: {x: 1, y: 1}
78+
m_Offset: {x: 0, y: 0}
79+
- _MettalicMap:
80+
m_Texture: {fileID: 0}
81+
m_Scale: {x: 1, y: 1}
82+
m_Offset: {x: 0, y: 0}
83+
- _NormalMap:
84+
m_Texture: {fileID: 0}
85+
m_Scale: {x: 1, y: 1}
86+
m_Offset: {x: 0, y: 0}
87+
- _OcclusionMap:
88+
m_Texture: {fileID: 0}
89+
m_Scale: {x: 1, y: 1}
90+
m_Offset: {x: 0, y: 0}
91+
- _ParallaxMap:
92+
m_Texture: {fileID: 0}
93+
m_Scale: {x: 1, y: 1}
94+
m_Offset: {x: 0, y: 0}
95+
- _SmoothnessMap:
96+
m_Texture: {fileID: 0}
97+
m_Scale: {x: 1, y: 1}
98+
m_Offset: {x: 0, y: 0}
99+
- _SpecularOcclusionMap:
100+
m_Texture: {fileID: 0}
101+
m_Scale: {x: 1, y: 1}
102+
m_Offset: {x: 0, y: 0}
103+
- _SubSurfaceRadiusMap:
104+
m_Texture: {fileID: 0}
105+
m_Scale: {x: 1, y: 1}
106+
m_Offset: {x: 0, y: 0}
107+
- _TangentMap:
108+
m_Texture: {fileID: 0}
109+
m_Scale: {x: 1, y: 1}
110+
m_Offset: {x: 0, y: 0}
111+
m_Floats:
112+
- _AlphaCutoff: 0.5
113+
- _AlphaCutoffEnable: 0
114+
- _Anisotropy: 0
115+
- _BlendMode: 0
116+
- _BumpScale: 1
117+
- _CullMode: 2
118+
- _Cutoff: 0.5
119+
- _DetailAOScale: 1
120+
- _DetailAlbedoScale: 1
121+
- _DetailHeightScale: 1
122+
- _DetailMapMode: 0
123+
- _DetailNormalMapScale: 1
124+
- _DetailNormalScale: 1
125+
- _DetailSmoothnessScale: 1
126+
- _DistortionDepthTest: 0
127+
- _DistortionOnly: 0
128+
- _DoubleSided: 1
129+
- _DoubleSidedLigthing: 1
130+
- _DoubleSidedMode: 0
131+
- _DstBlend: 0
132+
- _EmissiveColorMode: 1
133+
- _EmissiveIntensity: 0
134+
- _GlossMapScale: 1
135+
- _Glossiness: 0.5
136+
- _GlossyReflections: 1
137+
- _HeightBias: 0
138+
- _HeightMapMode: 0
139+
- _HeightScale: 1
140+
- _MaterialID: 0
141+
- _MaterialId: 0
142+
- _Metalic: 0
143+
- _Metallic: 0
144+
- _Mettalic: 0
145+
- _Mode: 0
146+
- _NormalMapSpace: 0
147+
- _OcclusionStrength: 1
148+
- _Parallax: 0.02
149+
- _Smoothness: 0
150+
- _SmoothnessTextureChannel: 0
151+
- _SpecularHighlights: 1
152+
- _SrcBlend: 1
153+
- _SubSurfaceRadius: 0
154+
- _SurfaceType: 0
155+
- _UVDetail: 0
156+
- _UVSec: 0
157+
- _ZWrite: 1
158+
m_Colors:
159+
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
160+
- _Color: {r: 0.5019608, g: 0.5019608, b: 0.5019608, a: 1}
161+
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
162+
- _EmissiveColor: {r: 0, g: 0, b: 0, a: 1}

Assets/TestScenes/HDTest/Material/HDRenderLoopMaterials/GGX Test/GGX_D_a00_s00.mat.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)