Programming of Spherical Harmonics Lighting (1)

This time I have decoded the SH lighting parameters of Grace Cathedral by GLSL fragment shader, mapped the upper and lower hemisphere to the disk.

今回は Grace Cathedral の SH のパラメータをデコードしたものについて, 上半球と下半球をそれぞれ円盤に対してマッピングしてみました.

Some part of upper hemisphere seems quite bright.

上半球のライティングが部分的に結構まぶしい感じです.

Decoding the Grace Cathedral SH lighting parameters ( upper hemisphere ).


Decoding the Grace Cathedral SH lighting parameters ( lower hemisphere ).


I have pasted part of my source code below.

下に今回, 僕が書いたソースコードの一部を貼り付けました.

//////////////////////////////////////////////////
// GLSL fragment shader to decode SH lighting
//   ( l_max = 2, 9 coefficients )
//                             hanecci
//
//////////////////////////////////////////////////

varying vec3 v_normal;

const int SH_NUM = 9;

uniform vec3 sh_light_array[ SH_NUM ];

float
computeSH( const vec4 normal4, const int colorIndex )
{
	const float SH_C1 = 0.429043;
	const float SH_C2 = 0.511664;
	const float SH_C3 = 0.743125;
	const float SH_C4 = 0.886227;
	const float SH_C5 = 0.247708;

	const int SH_L_0_0  = 0;
	const int SH_L_1_M1 = 1;
	const int SH_L_1_0  = 2;
	const int SH_L_1_1  = 3;
	const int SH_L_2_M2 = 4;
	const int SH_L_2_M1 = 5;
	const int SH_L_2_0  = 6;
	const int SH_L_2_1  = 7;
	const int SH_L_2_2  = 8;

	mat4 m44 = mat4( 
			SH_C1 * sh_light_array[ SH_L_2_2 ][ colorIndex ],
			SH_C1 * sh_light_array[ SH_L_2_M2 ][ colorIndex ],
			SH_C1 * sh_light_array[ SH_L_2_1 ][ colorIndex ],
			SH_C2 * sh_light_array[ SH_L_1_1 ][ colorIndex ],
			//
			SH_C1 * sh_light_array[ SH_L_2_M2 ][ colorIndex ],
			- SH_C1 * sh_light_array[ SH_L_2_2 ][ colorIndex ],
			SH_C1 * sh_light_array[ SH_L_2_M1 ][ colorIndex ],
			SH_C2 * sh_light_array[ SH_L_1_M1 ][ colorIndex ],
			//
			SH_C1 * sh_light_array[ SH_L_2_1 ][ colorIndex ],
			SH_C1 * sh_light_array[ SH_L_2_M1 ][ colorIndex ],
			SH_C3 * sh_light_array[ SH_L_2_0 ][ colorIndex ],
			SH_C2 * sh_light_array[ SH_L_1_0 ][ colorIndex ],
			//
			SH_C2 * sh_light_array[ SH_L_1_1 ][ colorIndex ],
			SH_C2 * sh_light_array[ SH_L_1_M1 ][ colorIndex ],
			SH_C2 * sh_light_array[ SH_L_1_0 ][ colorIndex ],
			SH_C4 * sh_light_array[ SH_L_0_0 ][ colorIndex ] -
                        SH_C5 * sh_light_array[ SH_L_2_0 ][ colorIndex ]
			);
		
	vec4 tmpNormal4 = m44 * normal4;
	
	return dot( normal4, tmpNormal4 );				   				   
}

void main (void)
{			
	const int redColorIndex   = 0;
	const int greenColorIndex = 1;
	const int blueColorIndex  = 2;

	vec3 normal = normalize( v_normal );
	vec4 normal4 = vec4( normal, 1.0 );			
	
	float red   = computeSH( normal4, redColorIndex );
	float green = computeSH( normal4, greenColorIndex );
	float blue  = computeSH( normal4, blueColorIndex );
		
	gl_FragColor = vec4( red, green, blue, 1.0 );
}
//////////////////////////////////////////////////
//
// Setting SH parameters of Grace Cathedral as GLSL uniform
//   ( l_max = 2, 9 coefficients )
//                             hanecci
//
//////////////////////////////////////////////////

