Sebastien Lagarde
8 年前
当前提交
caf80e26
共有 7 个文件被更改,包括 643 次插入 和 114 次删除
-
44Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Lighting/LightDefinition.cs
-
135Assets/ScriptableRenderLoop/HDRenderLoop/Shaders/Material/Lit/Lit.hlsl
-
32Assets/ScriptableRenderLoop/ShaderLibrary/CommonLighting.hlsl
-
145Assets/ScriptableRenderLoop/ShaderLibrary/ImageBasedLighting.hlsl
-
218Assets/ScriptableRenderLoop/ShaderLibrary/Sampling.hlsl
-
174Assets/ScriptableRenderLoop/ShaderLibrary/AreaLighting.hlsl
-
9Assets/ScriptableRenderLoop/ShaderLibrary/AreaLighting.hlsl.meta
|
|||
#ifndef UNITY_SAMPLING_INCLUDED |
|||
#define UNITY_SAMPLING_INCLUDED |
|||
|
|||
//----------------------------------------------------------------------------- |
|||
// Sample generator |
|||
//----------------------------------------------------------------------------- |
|||
|
|||
// Ref: http://holger.dammertz.org/stuff/notes_HammersleyOnHemisphere.html |
|||
uint ReverseBits32(uint bits) |
|||
{ |
|||
#if 0 // Shader model 5 |
|||
return reversebits(bits); |
|||
#else |
|||
bits = (bits << 16) | (bits >> 16); |
|||
bits = ((bits & 0x00ff00ff) << 8) | ((bits & 0xff00ff00) >> 8); |
|||
bits = ((bits & 0x0f0f0f0f) << 4) | ((bits & 0xf0f0f0f0) >> 4); |
|||
bits = ((bits & 0x33333333) << 2) | ((bits & 0xcccccccc) >> 2); |
|||
bits = ((bits & 0x55555555) << 1) | ((bits & 0xaaaaaaaa) >> 1); |
|||
return bits; |
|||
#endif |
|||
} |
|||
|
|||
float RadicalInverse_VdC(uint bits) |
|||
{ |
|||
return float(ReverseBits32(bits)) * 2.3283064365386963e-10; // 0x100000000 |
|||
} |
|||
|
|||
float2 Hammersley2d(uint i, uint maxSampleCount) |
|||
{ |
|||
return float2(float(i) / float(maxSampleCount), RadicalInverse_VdC(i)); |
|||
} |
|||
|
|||
float Hash(uint s) |
|||
{ |
|||
s = s ^ 2747636419u; |
|||
s = s * 2654435769u; |
|||
s = s ^ (s >> 16); |
|||
s = s * 2654435769u; |
|||
s = s ^ (s >> 16); |
|||
s = s * 2654435769u; |
|||
return float(s) / 4294967295.0; |
|||
} |
|||
|
|||
float2 InitRandom(float2 input) |
|||
{ |
|||
float2 r; |
|||
r.x = Hash(uint(input.x * 4294967295.0)); |
|||
r.y = Hash(uint(input.y * 4294967295.0)); |
|||
|
|||
return r; |
|||
} |
|||
|
|||
//----------------------------------------------------------------------------- |
|||
// Sampling function |
|||
//----------------------------------------------------------------------------- |
|||
|
|||
// Reference : Monte Carlo techniques for direct lighting calculations http://www.cs.virginia.edu/~jdl/bib/globillum/mis/shirley96.pdf + PBRT |
|||
float3 UniformSampleSphere(float u1, float u2) |
|||
{ |
|||
float phi = TWO_PI * u2; |
|||
float cosTheta = 1.0 - 2.0 * u1; |
|||
float sinTheta = sqrt(max(0.0, 1.0 - cosTheta * cosTheta)); |
|||
|
|||
return float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); // our light point backward (-Z) |
|||
} |
|||
|
|||
float3 UniformSampleHemisphere(float u1, float u2) |
|||
{ |
|||
float phi = TWO_PI * u2; |
|||
float cosTheta = u1; |
|||
float sinTheta = sqrt(max(0.0, 1.0 - cosTheta * cosTheta)); |
|||
|
|||
return float3(sinTheta * cos(phi), sinTheta * sin(phi), cosTheta); // our light point backward (-Z) |
|||
} |
|||
|
|||
float3 UniformSampleDisk(float u1, float u2) |
|||
{ |
|||
float r = sqrt(u1); |
|||
float phi = TWO_PI * u2; |
|||
|
|||
return float3(r * cos(phi), r * sin(phi), 0); // generate in the XY plane as light point backward (-Z) |
|||
} |
|||
|
|||
void SampleSphere( float2 u, |
|||
float4x4 localToWorld, |
|||
float radius, |
|||
out float lightPdf, |
|||
out float3 P, |
|||
out float3 Ns) |
|||
{ |
|||
float u1 = u.x; |
|||
float u2 = u.y; |
|||
|
|||
// Random point at light surface |
|||
Ns = uniformSampleSphere(u1, u2); |
|||
// Transform point on unit sphere to world space |
|||
P = radius * Ns + localToWorld[3].xyz; |
|||
// pdf is just the inverse of the area |
|||
lightPdf = 1.0 / (FOUR_PI * radius * radius); |
|||
} |
|||
|
|||
void SampleHemisphere( float2 u, |
|||
float4x4 localToWorld, |
|||
float radius, |
|||
out float lightPdf, |
|||
out float3 P, |
|||
out float3 Ns) |
|||
{ |
|||
float u1 = u.x; |
|||
float u2 = u.y; |
|||
|
|||
// Random point at light surface |
|||
Ns = -uniformSampleHemisphere(u1, u2); // We want the y down hemisphere |
|||
P = radius * Ns; |
|||
// Transform to world space |
|||
P = mul(float4(P, 1.0), localToWorld).xyz; |
|||
Ns = mul(Ns, convertFloat3x3(localToWorld)); |
|||
// pdf is just the inverse of the area |
|||
lightPdf = 1.0 / (TWO_PI * radius * radius); |
|||
} |
|||
|
|||
// Note: The cylinder has no end caps (i.e. no disk on the side) |
|||
void SampleCylinder(float2 u, |
|||
float4x4 localToWorld, |
|||
float radius, |
|||
float width, |
|||
out float lightPdf, |
|||
out float3 P, |
|||
out float3 Ns) |
|||
{ |
|||
float u1 = u.x; |
|||
float u2 = u.y; |
|||
|
|||
// Random point at light surface |
|||
float t = (u1 - 0.5) * width; |
|||
float theta = 2.0 * PI * u2; |
|||
float cosTheta = cos(theta); |
|||
float sinTheta = sin(theta); |
|||
P = float3(t, radius * cosTheta, radius * sinTheta); // Cylinder are align on the left axis in Frosbite |
|||
Ns = normalize(float3(0.0, cosTheta, sinTheta)); |
|||
// Transform to world space |
|||
P = mul(float4(P, 1.0), localToWorld).xyz; |
|||
Ns = mul(Ns, convertFloat3x3(localToWorld)); |
|||
// pdf is just the inverse of the area |
|||
lightPdf = 1.0 / (TWO_PI * radius * width); |
|||
} |
|||
|
|||
void SampleCapsule( float2 u, |
|||
float4x4 localToWorld, |
|||
float radius, |
|||
float width, |
|||
int passIt, |
|||
out float lightPdf, |
|||
out float3 P, |
|||
out float3 Ns) |
|||
{ |
|||
// Capsules are sampled in two times: |
|||
// - Pass 0: Cylinder |
|||
// - Pass 1: Hemisphere caps |
|||
if (passIt == 0) |
|||
{ |
|||
sampleCylinder(u, localToWorld, radius, width, lightPdf, P, Ns); |
|||
} |
|||
else |
|||
{ |
|||
float u1 = u.x; |
|||
float u2 = u.y; |
|||
|
|||
// Random point at light surface |
|||
Ns = uniformSampleSphere(u1, u2); |
|||
P = radius * Ns; |
|||
|
|||
// Split the sphere into two hemisphere and shift each hemisphere on one side of the cylinder |
|||
P.x += (Ns.x > 0.0 ? 1.0 : -1.0) * 0.5 * width; |
|||
|
|||
// Transform to world space |
|||
P = mul(float4(P, 1.0), localToWorld).xyz; |
|||
Ns = mul(Ns, convertFloat3x3(localToWorld)); |
|||
// pdf is just the inverse of the area |
|||
lightPdf = 1.0 / (FOUR_PI * radius * radius); |
|||
} |
|||
} |
|||
|
|||
void SampleRectangle( float2 u, |
|||
float4x4 localToWorld, |
|||
float width, |
|||
float height, |
|||
out float lightPdf, |
|||
out float3 P, |
|||
out float3 Ns) |
|||
{ |
|||
// Random point at light surface |
|||
P = float3((u.x - 0.5) * width, (u.y - 0.5) * height, 0); |
|||
Ns = float3(0, 0, -1); // By default our rectangle light point backward |
|||
|
|||
// Transform to world space |
|||
P = mul(float4(P, 1.0), localToWorld).xyz; |
|||
Ns = mul(Ns, convertFloat3x3(localToWorld)); |
|||
// pdf is just the inverse of the area |
|||
lightPdf = 1.0 / (width * height); |
|||
} |
|||
|
|||
void SampleDisk(float2 u, |
|||
float4x4 localToWorld, |
|||
float radius, |
|||
out float lightPdf, |
|||
out float3 P, |
|||
out float3 Ns) |
|||
{ |
|||
// Random point at light surface |
|||
P = uniformSampleDisk(u.x, u.y) * radius; |
|||
Ns = float3(0.0, 0.0, -1.0); |
|||
|
|||
// Transform to world space |
|||
P = mul(float4(P, 1.0), localToWorld).xyz; |
|||
Ns = mul(Ns, convertFloat3x3(localToWorld)); |
|||
|
|||
// pdf is just the inverse of the area |
|||
lightPdf = 1.0 / (PI * radius * radius); |
|||
} |
|||
|
|||
#endif // UNITY_SAMPLING_INCLUDED |
|
|||
#ifndef UNITY_AREA_LIGHTING_INCLUDED |
|||
// Upgrade NOTE: excluded shader from OpenGL ES 2.0 because it uses non-square matrices |
|||
#pragma exclude_renderers gles |
|||
#define UNITY_AREA_LIGHTING_INCLUDED |
|||
|
|||
float IntegrateEdge(float3 v1, float3 v2) |
|||
{ |
|||
float3 cosTheta = dot(v1, v2); |
|||
cosTheta = clamp(cosTheta, -0.9999, 0.9999); |
|||
|
|||
// TODO: Experiment with fastAcos |
|||
float3 theta = acos(cosTheta); |
|||
float3 res = cross(v1, v2).z * theta / sin(theta); |
|||
|
|||
return res; |
|||
} |
|||
|
|||
// Baum's equation |
|||
// Expects non-normalized vertex positions |
|||
float PolygonRadiance(float4x3 L, bool twoSided) |
|||
{ |
|||
// 1. ClipQuadToHorizon |
|||
|
|||
// detect clipping config |
|||
uint config = 0; |
|||
if (L[0].z > 0) config += 1; |
|||
if (L[1].z > 0) config += 2; |
|||
if (L[2].z > 0) config += 4; |
|||
if (L[3].z > 0) config += 8; |
|||
|
|||
// The fifth vertex for cases when clipping cuts off one corner. |
|||
// Due to a compiler bug, copying L into a vector array with 5 rows |
|||
// messes something up, so we need to stick with the matrix + the L4 vertex. |
|||
float3 L4 = L[3]; |
|||
|
|||
// This switch is surprisingly fast. Tried replacing it with a lookup array of vertices. |
|||
// Even though that replaced the switch with just some indexing and no branches, it became |
|||
// way, way slower - mem fetch stalls? |
|||
|
|||
uint n = 0; |
|||
switch (config) |
|||
{ |
|||
case 0: // clip all |
|||
break; |
|||
|
|||
case 1: // V1 clip V2 V3 V4 |
|||
n = 3; |
|||
L[1] = -L[1].z * L[0] + L[0].z * L[1]; |
|||
L[2] = -L[3].z * L[0] + L[0].z * L[3]; |
|||
break; |
|||
|
|||
case 2: // V2 clip V1 V3 V4 |
|||
n = 3; |
|||
L[0] = -L[0].z * L[1] + L[1].z * L[0]; |
|||
L[2] = -L[2].z * L[1] + L[1].z * L[2]; |
|||
break; |
|||
|
|||
case 3: // V1 V2 clip V3 V4 |
|||
n = 4; |
|||
L[2] = -L[2].z * L[1] + L[1].z * L[2]; |
|||
L[3] = -L[3].z * L[0] + L[0].z * L[3]; |
|||
break; |
|||
|
|||
case 4: // V3 clip V1 V2 V4 |
|||
n = 3; |
|||
L[0] = -L[3].z * L[2] + L[2].z * L[3]; |
|||
L[1] = -L[1].z * L[2] + L[2].z * L[1]; |
|||
break; |
|||
|
|||
case 5: // V1 V3 clip V2 V4: impossible |
|||
break; |
|||
|
|||
case 6: // V2 V3 clip V1 V4 |
|||
n = 4; |
|||
L[0] = -L[0].z * L[1] + L[1].z * L[0]; |
|||
L[3] = -L[3].z * L[2] + L[2].z * L[3]; |
|||
break; |
|||
|
|||
case 7: // V1 V2 V3 clip V4 |
|||
n = 5; |
|||
L4 = -L[3].z * L[0] + L[0].z * L[3]; |
|||
L[3] = -L[3].z * L[2] + L[2].z * L[3]; |
|||
break; |
|||
|
|||
case 8: // V4 clip V1 V2 V3 |
|||
n = 3; |
|||
L[0] = -L[0].z * L[3] + L[3].z * L[0]; |
|||
L[1] = -L[2].z * L[3] + L[3].z * L[2]; |
|||
L[2] = L[3]; |
|||
break; |
|||
|
|||
case 9: // V1 V4 clip V2 V3 |
|||
n = 4; |
|||
L[1] = -L[1].z * L[0] + L[0].z * L[1]; |
|||
L[2] = -L[2].z * L[3] + L[3].z * L[2]; |
|||
break; |
|||
|
|||
case 10: // V2 V4 clip V1 V3: impossible |
|||
break; |
|||
|
|||
case 11: // V1 V2 V4 clip V3 |
|||
n = 5; |
|||
L[3] = -L[2].z * L[3] + L[3].z * L[2]; |
|||
L[2] = -L[2].z * L[1] + L[1].z * L[2]; |
|||
break; |
|||
|
|||
case 12: // V3 V4 clip V1 V2 |
|||
n = 4; |
|||
L[1] = -L[1].z * L[2] + L[2].z * L[1]; |
|||
L[0] = -L[0].z * L[3] + L[3].z * L[0]; |
|||
break; |
|||
|
|||
case 13: // V1 V3 V4 clip V2 |
|||
n = 5; |
|||
L[3] = L[2]; |
|||
L[2] = -L[1].z * L[2] + L[2].z * L[1]; |
|||
L[1] = -L[1].z * L[0] + L[0].z * L[1]; |
|||
break; |
|||
|
|||
case 14: // V2 V3 V4 clip V1 |
|||
n = 5; |
|||
L4 = -L[0].z * L[3] + L[3].z * L[0]; |
|||
L[0] = -L[0].z * L[1] + L[1].z * L[0]; |
|||
break; |
|||
|
|||
case 15: // V1 V2 V3 V4 |
|||
n = 4; |
|||
break; |
|||
} |
|||
|
|||
if (n == 0) |
|||
return 0; |
|||
if (n == 3) |
|||
L[3] = L[0]; |
|||
if (n == 4) |
|||
L4 = L[0]; |
|||
|
|||
// 2. Project onto sphere |
|||
L[0] = normalize(L[0]); |
|||
L[1] = normalize(L[1]); |
|||
L[2] = normalize(L[2]); |
|||
L[3] = normalize(L[3]); |
|||
L4 = normalize(L4); |
|||
|
|||
// 3. Integrate |
|||
float sum = 0; |
|||
sum += IntegrateEdge(L[0], L[1]); |
|||
sum += IntegrateEdge(L[1], L[2]); |
|||
sum += IntegrateEdge(L[2], L[3]); |
|||
if (n >= 4) |
|||
sum += IntegrateEdge(L[3], L4); |
|||
if (n == 5) |
|||
sum += IntegrateEdge(L4, L[0]); |
|||
|
|||
return twoSided > 0.0 ? abs(sum) : max(0.0, sum); |
|||
} |
|||
|
|||
float LTCEvaluate(float3 V, float3 N, float3x3 minV, float4x3 L) |
|||
{ |
|||
// Construct local orthonormal basis around N, aligned with N |
|||
float3x3 basis; |
|||
basis[0] = normalize(V - N * dot(V, N)); |
|||
basis[1] = normalize(cross(N, basis[0])); |
|||
basis[2] = N; |
|||
|
|||
// rotate area light in local basis |
|||
minV = mul(transpose(basis), minV); |
|||
L = mul(L, minV); |
|||
|
|||
// Polygon radiance in transformed configuration - specular |
|||
return PolygonRadiance(L); |
|||
} |
|||
|
|||
#endif // UNITY_AREA_LIGHTING_INCLUDED |
|
|||
fileFormatVersion: 2 |
|||
guid: 2af09bb13e6547242913c40dfb0e50f9 |
|||
timeCreated: 1476726533 |
|||
licenseType: Pro |
|||
ShaderImporter: |
|||
defaultTextures: [] |
|||
userData: |
|||
assetBundleName: |
|||
assetBundleVariant: |
撰写
预览
正在加载...
取消
保存
Reference in new issue