# title: SH 求谐函数与立体角
date: 2022-04-07 12:00
count: true
tags: 图形学笔记
category: 图形学笔记

# SH 求谐函数与立体角

Untitled

# 直角坐标系转球面坐标系

Untitled

球坐标转 uv

Untitled

Untitled

//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;
	}
}