File size: 2,818 Bytes
b797337
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
131
import {
	Mesh,
	ShaderMaterial,
	SphereGeometry
} from 'three';

class LightProbeHelper extends Mesh {

	constructor( lightProbe, size ) {

		const material = new ShaderMaterial( {

			type: 'LightProbeHelperMaterial',

			uniforms: {

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

				intensity: { value: lightProbe.intensity }

			},

			vertexShader: [

				'varying vec3 vNormal;',

				'void main() {',

				'	vNormal = normalize( normalMatrix * normal );',

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

				'}',

			].join( '\n' ),

			fragmentShader: [

				'#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 ) );',

				'}'

			].join( '\n' )

		} );

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