diff --git a/docs/examples/en/utils/BufferGeometryUtils.html b/docs/examples/en/utils/BufferGeometryUtils.html index fa84fa4037bc4bfdcc663b37f49173e16fd41c8f..fe8f338847de301a4cf1ba418c0ff95be87529f8 100644 --- a/docs/examples/en/utils/BufferGeometryUtils.html +++ b/docs/examples/en/utils/BufferGeometryUtils.html @@ -73,6 +73,16 @@

+

[method:BufferGeometry convertToTriangles]( [param:BufferGeometry geometry], [param:TrianglesDrawMode drawMode] )

+

+ geometry -- Instance of [page:BufferGeometry BufferGeometry].
+ drawMode -- The draw mode of the given geometry.

+ + 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. + +

+

Source

diff --git a/docs/examples/zh/utils/BufferGeometryUtils.html b/docs/examples/zh/utils/BufferGeometryUtils.html index fa84fa4037bc4bfdcc663b37f49173e16fd41c8f..fe8f338847de301a4cf1ba418c0ff95be87529f8 100644 --- a/docs/examples/zh/utils/BufferGeometryUtils.html +++ b/docs/examples/zh/utils/BufferGeometryUtils.html @@ -73,6 +73,16 @@

+

[method:BufferGeometry convertToTriangles]( [param:BufferGeometry geometry], [param:TrianglesDrawMode drawMode] )

+

+ geometry -- Instance of [page:BufferGeometry BufferGeometry].
+ drawMode -- The draw mode of the given geometry.

+ + 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. + +

+

Source

diff --git a/examples/js/utils/BufferGeometryUtils.js b/examples/js/utils/BufferGeometryUtils.js index fd78b965e62fa02f57c7f4b33a52ce097e03f56a..ab1c2fabdc17d40618544ed48385b77ac9448c8c 100644 --- a/examples/js/utils/BufferGeometryUtils.js +++ b/examples/js/utils/BufferGeometryUtils.js @@ -622,6 +622,116 @@ 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 ); + + return newGeometry; + + } else { + + console.error( 'THREE.BufferGeometryUtils.convertToTriangles(): Unknown draw mode:', drawMode ); + return geometry; + + } + } }; diff --git a/examples/jsm/utils/BufferGeometryUtils.d.ts b/examples/jsm/utils/BufferGeometryUtils.d.ts index 14f4533c71c8effb8ceddc0a7e7bdb19e26c329e..b4137340c28e8fb8111533b19edee35365719ea8 100644 --- a/examples/jsm/utils/BufferGeometryUtils.d.ts +++ b/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; } diff --git a/examples/jsm/utils/BufferGeometryUtils.js b/examples/jsm/utils/BufferGeometryUtils.js index 3632ee58de4faeb6ab93449e623a42942d94f375..030fa12e05a105a04d8a9bb18e50981d7bfd34c0 100644 --- a/examples/jsm/utils/BufferGeometryUtils.js +++ b/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,116 @@ 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 ); + + return newGeometry; + + } else { + + console.error( 'THREE.BufferGeometryUtils.convertToTriangles(): Unknown draw mode:', drawMode ); + return geometry; + + } + } }; diff --git a/test/unit/example/utils/BufferGeometryUtils.tests.js b/test/unit/example/utils/BufferGeometryUtils.tests.js index 610710c8211e30af3d59f4f87ff2b8be804133cd..da2e1969fe7ba93cf1fa55acc982a7b89b32a002 100644 --- a/test/unit/example/utils/BufferGeometryUtils.tests.js +++ b/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' ); + + } ); + } );