|
26 | 26 | <script type="module"> |
27 | 27 |
|
28 | 28 | import * as THREE from 'three'; |
29 | | - import { Fn, vec2, length, abs, max, min, div, mul, clamp, acos } from 'three/tsl'; |
| 29 | + import { Fn, vec2, length, uniform, abs, max, min, sub, div, saturate, acos } from 'three/tsl'; |
30 | 30 |
|
31 | 31 | import { GUI } from 'three/addons/libs/lil-gui.module.min.js'; |
32 | 32 |
|
|
41 | 41 |
|
42 | 42 | function init() { |
43 | 43 |
|
| 44 | + // Renderer |
| 45 | + |
44 | 46 | renderer = new THREE.WebGPURenderer( { antialias: true } ); |
45 | 47 | renderer.setPixelRatio( window.devicePixelRatio ); |
46 | 48 | renderer.setSize( window.innerWidth, window.innerHeight ); |
|
58 | 60 | camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 0.1, 100 ); |
59 | 61 | camera.position.set( 7, 4, 1 ); |
60 | 62 |
|
| 63 | + // Controls |
| 64 | + |
61 | 65 | const controls = new OrbitControls( camera, renderer.domElement ); |
62 | 66 | controls.minDistance = 2; |
63 | 67 | controls.maxDistance = 10; |
64 | 68 | controls.maxPolarAngle = Math.PI / 2; |
65 | 69 | controls.target.set( 0, 1, 0 ); |
66 | 70 | controls.update(); |
67 | 71 |
|
68 | | - const ambient = new THREE.HemisphereLight( 0xffffff, 0x8d8d8d, 0.15 ); |
69 | | - scene.add( ambient ); |
| 72 | + // Textures |
70 | 73 |
|
71 | 74 | const loader = new THREE.TextureLoader().setPath( 'textures/' ); |
72 | 75 | const filenames = [ 'disturb.jpg', 'colors.png', 'uv_grid_opengl.jpg' ]; |
|
87 | 90 |
|
88 | 91 | } |
89 | 92 |
|
| 93 | + // Lights |
| 94 | + |
| 95 | + const ambient = new THREE.HemisphereLight( 0xffffff, 0x8d8d8d, 0.15 ); |
| 96 | + scene.add( ambient ); |
| 97 | + |
90 | 98 | const boxAttenuationFn = Fn( ( [ lightNode ], builder ) => { |
91 | 99 |
|
| 100 | + const light = lightNode.light; |
| 101 | + |
92 | 102 | const sdBox = Fn( ( [ p, b ] ) => { |
93 | 103 |
|
94 | 104 | const d = vec2( abs( p ).sub( b ) ).toVar(); |
|
97 | 107 |
|
98 | 108 | } ); |
99 | 109 |
|
100 | | - const penumbraCos = lightNode.penumbraCosNode; |
| 110 | + const penumbraCos = uniform( 'float' ).onRenderUpdate( () => Math.min( Math.cos( light.angle * ( 1 - light.penumbra ) ), .99999 ) ); |
101 | 111 | const spotLightCoord = lightNode.getSpotLightCoord( builder ); |
102 | 112 | const coord = spotLightCoord.xyz.div( spotLightCoord.w ); |
103 | 113 |
|
104 | 114 | const boxDist = sdBox( coord.xy.sub( vec2( 0.5 ) ), vec2( 0.5 ) ); |
105 | | - const angleFactor = div( 1.0, acos( penumbraCos ).sub( 1.0 ) ); |
106 | | - const attenuation = clamp( mul( 2.0, boxDist ).mul( angleFactor ), 0.0, 1.0 ); |
| 115 | + const angleFactor = div( -1.0, sub( 1.0, acos( penumbraCos ) ).sub( 1.0 ) ); |
| 116 | + const attenuation = saturate( boxDist.mul( - 2.0 ).mul( angleFactor ) ); |
107 | 117 |
|
108 | 118 | return attenuation; |
109 | 119 |
|
|
140 | 150 | mesh.receiveShadow = true; |
141 | 151 | scene.add( mesh ); |
142 | 152 |
|
143 | | - // |
| 153 | + // Models |
144 | 154 |
|
145 | 155 | new PLYLoader().load( 'models/ply/binary/Lucy100k.ply', function ( geometry ) { |
146 | 156 |
|
|
246 | 256 |
|
247 | 257 | spotLight.attenuationNode = val ? boxAttenuationFn : null; |
248 | 258 |
|
| 259 | + aspectGUI.setValue( 1 ).enable( val ); |
| 260 | + |
249 | 261 | } ); |
250 | 262 |
|
| 263 | + const aspectGUI = gui.add( spotLight.shadow, 'aspect', 0, 2 ).enable( false ); |
| 264 | + |
251 | 265 | gui.open(); |
252 | 266 |
|
253 | 267 | } |
|
0 commit comments