|
9 | 9 | <body> |
10 | 10 |
|
11 | 11 | <div id="container"></div> |
12 | | - <div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - Transparency with Premultiplied Alpha (right) and without (left)<br /> using RGBA8 Buffers by <a href="http://clara.io/" target="_blank" rel="noopener">Ben Houston</a>.</div> |
| 12 | + <div id="info"><a href="http://threejs.org" target="_blank" rel="noopener">threejs</a> - Transparency with Premultiplied Alpha (right) and without (left)</div> |
13 | 13 |
|
14 | 14 | <script type="module"> |
15 | 15 |
|
|
19 | 19 |
|
20 | 20 | import { GUI } from './jsm/libs/dat.gui.module.js'; |
21 | 21 | import { OrbitControls } from './jsm/controls/OrbitControls.js'; |
22 | | - |
23 | | - var params = { opacity: 0.25 }; |
| 22 | + import { HDRCubeTextureLoader } from './jsm/loaders/HDRCubeTextureLoader.js'; |
| 23 | + import { PMREMGenerator } from './jsm/pmrem/PMREMGenerator.js'; |
| 24 | + import { PMREMCubeUVPacker } from './jsm/pmrem/PMREMCubeUVPacker.js'; |
| 25 | + |
| 26 | + var params = { |
| 27 | + color: 0xffffff, |
| 28 | + transparency: 0.90, |
| 29 | + envMapIntensity: 1, |
| 30 | + lightIntensity: 1, |
| 31 | + exposure: 1 |
| 32 | + }; |
24 | 33 |
|
25 | 34 | var container, stats; |
26 | 35 | var camera, scene, renderer; |
27 | 36 |
|
28 | | - init(); |
29 | | - animate(); |
| 37 | + var hdrCubeRenderTarget; |
| 38 | + var spotLight1, spotLight2; |
| 39 | + var mesh1, mesh2; |
| 40 | + |
| 41 | + var hdrUrls = [ 'px.hdr', 'nx.hdr', 'py.hdr', 'ny.hdr', 'pz.hdr', 'nz.hdr' ]; |
| 42 | + |
| 43 | + var hdrCubeMap = new HDRCubeTextureLoader() |
| 44 | + .setPath( './textures/cube/pisaHDR/' ) |
| 45 | + .setDataType( THREE.UnsignedByteType ) |
| 46 | + .load( hdrUrls, function () { |
| 47 | + |
| 48 | + init(); |
| 49 | + animate(); |
| 50 | + |
| 51 | + } ); |
30 | 52 |
|
31 | 53 | function init() { |
32 | 54 |
|
33 | 55 | container = document.createElement( 'div' ); |
34 | 56 | document.body.appendChild( container ); |
35 | 57 |
|
36 | | - camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 ); |
37 | | - camera.position.set( 0.0, 40, 40 * 3.5 ); |
| 58 | + renderer = new THREE.WebGLRenderer( { antialias: true } ); |
| 59 | + renderer.setPixelRatio( window.devicePixelRatio ); |
| 60 | + renderer.setSize( window.innerWidth, window.innerHeight ); |
| 61 | + renderer.shadowMap.enabled = true; |
| 62 | + container.appendChild( renderer.domElement ); |
| 63 | + |
| 64 | + renderer.toneMapping = THREE.ACESFilmicToneMapping; |
| 65 | + renderer.toneMappingExposure = params.exposure; |
| 66 | + |
| 67 | + renderer.gammaOutput = true; |
38 | 68 |
|
39 | 69 | scene = new THREE.Scene(); |
| 70 | + scene.background = hdrCubeMap; |
| 71 | + |
| 72 | + camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 2000 ); |
| 73 | + camera.position.set( 0, 0, 120 ); |
40 | 74 |
|
41 | 75 | // |
42 | 76 |
|
43 | | - var geometry = new THREE.SphereBufferGeometry( 18, 30, 30 ); |
| 77 | + var pmremGenerator = new PMREMGenerator( hdrCubeMap ); |
| 78 | + pmremGenerator.update( renderer ); |
44 | 79 |
|
45 | | - var material1 = new THREE.MeshStandardMaterial( { |
46 | | - opacity: params.opacity, |
47 | | - transparent: true |
48 | | - } ); |
| 80 | + var pmremCubeUVPacker = new PMREMCubeUVPacker( pmremGenerator.cubeLods ); |
| 81 | + pmremCubeUVPacker.update( renderer ); |
49 | 82 |
|
50 | | - var material2 = new THREE.MeshStandardMaterial( { |
51 | | - opacity: params.opacity, |
52 | | - premultipliedAlpha: true, |
53 | | - transparent: true |
54 | | - } ); |
| 83 | + hdrCubeRenderTarget = pmremCubeUVPacker.CubeUVRenderTarget; |
55 | 84 |
|
56 | | - var textureLoader = new THREE.TextureLoader(); |
57 | | - textureLoader.load( "textures/hardwood2_diffuse.jpg", function ( map ) { |
| 85 | + hdrCubeMap.magFilter = THREE.LinearFilter; |
| 86 | + hdrCubeMap.needsUpdate = true; |
58 | 87 |
|
59 | | - map.anisotropy = 8; |
| 88 | + pmremGenerator.dispose(); |
| 89 | + pmremCubeUVPacker.dispose(); |
60 | 90 |
|
61 | | - material1.map = map; |
62 | | - material1.needsUpdate = true; |
63 | | - material2.map = map; |
64 | | - material2.needsUpdate = true; |
| 91 | + // |
65 | 92 |
|
| 93 | + var geometry = new THREE.SphereBufferGeometry( 20, 64, 32 ); |
| 94 | + |
| 95 | + var texture = new THREE.CanvasTexture( generateTexture() ); |
| 96 | + texture.magFilter = THREE.NearestFilter; |
| 97 | + texture.wrapT = THREE.RepeatWrapping; |
| 98 | + texture.wrapS = THREE.RepeatWrapping; |
| 99 | + texture.repeat.set( 1, 3.5 ); |
| 100 | + |
| 101 | + var material = new THREE.MeshPhysicalMaterial( { |
| 102 | + color: params.color, |
| 103 | + metalness: 0, |
| 104 | + roughness: 0, |
| 105 | + alphaMap: texture, |
| 106 | + alphaTest: 0.5, |
| 107 | + envMap: hdrCubeRenderTarget.texture, |
| 108 | + envMapIntensity: params.envMapIntensity, |
| 109 | + depthTest: false, |
| 110 | + transparency: params.transparency, |
| 111 | + transparent: true |
66 | 112 | } ); |
67 | 113 |
|
68 | | - var textureLoader = new THREE.TextureLoader(); |
69 | | - textureLoader.load( "textures/hardwood2_roughness.jpg", function ( map ) { |
| 114 | + var material1 = new THREE.MeshPhysicalMaterial().copy( material ); |
70 | 115 |
|
71 | | - map.anisotropy = 8; |
| 116 | + var material1b = new THREE.MeshPhysicalMaterial().copy( material ); |
| 117 | + material1b.side = THREE.BackSide; |
72 | 118 |
|
73 | | - material1.roughnessMap = map; |
74 | | - material1.needsUpdate = true; |
75 | | - material2.roughnessMap = map; |
76 | | - material2.needsUpdate = true; |
| 119 | + var material2 = new THREE.MeshPhysicalMaterial().copy( material ); |
| 120 | + material2.premultipliedAlpha = true; |
77 | 121 |
|
78 | | - } ); |
| 122 | + var material2b = new THREE.MeshPhysicalMaterial().copy( material ); |
| 123 | + material2b.premultipliedAlpha = true; |
| 124 | + material2b.side = THREE.BackSide; |
79 | 125 |
|
80 | | - var mesh = new THREE.Mesh( geometry, material1 ); |
81 | | - mesh.position.x = - 25.0; |
82 | | - scene.add( mesh ); |
| 126 | + mesh1 = new THREE.Mesh( geometry, material1 ); |
| 127 | + mesh1.position.x = - 30.0; |
| 128 | + scene.add( mesh1 ); |
83 | 129 |
|
84 | | - var mesh = new THREE.Mesh( geometry, material2 ); |
85 | | - mesh.position.x = 25.0; |
86 | | - scene.add( mesh ); |
| 130 | + var mesh = new THREE.Mesh( geometry, material1b ); |
| 131 | + mesh.renderOrder = - 1; |
| 132 | + mesh1.add( mesh ); |
87 | 133 |
|
88 | | - // |
| 134 | + mesh2 = new THREE.Mesh( geometry, material2 ); |
| 135 | + mesh2.position.x = 30.0; |
| 136 | + scene.add( mesh2 ); |
89 | 137 |
|
90 | | - var geometry = new THREE.PlaneBufferGeometry( 800, 800 ); |
91 | | - var material = new THREE.MeshStandardMaterial( { color: 0x333333 } ); |
92 | | - var mesh = new THREE.Mesh( geometry, material ); |
93 | | - mesh.position.y = - 50; |
94 | | - mesh.rotation.x = - Math.PI * 0.5; |
95 | | - scene.add( mesh ); |
| 138 | + var mesh = new THREE.Mesh( geometry, material2b ); |
| 139 | + mesh.renderOrder = - 1; |
| 140 | + mesh2.add( mesh ); |
96 | 141 |
|
97 | | - // Lights |
| 142 | + // |
98 | 143 |
|
99 | | - var spotLight = new THREE.SpotLight( 0xff8888 ); |
100 | | - spotLight.position.set( 100, 200, 100 ); |
101 | | - spotLight.angle = Math.PI / 6; |
102 | | - spotLight.penumbra = 0.9; |
103 | | - scene.add( spotLight ); |
| 144 | + spotLight1 = new THREE.SpotLight( 0xffffff, params.lightIntensity ); |
| 145 | + spotLight1.position.set( 100, 200, 100 ); |
| 146 | + spotLight1.angle = Math.PI / 6; |
| 147 | + scene.add( spotLight1 ); |
104 | 148 |
|
105 | | - var spotLight = new THREE.SpotLight( 0x8888ff ); |
106 | | - spotLight.position.set( - 100, - 200, - 100 ); |
107 | | - spotLight.angle = Math.PI / 6; |
108 | | - spotLight.penumbra = 0.9; |
109 | | - scene.add( spotLight ); |
| 149 | + spotLight2 = new THREE.SpotLight( 0xffffff, params.lightIntensity ); |
| 150 | + spotLight2.position.set( - 100, - 200, - 100 ); |
| 151 | + spotLight2.angle = Math.PI / 6; |
| 152 | + scene.add( spotLight2 ); |
110 | 153 |
|
111 | 154 | // |
112 | 155 |
|
113 | | - renderer = new THREE.WebGLRenderer( { antialias: true } ); |
114 | | - renderer.setPixelRatio( window.devicePixelRatio ); |
115 | | - renderer.setSize( window.innerWidth, window.innerHeight ); |
116 | | - renderer.shadowMap.enabled = true; |
117 | | - container.appendChild( renderer.domElement ); |
118 | | - |
119 | | - renderer.gammaInput = true; |
120 | | - renderer.gammaOutput = true; |
121 | | - |
122 | 156 | stats = new Stats(); |
123 | 157 | container.appendChild( stats.dom ); |
124 | 158 |
|
125 | 159 | var controls = new OrbitControls( camera, renderer.domElement ); |
| 160 | + controls.minDistance = 10; |
| 161 | + controls.maxDistance = 150; |
126 | 162 |
|
127 | 163 | window.addEventListener( 'resize', onWindowResize, false ); |
128 | 164 |
|
| 165 | + // |
| 166 | + |
129 | 167 | var gui = new GUI(); |
130 | | - gui.add( params, 'opacity', 0, 1 ).onChange( function () { |
131 | 168 |
|
132 | | - material1.opacity = params.opacity; |
133 | | - material2.opacity = params.opacity; |
| 169 | + gui.addColor( params, 'color' ) |
| 170 | + .onChange( function () { |
| 171 | + |
| 172 | + material1.color.set( params.color ); |
| 173 | + material2.color.set( params.color ); |
| 174 | + material1b.color.set( params.color ); |
| 175 | + material2b.color.set( params.color ); |
| 176 | + |
| 177 | + } ); |
| 178 | + |
| 179 | + gui.add( params, 'transparency', 0, 1 ) |
| 180 | + .onChange( function () { |
| 181 | + |
| 182 | + material1.transparency = material2.transparency = params.transparency; |
| 183 | + material1b.transparency = material2b.transparency = params.transparency; |
| 184 | + |
| 185 | + } ); |
| 186 | + |
| 187 | + gui.add( params, 'envMapIntensity', 0, 1 ) |
| 188 | + .name( 'envMap intensity' ) |
| 189 | + .onChange( function () { |
| 190 | + |
| 191 | + material1.envMapIntensity = material2.envMapIntensity = params.envMapIntensity; |
| 192 | + material1b.envMapIntensity = material2b.envMapIntensity = params.envMapIntensity; |
| 193 | + |
| 194 | + } ); |
| 195 | + |
| 196 | + gui.add( params, 'lightIntensity', 0, 1 ) |
| 197 | + .name( 'light intensity' ) |
| 198 | + .onChange( function () { |
| 199 | + |
| 200 | + spotLight1.intensity = spotLight2.intensity = params.lightIntensity; |
| 201 | + |
| 202 | + } ); |
| 203 | + |
| 204 | + gui.add( params, 'exposure', 0, 1 ) |
| 205 | + .onChange( function () { |
| 206 | + |
| 207 | + renderer.toneMappingExposure = params.exposure; |
| 208 | + |
| 209 | + } ); |
134 | 210 |
|
135 | | - } ); |
136 | 211 | gui.open(); |
137 | 212 |
|
138 | 213 | } |
|
151 | 226 |
|
152 | 227 | // |
153 | 228 |
|
154 | | - function animate() { |
| 229 | + function generateTexture() { |
155 | 230 |
|
156 | | - requestAnimationFrame( animate ); |
| 231 | + var canvas = document.createElement( 'canvas' ); |
| 232 | + canvas.width = 2; |
| 233 | + canvas.height = 2; |
157 | 234 |
|
158 | | - stats.begin(); |
159 | | - render(); |
160 | | - stats.end(); |
| 235 | + var context = canvas.getContext( '2d' ); |
| 236 | + context.fillStyle = 'white'; |
| 237 | + context.fillRect( 0, 1, 2, 1 ); |
161 | 238 |
|
162 | | - } |
| 239 | + return canvas; |
163 | 240 |
|
164 | | - function render() { |
165 | | - |
166 | | - for ( var i = 0, l = scene.children.length; i < l; i ++ ) { |
167 | | - |
168 | | - var object = scene.children[ i ]; |
| 241 | + } |
169 | 242 |
|
170 | | - if ( object.geometry instanceof THREE.SphereBufferGeometry ) { |
| 243 | + function animate() { |
171 | 244 |
|
172 | | - object.rotation.x = performance.now() * 0.0002; |
173 | | - object.rotation.y = - performance.now() * 0.0002; |
| 245 | + requestAnimationFrame( animate ); |
174 | 246 |
|
175 | | - } |
| 247 | + var t = performance.now(); |
176 | 248 |
|
177 | | - } |
| 249 | + mesh1.rotation.x = mesh2.rotation.x = t * 0.0002; |
| 250 | + mesh1.rotation.z = mesh2.rotation.z = - t * 0.0002; |
178 | 251 |
|
| 252 | + stats.begin(); |
179 | 253 | renderer.render( scene, camera ); |
| 254 | + stats.end(); |
180 | 255 |
|
181 | 256 | } |
182 | 257 |
|
|
0 commit comments