-
-
Notifications
You must be signed in to change notification settings - Fork 35.7k
/
Copy pathWebGLCubeRenderTarget.js
184 lines (126 loc) · 5.13 KB
/
WebGLCubeRenderTarget.js
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
import { BackSide, LinearFilter, LinearMipmapLinearFilter, NoBlending } from '../constants.js';
import { Mesh } from '../objects/Mesh.js';
import { BoxGeometry } from '../geometries/BoxGeometry.js';
import { ShaderMaterial } from '../materials/ShaderMaterial.js';
import { cloneUniforms } from './shaders/UniformsUtils.js';
import { WebGLRenderTarget } from './WebGLRenderTarget.js';
import { CubeCamera } from '../cameras/CubeCamera.js';
import { CubeTexture } from '../textures/CubeTexture.js';
/**
* A cube render target used in context of {@link WebGLRenderer}.
*
* @augments WebGLRenderTarget
*/
class WebGLCubeRenderTarget extends WebGLRenderTarget {
/**
* Constructs a new cube render target.
*
* @param {number} [size=1] - The size of the render target.
* @param {RenderTarget~Options} [options] - The configuration object.
*/
constructor( size = 1, options = {} ) {
super( size, size, options );
/**
* This flag can be used for type testing.
*
* @type {boolean}
* @readonly
* @default true
*/
this.isWebGLCubeRenderTarget = true;
const image = { width: size, height: size, depth: 1 };
const images = [ image, image, image, image, image, image ];
/**
* Overwritten with a different texture type.
*
* @type {DataArrayTexture}
*/
this.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );
// By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)
// in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,
// in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.
// three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped
// and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture
// as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures).
this.texture.isRenderTargetTexture = true;
this.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;
this.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;
}
/**
* Converts the given equirectangular texture to a cube map.
*
* @param {WebGLRenderer} renderer - The renderer.
* @param {Texture} texture - The equirectangular texture.
* @return {WebGLCubeRenderTarget} A reference to this cube render target.
*/
fromEquirectangularTexture( renderer, texture ) {
this.texture.type = texture.type;
this.texture.colorSpace = texture.colorSpace;
this.texture.generateMipmaps = texture.generateMipmaps;
this.texture.minFilter = texture.minFilter;
this.texture.magFilter = texture.magFilter;
const shader = {
uniforms: {
tEquirect: { value: null },
},
vertexShader: /* glsl */`
varying vec3 vWorldDirection;
vec3 transformDirection( in vec3 dir, in mat4 matrix ) {
return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz );
}
void main() {
vWorldDirection = transformDirection( position, modelMatrix );
#include <begin_vertex>
#include <project_vertex>
}
`,
fragmentShader: /* glsl */`
uniform sampler2D tEquirect;
varying vec3 vWorldDirection;
#include <common>
void main() {
vec3 direction = normalize( vWorldDirection );
vec2 sampleUV = equirectUv( direction );
gl_FragColor = texture2D( tEquirect, sampleUV );
}
`
};
const geometry = new BoxGeometry( 5, 5, 5 );
const material = new ShaderMaterial( {
name: 'CubemapFromEquirect',
uniforms: cloneUniforms( shader.uniforms ),
vertexShader: shader.vertexShader,
fragmentShader: shader.fragmentShader,
side: BackSide,
blending: NoBlending
} );
material.uniforms.tEquirect.value = texture;
const mesh = new Mesh( geometry, material );
const currentMinFilter = texture.minFilter;
// Avoid blurred poles
if ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;
const camera = new CubeCamera( 1, 10, this );
camera.update( renderer, mesh );
texture.minFilter = currentMinFilter;
mesh.geometry.dispose();
mesh.material.dispose();
return this;
}
/**
* Clears this cube render target.
*
* @param {WebGLRenderer} renderer - The renderer.
* @param {boolean} [color=true] - Whether the color buffer should be cleared or not.
* @param {boolean} [depth=true] - Whether the depth buffer should be cleared or not.
* @param {boolean} [stencil=true] - Whether the stencil buffer should be cleared or not.
*/
clear( renderer, color = true, depth = true, stencil = true ) {
const currentRenderTarget = renderer.getRenderTarget();
for ( let i = 0; i < 6; i ++ ) {
renderer.setRenderTarget( this, i );
renderer.clear( color, depth, stencil );
}
renderer.setRenderTarget( currentRenderTarget );
}
}
export { WebGLCubeRenderTarget };