提交 1f75413a 编写于 作者: M Mr.doob

Updated to latest GLTFExporter.

上级 1375e4cf
......@@ -197,9 +197,9 @@ Menubar.File = function ( editor ) {
saveArrayBuffer( result, 'scene.glb' );
// forceIndices: true to allow compatibility with facebook
// https://github.com/mrdoob/three.js/issues/13397
}, { binary: true, forceIndices: true } );
// forceIndices: true, forcePowerOfTwoTexture: true
// to allow compatibility with facebook
}, { binary: true, forceIndices: true, forcePowerOfTwoTexture: true } );
} );
options.add( option );
......
......@@ -69,7 +69,8 @@ THREE.GLTFExporter.prototype = {
truncateDrawRange: true,
embedImages: true,
animations: [],
forceIndices: false
forceIndices: false,
forcePowerOfTwoTexture: false
};
options = Object.assign( {}, DEFAULT_OPTIONS, options );
......@@ -98,8 +99,8 @@ THREE.GLTFExporter.prototype = {
var skins = [];
var cachedData = {
images: {},
materials: {}
materials: {},
textures: {}
};
......@@ -192,6 +193,19 @@ THREE.GLTFExporter.prototype = {
}
/**
* Checks if image size is POT.
*
* @param {Image} image The image to be checked.
* @returns {Boolean} Returns true if image size is POT.
*
*/
function isPowerOfTwo( image ) {
return THREE.Math.isPowerOfTwo( image.width ) && THREE.Math.isPowerOfTwo( image.height );
}
/**
* Get the required size + padding for a buffer, rounded to the next 4-byte boundary.
* https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#data-alignment
......@@ -205,7 +219,7 @@ THREE.GLTFExporter.prototype = {
return Math.ceil( bufferSize / 4 ) * 4;
}
/**
* Returns a buffer aligned to 4-byte boundary.
*
......@@ -256,8 +270,8 @@ THREE.GLTFExporter.prototype = {
// Create a new dataview and dump the attribute's array into it
var byteLength = count * attribute.itemSize * componentSize;
// adjust required size of array buffer with padding
// adjust required size of array buffer with padding
// to satisfy gltf requirement that the length is divisible by 4
byteLength = getPaddedBufferSize( byteLength );
......@@ -448,11 +462,7 @@ THREE.GLTFExporter.prototype = {
*/
function processImage( map ) {
if ( cachedData.images[ map.uuid ] !== undefined ) {
return cachedData.images[ map.uuid ];
}
// @TODO Cache
if ( ! outputJSON.images ) {
......@@ -461,23 +471,34 @@ THREE.GLTFExporter.prototype = {
}
var mimeType = map.format === THREE.RGBAFormat ? 'image/png' : 'image/jpeg';
var gltfImage = {mimeType: mimeType};
var gltfImage = { mimeType: mimeType };
if ( options.embedImages ) {
var canvas = cachedCanvas = cachedCanvas || document.createElement( 'canvas' );
canvas.width = map.image.width;
canvas.height = map.image.height;
if ( options.forcePowerOfTwoTexture && ! isPowerOfTwo( map.image ) ) {
console.warn( 'GLTFExporter: Resized non-power-of-two image.', map.image );
canvas.width = THREE.Math.floorPowerOfTwo( canvas.width );
canvas.height = THREE.Math.floorPowerOfTwo( canvas.height );
}
var ctx = canvas.getContext( '2d' );
if ( map.flipY === true ) {
ctx.translate( 0, map.image.height );
ctx.scale( 1, -1 );
ctx.translate( 0, canvas.height );
ctx.scale( 1, - 1 );
}
ctx.drawImage( map.image, 0, 0 );
ctx.drawImage( map.image, 0, 0, canvas.width, canvas.height );
// @TODO Embed in { bufferView } if options.binary set.
......@@ -491,10 +512,7 @@ THREE.GLTFExporter.prototype = {
outputJSON.images.push( gltfImage );
var index = outputJSON.images.length - 1;
cachedData.images[ map.uuid ] = index;
return index;
return outputJSON.images.length - 1;
}
......@@ -533,6 +551,12 @@ THREE.GLTFExporter.prototype = {
*/
function processTexture( map ) {
if ( cachedData.textures[ map.uuid ] !== undefined ) {
return cachedData.textures[ map.uuid ];
}
if ( ! outputJSON.textures ) {
outputJSON.textures = [];
......@@ -548,7 +572,10 @@ THREE.GLTFExporter.prototype = {
outputJSON.textures.push( gltfTexture );
return outputJSON.textures.length - 1;
var index = outputJSON.textures.length - 1;
cachedData.textures[ map.uuid ] = index;
return index;
}
......@@ -876,28 +903,87 @@ THREE.GLTFExporter.prototype = {
if ( mesh.morphTargetInfluences !== undefined && mesh.morphTargetInfluences.length > 0 ) {
var weights = [];
var targetNames = [];
var reverseDictionary = {};
if ( mesh.morphTargetDictionary !== undefined ) {
for ( var key in mesh.morphTargetDictionary ) {
reverseDictionary[ mesh.morphTargetDictionary[ key ] ] = key;
}
}
gltfMesh.primitives[ 0 ].targets = [];
for ( var i = 0; i < mesh.morphTargetInfluences.length; ++ i ) {
var target = {};
var warned = false;
for ( var attributeName in geometry.morphAttributes ) {
// glTF 2.0 morph supports only POSITION/NORMAL/TANGENT.
// Three.js doesn't support TANGENT yet.
if ( attributeName !== 'position' && attributeName !== 'normal' ) {
if ( ! warned ) {
console.warn( 'GLTFExporter: Only POSITION and NORMAL morph are supported.' );
warned = true;
}
continue;
}
var attribute = geometry.morphAttributes[ attributeName ][ i ];
attributeName = nameConversion[ attributeName ] || attributeName.toUpperCase();
target[ attributeName ] = processAccessor( attribute, geometry );
// Three.js morph attribute has absolute values while the one of glTF has relative values.
//
// glTF 2.0 Specification:
// https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#morph-targets
var baseAttribute = geometry.attributes[ attributeName ];
// Clones attribute not to override
var relativeAttribute = attribute.clone();
for ( var j = 0, jl = attribute.count; j < jl; j ++ ) {
relativeAttribute.setXYZ(
j,
attribute.getX( j ) - baseAttribute.getX( j ),
attribute.getY( j ) - baseAttribute.getY( j ),
attribute.getZ( j ) - baseAttribute.getZ( j )
);
}
target[ attributeName.toUpperCase() ] = processAccessor( relativeAttribute, geometry );
}
gltfMesh.primitives[ 0 ].targets.push( target );
weights.push( mesh.morphTargetInfluences[ i ] );
if ( mesh.morphTargetDictionary !== undefined ) targetNames.push( reverseDictionary[ i ] );
}
gltfMesh.weights = weights;
if ( targetNames.length > 0 ) {
gltfMesh.extras = {};
gltfMesh.extras.targetNames = targetNames;
}
}
outputJSON.meshes.push( gltfMesh );
......@@ -968,13 +1054,12 @@ THREE.GLTFExporter.prototype = {
*
* Status:
* - Only properties listed in PATH_PROPERTIES may be animated.
* - Only LINEAR and STEP interpolation currently supported.
*
* @param {THREE.AnimationClip} clip
* @param {THREE.Object3D} root
* @return {number}
*/
function processAnimation ( clip, root ) {
function processAnimation( clip, root ) {
if ( ! outputJSON.animations ) {
......@@ -1022,11 +1107,37 @@ THREE.GLTFExporter.prototype = {
}
var interpolation;
// @TODO export CubicInterpolant(InterpolateSmooth) as CUBICSPLINE
// Detecting glTF cubic spline interpolant by checking factory method's special property
// GLTFCubicSplineInterpolant is a custom interpolant and track doesn't return
// valid value from .getInterpolation().
if ( track.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline === true ) {
interpolation = 'CUBICSPLINE';
// itemSize of CUBICSPLINE keyframe is 9
// (VEC3 * 3: inTangent, splineVertex, and outTangent)
// but needs to be stored as VEC3 so dividing by 3 here.
outputItemSize /= 3;
} else if ( track.getInterpolation() === THREE.InterpolateDiscrete ) {
interpolation = 'STEP';
} else {
interpolation = 'LINEAR';
}
samplers.push( {
input: processAccessor( new THREE.BufferAttribute( track.times, inputItemSize ) ),
output: processAccessor( new THREE.BufferAttribute( track.values, outputItemSize ) ),
interpolation: track.getInterpolation() === THREE.InterpolateDiscrete ? 'STEP' : 'LINEAR'
interpolation: interpolation
} );
......@@ -1151,7 +1262,8 @@ THREE.GLTFExporter.prototype = {
}
if ( object.name ) {
// We don't export empty strings name because it represents no-name in Three.js.
if ( object.name !== '' ) {
gltfNode.name = String( object.name );
......@@ -1434,4 +1546,4 @@ THREE.GLTFExporter.prototype = {
}
};
};
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册