Sfoglia il codice sorgente

WebGPU Example: Skinning Points (#22695)

sunag 3 anni fa
parent
commit
a865d2e74b

+ 2 - 1
examples/files.json

@@ -323,7 +323,8 @@
 		"webgpu_materials",
 		"webgpu_rtt",
 		"webgpu_sandbox",
-		"webgpu_skinning"
+		"webgpu_skinning",
+		"webgpu_skinning_points"
 	],
 	"webaudio": [
 		"webaudio_orientation",

+ 4 - 0
examples/jsm/renderers/nodes/Nodes.js

@@ -1,6 +1,7 @@
 // core
 import ArrayInputNode from './core/ArrayInputNode.js';
 import AttributeNode from './core/AttributeNode.js';
+import BypassNode from './core/BypassNode.js';
 import CodeNode from './core/CodeNode.js';
 import ContextNode from './core/ContextNode.js';
 import ExpressionNode from './core/ExpressionNode.js';
@@ -33,6 +34,7 @@ import Object3DNode from './accessors/Object3DNode.js';
 import PointUVNode from './accessors/PointUVNode.js';
 import PositionNode from './accessors/PositionNode.js';
 import ReferenceNode from './accessors/ReferenceNode.js';
+import SkinningNode from './accessors/SkinningNode.js';
 import UVNode from './accessors/UVNode.js';
 
 // inputs
@@ -85,6 +87,7 @@ export {
 	// core
 	ArrayInputNode,
 	AttributeNode,
+	BypassNode,
 	CodeNode,
 	ContextNode,
 	ExpressionNode,
@@ -117,6 +120,7 @@ export {
 	PointUVNode,
 	PositionNode,
 	ReferenceNode,
+	SkinningNode,
 	UVNode,
 
 	// inputs

+ 7 - 1
examples/jsm/renderers/nodes/core/BypassNode.js

@@ -19,7 +19,13 @@ class BypassNode extends Node {
 
 	generate( builder, output ) {
 
-		builder.addFlowCode( this.callNode.build( builder, 'void' ) );
+		const snippet = this.callNode.build( builder, 'void' );
+
+		if ( snippet !== '' ) {
+
+			builder.addFlowCode( snippet );
+
+		}
 
 		return this.outputNode.build( builder, output );
 

+ 36 - 19
examples/jsm/renderers/nodes/math/OperatorNode.js

@@ -34,9 +34,16 @@ class OperatorNode extends TempNode {
 		const aNode = this.aNode;
 		const bNode = this.bNode;
 
-		if ( op === '=' ) {
+		const typeA = aNode.getNodeType( builder );
+		const typeB = bNode.getNodeType( builder );
 
-			return aNode.getNodeType( builder );
+		if ( typeA === 'void' || typeB === 'void' ) {
+
+			return 'void';
+
+		} else if ( op === '=' ) {
+
+			return typeA;
 
 		} else if ( op === '==' || op === '>' || op === '&&' ) {
 
@@ -44,9 +51,6 @@ class OperatorNode extends TempNode {
 
 		} else {
 
-			const typeA = aNode.getNodeType( builder );
-			const typeB = bNode.getNodeType( builder );
-
 			if ( typeA === 'float' && builder.isMatrix( typeB ) ) {
 
 				return typeB;
@@ -84,30 +88,43 @@ class OperatorNode extends TempNode {
 		const aNode = this.aNode;
 		const bNode = this.bNode;
 
-		let typeA = aNode.getNodeType( builder );
-		let typeB = bNode.getNodeType( builder );
+		const type = this.getNodeType( builder );
 
-		if ( op === '=' ) {
+		let typeA = null;
+		let typeB = null;
 
-			typeB = typeA;
+		if ( type !== 'void' ) {
 
-		} else if ( builder.isMatrix( typeA ) && builder.isVector( typeB ) ) {
+			typeA = aNode.getNodeType( builder );
+			typeB = bNode.getNodeType( builder );
 
-			// matrix x vector
+			if ( op === '=' ) {
 
-			typeB = builder.getVectorFromMatrix( typeA );
+				typeB = typeA;
 
-		} else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) {
+			} else if ( builder.isMatrix( typeA ) && builder.isVector( typeB ) ) {
 
-			// vector x matrix
+				// matrix x vector
 
-			typeA = builder.getVectorFromMatrix( typeB );
+				typeB = builder.getVectorFromMatrix( typeA );
 
-		} else {
+			} else if ( builder.isVector( typeA ) && builder.isMatrix( typeB ) ) {
 
-			// anytype x anytype
+				// vector x matrix
 
-			typeA = typeB = this.getNodeType( builder );
+				typeA = builder.getVectorFromMatrix( typeB );
+
+			} else {
+
+				// anytype x anytype
+
+				typeA = typeB = type;
+
+			}
+
+		} else {
+
+			typeA = typeB = type;
 
 		}
 
@@ -128,7 +145,7 @@ class OperatorNode extends TempNode {
 
 			}
 
-		} else {
+		} else if ( typeA !== 'void' ) {
 
 			return `${a} ${this.op} ${b}`;
 

BIN
examples/screenshots/webgpu_skinning_points.jpg


+ 129 - 0
examples/webgpu_skinning_points.html

@@ -0,0 +1,129 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js - WebGPU - Skinning Points</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 - Skinning Points<br />
+			(Chrome Canary with flag: --enable-unsafe-webgpu)
+		</div>
+
+		<script type="importmap">
+		{
+			"imports": {
+				"three": "../build/three.module.js"
+			}
+		}
+		</script>
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			import { FBXLoader } from './jsm/loaders/FBXLoader.js';
+
+			import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
+			import WebGPU from './jsm/renderers/webgpu/WebGPU.js';
+
+			import * as Nodes from './jsm/renderers/nodes/Nodes.js';
+
+			let camera, scene, renderer;
+
+			let mixer, clock;
+
+			init().then( animate ).catch( error );
+
+			async function init() {
+
+				if ( WebGPU.isAvailable() === false ) {
+
+					document.body.appendChild( WebGPU.getErrorMessage() );
+
+					throw 'No WebGPU support';
+
+				}
+
+				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
+				camera.position.set( 100, 200, 300 );
+
+				scene = new THREE.Scene();
+				camera.lookAt( 0, 100, 0 );
+
+				clock = new THREE.Clock();
+
+				const loader = new FBXLoader();
+				loader.load( 'models/fbx/Samba Dancing.fbx', function ( object ) {
+
+					mixer = new THREE.AnimationMixer( object );
+
+					const action = mixer.clipAction( object.animations[ 0 ] );
+					action.play();
+
+					object.traverse( function ( child ) {
+
+						if ( child.isMesh ) {
+
+							child.visible = false;
+
+							const materialPoints = new Nodes.PointsNodeMaterial();
+							materialPoints.colorNode = new Nodes.ColorNode();
+							materialPoints.positionNode = new Nodes.SkinningNode( child );
+
+							const pointCloud = new THREE.Points( child.geometry, materialPoints );
+							scene.add( pointCloud );
+
+						}
+
+					} );
+
+					scene.add( object );
+
+				} );
+
+				//renderer
+
+				renderer = new WebGPURenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResize );
+
+				return renderer.init();
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				const delta = clock.getDelta();
+
+				if ( mixer ) mixer.update( delta );
+
+				renderer.render( scene, camera );
+
+			}
+
+			function error( error ) {
+
+				console.error( error );
+
+			}
+
+		</script>
+	</body>
+</html>