Просмотр исходного кода

WebGPURenderer: Fix Material Arrays and Geometry Groups (#29278)

* WebGPURenderer: Fix Material Arrays and Geometry Groups

* rename to materials

* update screenshot name too
Renaud Rohlinger 1 год назад
Родитель
Сommit
8ca1d4dff9

+ 1 - 0
examples/files.json

@@ -345,6 +345,7 @@
 		"webgpu_loader_gltf_transmission",
 		"webgpu_loader_materialx",
 		"webgpu_materials",
+		"webgpu_materials_arrays",
 		"webgpu_materials_basic",
 		"webgpu_materials_displacementmap",
 		"webgpu_materials_envmaps",

BIN
examples/screenshots/webgpu_materials_arrays.jpg


+ 1 - 0
examples/tags.json

@@ -126,6 +126,7 @@
 	"webgpu_materials_lightmap": [ "shadow" ],
 	"webgpu_materials_sss": [ "subsurface scattering", "derivatives", "translucency" ],
 	"webgpu_materials_transmission": [ "alpha" ],
+	"webgpu_materials_arrays": [ "webgpu", "geometry", "groups", "array" ],
 	"webgpu_mirror": [ "reflection" ],
 	"webgpu_multiple_rendertargets": [ "mrt" ],
 	"webgpu_multiple_rendertargets_readback": [ "mrt" ],

+ 173 - 0
examples/webgpu_materials_arrays.html

@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgpu - materials arrays and geometry groups</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 Materials Arrays and Geometry Groups<br />
+		</div>
+
+		<script type="importmap">
+			{
+				"imports": {
+					"three": "../build/three.module.js",
+					"three/addons/": "./jsm/"
+				}
+			}
+		</script>
+
+		<script type="module">
+
+			import * as THREE from 'three';
+
+			import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
+			import { GUI } from 'three/addons/libs/lil-gui.module.min.js';
+
+			let renderer, scene, camera, controls;
+			let planeMesh, boxMesh, boxMeshWireframe, planeMeshWireframe;
+			let materials;
+
+			const api = {
+				webgpu: true
+			};
+
+
+			init( ! api.webgpu );
+
+			function init( forceWebGL = false ) {
+
+				if ( renderer ) {
+
+					renderer.dispose();
+					controls.dispose();
+					document.body.removeChild( renderer.domElement );
+
+				}
+
+				// renderer
+				renderer = new THREE.WebGLRenderer( {
+					forceWebGL,
+					antialias: true,
+				} );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setAnimationLoop( animate );
+				document.body.appendChild( renderer.domElement );
+
+				// scene
+				scene = new THREE.Scene();
+				scene.background = new THREE.Color( 0x000000 );
+
+				// camera
+				camera = new THREE.PerspectiveCamera( 40, window.innerWidth / window.innerHeight, 1, 100 );
+				camera.position.set( 0, 0, 10 );
+
+				// controls
+				controls = new OrbitControls( camera, renderer.domElement );
+
+				// materials
+				materials = [
+					new THREE.MeshBasicMaterial( { color: 0xff1493, side: THREE.DoubleSide } ),
+					new THREE.MeshBasicMaterial( { color: 0x0000ff, side: THREE.DoubleSide } ),
+					new THREE.MeshBasicMaterial( { color: 0x00ff00, side: THREE.DoubleSide } ),
+				];
+
+				// plane geometry
+				const planeGeometry = new THREE.PlaneGeometry( 1, 1, 4, 4 );
+
+				planeGeometry.clearGroups();
+				const numFacesPerRow = 4; // Number of faces in a row (since each face is made of 2 triangles)
+
+				planeGeometry.addGroup( 0, 6 * numFacesPerRow, 0 );
+				planeGeometry.addGroup( 6 * numFacesPerRow, 6 * numFacesPerRow, 1 );
+				planeGeometry.addGroup( 12 * numFacesPerRow, 6 * numFacesPerRow, 2 );
+
+				// box geometry
+				const boxGeometry = new THREE.BoxGeometry( .75, .75, .75 );
+
+				boxGeometry.clearGroups();
+				boxGeometry.addGroup( 0, 6, 0 ); // front face
+				boxGeometry.addGroup( 6, 6, 0 ); // back face
+				boxGeometry.addGroup( 12, 6, 2 ); // top face
+				boxGeometry.addGroup( 18, 6, 2 ); // bottom face
+				boxGeometry.addGroup( 24, 6, 1 ); // left face
+				boxGeometry.addGroup( 30, 6, 1 ); // right face
+
+				scene.background = forceWebGL ? new THREE.Color( 0x000000 ) : new THREE.Color( 0x222222 );
+
+				// meshes
+				planeMesh = new THREE.Mesh( planeGeometry, materials );
+
+				const materialsWireframe = [];
+
+				for ( let index = 0; index < materials.length; index ++ ) {
+
+					const material = new THREE.MeshBasicMaterial( { color: materials[ index ].color, side: THREE.DoubleSide, wireframe: true } );
+					materialsWireframe.push( material );
+
+				}
+
+				planeMeshWireframe = new THREE.Mesh( planeGeometry, materialsWireframe );
+				boxMeshWireframe = new THREE.Mesh( boxGeometry, materialsWireframe );
+
+				boxMesh = new THREE.Mesh( boxGeometry, materials );
+
+				planeMesh.position.set( - 1.5, - 1, 0 );
+				boxMesh.position.set( 1.5, - 0.75, 0 );
+				boxMesh.rotation.set( - Math.PI / 8, Math.PI / 4, Math.PI / 4 );
+
+				planeMeshWireframe.position.set( - 1.5, 1, 0 );
+				boxMeshWireframe.position.set( 1.5, 1.25, 0 );
+				boxMeshWireframe.rotation.set( - Math.PI / 8, Math.PI / 4, Math.PI / 4 );
+
+				scene.add( planeMesh, planeMeshWireframe );
+				scene.add( boxMesh, boxMeshWireframe );
+
+			}
+
+			function animate() {
+
+				boxMesh.rotation.y += 0.005;
+				boxMesh.rotation.x += 0.005;
+				boxMeshWireframe.rotation.y += 0.005;
+				boxMeshWireframe.rotation.x += 0.005;
+				renderer.render( scene, camera );
+
+			}
+
+
+			// gui
+
+			const gui = new GUI();
+
+			gui.add( api, 'webgpu' ).onChange( () => {
+
+				init( ! api.webgpu );
+
+			} );
+
+			// listeners
+
+			window.addEventListener( 'resize', onWindowResize );
+
+			function onWindowResize() {
+
+				const width = window.innerWidth;
+				const height = window.innerHeight;
+
+				camera.aspect = width / height;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( width, height );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 2 - 1
src/renderers/common/Renderer.js

@@ -1570,7 +1570,8 @@ class Renderer {
 	_renderObjectDirect( object, material, scene, camera, lightsNode, group, passId ) {
 
 		const renderObject = this._objects.get( object, material, scene, camera, lightsNode, this._currentRenderContext, passId );
-		renderObject.drawRange = group || object.geometry.drawRange;
+		renderObject.drawRange = object.geometry.drawRange;
+		renderObject.group = group;
 
 		//
 

+ 31 - 6
src/renderers/webgl-fallback/WebGLBackend.js

@@ -637,7 +637,6 @@ class WebGLBackend extends Backend {
 
 		const geometry = renderObject.geometry;
 		const drawRange = renderObject.drawRange;
-		const firstVertex = drawRange.start;
 
 		//
 
@@ -669,6 +668,7 @@ class WebGLBackend extends Backend {
 		}
 
 		//
+		let rangeFactor = 1;
 
 		const renderer = this.bufferRenderer;
 
@@ -683,6 +683,8 @@ class WebGLBackend extends Backend {
 				state.setLineWidth( material.wireframeLinewidth * this.renderer.getPixelRatio() );
 				renderer.mode = gl.LINES;
 
+				rangeFactor = 2;
+
 			} else {
 
 				renderer.mode = gl.TRIANGLES;
@@ -693,28 +695,51 @@ class WebGLBackend extends Backend {
 
 		//
 
+		const group = renderObject.group;
 
-		let count;
 
 		renderer.object = object;
 
+
+		let firstVertex = drawRange.start * rangeFactor;
+		let lastVertex = ( drawRange.start + drawRange.count ) * rangeFactor;
+
+		if ( group !== null ) {
+
+			firstVertex = Math.max( firstVertex, group.start * rangeFactor );
+			lastVertex = Math.min( lastVertex, ( group.start + group.count ) * rangeFactor );
+
+		}
+
 		if ( index !== null ) {
 
 			const indexData = this.get( index );
-			const indexCount = ( drawRange.count !== Infinity ) ? drawRange.count : index.count;
+			const indexCount = index.count;
 
 			renderer.index = index.count;
 			renderer.type = indexData.type;
 
-			count = indexCount;
+			firstVertex = Math.max( firstVertex, 0 );
+			lastVertex = Math.min( lastVertex, indexCount );
 
 		} else {
 
 			renderer.index = 0;
 
-			const vertexCount = ( drawRange.count !== Infinity ) ? drawRange.count : geometry.attributes.position.count;
+			const vertexCount = geometry.attributes.position.count;
+
+			firstVertex = Math.max( firstVertex, 0 );
+			lastVertex = Math.min( lastVertex, vertexCount );
+
+		}
+
+		const count = lastVertex - firstVertex;
+
+		if ( count < 0 || count === Infinity ) return;
+
+		if ( index !== null ) {
 
-			count = vertexCount;
+			firstVertex *= index.array.BYTES_PER_ELEMENT;
 
 		}
 

+ 39 - 6
src/renderers/webgpu/WebGPUBackend.js

@@ -829,7 +829,7 @@ class WebGPUBackend extends Backend {
 
 	draw( renderObject, info ) {
 
-		const { object, geometry, context, pipeline } = renderObject;
+		const { object, material, geometry, context, pipeline, group } = renderObject;
 		const bindings = renderObject.getBindings();
 		const renderContextData = this.get( context );
 		const pipelineGPU = this.get( pipeline ).pipeline;
@@ -930,7 +930,26 @@ class WebGPUBackend extends Backend {
 		// draw
 
 		const drawRange = renderObject.drawRange;
-		const firstVertex = drawRange.start;
+
+		let rangeFactor = 1;
+
+		if ( material.wireframe === true && ! object.isPoints && ! object.isLineSegments && ! object.isLine && ! object.isLineLoop ) {
+
+			rangeFactor = 2;
+
+		}
+
+		let firstVertex = drawRange.start * rangeFactor;
+		let lastVertex = ( drawRange.start + drawRange.count ) * rangeFactor;
+
+		if ( group !== null ) {
+
+			firstVertex = Math.max( firstVertex, group.start * rangeFactor );
+			lastVertex = Math.min( lastVertex, ( group.start + group.count ) * rangeFactor );
+
+		}
+
+
 
 		const instanceCount = this.getInstanceCount( renderObject );
 		if ( instanceCount === 0 ) return;
@@ -955,18 +974,32 @@ class WebGPUBackend extends Backend {
 
 		} else if ( hasIndex === true ) {
 
-			const indexCount = ( drawRange.count !== Infinity ) ? drawRange.count : index.count;
+			const indexCount = index.count;
+
+			firstVertex = Math.max( firstVertex, 0 );
+			lastVertex = Math.min( lastVertex, indexCount );
+
+			const count = lastVertex - firstVertex;
 
-			passEncoderGPU.drawIndexed( indexCount, instanceCount, firstVertex, 0, 0 );
+			if ( count < 0 || count === Infinity ) return;
+
+			passEncoderGPU.drawIndexed( count, instanceCount, firstVertex, 0, 0 );
 
 			info.update( object, indexCount, instanceCount );
 
 		} else {
 
 			const positionAttribute = geometry.attributes.position;
-			const vertexCount = ( drawRange.count !== Infinity ) ? drawRange.count : positionAttribute.count;
+			const vertexCount = positionAttribute.count;
+
+			firstVertex = Math.max( firstVertex, 0 );
+			lastVertex = Math.min( lastVertex, vertexCount );
+
+			const count = lastVertex - firstVertex;
+
+			if ( count < 0 || count === Infinity ) return;
 
-			passEncoderGPU.draw( vertexCount, instanceCount, firstVertex, 0 );
+			passEncoderGPU.draw( count, instanceCount, firstVertex, 0 );
 
 			info.update( object, vertexCount, instanceCount );
 

粤ICP备19079148号