Jelajahi Sumber

Merge pull request #18031 from Mugen87/dev39

BufferGeometryUtils: Provide function for drawMode conversion.
Mr.doob 5 tahun lalu
induk
melakukan
4a70b409b8

+ 10 - 0
docs/examples/en/utils/BufferGeometryUtils.html

@@ -73,6 +73,16 @@
 
 		</p>
 
+		<h3>[method:BufferGeometry convertToTriangles]( [param:BufferGeometry geometry], [param:TrianglesDrawMode drawMode] )</h3>
+		<p>
+		geometry -- Instance of [page:BufferGeometry BufferGeometry].<br />
+		drawMode -- The draw mode of the given geometry.<br /><br />
+
+		Returns a new indexed [page:BufferGeometry BufferGeometry] based on the [page:DrawModes THREE.TrianglesDrawMode] draw mode. This mode
+		corresponds to the *gl.TRIANGLES* WebGL primitive.
+
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 10 - 0
docs/examples/zh/utils/BufferGeometryUtils.html

@@ -73,6 +73,16 @@
 
 		</p>
 
+		<h3>[method:BufferGeometry convertToTriangles]( [param:BufferGeometry geometry], [param:TrianglesDrawMode drawMode] )</h3>
+		<p>
+		geometry -- Instance of [page:BufferGeometry BufferGeometry].<br />
+		drawMode -- The draw mode of the given geometry.<br /><br />
+
+		Returns a new indexed [page:BufferGeometry BufferGeometry] based on the [page:DrawModes THREE.TrianglesDrawMode] draw mode. This mode
+		corresponds to the *gl.TRIANGLES* WebGL primitive.
+
+		</p>
+
 		<h2>Source</h2>
 
 		<p>

+ 111 - 0
examples/js/utils/BufferGeometryUtils.js

@@ -622,6 +622,117 @@ THREE.BufferGeometryUtils = {
 
 		return result;
 
+	},
+
+	/**
+	 * @param {THREE.BufferGeometry} geometry
+	 * @param {number} drawMode
+	 * @return {THREE.BufferGeometry>}
+	 */
+	convertToTriangles: function ( geometry, drawMode ) {
+
+		if ( drawMode === THREE.TrianglesDrawMode ) {
+
+			console.warn( 'THREE.BufferGeometryUtils.convertToTriangles(): Geometry already defined as triangles.' );
+			return geometry;
+
+		}
+
+		if ( drawMode === THREE.TriangleFanDrawMode || drawMode === THREE.TriangleStripDrawMode ) {
+
+			var index = geometry.getIndex();
+
+			// generate index if not present
+
+			if ( index === null ) {
+
+				var indices = [];
+
+				var position = geometry.getAttribute( 'position' );
+
+				if ( position !== undefined ) {
+
+					for ( var i = 0; i < position.count; i ++ ) {
+
+						indices.push( i );
+
+					}
+
+					geometry.setIndex( indices );
+					index = geometry.getIndex();
+
+				} else {
+
+					console.error( 'THREE.BufferGeometryUtils.convertToTriangles(): Undefined position attribute. Unable to perform conversion.' );
+					return geometry;
+
+				}
+
+			}
+
+			//
+
+			var numberOfTriangles = index.count - 2;
+			var newIndices = [];
+
+			if ( drawMode === THREE.TriangleFanDrawMode ) {
+
+				// gl.TRIANGLE_FAN
+
+				for ( var i = 1; i <= numberOfTriangles; i ++ ) {
+
+					newIndices.push( index.getX( 0 ) );
+					newIndices.push( index.getX( i ) );
+					newIndices.push( index.getX( i + 1 ) );
+
+				}
+
+			} else {
+
+				// gl.TRIANGLE_STRIP
+
+				for ( var i = 0; i < numberOfTriangles; i ++ ) {
+
+					if ( i % 2 === 0 ) {
+
+						newIndices.push( index.getX( i ) );
+						newIndices.push( index.getX( i + 1 ) );
+						newIndices.push( index.getX( i + 2 ) );
+
+
+					} else {
+
+						newIndices.push( index.getX( i + 2 ) );
+						newIndices.push( index.getX( i + 1 ) );
+						newIndices.push( index.getX( i ) );
+
+					}
+
+				}
+
+			}
+
+			if ( ( newIndices.length / 3 ) !== numberOfTriangles ) {
+
+				console.error( 'THREE.BufferGeometryUtils.convertToTriangles(): Unable to generate correct amount of triangles.' );
+
+			}
+
+			// build final geometry
+
+			var newGeometry = geometry.clone();
+			newGeometry.setIndex( newIndices );
+			newGeometry.clearGroups();
+
+			return newGeometry;
+
+		} else {
+
+			console.error( 'THREE.BufferGeometryUtils.convertToTriangles(): Unknown draw mode:', drawMode );
+			return geometry;
+
+		}
+
 	}
 
 };

