|
| 1 | +/** |
| 2 | +* @author Richard M. / https://github.com/richardmonette |
| 3 | +* @author WestLangley / http://github.com/WestLangley |
| 4 | +*/ |
| 5 | + |
| 6 | +import { |
| 7 | + BackSide, |
| 8 | + BoxBufferGeometry, |
| 9 | + CubeCamera, |
| 10 | + Mesh, |
| 11 | + NoBlending, |
| 12 | + PerspectiveCamera, |
| 13 | + Scene, |
| 14 | + ShaderMaterial, |
| 15 | + UniformsUtils, |
| 16 | + WebGLRenderTargetCube |
| 17 | +} from "../../../build/three.module.js"; |
| 18 | + |
| 19 | +var CubemapGenerator = function ( renderer ) { |
| 20 | + |
| 21 | + this.renderer = renderer; |
| 22 | + |
| 23 | +}; |
| 24 | + |
| 25 | +CubemapGenerator.prototype.fromEquirectangular = function ( texture, options ) { |
| 26 | + |
| 27 | + options = options || {}; |
| 28 | + |
| 29 | + var scene = new Scene(); |
| 30 | + |
| 31 | + var shader = { |
| 32 | + |
| 33 | + uniforms: { |
| 34 | + tEquirect: { value: null }, |
| 35 | + }, |
| 36 | + |
| 37 | + vertexShader: |
| 38 | + |
| 39 | + ` |
| 40 | + varying vec3 vWorldDirection; |
| 41 | +
|
| 42 | + //include <common> |
| 43 | + vec3 transformDirection( in vec3 dir, in mat4 matrix ) { |
| 44 | +
|
| 45 | + return normalize( ( matrix * vec4( dir, 0.0 ) ).xyz ); |
| 46 | +
|
| 47 | + } |
| 48 | +
|
| 49 | + void main() { |
| 50 | +
|
| 51 | + vWorldDirection = transformDirection( position, modelMatrix ); |
| 52 | +
|
| 53 | + #include <begin_vertex> |
| 54 | + #include <project_vertex> |
| 55 | +
|
| 56 | + } |
| 57 | + `, |
| 58 | + |
| 59 | + fragmentShader: |
| 60 | + |
| 61 | + ` |
| 62 | + uniform sampler2D tEquirect; |
| 63 | +
|
| 64 | + varying vec3 vWorldDirection; |
| 65 | +
|
| 66 | + //include <common> |
| 67 | + #define RECIPROCAL_PI 0.31830988618 |
| 68 | + #define RECIPROCAL_PI2 0.15915494 |
| 69 | +
|
| 70 | + void main() { |
| 71 | +
|
| 72 | + vec3 direction = normalize( vWorldDirection ); |
| 73 | +
|
| 74 | + vec2 sampleUV; |
| 75 | +
|
| 76 | + sampleUV.y = asin( clamp( direction.y, - 1.0, 1.0 ) ) * RECIPROCAL_PI + 0.5; |
| 77 | +
|
| 78 | + sampleUV.x = atan( direction.z, direction.x ) * RECIPROCAL_PI2 + 0.5; |
| 79 | +
|
| 80 | + gl_FragColor = texture2D( tEquirect, sampleUV ); |
| 81 | +
|
| 82 | + } |
| 83 | + ` |
| 84 | + }; |
| 85 | + |
| 86 | + var material = new ShaderMaterial( { |
| 87 | + |
| 88 | + type: 'CubemapFromEquirect', |
| 89 | + |
| 90 | + uniforms: UniformsUtils.clone( shader.uniforms ), |
| 91 | + vertexShader: shader.vertexShader, |
| 92 | + fragmentShader: shader.fragmentShader, |
| 93 | + side: BackSide, |
| 94 | + blending: NoBlending |
| 95 | + |
| 96 | + } ); |
| 97 | + |
| 98 | + material.uniforms.tEquirect.value = texture; |
| 99 | + |
| 100 | + var mesh = new Mesh( new BoxBufferGeometry( 5, 5, 5 ), material ); |
| 101 | + |
| 102 | + scene.add( mesh ); |
| 103 | + |
| 104 | + var resolution = options.resolution || 512; |
| 105 | + |
| 106 | + var params = { |
| 107 | + type: texture.type, |
| 108 | + format: texture.format, |
| 109 | + encoding: texture.encoding, |
| 110 | + generateMipmaps: ( options.generateMipmaps !== undefined ) ? options.generateMipmaps : texture.generateMipmaps, |
| 111 | + minFilter: ( options.minFilter !== undefined ) ? options.minFilter : texture.minFilter, |
| 112 | + magFilter: ( options.magFilter !== undefined ) ? options.magFilter : texture.magFilter |
| 113 | + }; |
| 114 | + |
| 115 | + var camera = new CubeCamera( 1, 10, resolution, params ); |
| 116 | + |
| 117 | + camera.update( this.renderer, scene ); |
| 118 | + |
| 119 | + mesh.geometry.dispose(); |
| 120 | + mesh.material.dispose(); |
| 121 | + |
| 122 | + return camera.renderTarget; |
| 123 | + |
| 124 | +}; |
| 125 | + |
| 126 | +// |
| 127 | + |
| 128 | +var EquirectangularToCubeGenerator = ( function () { |
| 129 | + |
| 130 | + var camera = new PerspectiveCamera( 90, 1, 0.1, 10 ); |
| 131 | + var scene = new Scene(); |
| 132 | + var boxMesh = new Mesh( new BoxBufferGeometry( 1, 1, 1 ), getShader() ); |
| 133 | + boxMesh.material.side = BackSide; |
| 134 | + scene.add( boxMesh ); |
| 135 | + |
| 136 | + var EquirectangularToCubeGenerator = function ( sourceTexture, options ) { |
| 137 | + |
| 138 | + options = options || {}; |
| 139 | + |
| 140 | + this.sourceTexture = sourceTexture; |
| 141 | + this.resolution = options.resolution || 512; |
| 142 | + |
| 143 | + this.views = [ |
| 144 | + { t: [ 1, 0, 0 ], u: [ 0, - 1, 0 ] }, |
| 145 | + { t: [ - 1, 0, 0 ], u: [ 0, - 1, 0 ] }, |
| 146 | + { t: [ 0, 1, 0 ], u: [ 0, 0, 1 ] }, |
| 147 | + { t: [ 0, - 1, 0 ], u: [ 0, 0, - 1 ] }, |
| 148 | + { t: [ 0, 0, 1 ], u: [ 0, - 1, 0 ] }, |
| 149 | + { t: [ 0, 0, - 1 ], u: [ 0, - 1, 0 ] }, |
| 150 | + ]; |
| 151 | + |
| 152 | + var params = { |
| 153 | + format: options.format || this.sourceTexture.format, |
| 154 | + magFilter: this.sourceTexture.magFilter, |
| 155 | + minFilter: this.sourceTexture.minFilter, |
| 156 | + type: options.type || this.sourceTexture.type, |
| 157 | + generateMipmaps: this.sourceTexture.generateMipmaps, |
| 158 | + anisotropy: this.sourceTexture.anisotropy, |
| 159 | + encoding: this.sourceTexture.encoding |
| 160 | + }; |
| 161 | + |
| 162 | + this.renderTarget = new WebGLRenderTargetCube( this.resolution, this.resolution, params ); |
| 163 | + |
| 164 | + }; |
| 165 | + |
| 166 | + EquirectangularToCubeGenerator.prototype = { |
| 167 | + |
| 168 | + constructor: EquirectangularToCubeGenerator, |
| 169 | + |
| 170 | + update: function ( renderer ) { |
| 171 | + |
| 172 | + var currentRenderTarget = renderer.getRenderTarget(); |
| 173 | + |
| 174 | + boxMesh.material.uniforms.equirectangularMap.value = this.sourceTexture; |
| 175 | + |
| 176 | + for ( var i = 0; i < 6; i ++ ) { |
| 177 | + |
| 178 | + var v = this.views[ i ]; |
| 179 | + |
| 180 | + camera.position.set( 0, 0, 0 ); |
| 181 | + camera.up.set( v.u[ 0 ], v.u[ 1 ], v.u[ 2 ] ); |
| 182 | + camera.lookAt( v.t[ 0 ], v.t[ 1 ], v.t[ 2 ] ); |
| 183 | + |
| 184 | + renderer.setRenderTarget( this.renderTarget, i ); |
| 185 | + renderer.clear(); |
| 186 | + renderer.render( scene, camera ); |
| 187 | + |
| 188 | + } |
| 189 | + |
| 190 | + renderer.setRenderTarget( currentRenderTarget ); |
| 191 | + |
| 192 | + return this.renderTarget.texture; |
| 193 | + |
| 194 | + }, |
| 195 | + |
| 196 | + dispose: function () { |
| 197 | + |
| 198 | + this.renderTarget.dispose(); |
| 199 | + |
| 200 | + } |
| 201 | + |
| 202 | + }; |
| 203 | + |
| 204 | + function getShader() { |
| 205 | + |
| 206 | + var shaderMaterial = new ShaderMaterial( { |
| 207 | + |
| 208 | + uniforms: { |
| 209 | + "equirectangularMap": { value: null }, |
| 210 | + }, |
| 211 | + |
| 212 | + vertexShader: |
| 213 | + "varying vec3 localPosition;\n\ |
| 214 | + \n\ |
| 215 | + void main() {\n\ |
| 216 | + localPosition = position;\n\ |
| 217 | + gl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\ |
| 218 | + }", |
| 219 | + |
| 220 | + fragmentShader: |
| 221 | + "#include <common>\n\ |
| 222 | + varying vec3 localPosition;\n\ |
| 223 | + uniform sampler2D equirectangularMap;\n\ |
| 224 | + \n\ |
| 225 | + vec2 EquirectangularSampleUV(vec3 v) {\n\ |
| 226 | + vec2 uv = vec2(atan(v.z, v.x), asin(v.y));\n\ |
| 227 | + uv *= vec2(0.1591, 0.3183); // inverse atan\n\ |
| 228 | + uv += 0.5;\n\ |
| 229 | + return uv;\n\ |
| 230 | + }\n\ |
| 231 | + \n\ |
| 232 | + void main() {\n\ |
| 233 | + vec2 uv = EquirectangularSampleUV(normalize(localPosition));\n\ |
| 234 | + gl_FragColor = texture2D(equirectangularMap, uv);\n\ |
| 235 | + }", |
| 236 | + |
| 237 | + blending: NoBlending |
| 238 | + |
| 239 | + } ); |
| 240 | + |
| 241 | + shaderMaterial.type = 'EquirectangularToCubeGenerator'; |
| 242 | + |
| 243 | + return shaderMaterial; |
| 244 | + |
| 245 | + } |
| 246 | + |
| 247 | + return EquirectangularToCubeGenerator; |
| 248 | + |
| 249 | +} )(); |
| 250 | + |
| 251 | +export { CubemapGenerator, EquirectangularToCubeGenerator }; |
0 commit comments