球坐标转 uv
//uv 转 vector | |
float4 UniformSampleSphere( float2 E ) | |
{ | |
float Phi = 2 * PI * E.x; | |
float CosTheta = 1 - 2 * E.y; | |
float SinTheta = sqrt( 1 - CosTheta * CosTheta ); | |
float3 H; | |
H.x = SinTheta * cos( Phi ); | |
H.y = SinTheta * sin( Phi ); | |
H.z = CosTheta; | |
float PDF = 1.0 / (4 * PI); | |
return float4( H, PDF ); | |
} |
SH 求谐函数
UE 用的 2 阶
ue 存这 27 个 SH
FThreeBandSHVector SHBasisFunction3(half3 InputVector) | |
{ | |
FThreeBandSHVectorResult; | |
// These are derived from simplifying SHBasisFunction in C++ | |
Result.V0.x = 0.282095f; | |
Result.V0.y = -0.488603f * InputVector.y; | |
Result.V0.z = 0.488603f * InputVector.z; | |
Result.V0.w = -0.488603f * InputVector.x; | |
half3 VectorSquared = InputVector * InputVector; | |
Result.V1.x = 1.092548f * InputVector.x * InputVector.y; | |
Result.V1.y = -1.092548f * InputVector.y * InputVector.z; | |
Result.V1.z = 0.315392f * (3.0f * VectorSquared.z - 1.0f); | |
Result.V1.w = -1.092548f * InputVector.x * InputVector.z; | |
Result.V2 = 0.546274f * (VectorSquared.x - VectorSquared.y); | |
return Result; | |
} | |
FThreeBandSHVectorRGB SampleSHRGB(in float3 SampleDirection, in float weight, in float MipLevel) | |
{ | |
const float3 SampleColor = SourceCubemapTexture.SampleLevel(SourceCubemapSampler, SampleDirection, MipLevel).rgb; | |
FThreeBandSHVector Sh3Vector = SHBasisFunction3(SampleDirection); | |
FThreeBandSHVectorRGB Result; | |
Result.R = MulSH3(Sh3Vector, SampleColor.r * weight);//weight 是 4Π/ 采样次数 | |
Result.G = MulSH3(Sh3Vector, SampleColor.g * weight); | |
Result.B = MulSH3(Sh3Vector, SampleColor.b * weight); | |
return Result; | |
} | |
void ComputeSkyEnvMapDiffuseIrradianceCS(uint3 ThreadId : SV_DispatchThreadID) | |
{ | |
const uint LinearIndex = THREADGROUP_SIZE_X * ThreadId.y + ThreadId.x; | |
// For a 128x128 cubemap, sampling mip level 2 with only 8x8 samples matches closely the super sampled version. | |
const float3 SampleDirection = UniformSampleSphere((float2(ThreadId.xy)+0.5f) / float2(THREADGROUP_SIZE_X, THREADGROUP_SIZE_Y)).xyz; | |
IrradianceSHShared[LinearIndex] = SampleSHRGB(SampleDirection, UniformSampleSolidAngle, MipIndex); | |
#if THREADGROUP_SIZE != 64 | |
#error That is the only reduction supported today | |
#endif | |
// Wait for all group threads to be done | |
GroupMemoryBarrierWithGroupSync(); | |
if (LinearIndex < 32) | |
{ | |
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 32]); | |
} | |
GroupMemoryBarrierWithGroupSync(); | |
if (LinearIndex < 16) | |
{ | |
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 16]); | |
} | |
GroupMemoryBarrierWithGroupSync(); | |
// The smallest wave size is 16 on Intel hardware. So now we can do simple math operations without group sync. | |
if (LinearIndex < 8) | |
{ | |
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 8]); | |
} | |
if (LinearIndex < 4) | |
{ | |
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 4]); | |
} | |
if (LinearIndex < 2) | |
{ | |
IrradianceSHShared[LinearIndex] = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 2]); | |
} | |
if (LinearIndex < 1) | |
{ | |
FThreeBandSHVectorRGB SkyIrradiance = AddSH(IrradianceSHShared[LinearIndex], IrradianceSHShared[LinearIndex + 1]); | |
// Pack the SH coefficients in a way that makes applying the lighting use the least shader instructions | |
// This has the diffuse convolution coefficients baked in. See "Stupid Spherical Harmonics (SH) Tricks". | |
//https://wolfand11.gitee.io/blogs/graphics/StupidSphericalHarmonics.html | |
// Also see UpdateSkyIrradianceGpuBuffer. | |
const float SqrtPI = sqrt(PI); | |
const float Coefficient0 = 1.0f / (2.0f * SqrtPI); | |
const float Coefficient1 = sqrt(3.0f) / (3.0f * SqrtPI); | |
const float Coefficient2 = sqrt(15.0f) / (8.0f * SqrtPI); | |
const float Coefficient3 = sqrt(5.0f) / (16.0f * SqrtPI); | |
const float Coefficient4 = 0.5f * Coefficient2; | |
OutIrradianceEnvMapSH[0].x = -Coefficient1 * SkyIrradiance.R.V0[3]; | |
OutIrradianceEnvMapSH[0].y = -Coefficient1 * SkyIrradiance.R.V0[1]; | |
OutIrradianceEnvMapSH[0].z = Coefficient1 * SkyIrradiance.R.V0[2]; | |
OutIrradianceEnvMapSH[0].w = Coefficient0 * SkyIrradiance.R.V0[0] - Coefficient3 * SkyIrradiance.R.V1[2];//[6]; | |
OutIrradianceEnvMapSH[1].x = -Coefficient1 * SkyIrradiance.G.V0[3]; | |
OutIrradianceEnvMapSH[1].y = -Coefficient1 * SkyIrradiance.G.V0[1]; | |
OutIrradianceEnvMapSH[1].z = Coefficient1 * SkyIrradiance.G.V0[2]; | |
OutIrradianceEnvMapSH[1].w = Coefficient0 * SkyIrradiance.G.V0[0] - Coefficient3 * SkyIrradiance.G.V1[2];//[6]; | |
OutIrradianceEnvMapSH[2].x = -Coefficient1 * SkyIrradiance.B.V0[3]; | |
OutIrradianceEnvMapSH[2].y = -Coefficient1 * SkyIrradiance.B.V0[1]; | |
OutIrradianceEnvMapSH[2].z = Coefficient1 * SkyIrradiance.B.V0[2]; | |
OutIrradianceEnvMapSH[2].w = Coefficient0 * SkyIrradiance.B.V0[0] - Coefficient3 * SkyIrradiance.B.V1[2];//[6]; | |
OutIrradianceEnvMapSH[3].x = Coefficient2 * SkyIrradiance.R.V1[0];//[4]; | |
OutIrradianceEnvMapSH[3].y = -Coefficient2 * SkyIrradiance.R.V1[1];//V[5]; | |
OutIrradianceEnvMapSH[3].z = 3.0f * Coefficient3 * SkyIrradiance.R.V1[2];//[6]; | |
OutIrradianceEnvMapSH[3].w = -Coefficient2 * SkyIrradiance.R.V1[3];//[7]; | |
OutIrradianceEnvMapSH[4].x = Coefficient2 * SkyIrradiance.G.V1[0];//[4]; | |
OutIrradianceEnvMapSH[4].y = -Coefficient2 * SkyIrradiance.G.V1[1];//[5]; | |
OutIrradianceEnvMapSH[4].z = 3.0f * Coefficient3 * SkyIrradiance.G.V1[2];//[6]; | |
OutIrradianceEnvMapSH[4].w = -Coefficient2 * SkyIrradiance.G.V1[3];//[7]; | |
OutIrradianceEnvMapSH[5].x = Coefficient2 * SkyIrradiance.B.V1[0];//[4]; | |
OutIrradianceEnvMapSH[5].y = -Coefficient2 * SkyIrradiance.B.V1[1];//[5]; | |
OutIrradianceEnvMapSH[5].z = 3.0f * Coefficient3 * SkyIrradiance.B.V1[2];//[6]; | |
OutIrradianceEnvMapSH[5].w = -Coefficient2 * SkyIrradiance.B.V1[3];//[7]; | |
OutIrradianceEnvMapSH[6].x = Coefficient4 * SkyIrradiance.R.V2;//[8]; | |
OutIrradianceEnvMapSH[6].y = Coefficient4 * SkyIrradiance.G.V2;//[8]; | |
OutIrradianceEnvMapSH[6].z = Coefficient4 * SkyIrradiance.B.V2;//[8]; | |
OutIrradianceEnvMapSH[6].w = 1.0f; | |
} | |
} |