+ 5 - 1
examples/jsm/utils/BufferGeometryUtils.d.ts

@@ -1,7 +1,11 @@
-import { BufferAttribute, BufferGeometry } from '../../../src/Three';
+import { BufferAttribute, BufferGeometry, InterleavedBufferAttribute, TrianglesDrawModes } from '../../../src/Three';
 
 export namespace BufferGeometryUtils {
 	export function mergeBufferGeometries( geometries: BufferGeometry[], useGroups?: boolean ): BufferGeometry;
 	export function computeTangents( geometry: BufferGeometry ): null;
 	export function mergeBufferAttributes( attributes: BufferAttribute[] ): BufferAttribute;
+	export function interleaveAttributes( attributes: BufferAttribute[] ): InterleavedBufferAttribute;
+	export function estimateBytesUsed( geometry: BufferGeometry ): number;
+	export function mergeVertices( geometry: BufferGeometry, tolerance?: number ): BufferGeometry;
+	export function convertToTriangles( geometry: BufferGeometry, drawMode: TrianglesDrawModes ): BufferGeometry;
 }

+ 114 - 0
examples/jsm/utils/BufferGeometryUtils.js

@@ -7,6 +7,9 @@ import {
 	BufferGeometry,
 	InterleavedBuffer,
 	InterleavedBufferAttribute,
+	TriangleFanDrawMode,
+	TriangleStripDrawMode,
+	TrianglesDrawMode,
 	Vector2,
 	Vector3
 } from "../../../build/three.module.js";
@@ -631,6 +634,117 @@ var BufferGeometryUtils = {
 
 		return result;
 
+	},
+
+	/**
+	 * @param {BufferGeometry} geometry
+	 * @param {number} drawMode
+	 * @return {BufferGeometry>}
+	 */
+	convertToTriangles: function ( geometry, drawMode ) {
+
+		if ( drawMode === TrianglesDrawMode ) {
+
+			console.warn( 'THREE.BufferGeometryUtils.convertToTriangles(): Geometry already defined as triangles.' );
+			return geometry;
+
+		}
+
+		if ( drawMode === TriangleFanDrawMode || drawMode === TriangleStripDrawMode ) {
+
+			var index = geometry.getIndex();
+
+			// generate index if not present
+
+			if ( index === null ) {
+
+				var indices = [];
+
+				var position = geometry.getAttribute( 'position' );
+
+				if ( position !== undefined ) {
+
+					for ( var i = 0; i < position.count; i ++ ) {
+
+						indices.push( i );
+
+					}
+
+					geometry.setIndex( indices );
+					index = geometry.getIndex();
+
+				} else {
+
+					console.error( 'THREE.BufferGeometryUtils.convertToTriangles(): Undefined position attribute. Unable to perform conversion.' );
+					return geometry;
+
+				}
+
+			}
+
+			//
+
+			var numberOfTriangles = index.count - 2;
+			var newIndices = [];
+
+			if ( drawMode === TriangleFanDrawMode ) {
+
+				// gl.TRIANGLE_FAN
+
+				for ( var i = 1; i <= numberOfTriangles; i ++ ) {
+
+					newIndices.push( index.getX( 0 ) );
+					newIndices.push( index.getX( i ) );
+					newIndices.push( index.getX( i + 1 ) );
+
+				}
+
+			} else {
+
+				// gl.TRIANGLE_STRIP
+
+				for ( var i = 0; i < numberOfTriangles; i ++ ) {
+
+					if ( i % 2 === 0 ) {
+
+						newIndices.push( index.getX( i ) );
+						newIndices.push( index.getX( i + 1 ) );
+						newIndices.push( index.getX( i + 2 ) );
+
+
+					} else {
+
+						newIndices.push( index.getX( i + 2 ) );
+						newIndices.push( index.getX( i + 1 ) );
+						newIndices.push( index.getX( i ) );
+
+					}
+
+				}
+
+			}
+
+			if ( ( newIndices.length / 3 ) !== numberOfTriangles ) {
+
+				console.error( 'THREE.BufferGeometryUtils.convertToTriangles(): Unable to generate correct amount of triangles.' );
+
+			}
+
+			// build final geometry
+
+			var newGeometry = geometry.clone();
+			newGeometry.setIndex( newIndices );
+			newGeometry.clearGroups();
+
+			return newGeometry;
+
+		} else {
+
+			console.error( 'THREE.BufferGeometryUtils.convertToTriangles(): Unknown draw mode:', drawMode );
+			return geometry;
+
+		}
+
 	}
 
 };