const int SH_NUM       = 9;
const int RGB_NUM      = 3;
const int SH_ARRAY_NUM = SH_NUM * RGB_NUM;

float g_sh_light_array[ SH_ARRAY_NUM ];

GLint g_sh_light_array_location = -1;

void initSHLightArray()
{
	const int SH_L_0_0  = 0;
	const int SH_L_1_M1 = 1;
	const int SH_L_1_0  = 2;
	const int SH_L_1_1  = 3;
	const int SH_L_2_M2 = 4;
	const int SH_L_2_M1 = 5;
	const int SH_L_2_0  = 6;
	const int SH_L_2_1  = 7;
	const int SH_L_2_2  = 8;

	// SH parameters of Grace cathedral

	// L 0 0 ( rgb )
	g_sh_light_array[ 3 * SH_L_0_0 + 0 ] = 0.79f;
	g_sh_light_array[ 3 * SH_L_0_0 + 1 ] = 0.44f;
	g_sh_light_array[ 3 * SH_L_0_0 + 2 ] = 0.54f;

	// L 1 -1	
	g_sh_light_array[ 3 * SH_L_1_M1 + 0 ] = 0.39f;
	g_sh_light_array[ 3 * SH_L_1_M1 + 1 ] = 0.35f;
	g_sh_light_array[ 3 * SH_L_1_M1 + 2 ] = 0.60f;
		
	// L 1 0
	g_sh_light_array[ 3 * SH_L_1_0 + 0 ] = -0.34f;
	g_sh_light_array[ 3 * SH_L_1_0 + 1 ] = -0.18f;
	g_sh_light_array[ 3 * SH_L_1_0 + 2 ] = -0.27f;
			
	// L 1 1
	g_sh_light_array[ 3 * SH_L_1_1 + 0 ] = -0.29f;
	g_sh_light_array[ 3 * SH_L_1_1 + 1 ] = -0.06f;
	g_sh_light_array[ 3 * SH_L_1_1 + 2 ] =  0.01f;
			
	// L 2 -2
	g_sh_light_array[ 3 * SH_L_2_M2 + 0 ] = -0.11f;
	g_sh_light_array[ 3 * SH_L_2_M2 + 1 ] = -0.05f;
	g_sh_light_array[ 3 * SH_L_2_M2 + 2 ] =  0.12f;
			
	// L 2 -1
	g_sh_light_array[ 3 * SH_L_2_M1 + 0 ] = -0.26f;
	g_sh_light_array[ 3 * SH_L_2_M1 + 1 ] = -0.22f;
	g_sh_light_array[ 3 * SH_L_2_M1 + 2 ] = -0.47f;
				
	// L 2  0
	g_sh_light_array[ 3 * SH_L_2_0 + 0 ] = -0.16f;
	g_sh_light_array[ 3 * SH_L_2_0 + 1 ] = -0.09f;
	g_sh_light_array[ 3 * SH_L_2_0 + 2 ] = -0.15f;
			
	// L 2  1
	g_sh_light_array[ 3 * SH_L_2_1 + 0 ] = 0.56f;
	g_sh_light_array[ 3 * SH_L_2_1 + 1 ] = 0.21f;
	g_sh_light_array[ 3 * SH_L_2_1 + 2 ] = 0.14f;
		
	// L 2  2
	g_sh_light_array[ 3 * SH_L_2_2 + 0 ] = 0.21f;
	g_sh_light_array[ 3 * SH_L_2_2 + 1 ] = -0.05f;
	g_sh_light_array[ 3 * SH_L_2_2 + 2 ] = -0.30f;

	g_sh_light_array_location = 
		glGetUniformLocation( g_ProgramId, 
						      "sh_light_array" );
}

void setSHUniform()
{
	glUniform3fv( g_sh_light_array_location,
				  SH_NUM,
				  g_sh_light_array );
}