Skip to content

Commit

Permalink
GLTFExporter: Support EXT_mesh_gpu_instancing to export InstancedMesh. (
Browse files Browse the repository at this point in the history
#26854)

* Support EXT_mesh_gpu_instancing in GLTFExporter to export InstancedMesh.

* Update screen for misc_exporter_gltf example.

* Use _COLOR_0 in GLTFMeshGpuInstancing
  • Loading branch information
repalash authored Oct 5, 2023
1 parent 013a8d3 commit b72b7db
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 3 deletions.
70 changes: 69 additions & 1 deletion examples/jsm/exporters/GLTFExporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {
Source,
SRGBColorSpace,
CompressedTexture,
Vector3
Vector3,
Quaternion,
} from 'three';
import { decompress } from './../utils/TextureUtils.js';

Expand Down Expand Up @@ -134,6 +135,12 @@ class GLTFExporter {

} );

this.register( function ( writer ) {

return new GLTFMeshGpuInstancing( writer );

} );

}

register( callback ) {
Expand Down Expand Up @@ -2962,6 +2969,67 @@ class GLTFMaterialsEmissiveStrengthExtension {

}

/**
* GPU Instancing Extension
*
* Specification: https://github.com/KhronosGroup/glTF/tree/master/extensions/2.0/Vendor/EXT_mesh_gpu_instancing
*/
class GLTFMeshGpuInstancing {

constructor( writer ) {

this.writer = writer;
this.name = 'EXT_mesh_gpu_instancing';

}

writeNode( object, nodeDef ) {

if ( ! object.isInstancedMesh ) return;

const writer = this.writer;

const mesh = object;

const translationAttr = new Float32Array( mesh.count * 3 );
const rotationAttr = new Float32Array( mesh.count * 4 );
const scaleAttr = new Float32Array( mesh.count * 3 );

const matrix = new Matrix4();
const position = new Vector3();
const quaternion = new Quaternion();
const scale = new Vector3();

for ( let i = 0; i < mesh.count; i ++ ) {

mesh.getMatrixAt( i, matrix );
matrix.decompose( position, quaternion, scale );

position.toArray( translationAttr, i * 3 );
quaternion.toArray( rotationAttr, i * 4 );
scale.toArray( scaleAttr, i * 3 );

}

const attributes = {
TRANSLATION: writer.processAccessor( new BufferAttribute( translationAttr, 3 ) ),
ROTATION: writer.processAccessor( new BufferAttribute( rotationAttr, 4 ) ),
SCALE: writer.processAccessor( new BufferAttribute( scaleAttr, 3 ) ),
};

if ( mesh.instanceColor )
attributes._COLOR_0 = writer.processAccessor( mesh.instanceColor );

nodeDef.extensions = nodeDef.extensions || {};
nodeDef.extensions[ this.name ] = { attributes };

writer.extensionsUsed[ this.name ] = true;
writer.extensionsRequired[ this.name ] = true;

}

}

/**
* Static utility functions
*/
Expand Down
10 changes: 8 additions & 2 deletions examples/jsm/loaders/GLTFLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,8 @@ import {
Vector2,
Vector3,
VectorKeyframeTrack,
SRGBColorSpace
SRGBColorSpace,
InstancedBufferAttribute
} from 'three';
import { toTrianglesDrawMode } from '../utils/BufferGeometryUtils.js';

Expand Down Expand Up @@ -1679,7 +1680,12 @@ class GLTFMeshGpuInstancing {
// Add instance attributes to the geometry, excluding TRS.
for ( const attributeName in attributes ) {

if ( attributeName !== 'TRANSLATION' &&
if ( attributeName === '_COLOR_0' ) {

const attr = attributes[ attributeName ];
instancedMesh.instanceColor = new InstancedBufferAttribute( attr.array, attr.itemSize, attr.normalized );

} else if ( attributeName !== 'TRANSLATION' &&
attributeName !== 'ROTATION' &&
attributeName !== 'SCALE' ) {

Expand Down
21 changes: 21 additions & 0 deletions examples/misc_exporter_gltf.html
Original file line number Diff line number Diff line change
Expand Up @@ -427,6 +427,27 @@

} );

// ---------------------------------------------------------------------
// Model requiring KHR_mesh_quantization
// ---------------------------------------------------------------------

material = new THREE.MeshBasicMaterial( {
color: 0xffffff,
} );
object = new THREE.InstancedMesh( new THREE.BoxGeometry( 10, 10, 10, 2, 2, 2 ), material, 50 );
const matrix = new THREE.Matrix4();
const color = new THREE.Color();
for ( let i = 0; i < 50; i ++ ) {

matrix.setPosition( Math.random() * 100 - 50, Math.random() * 100 - 50, Math.random() * 100 - 50 );
object.setMatrixAt( i, matrix );
object.setColorAt( i, color.setHSL( i / 50, 1, 0.5 ) );

}

object.position.set( 400, 0, 200 );
scene1.add( object );

// ---------------------------------------------------------------------
// 2nd THREE.Scene
// ---------------------------------------------------------------------
Expand Down
Binary file modified examples/screenshots/misc_exporter_gltf.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit b72b7db

Please sign in to comment.