Skip to content

Commit 19816c7

Browse files
authored
Examples: Add new path demo. (#31209)
* Examples: Add new path demo. * update info * Update webgpu_instance_path.html ---------
1 parent a1db039 commit 19816c7

File tree

3 files changed

+172
-0
lines changed

3 files changed

+172
-0
lines changed

examples/files.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -329,6 +329,7 @@
329329
"webgpu_display_stereo",
330330
"webgpu_equirectangular",
331331
"webgpu_instance_mesh",
332+
"webgpu_instance_path",
332333
"webgpu_instance_points",
333334
"webgpu_instance_sprites",
334335
"webgpu_instance_uniform",
64.1 KB
Loading

examples/webgpu_instance_path.html

Lines changed: 171 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,171 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<title>three.js webgpu - geometry path</title>
5+
<meta charset="utf-8">
6+
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
7+
<link type="text/css" rel="stylesheet" href="main.css">
8+
</head>
9+
<body>
10+
11+
<div id="info">
12+
<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgpu - geometry path
13+
</div>
14+
15+
<script type="importmap">
16+
{
17+
"imports": {
18+
"three": "../build/three.webgpu.js",
19+
"three/webgpu": "../build/three.webgpu.js",
20+
"three/tsl": "../build/three.tsl.js",
21+
"three/addons/": "./jsm/"
22+
}
23+
}
24+
</script>
25+
26+
<script type="module">
27+
28+
import * as THREE from 'three';
29+
30+
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
31+
import { RoomEnvironment } from 'three/addons/environments/RoomEnvironment.js';
32+
33+
import { abs, add, instancedBufferAttribute, positionLocal, mod, time, sin, vec3, select, float, screenUV, color } from 'three/tsl';
34+
35+
let camera, scene, renderer, controls;
36+
37+
const count = 1000;
38+
39+
init();
40+
41+
async function init() {
42+
43+
camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 100 );
44+
camera.position.z = 15;
45+
46+
scene = new THREE.Scene();
47+
scene.backgroundNode = screenUV.distance( .5 ).remap( 0, 0.65 ).mix( color( 0x94254c ), color( 0x000000 ) );
48+
49+
// generate a path representing a heart shape
50+
51+
const x = 0, y = 0;
52+
53+
const path = new THREE.Path()
54+
.moveTo( x - 2.5, y - 2.5 )
55+
.bezierCurveTo( x - 2.5, y - 2.5, x - 2, y, x, y )
56+
.bezierCurveTo( x + 3, y, x + 3, y - 3.5, x + 3, y - 3.5 )
57+
.bezierCurveTo( x + 3, y - 5.5, x + 1, y - 7.7, x - 2.5, y - 9.5 )
58+
.bezierCurveTo( x - 6, y - 7.7, x - 8, y - 5.5, x - 8, y - 3.5 )
59+
.bezierCurveTo( x - 8, y - 3.5, x - 8, y, x - 5, y )
60+
.bezierCurveTo( x - 3.5, y, x - 2.5, y - 2.5, x - 2.5, y - 2.5 );
61+
62+
// generate instanced ico-spheres along the path
63+
64+
const geometry = new THREE.IcosahedronGeometry( 0.1 );
65+
const material = new THREE.MeshStandardNodeMaterial();
66+
67+
const mesh = new THREE.Mesh( geometry, material );
68+
mesh.position.set( 2.5, 5, 0 );
69+
mesh.count = count;
70+
mesh.frustumCulled = false;
71+
72+
scene.add( mesh );
73+
74+
// instance data
75+
76+
const v = new THREE.Vector3();
77+
const c = new THREE.Color();
78+
79+
const positions = [];
80+
const times = [];
81+
const seeds = [];
82+
const colors = [];
83+
84+
for ( let i = 0; i < count; i ++ ) {
85+
86+
const t = i / count;
87+
path.getPointAt( t, v );
88+
89+
v.x += ( 0.5 - Math.random() );
90+
v.y += ( 0.5 - Math.random() );
91+
v.z = ( 0.5 - Math.random() );
92+
93+
positions.push( v.x, v.y, v.z );
94+
times.push( t );
95+
seeds.push( Math.random() );
96+
97+
c.setHSL( 0.75 + ( Math.random() * 0.25 ), 1, 0.4 );
98+
99+
colors.push( c.r, c.g, c.b );
100+
101+
}
102+
103+
const positionAttribute = new THREE.InstancedBufferAttribute( new Float32Array( positions ), 3 );
104+
const colorAttribute = new THREE.InstancedBufferAttribute( new Float32Array( colors ), 3 );
105+
const timeAttribute = new THREE.InstancedBufferAttribute( new Float32Array( times ), 1 );
106+
const seedAttribute = new THREE.InstancedBufferAttribute( new Float32Array( seeds ), 1 );
107+
108+
// TSL
109+
110+
const instancePosition = instancedBufferAttribute( positionAttribute );
111+
const instanceColor = instancedBufferAttribute( colorAttribute );
112+
const instanceSeed = instancedBufferAttribute( seedAttribute );
113+
const instanceTime = instancedBufferAttribute( timeAttribute );
114+
115+
const localTime = instanceTime.add( time );
116+
const modTime = mod( time.mul( 0.4 ), 1 );
117+
118+
const s0 = sin( localTime.add( instanceSeed ) ).mul( 0.25 );
119+
120+
const dist = abs( instanceTime.sub( modTime ) ).toConst(); // modTime and instanceTime are in the range [0,1]
121+
const wrapDist = select( dist.greaterThan( 0.5 ), dist.oneMinus(), dist ).toConst(); // the normalized distance should wrap around 0/1
122+
const s1 = select( wrapDist.greaterThan( 0.1 ), float( 1 ), wrapDist.remap( 0, 0.1, 3, 1 ) ); // compute a scale in a range around the current interpolated value
123+
124+
const offset = vec3( instancePosition.x, instancePosition.y.add( s0 ), instancePosition.z ).toConst( 'offset' );
125+
material.positionNode = add( positionLocal.mul( s1 ), offset );
126+
material.colorNode = instanceColor;
127+
128+
//
129+
130+
renderer = new THREE.WebGPURenderer( { antialias: true } );
131+
renderer.setPixelRatio( window.devicePixelRatio );
132+
renderer.setSize( window.innerWidth, window.innerHeight );
133+
renderer.setAnimationLoop( animate );
134+
renderer.toneMapping = THREE.NeutralToneMapping;
135+
document.body.appendChild( renderer.domElement );
136+
137+
await renderer.init();
138+
139+
const pmremGenerator = new THREE.PMREMGenerator( renderer );
140+
scene.environment = pmremGenerator.fromScene( new RoomEnvironment(), 0.04 ).texture;
141+
142+
controls = new OrbitControls( camera, renderer.domElement );
143+
controls.enableDamping = true;
144+
145+
//
146+
147+
window.addEventListener( 'resize', onWindowResize );
148+
149+
}
150+
151+
function onWindowResize() {
152+
153+
camera.aspect = window.innerWidth / window.innerHeight;
154+
camera.updateProjectionMatrix();
155+
156+
renderer.setSize( window.innerWidth, window.innerHeight );
157+
158+
}
159+
160+
function animate() {
161+
162+
controls.update();
163+
164+
renderer.render( scene, camera );
165+
166+
}
167+
168+
</script>
169+
170+
</body>
171+
</html>

0 commit comments

Comments
 (0)