Skip to content

Commit

Permalink
GLTFExporter: create separate accessors per group for non-indexed geo…
Browse files Browse the repository at this point in the history
…metry
  • Loading branch information
jtbandes committed Jan 25, 2022
1 parent 464a5f0 commit 5069b57
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 35 deletions.
81 changes: 46 additions & 35 deletions examples/jsm/exporters/GLTFExporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -1437,7 +1437,7 @@ class GLTFWriter {
}

const meshDef = {};
const attributes = {};
const attributesPerGroup = []; // one entry if indexed, one entry per group if indexed
const primitives = [];
const targets = [];

Expand All @@ -1464,56 +1464,74 @@ class GLTFWriter {
// For every attribute create an accessor
let modifiedAttribute = null;

for ( let attributeName in geometry.attributes ) {
const isMultiMaterial = Array.isArray( mesh.material );

if ( isMultiMaterial && geometry.groups.length === 0 ) return null;

const isIndexed = geometry.index !== null;
const materials = isMultiMaterial ? mesh.material : [ mesh.material ];
const groups = isMultiMaterial ? geometry.groups : [ { materialIndex: 0, start: undefined, count: undefined } ];

for ( let group = 0, il = isIndexed ? 1 : groups.length; group < il; group ++ ) {

// Ignore morph target attributes, which are exported later.
if ( attributeName.substr( 0, 5 ) === 'morph' ) continue;
const attributes = {};

const attribute = geometry.attributes[ attributeName ];
attributeName = nameConversion[ attributeName ] || attributeName.toUpperCase();
for ( let attributeName in geometry.attributes ) {

// Prefix all geometry attributes except the ones specifically
// listed in the spec; non-spec attributes are considered custom.
const validVertexAttributes =
// Ignore morph target attributes, which are exported later.
if ( attributeName.substr( 0, 5 ) === 'morph' ) continue;

const attribute = geometry.attributes[ attributeName ];
attributeName = nameConversion[ attributeName ] || attributeName.toUpperCase();

// Prefix all geometry attributes except the ones specifically
// listed in the spec; non-spec attributes are considered custom.
const validVertexAttributes =
/^(POSITION|NORMAL|TANGENT|TEXCOORD_\d+|COLOR_\d+|JOINTS_\d+|WEIGHTS_\d+)$/;

if ( ! validVertexAttributes.test( attributeName ) ) attributeName = '_' + attributeName;
if ( ! validVertexAttributes.test( attributeName ) ) attributeName = '_' + attributeName;

if ( cache.attributes.has( this.getUID( attribute ) ) ) {
const cacheKey = this.getUID( attribute ) + ':' + group;

attributes[ attributeName ] = cache.attributes.get( this.getUID( attribute ) );
continue;
if ( cache.attributes.has( cacheKey ) ) {

}
attributes[ attributeName ] = cache.attributes.get( cacheKey );
continue;

}

// JOINTS_0 must be UNSIGNED_BYTE or UNSIGNED_SHORT.
modifiedAttribute = null;
const array = attribute.array;
// JOINTS_0 must be UNSIGNED_BYTE or UNSIGNED_SHORT.
modifiedAttribute = null;
const array = attribute.array;

if ( attributeName === 'JOINTS_0' &&
if ( attributeName === 'JOINTS_0' &&
! ( array instanceof Uint16Array ) &&
! ( array instanceof Uint8Array ) ) {

console.warn( 'GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.' );
modifiedAttribute = new BufferAttribute( new Uint16Array( array ), attribute.itemSize, attribute.normalized );
console.warn( 'GLTFExporter: Attribute "skinIndex" converted to type UNSIGNED_SHORT.' );
modifiedAttribute = new BufferAttribute( new Uint16Array( array ), attribute.itemSize, attribute.normalized );

}
}

const accessor = this.processAccessor( modifiedAttribute || attribute, geometry );
const accessor = this.processAccessor( modifiedAttribute || attribute, geometry, isIndexed ? undefined : groups[ group ].start, isIndexed ? undefined : groups[ group ].count );

if ( accessor !== null ) {
if ( accessor !== null ) {

attributes[ attributeName ] = accessor;
cache.attributes.set( this.getUID( attribute ), accessor );
attributes[ attributeName ] = accessor;
cache.attributes.set( cacheKey, accessor );

}

}

attributesPerGroup.push( attributes );

}

if ( originalNormal !== undefined ) geometry.setAttribute( 'normal', originalNormal );

// Skip if no exportable attributes found
if ( Object.keys( attributes ).length === 0 ) return null;
if ( attributesPerGroup[ 0 ] && Object.keys( attributesPerGroup[ 0 ] ).length === 0 ) return null;

// Morph targets
if ( mesh.morphTargetInfluences !== undefined && mesh.morphTargetInfluences.length > 0 ) {
Expand Down Expand Up @@ -1614,25 +1632,18 @@ class GLTFWriter {

}

const isMultiMaterial = Array.isArray( mesh.material );

if ( isMultiMaterial && geometry.groups.length === 0 ) return null;

const materials = isMultiMaterial ? mesh.material : [ mesh.material ];
const groups = isMultiMaterial ? geometry.groups : [ { materialIndex: 0, start: undefined, count: undefined } ];

for ( let i = 0, il = groups.length; i < il; i ++ ) {

const primitive = {
mode: mode,
attributes: attributes,
attributes: attributesPerGroup[ isIndexed ? 0 : i ],
};

this.serializeUserData( geometry, primitive );

if ( targets.length > 0 ) primitive.targets = targets;

if ( geometry.index !== null ) {
if ( isIndexed ) {

let cacheKey = this.getUID( geometry.index );

Expand Down
28 changes: 28 additions & 0 deletions examples/misc_exporter_gltf.html
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,34 @@
object.visible = false;
scene1.add( object );

// ---------------------------------------------------------------------
// Indexed and non-indexed geometry using `groups`
// ---------------------------------------------------------------------
geometry = new THREE.BoxBufferGeometry( 50, 50, 50 );
geometry.clearGroups();
geometry.addGroup( 0, 6, 0 );
geometry.addGroup( 6, 6, 1 );
geometry.addGroup( 12, 6, 2 );
geometry.addGroup( 18, 6, 3 );
geometry.addGroup( 24, 6, 4 );
geometry.addGroup( 30, 6, 5 );

const materials = [
new THREE.MeshBasicMaterial( { color: 0xFFFFFF, visible: true } ),
new THREE.MeshBasicMaterial( { color: 0xFF0000, visible: true } ),
new THREE.MeshBasicMaterial( { color: 0x00FF00, visible: true } ),
new THREE.MeshBasicMaterial( { color: 0x0000FF, visible: true } ),
new THREE.MeshBasicMaterial( { color: 0xFFFF00, visible: true } ),
new THREE.MeshBasicMaterial( { color: 0x00FFFF, visible: true } )
];

object = new THREE.Mesh( geometry, materials );
object.translateX( 350 ).translateZ( 200 );
scene1.add( object );
object = new THREE.Mesh( geometry.toNonIndexed(), materials );
object.translateX( 350 ).translateZ( 300 );
scene1.add( object );

// ---------------------------------------------------------------------
//
//
Expand Down

0 comments on commit 5069b57

Please sign in to comment.