| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- <!DOCTYPE html>
- <html lang="en">
- <head>
- <title>three.js webgpu - layers</title>
- <meta charset="utf-8">
- <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
- <link type="text/css" rel="stylesheet" href="example.css">
- </head>
- <body>
- <div id="info">
- <a href="https://threejs.org/" target="_blank" rel="noopener" class="logo-link"></a>
- <div class="title-wrapper">
- <a href="https://threejs.org/" target="_blank" rel="noopener">three.js</a><span>Layers</span>
- </div>
- <small>
- Organizing 3D objects in different layers.
- </small>
- </div>
- <script type="importmap">
- {
- "imports": {
- "three": "../build/three.webgpu.js",
- "three/webgpu": "../build/three.webgpu.js",
- "three/tsl": "../build/three.tsl.js",
- "three/addons/": "./jsm/"
- }
- }
- </script>
- <script type="module">
- import * as THREE from 'three/webgpu';
- import { Inspector } from 'three/addons/inspector/Inspector.js';
- import { positionLocal, time, mod, instancedBufferAttribute, rotate, screenUV, color, vec2 } from 'three/tsl';
- let camera, scene, renderer;
- init();
- function init() {
- camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 100 );
- camera.layers.enable( 0 ); // enabled by default
- camera.layers.enable( 1 );
- camera.layers.enable( 2 );
- camera.position.z = 10;
- scene = new THREE.Scene();
- const horizontalEffect = screenUV.x.mix( color( 0xf996ae ), color( 0xf6f0a3 ) );
- const lightEffect = screenUV.distance( vec2( 0.5, 1.0 ) ).oneMinus().mul( color( 0xd9b6fd ) );
- scene.backgroundNode = horizontalEffect.add( lightEffect );
- const sprite = new THREE.TextureLoader().load( 'textures/sprites/blossom.png' );
- sprite.colorSpace = THREE.SRGBColorSpace;
- const count = 2500;
- const geometry = new THREE.PlaneGeometry( 0.25, 0.25 );
- const colors = [ 0xD70654, 0xFFD95F, 0xB8D576 ];
- for ( let i = 0; i < 3; i ++ ) {
- const particles = new THREE.Mesh( geometry, getMaterial( count, colors[ i ], sprite ) );
- particles.layers.set( i );
- particles.count = count;
- scene.add( particles );
- }
- renderer = new THREE.WebGPURenderer( { antialias: true } );
- renderer.setPixelRatio( window.devicePixelRatio );
- renderer.setSize( window.innerWidth, window.innerHeight );
- renderer.setAnimationLoop( animate );
- renderer.inspector = new Inspector();
- document.body.appendChild( renderer.domElement );
- // GUI
- const layers = {
- 'Red': true,
- 'Yellow': true,
- 'Green': true
- };
- const gui = renderer.inspector.createParameters( 'Layers' );
- gui.add( layers, 'Red' ).onChange( () => {
- camera.layers.toggle( 0 );
- } );
- gui.add( layers, 'Yellow' ).onChange( () => {
- camera.layers.toggle( 1 );
- } );
- gui.add( layers, 'Green' ).onChange( () => {
- camera.layers.toggle( 2 );
- } );
- //
- window.addEventListener( 'resize', onWindowResize );
- }
- function getMaterial( count, color, sprite ) {
- // instance data
- const positions = [];
- const rotations = [];
- const directions = [];
- const timeOffsets = [];
- const v = new THREE.Vector3();
- for ( let i = 0; i < count; i ++ ) {
- positions.push(
- THREE.MathUtils.randFloat( - 25, - 20 ),
- THREE.MathUtils.randFloat( - 10, 50 ),
- THREE.MathUtils.randFloat( - 5, 5 )
- );
- v.set( THREE.MathUtils.randFloat( 0.7, 0.9 ), THREE.MathUtils.randFloat( - 0.3, - 0.15 ), 0 ).normalize();
- rotations.push( Math.random(), Math.random(), Math.random() );
- directions.push( v.x, v.y, v.z );
- timeOffsets.push( i / count );
- }
- const positionAttribute = new THREE.InstancedBufferAttribute( new Float32Array( positions ), 3 );
- const rotationAttribute = new THREE.InstancedBufferAttribute( new Float32Array( rotations ), 3 );
- const directionAttribute = new THREE.InstancedBufferAttribute( new Float32Array( directions ), 3 );
- const timeAttribute = new THREE.InstancedBufferAttribute( new Float32Array( timeOffsets ), 1 );
- // material
- const material = new THREE.MeshBasicNodeMaterial( {
- color: color,
- map: sprite,
- alphaMap: sprite,
- alphaTest: 0.1,
- side: THREE.DoubleSide,
- forceSinglePass: true
- } );
- // TSL
- const instancePosition = instancedBufferAttribute( positionAttribute );
- const instanceDirection = instancedBufferAttribute( directionAttribute );
- const instanceRotation = instancedBufferAttribute( rotationAttribute );
- const localTime = instancedBufferAttribute( timeAttribute ).add( time.mul( 0.02 ) );
- const modTime = mod( localTime, 1.0 );
- const rotatedPosition = rotate( positionLocal, instanceRotation.mul( modTime.mul( 20 ) ) );
- material.positionNode = rotatedPosition.add( instancePosition ).add( instanceDirection.mul( modTime.mul( 50 ) ) );
- return material;
- }
- function onWindowResize() {
- camera.aspect = window.innerWidth / window.innerHeight;
- camera.updateProjectionMatrix();
- renderer.setSize( window.innerWidth, window.innerHeight );
- }
- //
- function animate() {
- renderer.render( scene, camera );
- }
- </script>
- </body>
- </html>
|