From bc2821adb11a30244fc4663f4fafb756877d9508 Mon Sep 17 00:00:00 2001 From: Yasutake Yohei <61961825+yasutakeyohei@users.noreply.github.com> Date: Wed, 7 Oct 2026 23:09:40 +0900 Subject: bluebey-studio: public/ の外へ移動し非公開化 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../examples/jsm/utils/BufferGeometryUtils.js | 1501 -------------------- .../three/examples/jsm/utils/SkeletonUtils.js | 496 ------- 2 files changed, 1997 deletions(-) delete mode 100644 public/bluebey-studio/vendor/three/examples/jsm/utils/BufferGeometryUtils.js delete mode 100644 public/bluebey-studio/vendor/three/examples/jsm/utils/SkeletonUtils.js (limited to 'public/bluebey-studio/vendor/three/examples/jsm/utils') diff --git a/public/bluebey-studio/vendor/three/examples/jsm/utils/BufferGeometryUtils.js b/public/bluebey-studio/vendor/three/examples/jsm/utils/BufferGeometryUtils.js deleted file mode 100644 index a167e11..0000000 --- a/public/bluebey-studio/vendor/three/examples/jsm/utils/BufferGeometryUtils.js +++ /dev/null @@ -1,1501 +0,0 @@ -import { - BufferAttribute, - BufferGeometry, - Float32BufferAttribute, - InstancedBufferAttribute, - InterleavedBuffer, - InterleavedBufferAttribute, - TriangleFanDrawMode, - TriangleStripDrawMode, - TrianglesDrawMode, - Vector3, -} from 'three'; - -/** - * @module BufferGeometryUtils - * @three_import import * as BufferGeometryUtils from 'three/addons/utils/BufferGeometryUtils.js'; - */ - -/** - * Computes vertex tangents using the MikkTSpace algorithm. MikkTSpace generates the same tangents consistently, - * and is used in most modelling tools and normal map bakers. Use MikkTSpace for materials with normal maps, - * because inconsistent tangents may lead to subtle visual issues in the normal map, particularly around mirrored - * UV seams. - * - * In comparison to this method, {@link BufferGeometry#computeTangents} (a custom algorithm) generates tangents that - * probably will not match the tangents in other software. The custom algorithm is sufficient for general use with a - * custom material, and may be faster than MikkTSpace. - * - * Returns the original BufferGeometry. Indexed geometries will be de-indexed. Requires position, normal, and uv attributes. - * - * @param {BufferGeometry} geometry - The geometry to compute tangents for. - * @param {Object} MikkTSpace - Instance of `examples/jsm/libs/mikktspace.module.js`, or `mikktspace` npm package. - * Await `MikkTSpace.ready` before use. - * @param {boolean} [negateSign=true] - Whether to negate the sign component (.w) of each tangent. - * Required for normal map conventions in some formats, including glTF. - * @return {BufferGeometry} The updated geometry. - */ -function computeMikkTSpaceTangents( geometry, MikkTSpace, negateSign = true ) { - - if ( ! MikkTSpace || ! MikkTSpace.isReady ) { - - throw new Error( 'THREE.BufferGeometryUtils: Initialized MikkTSpace library required.' ); - - } - - if ( ! geometry.hasAttribute( 'position' ) || ! geometry.hasAttribute( 'normal' ) || ! geometry.hasAttribute( 'uv' ) ) { - - throw new Error( 'THREE.BufferGeometryUtils: Tangents require "position", "normal", and "uv" attributes.' ); - - } - - function getAttributeArray( attribute ) { - - if ( attribute.normalized || attribute.isInterleavedBufferAttribute ) { - - const dstArray = new Float32Array( attribute.count * attribute.itemSize ); - - for ( let i = 0, j = 0; i < attribute.count; i ++ ) { - - dstArray[ j ++ ] = attribute.getX( i ); - dstArray[ j ++ ] = attribute.getY( i ); - - if ( attribute.itemSize > 2 ) { - - dstArray[ j ++ ] = attribute.getZ( i ); - - } - - } - - return dstArray; - - } - - if ( attribute.array instanceof Float32Array ) { - - return attribute.array; - - } - - return new Float32Array( attribute.array ); - - } - - // MikkTSpace algorithm requires non-indexed input. - - const _geometry = geometry.index ? geometry.toNonIndexed() : geometry; - - // Compute vertex tangents. - - const tangents = MikkTSpace.generateTangents( - - getAttributeArray( _geometry.attributes.position ), - getAttributeArray( _geometry.attributes.normal ), - getAttributeArray( _geometry.attributes.uv ) - - ); - - // Texture coordinate convention of glTF differs from the apparent - // default of the MikkTSpace library; .w component must be flipped. - - if ( negateSign ) { - - for ( let i = 3; i < tangents.length; i += 4 ) { - - tangents[ i ] *= - 1; - - } - - } - - // - - _geometry.setAttribute( 'tangent', new BufferAttribute( tangents, 4 ) ); - - if ( geometry !== _geometry ) { - - geometry.copy( _geometry ); - - } - - return geometry; - -} - -/** - * Merges a set of geometries into a single instance. All geometries must have compatible attributes. - * - * @param {Array} geometries - The geometries to merge. - * @param {boolean} [useGroups=false] - Whether to use groups or not. - * @return {?BufferGeometry} The merged geometry. Returns `null` if the merge does not succeed. - */ -function mergeGeometries( geometries, useGroups = false ) { - - const isIndexed = geometries[ 0 ].index !== null; - - const attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) ); - const morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) ); - - const attributes = {}; - const morphAttributes = {}; - - const morphTargetsRelative = geometries[ 0 ].morphTargetsRelative; - - const mergedGeometry = new BufferGeometry(); - - let offset = 0; - - for ( let i = 0; i < geometries.length; ++ i ) { - - const geometry = geometries[ i ]; - let attributesCount = 0; - - // ensure that all geometries are indexed, or none - - if ( isIndexed !== ( geometry.index !== null ) ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure index attribute exists among all geometries, or in none of them.' ); - return null; - - } - - // gather attributes, exit early if they're different - - for ( const name in geometry.attributes ) { - - if ( ! attributesUsed.has( name ) ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. All geometries must have compatible attributes; make sure "' + name + '" attribute exists among all geometries, or in none of them.' ); - return null; - - } - - if ( attributes[ name ] === undefined ) attributes[ name ] = []; - - attributes[ name ].push( geometry.attributes[ name ] ); - - attributesCount ++; - - } - - // ensure geometries have the same number of attributes - - if ( attributesCount !== attributesUsed.size ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. Make sure all geometries have the same number of attributes.' ); - return null; - - } - - // gather morph attributes, exit early if they're different - - if ( morphTargetsRelative !== geometry.morphTargetsRelative ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. .morphTargetsRelative must be consistent throughout all geometries.' ); - return null; - - } - - for ( const name in geometry.morphAttributes ) { - - if ( ! morphAttributesUsed.has( name ) ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. .morphAttributes must be consistent throughout all geometries.' ); - return null; - - } - - if ( morphAttributes[ name ] === undefined ) morphAttributes[ name ] = []; - - morphAttributes[ name ].push( geometry.morphAttributes[ name ] ); - - } - - if ( useGroups ) { - - let count; - - if ( isIndexed ) { - - count = geometry.index.count; - - } else if ( geometry.attributes.position !== undefined ) { - - count = geometry.attributes.position.count; - - } else { - - console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed with geometry at index ' + i + '. The geometry must have either an index or a position attribute' ); - return null; - - } - - mergedGeometry.addGroup( offset, count, i ); - - offset += count; - - } - - } - - // merge indices - - if ( isIndexed ) { - - let indexOffset = 0; - const mergedIndex = []; - - for ( let i = 0; i < geometries.length; ++ i ) { - - const index = geometries[ i ].index; - - for ( let j = 0; j < index.count; ++ j ) { - - mergedIndex.push( index.getX( j ) + indexOffset ); - - } - - indexOffset += geometries[ i ].attributes.position.count; - - } - - mergedGeometry.setIndex( mergedIndex ); - - } - - // merge attributes - - for ( const name in attributes ) { - - const mergedAttribute = mergeAttributes( attributes[ name ] ); - - if ( ! mergedAttribute ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed while trying to merge the ' + name + ' attribute.' ); - return null; - - } - - mergedGeometry.setAttribute( name, mergedAttribute ); - - } - - // merge morph attributes - - for ( const name in morphAttributes ) { - - const numMorphTargets = morphAttributes[ name ][ 0 ].length; - if ( numMorphTargets === 0 ) continue; - - mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {}; - mergedGeometry.morphAttributes[ name ] = []; - - for ( let i = 0; i < numMorphTargets; ++ i ) { - - const morphAttributesToMerge = []; - - for ( let j = 0; j < morphAttributes[ name ].length; ++ j ) { - - morphAttributesToMerge.push( morphAttributes[ name ][ j ][ i ] ); - - } - - const mergedMorphAttribute = mergeAttributes( morphAttributesToMerge ); - - if ( ! mergedMorphAttribute ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeGeometries() failed while trying to merge the ' + name + ' morphAttribute.' ); - return null; - - } - - mergedGeometry.morphAttributes[ name ].push( mergedMorphAttribute ); - - } - - } - - return mergedGeometry; - -} - -/** - * Merges a set of attributes into a single instance. All attributes must have compatible properties and types. - * Instances of {@link InterleavedBufferAttribute} are not supported. - * - * @param {Array} attributes - The attributes to merge. - * @return {?BufferAttribute} The merged attribute. Returns `null` if the merge does not succeed. - */ -function mergeAttributes( attributes ) { - - let TypedArray; - let itemSize; - let normalized; - let gpuType = - 1; - let arrayLength = 0; - - for ( let i = 0; i < attributes.length; ++ i ) { - - const attribute = attributes[ i ]; - - if ( TypedArray === undefined ) TypedArray = attribute.array.constructor; - if ( TypedArray !== attribute.array.constructor ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.array must be of consistent array types across matching attributes.' ); - return null; - - } - - if ( itemSize === undefined ) itemSize = attribute.itemSize; - if ( itemSize !== attribute.itemSize ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.itemSize must be consistent across matching attributes.' ); - return null; - - } - - if ( normalized === undefined ) normalized = attribute.normalized; - if ( normalized !== attribute.normalized ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.normalized must be consistent across matching attributes.' ); - return null; - - } - - if ( gpuType === - 1 ) gpuType = attribute.gpuType; - if ( gpuType !== attribute.gpuType ) { - - console.error( 'THREE.BufferGeometryUtils: .mergeAttributes() failed. BufferAttribute.gpuType must be consistent across matching attributes.' ); - return null; - - } - - arrayLength += attribute.count * itemSize; - - } - - const array = new TypedArray( arrayLength ); - const result = new BufferAttribute( array, itemSize, normalized ); - let offset = 0; - - for ( let i = 0; i < attributes.length; ++ i ) { - - const attribute = attributes[ i ]; - if ( attribute.isInterleavedBufferAttribute ) { - - const tupleOffset = offset / itemSize; - for ( let j = 0, l = attribute.count; j < l; j ++ ) { - - for ( let c = 0; c < itemSize; c ++ ) { - - const value = attribute.getComponent( j, c ); - result.setComponent( j + tupleOffset, c, value ); - - } - - } - - } else { - - array.set( attribute.array, offset ); - - } - - offset += attribute.count * itemSize; - - } - - if ( gpuType !== undefined ) { - - result.gpuType = gpuType; - - } - - return result; - -} - -/** - * Performs a deep clone of the given buffer attribute. - * - * @param {BufferAttribute} attribute - The attribute to clone. - * @return {BufferAttribute} The cloned attribute. - */ -function deepCloneAttribute( attribute ) { - - if ( attribute.isInstancedInterleavedBufferAttribute || attribute.isInterleavedBufferAttribute ) { - - return deinterleaveAttribute( attribute ); - - } - - if ( attribute.isInstancedBufferAttribute ) { - - return new InstancedBufferAttribute().copy( attribute ); - - } - - return new BufferAttribute().copy( attribute ); - -} - -/** - * Interleaves a set of attributes and returns a new array of corresponding attributes that share a - * single {@link InterleavedBuffer} instance. All attributes must have compatible types. - * - * @param {Array} attributes - The attributes to interleave. - * @return {?Array} An array of interleaved attributes. If interleave does not succeed, the method returns `null`. - */ -function interleaveAttributes( attributes ) { - - // Interleaves the provided attributes into an InterleavedBuffer and returns - // a set of InterleavedBufferAttributes for each attribute - let TypedArray; - let arrayLength = 0; - let stride = 0; - - // calculate the length and type of the interleavedBuffer - for ( let i = 0, l = attributes.length; i < l; ++ i ) { - - const attribute = attributes[ i ]; - - if ( TypedArray === undefined ) TypedArray = attribute.array.constructor; - if ( TypedArray !== attribute.array.constructor ) { - - console.error( 'AttributeBuffers of different types cannot be interleaved' ); - return null; - - } - - arrayLength += attribute.array.length; - stride += attribute.itemSize; - - } - - // Create the set of buffer attributes - const interleavedBuffer = new InterleavedBuffer( new TypedArray( arrayLength ), stride ); - let offset = 0; - const res = []; - const getters = [ 'getX', 'getY', 'getZ', 'getW' ]; - const setters = [ 'setX', 'setY', 'setZ', 'setW' ]; - - for ( let j = 0, l = attributes.length; j < l; j ++ ) { - - const attribute = attributes[ j ]; - const itemSize = attribute.itemSize; - const count = attribute.count; - const iba = new InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, attribute.normalized ); - res.push( iba ); - - offset += itemSize; - - // Move the data for each attribute into the new interleavedBuffer - // at the appropriate offset - for ( let c = 0; c < count; c ++ ) { - - for ( let k = 0; k < itemSize; k ++ ) { - - iba[ setters[ k ] ]( c, attribute[ getters[ k ] ]( c ) ); - - } - - } - - } - - return res; - -} - -/** - * Returns a new, non-interleaved version of the given attribute. - * - * @param {InterleavedBufferAttribute} attribute - The interleaved attribute. - * @return {BufferAttribute} The non-interleaved attribute. - */ -function deinterleaveAttribute( attribute ) { - - const cons = attribute.data.array.constructor; - const count = attribute.count; - const itemSize = attribute.itemSize; - const normalized = attribute.normalized; - - const array = new cons( count * itemSize ); - let newAttribute; - if ( attribute.isInstancedInterleavedBufferAttribute ) { - - newAttribute = new InstancedBufferAttribute( array, itemSize, normalized, attribute.meshPerAttribute ); - - } else { - - newAttribute = new BufferAttribute( array, itemSize, normalized ); - - } - - for ( let i = 0; i < count; i ++ ) { - - newAttribute.setX( i, attribute.getX( i ) ); - - if ( itemSize >= 2 ) { - - newAttribute.setY( i, attribute.getY( i ) ); - - } - - if ( itemSize >= 3 ) { - - newAttribute.setZ( i, attribute.getZ( i ) ); - - } - - if ( itemSize >= 4 ) { - - newAttribute.setW( i, attribute.getW( i ) ); - - } - - } - - return newAttribute; - -} - -/** - * Deinterleaves all attributes on the given geometry. - * - * @param {BufferGeometry} geometry - The geometry to deinterleave. - */ -function deinterleaveGeometry( geometry ) { - - const attributes = geometry.attributes; - const morphTargets = geometry.morphTargets; - const attrMap = new Map(); - - for ( const key in attributes ) { - - const attr = attributes[ key ]; - if ( attr.isInterleavedBufferAttribute ) { - - if ( ! attrMap.has( attr ) ) { - - attrMap.set( attr, deinterleaveAttribute( attr ) ); - - } - - attributes[ key ] = attrMap.get( attr ); - - } - - } - - for ( const key in morphTargets ) { - - const attr = morphTargets[ key ]; - if ( attr.isInterleavedBufferAttribute ) { - - if ( ! attrMap.has( attr ) ) { - - attrMap.set( attr, deinterleaveAttribute( attr ) ); - - } - - morphTargets[ key ] = attrMap.get( attr ); - - } - - } - -} - -/** - * Returns the amount of bytes used by all attributes to represent the geometry. - * - * @param {BufferGeometry} geometry - The geometry. - * @return {number} The estimate bytes used. - */ -function estimateBytesUsed( geometry ) { - - // Return the estimated memory used by this geometry in bytes - // Calculate using itemSize, count, and BYTES_PER_ELEMENT to account - // for InterleavedBufferAttributes. - let mem = 0; - for ( const name in geometry.attributes ) { - - const attr = geometry.getAttribute( name ); - mem += attr.count * attr.itemSize * attr.array.BYTES_PER_ELEMENT; - - } - - const indices = geometry.getIndex(); - mem += indices ? indices.count * indices.itemSize * indices.array.BYTES_PER_ELEMENT : 0; - return mem; - -} - -/** - * Returns a new geometry with vertices for which all similar vertex attributes (within tolerance) are merged. - * - * @param {BufferGeometry} geometry - The geometry to merge vertices for. - * @param {number} [tolerance=1e-4] - The tolerance value. - * @return {BufferGeometry} - The new geometry with merged vertices. - */ -function mergeVertices( geometry, tolerance = 1e-4 ) { - - tolerance = Math.max( tolerance, Number.EPSILON ); - - // Generate an index buffer if the geometry doesn't have one, or optimize it - // if it's already available. - const hashToIndex = {}; - const indices = geometry.getIndex(); - const positions = geometry.getAttribute( 'position' ); - const vertexCount = indices ? indices.count : positions.count; - - // next value for triangle indices - let nextIndex = 0; - - // attributes and new attribute arrays - const attributeNames = Object.keys( geometry.attributes ); - const tmpAttributes = {}; - const tmpMorphAttributes = {}; - const newIndices = []; - const getters = [ 'getX', 'getY', 'getZ', 'getW' ]; - const setters = [ 'setX', 'setY', 'setZ', 'setW' ]; - - // Initialize the arrays, allocating space conservatively. Extra - // space will be trimmed in the last step. - for ( let i = 0, l = attributeNames.length; i < l; i ++ ) { - - const name = attributeNames[ i ]; - const attr = geometry.attributes[ name ]; - - tmpAttributes[ name ] = new attr.constructor( - new attr.array.constructor( attr.count * attr.itemSize ), - attr.itemSize, - attr.normalized - ); - - const morphAttributes = geometry.morphAttributes[ name ]; - if ( morphAttributes ) { - - if ( ! tmpMorphAttributes[ name ] ) tmpMorphAttributes[ name ] = []; - morphAttributes.forEach( ( morphAttr, i ) => { - - const array = new morphAttr.array.constructor( morphAttr.count * morphAttr.itemSize ); - tmpMorphAttributes[ name ][ i ] = new morphAttr.constructor( array, morphAttr.itemSize, morphAttr.normalized ); - - } ); - - } - - } - - // convert the error tolerance to an amount of decimal places to truncate to - const halfTolerance = tolerance * 0.5; - const exponent = Math.log10( 1 / tolerance ); - const hashMultiplier = Math.pow( 10, exponent ); - const hashAdditive = halfTolerance * hashMultiplier; - for ( let i = 0; i < vertexCount; i ++ ) { - - const index = indices ? indices.getX( i ) : i; - - // Generate a hash for the vertex attributes at the current index 'i' - let hash = ''; - for ( let j = 0, l = attributeNames.length; j < l; j ++ ) { - - const name = attributeNames[ j ]; - const attribute = geometry.getAttribute( name ); - const itemSize = attribute.itemSize; - - for ( let k = 0; k < itemSize; k ++ ) { - - // Math.trunc() preserves the full Number range, ~~ would wrap to int32 - hash += `${ Math.trunc( attribute[ getters[ k ] ]( index ) * hashMultiplier + hashAdditive ) },`; - - } - - } - - // Add another reference to the vertex if it's already - // used by another index - if ( hash in hashToIndex ) { - - newIndices.push( hashToIndex[ hash ] ); - - } else { - - // copy data to the new index in the temporary attributes - for ( let j = 0, l = attributeNames.length; j < l; j ++ ) { - - const name = attributeNames[ j ]; - const attribute = geometry.getAttribute( name ); - const morphAttributes = geometry.morphAttributes[ name ]; - const itemSize = attribute.itemSize; - const newArray = tmpAttributes[ name ]; - const newMorphArrays = tmpMorphAttributes[ name ]; - - for ( let k = 0; k < itemSize; k ++ ) { - - const getterFunc = getters[ k ]; - const setterFunc = setters[ k ]; - newArray[ setterFunc ]( nextIndex, attribute[ getterFunc ]( index ) ); - - if ( morphAttributes ) { - - for ( let m = 0, ml = morphAttributes.length; m < ml; m ++ ) { - - newMorphArrays[ m ][ setterFunc ]( nextIndex, morphAttributes[ m ][ getterFunc ]( index ) ); - - } - - } - - } - - } - - hashToIndex[ hash ] = nextIndex; - newIndices.push( nextIndex ); - nextIndex ++; - - } - - } - - // generate result BufferGeometry - const result = geometry.clone(); - for ( const name in geometry.attributes ) { - - const tmpAttribute = tmpAttributes[ name ]; - - result.setAttribute( name, new tmpAttribute.constructor( - tmpAttribute.array.slice( 0, nextIndex * tmpAttribute.itemSize ), - tmpAttribute.itemSize, - tmpAttribute.normalized, - ) ); - - if ( ! ( name in tmpMorphAttributes ) ) continue; - - for ( let j = 0; j < tmpMorphAttributes[ name ].length; j ++ ) { - - const tmpMorphAttribute = tmpMorphAttributes[ name ][ j ]; - - result.morphAttributes[ name ][ j ] = new tmpMorphAttribute.constructor( - tmpMorphAttribute.array.slice( 0, nextIndex * tmpMorphAttribute.itemSize ), - tmpMorphAttribute.itemSize, - tmpMorphAttribute.normalized, - ); - - } - - } - - // indices - - result.setIndex( newIndices ); - - return result; - -} - -/** - * Converts the given geometry to the `TrianglesDrawMode` draw mode, which - * corresponds to the `gl.TRIANGLES` primitive in WebGL. The conversion only - * rewrites the index, so the geometry is modified in place and returned. - * - * @param {BufferGeometry} geometry - The geometry to convert. - * @param {number} drawMode - The current draw mode. - * @return {BufferGeometry} The converted geometry using `TrianglesDrawMode`. - */ -function toTrianglesDrawMode( geometry, drawMode ) { - - if ( drawMode === TrianglesDrawMode ) { - - console.warn( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Geometry already defined as triangles.' ); - return geometry; - - } - - if ( drawMode === TriangleFanDrawMode || drawMode === TriangleStripDrawMode ) { - - let index = geometry.getIndex(); - - // generate index if not present - - if ( index === null ) { - - const indices = []; - - const position = geometry.getAttribute( 'position' ); - - if ( position !== undefined ) { - - for ( let i = 0; i < position.count; i ++ ) { - - indices.push( i ); - - } - - geometry.setIndex( indices ); - index = geometry.getIndex(); - - } else { - - console.error( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Undefined position attribute. Processing not possible.' ); - return geometry; - - } - - } - - // - - const numberOfTriangles = index.count - 2; - const newIndices = []; - - if ( drawMode === TriangleFanDrawMode ) { - - // gl.TRIANGLE_FAN - - for ( let 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 ( let 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.toTrianglesDrawMode(): Unable to generate correct amount of triangles.' ); - - } - - // updated indices - - geometry.setIndex( newIndices ); - geometry.clearGroups(); - - return geometry; - - } else { - - console.error( 'THREE.BufferGeometryUtils.toTrianglesDrawMode(): Unknown draw mode:', drawMode ); - return geometry; - - } - -} - -/** - * Calculates the morphed attributes of a morphed/skinned BufferGeometry. - * - * Helpful for Raytracing or Decals (i.e. a `DecalGeometry` applied to a morphed Object with a `BufferGeometry` - * will use the original `BufferGeometry`, not the morphed/skinned one, generating an incorrect result. - * Using this function to create a shadow `Object3`D the `DecalGeometry` can be correctly generated). - * - * @param {Mesh|Line|Points} object - The 3D object to compute morph attributes for. - * @return {Object} An object with original position/normal attributes and morphed ones. - */ -function computeMorphedAttributes( object ) { - - const _vA = new Vector3(); - const _vB = new Vector3(); - const _vC = new Vector3(); - - const _tempA = new Vector3(); - const _tempB = new Vector3(); - const _tempC = new Vector3(); - - const _morphA = new Vector3(); - const _morphB = new Vector3(); - const _morphC = new Vector3(); - - function _calculateMorphedAttributeData( - object, - attribute, - morphAttribute, - morphTargetsRelative, - a, - b, - c, - modifiedAttributeArray - ) { - - _vA.fromBufferAttribute( attribute, a ); - _vB.fromBufferAttribute( attribute, b ); - _vC.fromBufferAttribute( attribute, c ); - - const morphInfluences = object.morphTargetInfluences; - - if ( morphAttribute && morphInfluences ) { - - _morphA.set( 0, 0, 0 ); - _morphB.set( 0, 0, 0 ); - _morphC.set( 0, 0, 0 ); - - for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) { - - const influence = morphInfluences[ i ]; - const morph = morphAttribute[ i ]; - - if ( influence === 0 ) continue; - - _tempA.fromBufferAttribute( morph, a ); - _tempB.fromBufferAttribute( morph, b ); - _tempC.fromBufferAttribute( morph, c ); - - if ( morphTargetsRelative ) { - - _morphA.addScaledVector( _tempA, influence ); - _morphB.addScaledVector( _tempB, influence ); - _morphC.addScaledVector( _tempC, influence ); - - } else { - - _morphA.addScaledVector( _tempA.sub( _vA ), influence ); - _morphB.addScaledVector( _tempB.sub( _vB ), influence ); - _morphC.addScaledVector( _tempC.sub( _vC ), influence ); - - } - - } - - _vA.add( _morphA ); - _vB.add( _morphB ); - _vC.add( _morphC ); - - } - - if ( object.isSkinnedMesh ) { - - object.applyBoneTransform( a, _vA ); - object.applyBoneTransform( b, _vB ); - object.applyBoneTransform( c, _vC ); - - } - - modifiedAttributeArray[ a * 3 + 0 ] = _vA.x; - modifiedAttributeArray[ a * 3 + 1 ] = _vA.y; - modifiedAttributeArray[ a * 3 + 2 ] = _vA.z; - modifiedAttributeArray[ b * 3 + 0 ] = _vB.x; - modifiedAttributeArray[ b * 3 + 1 ] = _vB.y; - modifiedAttributeArray[ b * 3 + 2 ] = _vB.z; - modifiedAttributeArray[ c * 3 + 0 ] = _vC.x; - modifiedAttributeArray[ c * 3 + 1 ] = _vC.y; - modifiedAttributeArray[ c * 3 + 2 ] = _vC.z; - - } - - const geometry = object.geometry; - const material = object.material; - - let a, b, c; - const index = geometry.index; - const positionAttribute = geometry.attributes.position; - const morphPosition = geometry.morphAttributes.position; - const morphTargetsRelative = geometry.morphTargetsRelative; - const normalAttribute = geometry.attributes.normal; - const morphNormal = geometry.morphAttributes.normal; - - const groups = geometry.groups; - const drawRange = geometry.drawRange; - let i, j, il, jl; - let group; - let start, end; - - const modifiedPosition = new Float32Array( positionAttribute.count * positionAttribute.itemSize ); - const modifiedNormal = new Float32Array( normalAttribute.count * normalAttribute.itemSize ); - - if ( index !== null ) { - - // indexed buffer geometry - - if ( Array.isArray( material ) ) { - - for ( i = 0, il = groups.length; i < il; i ++ ) { - - group = groups[ i ]; - - start = Math.max( group.start, drawRange.start ); - end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); - - for ( j = start, jl = end; j < jl; j += 3 ) { - - a = index.getX( j ); - b = index.getX( j + 1 ); - c = index.getX( j + 2 ); - - _calculateMorphedAttributeData( - object, - positionAttribute, - morphPosition, - morphTargetsRelative, - a, b, c, - modifiedPosition - ); - - _calculateMorphedAttributeData( - object, - normalAttribute, - morphNormal, - morphTargetsRelative, - a, b, c, - modifiedNormal - ); - - } - - } - - } else { - - start = Math.max( 0, drawRange.start ); - end = Math.min( index.count, ( drawRange.start + drawRange.count ) ); - - for ( i = start, il = end; i < il; i += 3 ) { - - a = index.getX( i ); - b = index.getX( i + 1 ); - c = index.getX( i + 2 ); - - _calculateMorphedAttributeData( - object, - positionAttribute, - morphPosition, - morphTargetsRelative, - a, b, c, - modifiedPosition - ); - - _calculateMorphedAttributeData( - object, - normalAttribute, - morphNormal, - morphTargetsRelative, - a, b, c, - modifiedNormal - ); - - } - - } - - } else { - - // non-indexed buffer geometry - - if ( Array.isArray( material ) ) { - - for ( i = 0, il = groups.length; i < il; i ++ ) { - - group = groups[ i ]; - - start = Math.max( group.start, drawRange.start ); - end = Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ); - - for ( j = start, jl = end; j < jl; j += 3 ) { - - a = j; - b = j + 1; - c = j + 2; - - _calculateMorphedAttributeData( - object, - positionAttribute, - morphPosition, - morphTargetsRelative, - a, b, c, - modifiedPosition - ); - - _calculateMorphedAttributeData( - object, - normalAttribute, - morphNormal, - morphTargetsRelative, - a, b, c, - modifiedNormal - ); - - } - - } - - } else { - - start = Math.max( 0, drawRange.start ); - end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) ); - - for ( i = start, il = end; i < il; i += 3 ) { - - a = i; - b = i + 1; - c = i + 2; - - _calculateMorphedAttributeData( - object, - positionAttribute, - morphPosition, - morphTargetsRelative, - a, b, c, - modifiedPosition - ); - - _calculateMorphedAttributeData( - object, - normalAttribute, - morphNormal, - morphTargetsRelative, - a, b, c, - modifiedNormal - ); - - } - - } - - } - - const morphedPositionAttribute = new Float32BufferAttribute( modifiedPosition, 3 ); - const morphedNormalAttribute = new Float32BufferAttribute( modifiedNormal, 3 ); - - return { - - positionAttribute: positionAttribute, - normalAttribute: normalAttribute, - morphedPositionAttribute: morphedPositionAttribute, - morphedNormalAttribute: morphedNormalAttribute - - }; - -} - -/** - * Merges the {@link BufferGeometry#groups} for the given geometry. - * - * @param {BufferGeometry} geometry - The geometry to modify. - * @return {BufferGeometry} - The updated geometry - */ -function mergeGroups( geometry ) { - - if ( geometry.groups.length === 0 ) { - - console.warn( 'THREE.BufferGeometryUtils.mergeGroups(): No groups are defined. Nothing to merge.' ); - return geometry; - - } - - let groups = geometry.groups; - - // sort groups by material index - - groups = groups.sort( ( a, b ) => { - - if ( a.materialIndex !== b.materialIndex ) return a.materialIndex - b.materialIndex; - - return a.start - b.start; - - } ); - - // create index for non-indexed geometries - - if ( geometry.getIndex() === null ) { - - const positionAttribute = geometry.getAttribute( 'position' ); - const indices = []; - - for ( let i = 0; i < positionAttribute.count; i += 3 ) { - - indices.push( i, i + 1, i + 2 ); - - } - - geometry.setIndex( indices ); - - } - - // sort index - - const index = geometry.getIndex(); - - const newIndices = []; - - for ( let i = 0; i < groups.length; i ++ ) { - - const group = groups[ i ]; - - const groupStart = group.start; - const groupLength = groupStart + group.count; - - for ( let j = groupStart; j < groupLength; j ++ ) { - - newIndices.push( index.getX( j ) ); - - } - - } - - geometry.dispose(); // Required to force buffer recreation - geometry.setIndex( newIndices ); - - // update groups indices - - let start = 0; - - for ( let i = 0; i < groups.length; i ++ ) { - - const group = groups[ i ]; - - group.start = start; - start += group.count; - - } - - // merge groups - - let currentGroup = groups[ 0 ]; - - geometry.groups = [ currentGroup ]; - - for ( let i = 1; i < groups.length; i ++ ) { - - const group = groups[ i ]; - - if ( currentGroup.materialIndex === group.materialIndex ) { - - currentGroup.count += group.count; - - } else { - - currentGroup = group; - geometry.groups.push( currentGroup ); - - } - - } - - return geometry; - -} - -/** - * Modifies the supplied geometry if it is non-indexed, otherwise creates a new, - * non-indexed geometry. Returns the geometry with smooth normals everywhere except - * faces that meet at an angle greater than the crease angle. - * - * @param {BufferGeometry} geometry - The geometry to modify. - * @param {number} [creaseAngle=Math.PI/3] - The crease angle in radians. - * @return {BufferGeometry} - The updated geometry - */ -function toCreasedNormals( geometry, creaseAngle = Math.PI / 3 /* 60 degrees */ ) { - - // BufferGeometry.toNonIndexed() warns if the geometry is non-indexed - // and returns the original geometry - const resultGeometry = geometry.index ? geometry.toNonIndexed() : geometry; - const posAttr = resultGeometry.attributes.position; - const vertexCount = posAttr.count; - - let positions; - - if ( posAttr.isBufferAttribute === true && posAttr.itemSize === 3 && posAttr.normalized === false ) { - - positions = posAttr.array; - - } else { - - // flatten the position buffer so the math below operates on plain numbers - positions = new Float64Array( vertexCount * 3 ); - - for ( let i = 0; i < vertexCount; i ++ ) { - - positions[ 3 * i + 0 ] = posAttr.getX( i ); - positions[ 3 * i + 1 ] = posAttr.getY( i ); - positions[ 3 * i + 2 ] = posAttr.getZ( i ); - - } - - } - - const creaseDot = Math.cos( creaseAngle ); - const hashMultiplier = ( 1 + 1e-10 ) * 1e2; - const faceCount = vertexCount / 3; - - // compute the normal of each face - const faceNormals = new Float64Array( faceCount * 3 ); - for ( let f = 0; f < faceCount; f ++ ) { - - const f9 = 9 * f; - const ax = positions[ f9 + 0 ], ay = positions[ f9 + 1 ], az = positions[ f9 + 2 ]; - const bx = positions[ f9 + 3 ], by = positions[ f9 + 4 ], bz = positions[ f9 + 5 ]; - const cx = positions[ f9 + 6 ], cy = positions[ f9 + 7 ], cz = positions[ f9 + 8 ]; - - const v1x = cx - bx, v1y = cy - by, v1z = cz - bz; - const v2x = ax - bx, v2y = ay - by, v2z = az - bz; - - const nx = v1y * v2z - v1z * v2y; - const ny = v1z * v2x - v1x * v2z; - const nz = v1x * v2y - v1y * v2x; - - const invLength = 1 / ( Math.sqrt( nx * nx + ny * ny + nz * nz ) || 1 ); - faceNormals[ 3 * f + 0 ] = nx * invLength; - faceNormals[ 3 * f + 1 ] = ny * invLength; - faceNormals[ 3 * f + 2 ] = nz * invLength; - - } - - // assign an id to each vertex, sharing the id between vertices with the same - // quantized position via an open-addressed hash table (slots hold id + 1, 0 means empty) - const vertexIds = new Int32Array( vertexCount ); - const quantized = new Float64Array( vertexCount * 3 ); - - let tableSize = 1; - while ( tableSize < vertexCount * 2 ) tableSize <<= 1; - const tableMask = tableSize - 1; - const table = new Int32Array( tableSize ); - - let uniqueCount = 0; - for ( let i = 0; i < vertexCount; i ++ ) { - - const i3 = 3 * i; - const qx = Math.trunc( positions[ i3 + 0 ] * hashMultiplier ); - const qy = Math.trunc( positions[ i3 + 1 ] * hashMultiplier ); - const qz = Math.trunc( positions[ i3 + 2 ] * hashMultiplier ); - - let slot = ( Math.imul( qx, 73856093 ) ^ Math.imul( qy, 19349663 ) ^ Math.imul( qz, 83492791 ) ) & tableMask; - - while ( true ) { - - const id = table[ slot ]; - - if ( id === 0 ) { - - const q3 = 3 * uniqueCount; - quantized[ q3 + 0 ] = qx; - quantized[ q3 + 1 ] = qy; - quantized[ q3 + 2 ] = qz; - - table[ slot ] = uniqueCount + 1; - vertexIds[ i ] = uniqueCount ++; - break; - - } - - const q3 = 3 * ( id - 1 ); - - if ( quantized[ q3 + 0 ] === qx && quantized[ q3 + 1 ] === qy && quantized[ q3 + 2 ] === qz ) { - - vertexIds[ i ] = id - 1; - break; - - } - - slot = ( slot + 1 ) & tableMask; - - } - - } - - // bucket the faces surrounding each unique vertex position - const bucketOffsets = new Int32Array( uniqueCount + 1 ); - for ( let i = 0; i < vertexCount; i ++ ) bucketOffsets[ vertexIds[ i ] + 1 ] ++; - for ( let i = 0; i < uniqueCount; i ++ ) bucketOffsets[ i + 1 ] += bucketOffsets[ i ]; - - const bucketFaces = new Int32Array( vertexCount ); - const bucketCursors = bucketOffsets.slice( 0, uniqueCount ); - for ( let f = 0; f < faceCount; f ++ ) { - - const f3 = 3 * f; - bucketFaces[ bucketCursors[ vertexIds[ f3 + 0 ] ] ++ ] = f; - bucketFaces[ bucketCursors[ vertexIds[ f3 + 1 ] ] ++ ] = f; - bucketFaces[ bucketCursors[ vertexIds[ f3 + 2 ] ] ++ ] = f; - - } - - // average the normals of the faces surrounding each vertex if they are within the - // provided crease threshold - const normalArray = new Float32Array( vertexCount * 3 ); - for ( let f = 0; f < faceCount; f ++ ) { - - const f3 = 3 * f; - const nx = faceNormals[ f3 + 0 ]; - const ny = faceNormals[ f3 + 1 ]; - const nz = faceNormals[ f3 + 2 ]; - - for ( let n = 0; n < 3; n ++ ) { - - const i = f3 + n; - const id = vertexIds[ i ]; - - let sumX = 0, sumY = 0, sumZ = 0; - - for ( let k = bucketOffsets[ id ], end = bucketOffsets[ id + 1 ]; k < end; k ++ ) { - - const o3 = 3 * bucketFaces[ k ]; - const ox = faceNormals[ o3 + 0 ]; - const oy = faceNormals[ o3 + 1 ]; - const oz = faceNormals[ o3 + 2 ]; - - if ( nx * ox + ny * oy + nz * oz > creaseDot ) { - - sumX += ox; - sumY += oy; - sumZ += oz; - - } - - } - - const invLength = 1 / ( Math.sqrt( sumX * sumX + sumY * sumY + sumZ * sumZ ) || 1 ); - normalArray[ 3 * i + 0 ] = sumX * invLength; - normalArray[ 3 * i + 1 ] = sumY * invLength; - normalArray[ 3 * i + 2 ] = sumZ * invLength; - - } - - } - - resultGeometry.setAttribute( 'normal', new BufferAttribute( normalArray, 3, false ) ); - return resultGeometry; - -} - -export { - computeMikkTSpaceTangents, - mergeGeometries, - mergeAttributes, - deepCloneAttribute, - deinterleaveAttribute, - deinterleaveGeometry, - interleaveAttributes, - estimateBytesUsed, - mergeVertices, - toTrianglesDrawMode, - computeMorphedAttributes, - mergeGroups, - toCreasedNormals -}; diff --git a/public/bluebey-studio/vendor/three/examples/jsm/utils/SkeletonUtils.js b/public/bluebey-studio/vendor/three/examples/jsm/utils/SkeletonUtils.js deleted file mode 100644 index 836c2e2..0000000 --- a/public/bluebey-studio/vendor/three/examples/jsm/utils/SkeletonUtils.js +++ /dev/null @@ -1,496 +0,0 @@ -import { - AnimationClip, - AnimationMixer, - Matrix4, - Quaternion, - QuaternionKeyframeTrack, - SkeletonHelper, - Vector3, - VectorKeyframeTrack -} from 'three'; - -/** - * @module SkeletonUtils - * @three_import import * as SkeletonUtils from 'three/addons/utils/SkeletonUtils.js'; - */ - -function getBoneName( bone, options ) { - - if ( options.getBoneName !== undefined ) { - - return options.getBoneName( bone ); - - } - - return options.names[ bone.name ]; - -} - -/** - * Retargets the skeleton from the given source to the target. - * - * Both `target` and `source` can be a 3D object with a skeleton property (e.g. a skinned mesh) - * or a {@link Skeleton} directly. - * - * @param {Object3D|Skeleton} target - The target object. - * @param {Object3D|Skeleton} source - The source object. - * @param {module:SkeletonUtils~RetargetOptions} options - The options. - */ -function retarget( target, source, options = {} ) { - - const quat = new Quaternion(), - scale = new Vector3(), - relativeMatrix = new Matrix4(), - globalMatrix = new Matrix4(); - - options.preserveBoneMatrix = options.preserveBoneMatrix !== undefined ? options.preserveBoneMatrix : true; - options.preserveBonePositions = options.preserveBonePositions !== undefined ? options.preserveBonePositions : true; - options.useTargetMatrix = options.useTargetMatrix !== undefined ? options.useTargetMatrix : false; - options.hip = options.hip !== undefined ? options.hip : 'hip'; - options.hipInfluence = options.hipInfluence !== undefined ? options.hipInfluence : new Vector3( 1, 1, 1 ); - options.scale = options.scale !== undefined ? options.scale : 1; - options.names = options.names || {}; - - const sourceBones = source.isObject3D ? source.skeleton.bones : getBones( source ), - bones = target.isObject3D ? target.skeleton.bones : getBones( target ); - - let bone, name, boneTo, - bonesPosition; - - // reset bones - - if ( target.isObject3D ) { - - target.skeleton.pose(); - - } else { - - options.useTargetMatrix = true; - options.preserveBoneMatrix = false; - - } - - if ( options.preserveBonePositions ) { - - bonesPosition = []; - - for ( let i = 0; i < bones.length; i ++ ) { - - bonesPosition.push( bones[ i ].position.clone() ); - - } - - } - - if ( options.preserveBoneMatrix ) { - - // reset matrix - - target.updateMatrixWorld(); - - target.matrixWorld.identity(); - - // reset children matrix - - for ( let i = 0; i < target.children.length; ++ i ) { - - target.children[ i ].updateMatrixWorld( true ); - - } - - } - - for ( let i = 0; i < bones.length; ++ i ) { - - bone = bones[ i ]; - name = getBoneName( bone, options ); - - boneTo = getBoneByName( name, sourceBones ); - - globalMatrix.copy( bone.matrixWorld ); - - if ( boneTo ) { - - boneTo.updateMatrixWorld(); - - if ( options.useTargetMatrix ) { - - relativeMatrix.copy( boneTo.matrixWorld ); - - } else { - - relativeMatrix.copy( target.matrixWorld ).invert(); - relativeMatrix.multiply( boneTo.matrixWorld ); - - } - - // ignore scale to extract rotation - - scale.setFromMatrixScale( relativeMatrix ); - relativeMatrix.scale( scale.set( 1 / scale.x, 1 / scale.y, 1 / scale.z ) ); - - // apply to global matrix - - globalMatrix.makeRotationFromQuaternion( quat.setFromRotationMatrix( relativeMatrix ) ); - - if ( target.isObject3D ) { - - if ( options.localOffsets ) { - - if ( options.localOffsets[ bone.name ] ) { - - globalMatrix.multiply( options.localOffsets[ bone.name ] ); - - } - - } - - } - - globalMatrix.copyPosition( relativeMatrix ); - - } - - if ( name === options.hip ) { - - globalMatrix.elements[ 12 ] *= options.scale * options.hipInfluence.x; - globalMatrix.elements[ 13 ] *= options.scale * options.hipInfluence.y; - globalMatrix.elements[ 14 ] *= options.scale * options.hipInfluence.z; - - if ( options.hipPosition !== undefined ) { - - globalMatrix.elements[ 12 ] += options.hipPosition.x * options.scale; - globalMatrix.elements[ 13 ] += options.hipPosition.y * options.scale; - globalMatrix.elements[ 14 ] += options.hipPosition.z * options.scale; - - } - - } - - if ( bone.parent ) { - - bone.matrix.copy( bone.parent.matrixWorld ).invert(); - bone.matrix.multiply( globalMatrix ); - - } else { - - bone.matrix.copy( globalMatrix ); - - } - - bone.matrix.decompose( bone.position, bone.quaternion, bone.scale ); - - bone.updateMatrixWorld(); - - } - - if ( options.preserveBonePositions ) { - - for ( let i = 0; i < bones.length; ++ i ) { - - bone = bones[ i ]; - name = getBoneName( bone, options ) || bone.name; - - if ( name !== options.hip ) { - - bone.position.copy( bonesPosition[ i ] ); - - } - - } - - } - - if ( options.preserveBoneMatrix ) { - - // restore matrix - - target.updateMatrixWorld( true ); - - } - -} - -/** - * Retargets the animation clip of the source to the target 3D object. - * - * The `source` can be a 3D object with a skeleton property (e.g. a skinned mesh) - * or a {@link Skeleton} directly. - * - * @param {Object3D} target - The target 3D object. Must have a `skeleton` property. - * @param {Object3D|Skeleton} source - The source object. - * @param {AnimationClip} clip - The animation clip. - * @param {module:SkeletonUtils~RetargetOptions} options - The options. - * @return {AnimationClip} The retargeted animation clip. - */ -function retargetClip( target, source, clip, options = {} ) { - - options.useFirstFramePosition = options.useFirstFramePosition !== undefined ? options.useFirstFramePosition : false; - - // Calculate the fps from the source clip based on the track with the most frames, unless fps is already provided. - options.fps = options.fps !== undefined ? options.fps : ( Math.max( ...clip.tracks.map( track => track.times.length ) ) / clip.duration ); - options.names = options.names || []; - - if ( ! source.isObject3D ) { - - source = getHelperFromSkeleton( source ); - - } - - const numFrames = Math.round( clip.duration * ( options.fps / 1000 ) * 1000 ), - delta = clip.duration / ( numFrames - 1 ), - convertedTracks = [], - mixer = new AnimationMixer( source ), - bones = getBones( target.skeleton ), - boneDatas = []; - - let positionOffset, - bone, boneTo, boneData, - name; - - mixer.clipAction( clip ).play(); - - // trim - - let start = 0, end = numFrames; - - if ( options.trim !== undefined ) { - - start = Math.round( options.trim[ 0 ] * options.fps ); - end = Math.min( Math.round( options.trim[ 1 ] * options.fps ), numFrames ) - start; - - mixer.update( options.trim[ 0 ] ); - - } else { - - mixer.update( 0 ); - - } - - source.updateMatrixWorld(); - - // - - for ( let frame = 0; frame < end; ++ frame ) { - - const time = frame * delta; - - retarget( target, source, options ); - - for ( let j = 0; j < bones.length; ++ j ) { - - bone = bones[ j ]; - name = getBoneName( bone, options ) || bone.name; - boneTo = getBoneByName( name, source.skeleton ); - - if ( boneTo ) { - - boneData = boneDatas[ j ] = boneDatas[ j ] || { bone: bone }; - - if ( options.hip === name ) { - - if ( ! boneData.pos ) { - - boneData.pos = { - times: new Float32Array( end ), - values: new Float32Array( end * 3 ) - }; - - } - - if ( options.useFirstFramePosition ) { - - if ( frame === 0 ) { - - positionOffset = bone.position.clone(); - - } - - bone.position.sub( positionOffset ); - - } - - boneData.pos.times[ frame ] = time; - - bone.position.toArray( boneData.pos.values, frame * 3 ); - - } - - if ( ! boneData.quat ) { - - boneData.quat = { - times: new Float32Array( end ), - values: new Float32Array( end * 4 ) - }; - - } - - boneData.quat.times[ frame ] = time; - - bone.quaternion.toArray( boneData.quat.values, frame * 4 ); - - } - - } - - if ( frame === end - 2 ) { - - // last mixer update before final loop iteration - // make sure we do not go over or equal to clip duration - mixer.update( delta - 0.0000001 ); - - } else { - - mixer.update( delta ); - - } - - source.updateMatrixWorld(); - - } - - for ( let i = 0; i < boneDatas.length; ++ i ) { - - boneData = boneDatas[ i ]; - - if ( boneData ) { - - if ( boneData.pos ) { - - convertedTracks.push( new VectorKeyframeTrack( - '.bones[' + boneData.bone.name + '].position', - boneData.pos.times, - boneData.pos.values - ) ); - - } - - convertedTracks.push( new QuaternionKeyframeTrack( - '.bones[' + boneData.bone.name + '].quaternion', - boneData.quat.times, - boneData.quat.values - ) ); - - } - - } - - mixer.uncacheAction( clip ); - - return new AnimationClip( clip.name, - 1, convertedTracks ); - -} - -/** - * Clones the given 3D object and its descendants, ensuring that any `SkinnedMesh` instances are - * correctly associated with their bones. Bones are also cloned, and must be descendants of the - * object passed to this method. Other data, like geometries and materials, are reused by reference. - * - * @param {Object3D} source - The 3D object to clone. - * @return {Object3D} The cloned 3D object. - */ -function clone( source ) { - - const sourceLookup = new Map(); - const cloneLookup = new Map(); - - const clone = source.clone(); - - parallelTraverse( source, clone, function ( sourceNode, clonedNode ) { - - sourceLookup.set( clonedNode, sourceNode ); - cloneLookup.set( sourceNode, clonedNode ); - - } ); - - clone.traverse( function ( node ) { - - if ( ! node.isSkinnedMesh ) return; - - const clonedMesh = node; - const sourceMesh = sourceLookup.get( node ); - const sourceBones = sourceMesh.skeleton.bones; - - clonedMesh.skeleton = sourceMesh.skeleton.clone(); - clonedMesh.bindMatrix.copy( sourceMesh.bindMatrix ); - - clonedMesh.skeleton.bones = sourceBones.map( function ( bone ) { - - return cloneLookup.get( bone ); - - } ); - - clonedMesh.bind( clonedMesh.skeleton, clonedMesh.bindMatrix ); - - } ); - - return clone; - -} - -// internal helper - -function getBoneByName( name, skeleton ) { - - for ( let i = 0, bones = getBones( skeleton ); i < bones.length; i ++ ) { - - if ( name === bones[ i ].name ) - - return bones[ i ]; - - } - -} - -function getBones( skeleton ) { - - return Array.isArray( skeleton ) ? skeleton : skeleton.bones; - -} - - -function getHelperFromSkeleton( skeleton ) { - - const source = new SkeletonHelper( skeleton.bones[ 0 ] ); - source.skeleton = skeleton; - - return source; - -} - -function parallelTraverse( a, b, callback ) { - - callback( a, b ); - - for ( let i = 0; i < a.children.length; i ++ ) { - - parallelTraverse( a.children[ i ], b.children[ i ], callback ); - - } - -} - -/** - * Retarget options of `SkeletonUtils`. - * - * @typedef {Object} module:SkeletonUtils~RetargetOptions - * @property {boolean} [useFirstFramePosition=false] - Whether to use the position of the first frame or not. - * @property {number} [fps] - The FPS of the clip. - * @property {Object} [names] - A dictionary for mapping target to source bone names. - * @property {function(string):string} [getBoneName] - A function for mapping bone names. Alternative to `names`. - * @property {Array} [trim] - Whether to trim the clip or not. If set the array should hold two values for the start and end. - * @property {boolean} [preserveBoneMatrix=true] - Whether to preserve bone matrices or not. - * @property {boolean} [preserveBonePositions=true] - Whether to preserve bone positions or not. - * @property {boolean} [useTargetMatrix=false] - Whether to use the target matrix or not. - * @property {string} [hip='hip'] - The name of the source's hip bone. - * @property {Vector3} [hipInfluence=(1,1,1)] - The hip influence. - * @property {number} [scale=1] - The scale. - * @property {Object} [localOffsets] - Per-bone local offset matrices, keyed by bone name. - * @property {Vector3} [hipPosition] - An additional position offset applied to the hip bone. - **/ - -export { - retarget, - retargetClip, - clone, -}; -- cgit v1.3.1