ソースを参照

init nodematerial webgpu

sunag 4 年 前
コミット
ac23d8535d

+ 89 - 0
examples/jsm/renderers/webgpu/WebGPUNodeBuilder.js

@@ -0,0 +1,89 @@
+import { NodeBuilder } from '../../nodes/core/NodeBuilder.js';
+
+class WebGPUNodeBuilder extends NodeBuilder {
+
+	constructor() {
+
+		super();
+
+	}
+	
+	parseDefines( code, defines ) {
+		
+		// use regex maybe for security?
+		let versionStrIndex = code.indexOf("\n");
+		
+		let shaderCode = code.substr( 0, versionStrIndex ) + "\n";
+		const names = Object.keys( defines );
+		
+		if (names.length) {
+
+			shaderCode += "\n#define NODE\n";
+
+			for ( let i = 0; i < names.length; i ++ ) {
+
+				let name = names[i];
+
+				shaderCode += `#define NODE_${name} ${defines[name]}\n`;
+
+			}
+
+		}
+
+		shaderCode += code.substr( versionStrIndex );
+
+		return shaderCode;
+		
+	}
+	
+	parse( vertexShader, fragmentShader ) {
+		
+		const material = this.material;
+		
+		const nodesSlots = [];
+		const defines = [];
+		
+		let i, slot;
+		
+		if ( material.isMeshBasicMaterial ) {
+			
+			if ( material.color.isNode ) {
+				
+				slot = { name: 'COLOR', node: material.color, output: 'v3' };
+				
+				nodesSlots.push( slot );
+				
+			}
+			
+		}
+		
+		for( i = 0; i < nodesSlots.length; i++) {
+			
+			nodesSlots[i].node.analyze( this );
+			
+		}
+		
+		for( i = 0; i < nodesSlots.length; i++) {
+			
+			slot = nodesSlots[i];
+			
+			let flowData = slot.node.flow( this, slot.output );
+			
+			defines[slot.name] = flowData.result;
+			defines[slot.name + '_CODE'] = flowData.code || '';
+			
+		}
+		
+		vertexShader = this.parseDefines( vertexShader, defines );
+		fragmentShader = this.parseDefines( fragmentShader, defines );
+
+		return {
+			vertexShader,
+			fragmentShader
+		};
+		
+	}
+
+}
+
+export default WebGPUNodeBuilder;

+ 18 - 0
examples/jsm/renderers/webgpu/WebGPURenderPipelines.js

@@ -9,6 +9,8 @@ import {
 	ZeroFactor, OneFactor, SrcColorFactor, OneMinusSrcColorFactor, SrcAlphaFactor, OneMinusSrcAlphaFactor, DstAlphaFactor, OneMinusDstAlphaFactor, DstColorFactor, OneMinusDstColorFactor, SrcAlphaSaturateFactor
 } from '../../../../build/three.module.js';
 
