ソースを参照

Examples: `webgpu_lights_clustered` firefly-style HDR sprites (#33660)

mrdoob 1 ヶ月 前
コミット
40079b0aa5

BIN
examples/screenshots/webgpu_lights_clustered.jpg


+ 46 - 11
examples/webgpu_lights_clustered.html

@@ -38,7 +38,7 @@
 		<script type="module">
 
 			import * as THREE from 'three/webgpu';
-			import { pass, uniform, vec3, float, mix, step } from 'three/tsl';
+			import { pass, uniform, vec3, float, mix, step, uv, instancedBufferAttribute } from 'three/tsl';
 
 			import { ClusteredLighting } from 'three/addons/lighting/ClusteredLighting.js';
 
@@ -54,6 +54,7 @@
 
 			let camera, scene, renderer,
 				lights, lightDummy,
+				lightPositionAttribute,
 				controls,
 				scenePass, clusterInfluence, debugZSliceNode,
 				lighting,
@@ -102,12 +103,37 @@
 				const modelSize = box.getSize( new THREE.Vector3() );
 				const modelCenter = box.getCenter( new THREE.Vector3() );
 
-				const material = new THREE.MeshBasicMaterial();
+				const lightPositions = new Float32Array( maxCount * 3 );
+				const lightColors = new Float32Array( maxCount * 3 );
 
-				lightDummy = new THREE.InstancedMesh( new THREE.SphereGeometry( 0.05, 16, 8 ), material, maxCount );
-				lightDummy.instanceMatrix.setUsage( THREE.DynamicDrawUsage );
-				lightDummy.frustumCulled = false;
+				lightPositionAttribute = new THREE.InstancedBufferAttribute( lightPositions, 3 );
+				lightPositionAttribute.setUsage( THREE.DynamicDrawUsage );
+
+				const lightColorAttribute = new THREE.InstancedBufferAttribute( lightColors, 3 );
+
+				// Physical 1/r² point-source falloff (Plummer profile): I = peak * r0² / ( r² + r0² )
+				// Subtract the value at r = 0.5 so the soft tail reaches exactly 0 at the sprite edge.
+				const coreRadius = 0.02;
+				const peak = 16;
+				const r0sq = coreRadius * coreRadius;
+				const edgeBias = r0sq / ( 0.25 + r0sq );
+
+				const offset = uv().sub( 0.5 );
+				const r2 = offset.dot( offset );
+				const glow = float( r0sq ).div( r2.add( r0sq ) ).sub( edgeBias ).max( 0 ).mul( peak );
+
+				const spriteMaterial = new THREE.SpriteNodeMaterial( {
+					transparent: true,
+					depthWrite: false,
+					blending: THREE.AdditiveBlending
+				} );
+				spriteMaterial.positionNode = instancedBufferAttribute( lightPositionAttribute );
+				spriteMaterial.colorNode = glow.mul( instancedBufferAttribute( lightColorAttribute ) );
+				spriteMaterial.scaleNode = uniform( 0.2 );
+
+				lightDummy = new THREE.Sprite( spriteMaterial );
 				lightDummy.count = count;
+				lightDummy.frustumCulled = false;
 				scene.add( lightDummy );
 
 				// lights
@@ -115,7 +141,7 @@
 				lights = new THREE.Group();
 				scene.add( lights );
 
-				const addLight = ( hexColor, power = 30, distance = 1 ) => {
+				const addLight = ( hexColor, power = 10, distance = 1 ) => {
 
 					const light = new THREE.PointLight( hexColor, 1, distance );
 					light.position.set(
@@ -128,9 +154,10 @@
 					light.userData.fixedPosition = light.position.clone();
 					light.visible = ( lights.children.length < count );
 
-					light.updateMatrixWorld();
-
-					lightDummy.setMatrixAt( lights.children.length, light.matrixWorld );
+					const i = lights.children.length;
+					lightPositions[ i * 3 + 0 ] = light.position.x;
+					lightPositions[ i * 3 + 1 ] = light.position.y;
+					lightPositions[ i * 3 + 2 ] = light.position.z;
 
 					lights.add( light );
 
@@ -144,7 +171,10 @@
 
 					const hex = ( Math.random() * 0x888888 ) + 0x888888;
 
-					lightDummy.setColorAt( i, color.setHex( hex ) );
+					color.setHex( hex );
+					lightColors[ i * 3 + 0 ] = color.r;
+					lightColors[ i * 3 + 1 ] = color.g;
+					lightColors[ i * 3 + 2 ] = color.b;
 
 					addLight( hex );
 
@@ -279,6 +309,7 @@
 			function animate() {
 
 				const time = performance.now() / 1000;
+				const positions = lightPositionAttribute.array;
 
 				for ( let i = 0; i < lights.children.length; i ++ ) {
 
@@ -290,10 +321,14 @@
 					light.position.y += Math.cos( lightTime * 0.5 ) * .3;
 					light.position.z += Math.cos( lightTime * 0.3 ) * 1.5;
 
-					lightDummy.setMatrixAt( i, light.matrixWorld );
+					positions[ i * 3 + 0 ] = light.position.x;
+					positions[ i * 3 + 1 ] = light.position.y;
+					positions[ i * 3 + 2 ] = light.position.z;
 
 				}
 
+				lightPositionAttribute.needsUpdate = true;
+
 				renderPipeline.render();
 
 			}

粤ICP备19079148号