|
29 | 29 |
|
30 | 30 | import * as THREE from 'three/webgpu'; |
31 | 31 |
|
32 | | - import { abs, blendOverlay, color, float, Fn, instancedBufferAttribute, materialColor, normalWorldGeometry, pass, positionGeometry, positionLocal, reflector, screenUV, sin, sub, texture, time, uniform, uv, vec3 } from 'three/tsl'; |
| 32 | + import { abs, blendOverlay, color, float, Fn, instancedBufferAttribute, materialColor, max, normalWorldGeometry, pass, positionGeometry, positionLocal, pow2, reflector, screenUV, sin, sub, texture, time, uniform, uv, vec2, vec3 } from 'three/tsl'; |
33 | 33 | import { gaussianBlur } from 'three/addons/tsl/display/GaussianBlurNode.js'; |
34 | 34 |
|
35 | 35 | import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; |
|
55 | 55 | camera.position.set( 4, 2, 4 ); |
56 | 56 |
|
57 | 57 | scene = new THREE.Scene(); |
58 | | - scene.fog = new THREE.Fog( 0x4195a4, 1, 25 ); |
| 58 | + scene.fog = new THREE.Fog( 0x4195a4, 1, 20 ); |
59 | 59 | scene.backgroundNode = normalWorldGeometry.y.mix( color( 0x4195a4 ), color( 0x0066ff ) ); |
60 | 60 | camera.lookAt( 0, 1, 0 ); |
61 | 61 |
|
|
79 | 79 | floorColor.wrapS = THREE.RepeatWrapping; |
80 | 80 | floorColor.wrapT = THREE.RepeatWrapping; |
81 | 81 | floorColor.colorSpace = THREE.SRGBColorSpace; |
| 82 | + floorColor.repeat.set( 15, 15 ); |
82 | 83 |
|
83 | 84 | const floorNormal = await textureLoader.loadAsync( 'textures/floors/FloorsCheckerboard_S_Normal.jpg' ); |
84 | 85 | floorNormal.wrapS = THREE.RepeatWrapping; |
85 | 86 | floorNormal.wrapT = THREE.RepeatWrapping; |
86 | 87 | floorNormal.repeat.set( 15, 15 ); |
87 | 88 |
|
88 | | - const boxMap = await textureLoader.loadAsync( 'textures/edge3.jpg' ); |
89 | | - boxMap.colorSpace = THREE.SRGBColorSpace; |
90 | | - |
91 | 89 | // tree |
92 | 90 |
|
93 | | - const treeMesh = createTreeMesh( boxMap ); |
| 91 | + const treeMesh = createTreeMesh(); |
94 | 92 | treeMesh.castShadow = true; |
95 | 93 | treeMesh.receiveShadow = true; |
96 | 94 | scene.add( treeMesh ); |
|
100 | 98 | const floorUV = uv().mul( 15 ); |
101 | 99 | const floorNormalOffset = texture( floorNormal, floorUV ).xy.mul( 2 ).sub( 1 ).mul( .02 ); |
102 | 100 |
|
103 | | - const reflection = reflector( { resolution: 0.5 } ); // 0.5 is half of the rendering view |
| 101 | + const reflection = reflector( { resolution: 0.2 } ); |
104 | 102 | reflection.target.rotateX( - Math.PI / 2 ); |
105 | 103 | reflection.uvNode = reflection.uvNode.add( floorNormalOffset ); |
106 | 104 | scene.add( reflection.target ); |
107 | 105 |
|
108 | 106 | const floorMaterial = new THREE.MeshPhongNodeMaterial(); |
109 | | - floorMaterial.colorNode = texture( floorColor, floorUV ).add( reflection ); |
| 107 | + floorMaterial.colorNode = texture( floorColor, floorUV ); |
| 108 | + floorMaterial.emissiveNode = reflection.mul( 0.25 ); |
110 | 109 | floorMaterial.normalMap = floorNormal; |
111 | 110 | floorMaterial.normalScale.set( 0.2, - 0.2 ); |
112 | 111 |
|
|
202 | 201 |
|
203 | 202 | } |
204 | 203 |
|
205 | | - |
206 | | - |
207 | | - function createTreeMesh( boxMap ) { |
| 204 | + function createTreeMesh() { |
208 | 205 |
|
209 | 206 | const maxSteps = 5; |
210 | 207 | const lengthMult = 0.8; |
|
239 | 236 |
|
240 | 237 | size = size / 100; |
241 | 238 |
|
242 | | - const subSteps = 200; |
| 239 | + const subSteps = 50; |
243 | 240 |
|
244 | 241 | // below loop generates the instanced data for a tree part |
245 | 242 |
|
|
255 | 252 | newPosition.set( x, y, z ).lerp( new THREE.Vector3( newX, newY, newZ ), percent ); |
256 | 253 | position.copy( newPosition ); |
257 | 254 |
|
258 | | - position.x += Math.random() * ( size * 3 ) - ( size * 1.5 ); |
259 | | - position.y += Math.random() * ( size * 3 ) - ( size * 1.5 ); |
260 | | - position.z += Math.random() * ( size * 3 ) - ( size * 1.5 ); |
| 255 | + position.x += random() * size * 3; |
| 256 | + position.y += random() * size * 3; |
| 257 | + position.z += random() * size * 3; |
261 | 258 |
|
262 | 259 | positions.push( position.x, position.y, position.z ); |
263 | 260 |
|
264 | | - const scale = Math.random(); |
| 261 | + const scale = Math.random() + 5; |
265 | 262 |
|
266 | 263 | // normal |
267 | 264 |
|
|
301 | 298 | createTreePart( angle, 0, 0, 0, 16, 0 ); |
302 | 299 |
|
303 | 300 | const geometry = new THREE.BoxGeometry(); |
304 | | - const material = new THREE.MeshStandardNodeMaterial( { map: boxMap } ); |
| 301 | + const material = new THREE.MeshStandardNodeMaterial(); |
305 | 302 | const mesh = new THREE.Mesh( geometry, material ); |
306 | 303 | mesh.scale.setScalar( 0.05 ); |
307 | 304 | mesh.count = instanceCount; |
|
349 | 346 |
|
350 | 347 | } )(); |
351 | 348 |
|
| 349 | + const squareEdge = Fn( () => { |
| 350 | + |
| 351 | + const pos = uv().sub( vec2( 0.5, 0.5 ) ); |
| 352 | + const squareDistance = max( abs( pos.x ), abs( pos.y ) ); |
| 353 | + return squareDistance.div( 0.5 ).clamp( 0.85, 1 ).sub( 0.5 ).mul( 2.0 ); |
| 354 | + |
| 355 | + } )(); |
| 356 | + |
352 | 357 | material.colorNode = Fn( () => { |
353 | 358 |
|
354 | | - return materialColor.mul( instanceColor ); |
| 359 | + return squareEdge.sub( instanceColor ); |
355 | 360 |
|
356 | 361 | } )(); |
357 | 362 |
|
|
365 | 370 | const dif2 = abs( instanceTime.sub( uniformEffector2 ) ).toConst(); |
366 | 371 | const effect2 = dif2.lessThanEqual( 0.15 ).select( sub( 0.15, dif2 ).mul( sub( 1.7, instanceTime ).mul( 10 ) ), effect1 ); |
367 | 372 |
|
368 | | - return vec3( effect1, 0, effect2 ).mul( instanceColor ); |
| 373 | + return pow2( vec3( effect1, 0, effect2 ) ).mul( instanceColor ); |
369 | 374 |
|
370 | 375 | } )(); |
371 | 376 |
|
|
0 commit comments