+import WebGPUNodeBuilder from './WebGPUNodeBuilder.js';
+
 class WebGPURenderPipelines {
 
 	constructor( renderer, properties, device, glslang, sampleCount ) {
@@ -59,6 +61,14 @@ class WebGPURenderPipelines {
 
 			}
 
+			// parse nodes
+
+			const nodeBuilder = new WebGPUNodeBuilder();
+
+			nodeBuilder.setMaterial( material );
+			
+			shader = nodeBuilder.parse( shader.vertexShader, shader.fragmentShader );
+
 			// shader modules
 
 			const glslang = this.glslang;
@@ -808,11 +818,19 @@ const ShaderLib = {
 		layout(set = 0, binding = 3) uniform sampler mySampler;
 		layout(set = 0, binding = 4) uniform texture2D myTexture;
 
+		#pragma node_uniforms
+
 		layout(location = 0) in vec2 vUv;
 		layout(location = 0) out vec4 outColor;
 
 		void main() {
 			outColor = texture( sampler2D( myTexture, mySampler ), vUv );
+
+			#ifdef NODE_COLOR
+				NODE_COLOR_CODE
+				outColor.rgb = NODE_COLOR;
+			#endif
+
 			outColor.a *= opacityUniforms.opacity;
 		}`
 	},

+ 181 - 0
examples/webgpu_sandbox_nodes.html

@@ -0,0 +1,181 @@
+<html lang="en">
+	<head>
+		<title>WebGPU Sandbox</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 - sandbox<br/>(Chrome Canary with flag: --enable-unsafe-webgpu)
+		</div>
+
+		<script type="module">
+
+			import * as THREE from '../build/three.module.js';
+
+			import { DDSLoader } from './jsm/loaders/DDSLoader.js';
+
+			import WebGPURenderer from './jsm/renderers/webgpu/WebGPURenderer.js';
+			import WebGPU from './jsm/renderers/webgpu/WebGPU.js';
+
+			import * as Nodes from './jsm/nodes/Nodes.js';
+
+			let camera, scene, renderer;
+
+			let box;
+
+			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( 70, window.innerWidth / window.innerHeight, 0.1, 10 );
+				camera.position.z = 4;
+
+				scene = new THREE.Scene();
+				scene.background = new THREE.Color( 0x222222 );
+
+				// textured mesh
+
+				const textureLoader = new THREE.TextureLoader();
+				const texture = textureLoader.load( './textures/uv_grid_opengl.jpg' );
+
+				const geometryBox = new THREE.BoxBufferGeometry();
+				const materialBox = new THREE.MeshBasicMaterial( { map: texture } );
+
+				materialBox.color = new Nodes.ColorNode( 0x0099FF ).setReadonly( true );
+
+				box = new THREE.Mesh( geometryBox, materialBox );
+				box.position.set( 0, 1, 0 );
+				scene.add( box );
+
+				// data texture
+
+				const geometryPlane = new THREE.PlaneBufferGeometry();
+				const materialPlane = new THREE.MeshBasicMaterial( { map: createDataTexture(), transparent: true, opacity: 0.5 } );
+
+				const plane = new THREE.Mesh( geometryPlane, materialPlane );
+				plane.position.set( 0, - 1, 0 );
+				scene.add( plane );
+
+				// compressed texture
+
+				const ddsLoader = new DDSLoader();
+				const dxt5Texture = ddsLoader.load( './textures/compressed/explosion_dxt5_mip.dds' );
+
+				const materialCompressed = new THREE.MeshBasicMaterial( { map: dxt5Texture, transparent: true } );
+
+				const boxCompressed = new THREE.Mesh( geometryBox, materialCompressed );
+				boxCompressed.position.set( - 2, 1, 0 );
+				scene.add( boxCompressed );
+
+				// points
+
+				const points = [];
+
+				for ( let i = 0; i < 1000; i ++ ) {
+
+					const point = new THREE.Vector3().random().subScalar( 0.5 );
+					points.push( point );
+
+				}
+
+				const geometryPoints = new THREE.BufferGeometry().setFromPoints( points );
+				const materialPoints = new THREE.PointsMaterial();
+
+				const pointCloud = new THREE.Points( geometryPoints, materialPoints );
+				pointCloud.position.set( 2, - 1, 0 );
+				scene.add( pointCloud );
+
+				// lines
+
+				const geometryLine = new THREE.BufferGeometry().setFromPoints( [
+					new THREE.Vector3( - 0.5, - 0.5, 0 ),
+					new THREE.Vector3( 0.5, - 0.5, 0 ),
+					new THREE.Vector3( 0.5, 0.5, 0 ),
+					new THREE.Vector3( - 0.5, 0.5, 0 )
+				] );
+				const materialLine = new THREE.LineBasicMaterial();
+				const line = new THREE.Line( geometryLine, materialLine );
+				line.position.set( 2, 1, 0 );
+				scene.add( line );
+
+				//
+
+				renderer = new WebGPURenderer( { extensions: [ 'texture-compression-bc' ] } );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+				return renderer.init();
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				box.rotation.x += 0.01;
+				box.rotation.y += 0.02;
+
+				renderer.render( scene, camera );
+
+			}
+
+			function createDataTexture() {
+
+				const color = new THREE.Color( 0xff0000 );
+
+				const width = 512;
+				const height = 512;
+
+				const size = width * height;
+				const data = new Uint8Array( 4 * size );
+
+				const r = Math.floor( color.r * 255 );
+				const g = Math.floor( color.g * 255 );
+				const b = Math.floor( color.b * 255 );
+
+				for ( let i = 0; i < size; i ++ ) {
+
+					const stride = i * 4;
+
+					data[ stride ] = r;
+					data[ stride + 1 ] = g;
+					data[ stride + 2 ] = b;
+					data[ stride + 3 ] = 255;
+
+				}
+
+				return new THREE.DataTexture( data, width, height, THREE.RGBAFormat );
+
+			}
+
+			function error( error ) {
+
+				console.error( error );
+
+			}
+
+		</script>
+	</body>
+</html>