1
0
Эх сурвалжийг харах

WebGPURenderer: Instance Sprite Example (#29503)

* WebGPURenderer: Introduce InstancedSprites

* adapt the geometry accordingly to feedbacks

* use instancedBufferAttribute approach instead

* cleanup

---------
Renaud Rohlinger 1 жил өмнө
parent
commit
64072a15fa

+ 1 - 0
examples/files.json

@@ -328,6 +328,7 @@
 		"webgpu_equirectangular",
 		"webgpu_equirectangular",
 		"webgpu_instance_mesh",
 		"webgpu_instance_mesh",
 		"webgpu_instance_points",
 		"webgpu_instance_points",
+		"webgpu_instance_sprites",
 		"webgpu_instance_uniform",
 		"webgpu_instance_uniform",
 		"webgpu_instancing_morph",
 		"webgpu_instancing_morph",
 		"webgpu_lensflares",
 		"webgpu_lensflares",

+ 2 - 0
examples/jsm/geometries/InstancedPointsGeometry.js

@@ -78,6 +78,8 @@ class InstancedPointsGeometry extends InstancedBufferGeometry {
 		this.computeBoundingBox();
 		this.computeBoundingBox();
 		this.computeBoundingSphere();
 		this.computeBoundingSphere();
 
 
+		this.instanceCount = points.length / 3;
+
 		return this;
 		return this;
 
 
 	}
 	}

BIN
examples/screenshots/webgpu_instance_sprites.jpg


+ 172 - 0
examples/webgpu_instance_sprites.html

@@ -0,0 +1,172 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgpu - instance sprites</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="main.css">
+	</head>
+	<body>
+
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgpu - instance sprites
+		</div>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.webgpu.js",
+					"three/tsl": "../build/three.webgpu.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			import Stats from 'three/addons/libs/stats.module.js';
+			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
+
+			import { uniform, timerGlobal, instanceIndex, instancedBufferAttribute } from 'three/tsl';
+
+
+			let camera, scene, renderer, stats, material;
+			let mouseX = 0, mouseY = 0;
+
+			let windowHalfX = window.innerWidth / 2;
+			let windowHalfY = window.innerHeight / 2;
+
+			init();
+
+			function init() {
+
+				camera = new THREE.PerspectiveCamera( 55, window.innerWidth / window.innerHeight, 2, 2000 );
+				camera.position.z = 1000;
+
+				scene = new THREE.Scene();
+				scene.fog = new THREE.FogExp2( 0x000000, 0.001 );
+
+				// positions
+
+				const count = 10000;
+
+				const positions = [];
+
+				for ( let i = 0; i < count; i ++ ) {
+
+					positions.push( 2000 * Math.random() - 1000, 2000 * Math.random() - 1000, 2000 * Math.random() - 1000 );
+
+				}
+
+				const positionAttribute = new THREE.InstancedBufferAttribute( new Float32Array( positions ), 3 );
+
+				// texture
+
+				const map = new THREE.TextureLoader().load( 'textures/sprites/snowflake1.png' );
+				map.colorSpace = THREE.SRGBColorSpace;
+
+				// material
+
+				const timer = timerGlobal();
+
+				material = new THREE.SpriteNodeMaterial( { sizeAttenuation: true, map, alphaMap: map, alphaTest: 0.1, transparent: true } );
+				material.color.setHSL( 1.0, 0.3, 0.7, THREE.SRGBColorSpace );
+				material.positionNode = instancedBufferAttribute( positionAttribute );
+				material.rotationNode = timer.add( instanceIndex ).sin();
+				material.scaleNode = uniform( 15 );
+
+				// sprites
+
+				const particles = new THREE.Sprite( material );
+				particles.count = count;
+
+				scene.add( particles );
+
+				//
+
+				renderer = new THREE.WebGPURenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setAnimationLoop( animate );
+				document.body.appendChild( renderer.domElement );
+
+				//
+
+				stats = new Stats();
+				document.body.appendChild( stats.dom );
+
+				//
+
+				const gui = new GUI();
+
+				gui.add( material, 'sizeAttenuation' ).onChange( function () {
+
+					material.needsUpdate = true;
+					material.scaleNode.value = material.sizeAttenuation ? 15 : 0.03;
+			
+				} );
+
+				gui.open();
+
+				//
+
+				document.body.style.touchAction = 'none';
+				document.body.addEventListener( 'pointermove', onPointerMove );
+
+				//
+
+				window.addEventListener( 'resize', onWindowResize );
+
+			}
+
+			function onWindowResize() {
+
+				windowHalfX = window.innerWidth / 2;
+				windowHalfY = window.innerHeight / 2;
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function onPointerMove( event ) {
+
+				if ( event.isPrimary === false ) return;
+
+				mouseX = event.clientX - windowHalfX;
+				mouseY = event.clientY - windowHalfY;
+
+			}
+
+			//
+
+			function animate() {
+
+				render();
+				stats.update();
+
+			}
+
+			function render() {
+
+				const time = Date.now() * 0.00005;
+
+				camera.position.x += ( mouseX - camera.position.x ) * 0.05;
+				camera.position.y += ( - mouseY - camera.position.y ) * 0.05;
+
+				camera.lookAt( scene.position );
+
+				const h = ( 360 * ( 1.0 + time ) % 360 ) / 360;
+				material.color.setHSL( h, 0.5, 0.5 );
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+	</body>
+</html>

+ 4 - 1
src/materials/nodes/SpriteNodeMaterial.js

@@ -2,7 +2,7 @@ import NodeMaterial from './NodeMaterial.js';
 import { cameraProjectionMatrix } from '../../nodes/accessors/Camera.js';
 import { cameraProjectionMatrix } from '../../nodes/accessors/Camera.js';
 import { materialRotation } from '../../nodes/accessors/MaterialNode.js';
 import { materialRotation } from '../../nodes/accessors/MaterialNode.js';
 import { modelViewMatrix, modelWorldMatrix } from '../../nodes/accessors/ModelNode.js';
 import { modelViewMatrix, modelWorldMatrix } from '../../nodes/accessors/ModelNode.js';
-import { positionLocal } from '../../nodes/accessors/Position.js';
+import { positionLocal, positionView } from '../../nodes/accessors/Position.js';
 import { rotate } from '../../nodes/utils/RotateNode.js';
 import { rotate } from '../../nodes/utils/RotateNode.js';
 import { float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
 import { float, vec2, vec3, vec4 } from '../../nodes/tsl/TSLBase.js';
 
 
@@ -83,6 +83,9 @@ class SpriteNodeMaterial extends NodeMaterial {
 
 
 		mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw );
 		mvPosition = vec4( mvPosition.xy.add( rotatedPosition ), mvPosition.zw );
 
 
+		positionView.assign( mvPosition );
+		positionLocal.assign( rotatedPosition );
+
 		const modelViewProjection = cameraProjectionMatrix.mul( mvPosition );
 		const modelViewProjection = cameraProjectionMatrix.mul( mvPosition );
 
 
 		context.vertex = vertex;
 		context.vertex = vertex;

粤ICP备19079148号