summaryrefslogtreecommitdiff
path: root/Runtime/Math/SphericalHarmonics.h
blob: 539d31613ca3cd70de67758153a818246de42337 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
#pragma once


static inline void SHEvalDirection9 (float x, float y, float z, float outsh[9])
{
	// Core i7 920, VS2008 Release, FPU code:

	// 114 clocks
	//D3DXSHEvalDirection (outsh, 3, &D3DXVECTOR3(x,y,z));

	/*
	// 314 clocks
	// Reference implementation from Stupid Spherical Harmonics Tricks
	// http://www.ppsloan.org/publications/StupidSH36.pdf
	const float kSqrtPI = sqrtf(kPI);
	const float kSqrt3 = sqrtf(3.0f);
	const float kSqrt15 = sqrtf(15.0f);
	outsh[0] = 1.0f / (2.0f * kSqrtPI);
	outsh[1] = -(kSqrt3 * y) / (2.0f * kSqrtPI);
	outsh[2] = (kSqrt3 * z) / (2.0f * kSqrtPI);
	outsh[3] = -(kSqrt3 * x) / (2.0f * kSqrtPI);
	outsh[4] = (kSqrt15 * x * y) / (2.0f * kSqrtPI);
	outsh[5] = -(kSqrt15 * y * z) / (2.0f * kSqrtPI);
	outsh[6] = (sqrtf(5.0f) * (3.0f*z*z-1.0f)) / (4.0f * kSqrtPI);
	outsh[7] = -(kSqrt15 * x * z) / (2.0f * kSqrtPI);
	outsh[8] = (kSqrt15 * (x*x - y*y)) / (4.0f * kSqrtPI);
	*/

	// 86 clocks
	// Make sure all constants are never computed at runtime
	const float kInv2SqrtPI = 0.28209479177387814347403972578039f; // 1 / (2*sqrt(kPI))
	const float kSqrt3Div2SqrtPI = 0.48860251190291992158638462283835f; // sqrt(3) / (2*sqrt(kPI))
	const float kSqrt15Div2SqrtPI = 1.0925484305920790705433857058027f; // sqrt(15) / (2*sqrt(kPI))
	const float k3Sqrt5Div4SqrtPI = 0.94617469575756001809268107088713f; // 3 * sqrtf(5) / (4*sqrt(kPI))
	const float kSqrt15Div4SqrtPI = 0.54627421529603953527169285290135f; // sqrt(15) / (4*sqrt(kPI))
	const float kOneThird = 0.3333333333333333333333f; // 1.0/3.0
	outsh[0] = kInv2SqrtPI;
	outsh[1] = - y * kSqrt3Div2SqrtPI;
	outsh[2] =   z * kSqrt3Div2SqrtPI;
	outsh[3] = - x * kSqrt3Div2SqrtPI;
	outsh[4] =   x * y * kSqrt15Div2SqrtPI;
	outsh[5] = - y * z * kSqrt15Div2SqrtPI;
	outsh[6] =  (z*z-kOneThird) * k3Sqrt5Div4SqrtPI;
	outsh[7] = - x * z * kSqrt15Div2SqrtPI;
	outsh[8] =  (x*x-y*y) * kSqrt15Div4SqrtPI;
}


static inline void SHEvalDirectionalLight9 (
	float x, float y, float z,
	float colorR, float colorG, float colorB,
	float outR[9], float outG[9], float outB[9])
{
	// Core i7 920, VS2008 Release, FPU code:

	// 397 clocks
	//D3DXSHEvalDirectionalLight (3, &D3DXVECTOR3(x,y,z), colorR, colorG, colorB, outR, outG, outB);

	// 300 clocks
	float sh[9];
	SHEvalDirection9 (x, y, z, sh);
	// Normalization factor from http://www.ppsloan.org/publications/StupidSH36.pdf
	const float kNormalization = 2.9567930857315701067858823529412f; // 16*kPI/17
	float rscale = colorR * kNormalization;
	float gscale = colorG * kNormalization;
	float bscale = colorB * kNormalization;
	for (int i = 0; i < 9; ++i)
	{
		float c = sh[i];
		outR[i] = c * rscale;
		outG[i] = c * gscale;
		outB[i] = c * bscale;
	}
}

// Add 'out' to the 0th SH coefficients
static inline void SHEvalAmbientLight(const ColorRGBAf& ambient, float out[3])
{
	const float k2SqrtPI = 3.54490770181103205459633496668229f; // 2*sqrt(kPI)
	out[0] = ambient.r * k2SqrtPI;
	out[1] = ambient.g * k2SqrtPI;
	out[2] = ambient.b * k2SqrtPI;
}