File size: 2,708 Bytes
a28eca3
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import {
	Mesh,
	ShaderMaterial,
	SphereGeometry
} from 'three';

class LightProbeHelper extends Mesh {

	constructor( lightProbe, size = 1 ) {

		const material = new ShaderMaterial( {

			type: 'LightProbeHelperMaterial',

			uniforms: {

				sh: { value: lightProbe.sh.coefficients }, // by reference

				intensity: { value: lightProbe.intensity }

			},

			vertexShader: /* glsl */`

				varying vec3 vNormal;

				void main() {

					vNormal = normalize( normalMatrix * normal );

					gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );

				}

			`,

			fragmentShader: /* glsl */`

				#define RECIPROCAL_PI 0.318309886

				vec3 inverseTransformDirection( in vec3 normal, in mat4 matrix ) {

					// matrix is assumed to be orthogonal

					return normalize( ( vec4( normal, 0.0 ) * matrix ).xyz );

				}

				// source: https://graphics.stanford.edu/papers/envmap/envmap.pdf,
				vec3 shGetIrradianceAt( in vec3 normal, in vec3 shCoefficients[ 9 ] ) {

					// normal is assumed to have unit length,

					float x = normal.x, y = normal.y, z = normal.z;

					// band 0,
					vec3 result = shCoefficients[ 0 ] * 0.886227;

					// band 1,
					result += shCoefficients[ 1 ] * 2.0 * 0.511664 * y;
					result += shCoefficients[ 2 ] * 2.0 * 0.511664 * z;
					result += shCoefficients[ 3 ] * 2.0 * 0.511664 * x;

					// band 2,
					result += shCoefficients[ 4 ] * 2.0 * 0.429043 * x * y;
					result += shCoefficients[ 5 ] * 2.0 * 0.429043 * y * z;
					result += shCoefficients[ 6 ] * ( 0.743125 * z * z - 0.247708 );
					result += shCoefficients[ 7 ] * 2.0 * 0.429043 * x * z;
					result += shCoefficients[ 8 ] * 0.429043 * ( x * x - y * y );
					return result;

				}

				uniform vec3 sh[ 9 ]; // sh coefficients

				uniform float intensity; // light probe intensity

				varying vec3 vNormal;

				void main() {

					vec3 normal = normalize( vNormal );

					vec3 worldNormal = inverseTransformDirection( normal, viewMatrix );

					vec3 irradiance = shGetIrradianceAt( worldNormal, sh );

					vec3 outgoingLight = RECIPROCAL_PI * irradiance * intensity;

					gl_FragColor = linearToOutputTexel( vec4( outgoingLight, 1.0 ) );

				}

			`,

		} );

		const geometry = new SphereGeometry( 1, 32, 16 );

		super( geometry, material );

		this.lightProbe = lightProbe;
		this.size = size;
		this.type = 'LightProbeHelper';

		this.onBeforeRender();

	}

	dispose() {

		this.geometry.dispose();
		this.material.dispose();

	}

	onBeforeRender() {

		this.position.copy( this.lightProbe.position );

		this.scale.set( 1, 1, 1 ).multiplyScalar( this.size );

		this.material.uniforms.intensity.value = this.lightProbe.intensity;

	}

}

export { LightProbeHelper };