+ 41 - 0
test/unit/example/utils/BufferGeometryUtils.tests.js

@@ -7,6 +7,7 @@ import { BufferGeometryUtils } from '../../../../examples/jsm/utils/BufferGeomet
 
 import { BufferAttribute } from '../../../../src/core/BufferAttribute';
 import { BufferGeometry } from '../../../../src/core/BufferGeometry';
+import { TriangleStripDrawMode, TriangleFanDrawMode } from '../../../../src/constants';
 
 export default QUnit.module( 'BufferGeometryUtils', () => {
 
@@ -129,4 +130,44 @@ export default QUnit.module( 'BufferGeometryUtils', () => {
 
 	} );
 
+	QUnit.test( 'convertToTriangles()', ( assert ) => {
+
+		// TRIANGLE_STRIP
+
+		const vertices1 = [];
+
+		vertices1.push( 0, 0, 0 ); // v0
+		vertices1.push( 1, 0, 0 ); // v1
+		vertices1.push( 0, 1, 0 ); // v2
+		vertices1.push( 2, 0, 0 ); // v3
+		vertices1.push( 2, 1, 0 ); // v4
+		vertices1.push( 3, 0, 0 ); // v5
+
+		var geometry1 = new BufferGeometry();
+
+		geometry1.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices1 ), 3 ) );
+		geometry1 = BufferGeometryUtils.convertToTriangles( geometry1, TriangleStripDrawMode );
+
+		assert.deepEqual( geometry1.index.array, new Uint16Array( [ 0, 1, 2, 3, 2, 1, 2, 3, 4, 5, 4, 3 ] ), 'correct triangle indices from triangle strip' );
+
+		// TRIANGLE_FAN
+
+		const vertices2 = [];
+
+		vertices2.push( 0, 0, 0 ); // v0
+		vertices2.push( 1, 0, 0 ); // v1
+		vertices2.push( 1, 1, 0 ); // v2
+		vertices2.push( 0, 1, 0 ); // v3
+		vertices2.push( - 1, 1, 0 ); // v4
+		vertices2.push( - 1, 0, 0 ); // v5
+
+		var geometry2 = new BufferGeometry();
+
+		geometry2.setAttribute( 'position', new BufferAttribute( new Float32Array( vertices2 ), 3 ) );
+		geometry2 = BufferGeometryUtils.convertToTriangles( geometry2, TriangleFanDrawMode );
+
+		assert.deepEqual( geometry2.index.array, new Uint16Array( [ 0, 1, 2, 0, 2, 3, 0, 3, 4, 0, 4, 5 ] ), 'correct triangle indices from triangle fan' );
+
+	} );
+
 } );