import EntityRepository from '../core/EntityRepository' ; import TransformComponent from '../components/TransformComponent' ; import SceneGraphComponent from '../components/SceneGraphComponent' ; import MeshComponent from '../components/MeshComponent' ; import Entity from '../core/Entity' ; import Vector3 from '../math/Vector3' ; import Quaternion from '../math/Quaternion' ; import Matrix44 from '../math/Matrix44' ; import MeshRendererComponent from '../components/MeshRendererComponent' ; import { Primitive } from '../geometry/Primitive' ; import Buffer from '../memory/Buffer' ; import { PrimitiveMode } from '../definitions/PrimitiveMode' ; import { CompositionType } from '../definitions/CompositionType' ; import { ComponentType } from '../definitions/ComponentType' ; import { VertexAttribute , VertexAttributeEnum , } from '../definitions/VertexAttribute' ; import CameraComponent from '../components/CameraComponent' ; import { CameraType } from '../definitions/CameraType' ; import Texture from '../textures/Texture' ; import Vector4 from '../math/Vector4' ; import AnimationComponent from '../components/AnimationComponent' ; import { AnimationInterpolation } from '../definitions/AnimationInterpolation' ; import { MathUtil } from '../math/MathUtil' ; import SkeletalComponent from '../components/SkeletalComponent' ; import { AlphaMode } from '../definitions/AlphaMode' ; import MaterialHelper from '../helpers/MaterialHelper' ; import { ShaderSemantics , ShaderSemanticsEnum , } from '../definitions/ShaderSemantics' ; import Vector2 from '../math/Vector2' ; import Material from '../materials/core/Material' ; import { ShadingModel } from '../definitions/ShadingModel' ; import Component from '../core/Component' ; import Accessor from '../memory/Accessor' ; import Mesh from '../geometry/Mesh' ; import MutableVector4 from '../math/MutableVector4' ; import LightComponent from '../components/LightComponent' ; import { LightType } from '../definitions/LightType' ; import { Count , Byte , Size , Index , TypedArray , TypedArrayConstructor , Array4 , } from '../../types/CommonTypes' ; import { GltfLoadOption , RnM2 , RnM2Node , RnM2Accessor , RnM2BufferView , RnM2Primitive , RnM2Material , RnM2Image , RnM2Camera , RnM2Texture , RnM2Mesh , KHR_lights_punctual_Light , RnM2TextureInfo , RnM2SparseIndices , } from '../../types/RnM2' ; import Config from '../core/Config' ; import { BufferUse } from '../definitions/BufferUse' ; import MemoryManager from '../core/MemoryManager' ; import ILoaderExtension from './ILoaderExtension' ; import BlendShapeComponent from '../components/BlendShapeComponent' ; import GlobalDataRepository from '../core/GlobalDataRepository' ; import PbrShadingSingleMaterialNode from '../materials/singles/PbrShadingSingleMaterialNode' ; import Scalar from '../math/Scalar' ; import { TextureParameter } from '../definitions/TextureParameter' ; import CGAPIResourceRepository from '../renderer/CGAPIResourceRepository' ; import { Is } from '../misc/Is' ; import DataUtil from '../misc/DataUtil' ; import { AnimationPathName } from '../../types/AnimationTypes' ; declare let DracoDecoderModule ; /**
 * A converter class from glTF2 model to Rhodonite Native data
 */ export default class ModelConverter { private static __instance : ModelConverter ; private constructor ( ) { } return static getInstance ( ) { if ( ! this . __instance ) { this . __instance = new ModelConverter ( ) ; } return this . __instance ; } _getDefaultShader ( options ) { const defaultShader = null ; return defaultShader ; } private __generateEntity ( components , gltfModel ) { const repo = EntityRepository . getInstance ( ) ; const entity = repo . createEntity ( components ) ; entity . tryToSetTag ( { tag : 'SourceType' , value : gltfModel . asset . extras ! . fileType ! , } ) ; entity . tryToSetTag ( { tag : 'SourceTypeVersion' , value : gltfModel . asset . extras ! . version ! , } ) ; return entity ; } private __generateGroupEntity ( gltfModel ) { const entity = this . __generateEntity ( [ TransformComponent , SceneGraphComponent ] , gltfModel ) ; return entity ; } private __generateMeshEntity ( gltfModel ) { const entity = this . __generateEntity ( [ TransformComponent , SceneGraphComponent , MeshComponent , MeshRendererComponent , ] , gltfModel ) ; return entity ; } private __generateCameraEntity ( gltfModel ) { const entity = this . __generateEntity ( [ TransformComponent , SceneGraphComponent , CameraComponent ] , gltfModel ) ; return entity ; } private __generateLightEntity ( gltfModel ) { const entity = this . __generateEntity ( [ TransformComponent , SceneGraphComponent , LightComponent ] , gltfModel ) ; return entity ; } convertToRhodoniteObject ( gltfModel ) { ( gltfModel . asset . extras as any ) . rnMeshesAtGltMeshIdx = [ ] ; const rnBuffers = this . createRnBuffer ( gltfModel ) ; gltfModel . asset . extras ! . rnMaterials = { } ; const { rnEntities , rnEntitiesByNames } = this . __setupObjects ( gltfModel , rnBuffers ) ; gltfModel . asset . extras ! . rnEntities = rnEntities ; this . _setupTransform ( gltfModel , rnEntities ) ; this . _setupSkeleton ( gltfModel , rnEntities ) ; this . _setupHierarchy ( gltfModel , rnEntities ) ; this . _setupAnimation ( gltfModel , rnEntities ) ; const rootGroup = this . __generateGroupEntity ( gltfModel ) ; rootGroup . tryToSetUniqueName ( 'FileRoot' , true ) ; rootGroup . tryToSetTag ( { tag : 'ObjectType' , value : 'top' } ) ; if ( gltfModel . scenes [ 0 ] . nodes ) { for ( const nodesIndex of gltfModel . scenes [ 0 ] . nodes ) { rootGroup . getSceneGraph ( ) . addChild ( rnEntities [ nodesIndex ] . getSceneGraph ( ) ) ; } } if ( gltfModel . asset . extras && gltfModel . asset . extras . rnLoaderOptions ) { const options = gltfModel . asset . extras ! . rnLoaderOptions ; if ( options && options . loaderExtension && options ?. loaderExtension ?. loadExtensionInfoAndSetToRootGroup ) { options . loaderExtension . loadExtensionInfoAndSetToRootGroup ( rootGroup , gltfModel ) ; } } rootGroup . tryToSetTag ( { tag : 'rnEntities' , value : rnEntities } ) ; rootGroup . tryToSetTag ( { tag : 'rnEntitiesByNames' , value : rnEntitiesByNames } ) ; rootGroup . tryToSetTag ( { tag : 'gltfModel' , value : gltfModel } ) ; return rootGroup ; } _setupCamera ( gltfModel ) { } private createRnBuffer ( gltfModel ) { const rnBuffers = [ ] ; for ( const buffer of gltfModel . buffers ) { const rnBuffer = new Buffer ( { byteLength : buffer . byteLength , buffer : buffer . buffer ! , name : `gltf2Buffer_0_(${ buffer . uri })` , byteAlign : 4 , } ) ; rnBuffers . push ( rnBuffer ) ; } return rnBuffers ; } _setupTransform ( gltfModel , groups ) { for ( const node_i in gltfModel . nodes ) { const group = groups [ node_i ] ; const nodeJson = gltfModel . nodes [ node_i ] ; if ( nodeJson . translation ) { group . getTransform ( ) . translate = Vector3 . fromCopyArray ( [ nodeJson . translation [ 0 ] , nodeJson . translation [ 1 ] , nodeJson . translation [ 2 ] , ] ) ; } if ( nodeJson . scale ) { group . getTransform ( ) . scale = Vector3 . fromCopyArray ( [ nodeJson . scale [ 0 ] , nodeJson . scale [ 1 ] , nodeJson . scale [ 2 ] , ] ) ; } if ( nodeJson . rotation ) { group . getTransform ( ) . quaternion = new Quaternion ( nodeJson . rotation [ 0 ] , nodeJson . rotation [ 1 ] , nodeJson . rotation [ 2 ] , nodeJson . rotation [ 3 ] ) ; } if ( nodeJson . matrix ) { group . getTransform ( ) . matrix = new Matrix44 ( nodeJson . matrix , true ) ; } } } _setupHierarchy ( gltfModel , rnEntities ) { const groupSceneComponents = rnEntities . map ( group => { return group . getSceneGraph ( ) ; } ) ; for ( const node_i in gltfModel . nodes ) { const parentNode_i = parseInt ( node_i ) ; const node = gltfModel . nodes [ parentNode_i ] ; if ( Is . exist ( node . children ) ) { const parentGroup = groupSceneComponents [ parentNode_i ] ; for ( const childNode_i of node . children ) { const childGroup = groupSceneComponents [ childNode_i ] ; parentGroup . addChild ( childGroup ) ; } } } } private _setupAnimation ( gltfModel , rnEntities ) { if ( gltfModel . animations ) { for ( const animation of gltfModel . animations ) { for ( const sampler of animation . samplers ) { this . _accessBinaryWithAccessor ( sampler . inputObject ! ) ; this . _accessBinaryWithAccessor ( sampler . outputObject ! ) ; } } } const entityRepository = EntityRepository . getInstance ( ) ; if ( Is . exist ( gltfModel . animations ) && gltfModel . animations . length > 0 ) { for ( const animation of gltfModel . animations ) { for ( const channel of animation . channels ) { if ( Is . exist ( channel . samplerObject ) ) { const animInputArray = channel . samplerObject . inputObject ! . extras ! . typedDataArray ! ; const animOutputArray = channel . samplerObject . outputObject ! . extras ! . typedDataArray ! ; const interpolation = channel . samplerObject . interpolation ?? 'LINEAR' ; let animationAttributeType = 'undefined' ; if ( channel . target ! . path === 'translation' ) { animationAttributeType = 'translate' ; } else if ( channel . target ! . path === 'rotation' ) { animationAttributeType = 'quaternion' ; } else { animationAttributeType = channel . target ! . path as AnimationPathName ; } const rnEntity = rnEntities [ channel . target ! . node ! ] ; if ( Is . exist ( rnEntity ) ) { entityRepository . addComponentsToEntity ( [ AnimationComponent ] , rnEntity . entityUID ) ; const animationComponent = rnEntity . getComponent ( AnimationComponent ) as AnimationComponent ; if ( Is . exist ( animationComponent ) ) { const outputComponentN = channel . samplerObject . outputObject ! . extras ! . componentN ! ; animationComponent . setAnimation ( Is . exist ( animation . name ) ? animation . name ! : 'Untitled' , animationAttributeType , animInputArray , animOutputArray , outputComponentN , AnimationInterpolation . fromString ( interpolation ) ) ; } } } } } } } _setupSkeleton ( gltfModel , rnEntities ) { if ( gltfModel . skins == null ) { return ; } const globalDataRepository = GlobalDataRepository . getInstance ( ) ; const entityRepository = EntityRepository . getInstance ( ) ; for ( const skin of gltfModel . skins ) { if ( Is . exist ( skin . inverseBindMatricesObject ) ) { this . _accessBinaryWithAccessor ( skin . inverseBindMatricesObject ) ; } } for ( const node_i in gltfModel . nodes ) { const node = gltfModel . nodes [ node_i ] ; const sg = rnEntities [ node_i ] . getSceneGraph ( ) ; let skeletalComponent ; if ( Is . exist ( node . skinObject ) ) { const rnEntity = rnEntities [ node_i ] ; entityRepository . addComponentsToEntity ( [ SkeletalComponent ] , rnEntity . entityUID ) ; skeletalComponent = rnEntity . getComponent ( SkeletalComponent ) as SkeletalComponent ; skeletalComponent . _jointIndices = node . skinObject . joints ; if ( Is . exist ( node . skinObject . bindShapeMatrix ) ) { skeletalComponent . _bindShapeMatrix = new Matrix44 ( node . skinObject . bindShapeMatrix , true ) ; } if ( node . skinObject . skeleton ) { sg . isRootJoint = true ; if ( Is . exist ( node . mesh ) ) { const joints = [ ] ; for ( const i of node . skinObject . joints ) { joints . push ( rnEntities [ i ] . getSceneGraph ( ) ) ; } skeletalComponent ! . joints = joints ; if ( Is . exist ( node . skinObject . skeleton ) ) { skeletalComponent ! . jointsHierarchy = rnEntities [ node . skinObject . skeleton ] . getSceneGraph ( ) ; } else { skeletalComponent ! . jointsHierarchy = joints [ 0 ] ; } } } if ( node . skinObject . joints ) { for ( const joint_i of node . skinObject . joints ) { const sg = rnEntities [ joint_i ] . getSceneGraph ( ) ; sg . jointIndex = joint_i ; } } const inverseBindMatAccessor = node . skinObject . inverseBindMatricesObject ; if ( Is . exist ( inverseBindMatAccessor ) && Is . exist ( inverseBindMatAccessor . extras ) && Is . exist ( inverseBindMatAccessor . extras . typedDataArray ) ) { const matrixN = ( inverseBindMatAccessor . extras . typedDataArray . length / 16 ) as number ; const matrices = new Array ( matrixN ) ; for ( let i = 0 ; i < matrixN ; i ++ ) { matrices [ i ] = new Matrix44 ( inverseBindMatAccessor . extras . typedDataArray . subarray ( 16 * i , 16 * ( i + 1 ) ) , true , true ) ; } skeletalComponent ! . _inverseBindMatrices = matrices ; } } } } __setupObjects ( gltfModel , rnBuffers ) { const rnEntities = [ ] ; const rnEntitiesByNames = new Map ( ) ; for ( const node_i in gltfModel . nodes ) { const node = gltfModel . nodes [ parseInt ( node_i ) ] as RnM2Node ; let entity ; if ( node . mesh != null ) { const meshIdx = node . mesh ; const meshEntity = this . __setupMesh ( node , node . meshObject ! , meshIdx , rnBuffers , gltfModel ) ; if ( node . name ) { meshEntity . tryToSetUniqueName ( node . name , true ) ; } if ( node . meshObject ?. name ) { const meshComponent = meshEntity . getComponent ( MeshComponent ) ! ; meshComponent . tryToSetUniqueName ( node . meshObject . name , true ) ; } entity = meshEntity ; } else if ( node . cameraObject != null ) { const cameraEntity = this . __setupCamera ( node . cameraObject , gltfModel ) ; if ( node . name ) { cameraEntity . tryToSetUniqueName ( node . name , true ) ; } entity = cameraEntity ; } else if ( node . extensions ?. KHR_lights_punctual ) { const lightEntity = this . __setupLight ( node . extensions . KHR_lights_punctual . light , gltfModel ) ; entity = lightEntity ; } else { const group = this . __generateGroupEntity ( gltfModel ) ; if ( node . name ) { group . tryToSetUniqueName ( node . name , true ) ; } entity = group ; } entity . tryToSetTag ( { tag : 'gltf_node_index' , value : '' + node_i } ) ; rnEntities . push ( entity ) ; rnEntitiesByNames . set ( node . name ! , entity ) ; if ( this . __isMorphing ( node , gltfModel ) ) { let weights = [ ] ; if ( node . weights ) { weights = node . weights ; } else if ( node . meshObject ?. weights ) { weights = node . meshObject . weights ; } const entityRepository = EntityRepository . getInstance ( ) ; entityRepository . addComponentsToEntity ( [ BlendShapeComponent ] , entity . entityUID ) ; const blendShapeComponent = entity . getComponent ( BlendShapeComponent ) as BlendShapeComponent ; blendShapeComponent . weights = weights ; if ( node . meshObject ?. primitives [ 0 ] . extras ?. targetNames ) { blendShapeComponent . targetNames = node . meshObject . primitives [ 0 ] . extras . targetNames ; } } } return { rnEntities , rnEntitiesByNames } ; } private __isMorphing ( node , gltfModel ) { const argument = gltfModel . asset . extras ?. rnLoaderOptions ?. defaultMaterialHelperArgumentArray ! [ 0 ] ; if ( argument ?. isMorphing === false ) { return false ; } else { return node . meshObject ?. primitives [ 0 ] . targets != null ; } } private __setupLight ( light , gltfModel ) { const lightEntity = this . __generateLightEntity ( gltfModel ) ; const lightComponent = lightEntity . getComponent ( LightComponent ) ! as LightComponent ; if ( light . name != null ) { lightComponent . tryToSetUniqueName ( light . name , true ) ; lightComponent . type = LightType . fromString ( light . type ) ; let color = Vector3 . fromCopyArray3 ( [ 1 , 1 , 1 ] ) ; let intensity = 1 ; if ( light . color != null ) { color = Vector3 . fromCopyArray3 ( light . color ) ; } if ( light . intensity != null ) { intensity = light . intensity ; } lightComponent . intensity = Vector3 . multiply ( color , intensity ) ; if ( light . range != null ) { lightComponent . range = light . range ; } } return lightEntity ; } private __setupCamera ( camera , gltfModel ) { const cameraEntity = this . __generateCameraEntity ( gltfModel ) ; const cameraComponent = cameraEntity . getComponent ( CameraComponent ) ! as CameraComponent ; cameraComponent . direction = Vector3 . fromCopyArray ( [ 0 , 0 , - 1 ] ) ; if ( gltfModel . asset && ( gltfModel . asset as any ) . LastSaved_ApplicationVendor ) { cameraComponent . direction = Vector3 . fromCopyArray ( [ 1 , 0 , 0 ] ) ; cameraComponent . directionInner = Vector3 . fromCopyArray ( [ 1 , 0 , 0 ] ) ; } cameraComponent . up = Vector3 . fromCopyArray ( [ 0 , 1 , 0 ] ) ; cameraComponent . type = CameraType . fromString ( camera . type ) ; if ( cameraComponent . type === CameraType . Perspective ) { cameraComponent . aspect = camera . perspective ! . aspectRatio ? camera . perspective ! . aspectRatio : 1 ; cameraComponent . setFovyAndChangeFocalLength ( MathUtil . radianToDegree ( camera . perspective ! . yfov ) ) ; cameraComponent . zNear = camera . perspective ! . znear ; cameraComponent . zFar = camera . perspective ! . zfar ? camera . perspective ! . zfar : 100000 ; } else if ( cameraComponent . type === CameraType . Orthographic ) { cameraComponent . xMag = camera . orthographic ! . xmag ; cameraComponent . yMag = camera . orthographic ! . ymag ; cameraComponent . zNear = camera . orthographic ! . znear ; cameraComponent . zFar = camera . orthographic ! . zfar ; } return cameraEntity ; } private __setupMesh ( node , mesh , meshIndex , rnBuffers , gltfModel ) { const meshEntity = this . __generateMeshEntity ( gltfModel ) ; const existingRnMesh = ( gltfModel . asset . extras as any ) . rnMeshesAtGltMeshIdx [ meshIndex ] ; let rnPrimitiveMode = PrimitiveMode . Triangles ; const meshComponent = meshEntity . getMesh ( ) ; const rnMesh = new Mesh ( ) ; const rnLoaderOptions = gltfModel . asset . extras ! . rnLoaderOptions ; if ( rnLoaderOptions ?. tangentCalculationMode != null ) { rnMesh . tangentCalculationMode = rnLoaderOptions . tangentCalculationMode ; } if ( rnLoaderOptions ?. isPreComputeForRayCastPickingEnable != null ) { rnMesh . isPreComputeForRayCastPickingEnable = rnLoaderOptions . isPreComputeForRayCastPickingEnable ; } let originalRnMesh = rnMesh ; if ( existingRnMesh != null ) { rnMesh . setOriginalMesh ( existingRnMesh ) ; originalRnMesh = existingRnMesh ; } else { for ( const i in mesh . primitives ) { const primitive = mesh . primitives [ i ] as RnM2Primitive ; if ( primitive . mode != null ) { rnPrimitiveMode = PrimitiveMode . from ( primitive . mode ) ! ; } const rnPrimitive = new Primitive ( ) ; const material = this . __setupMaterial ( rnPrimitive , node , gltfModel , primitive , primitive . materialObject ! ) ; if ( material . isEmptyMaterial ( ) === false ) { ModelConverter . setDefaultTextures ( material , gltfModel ) ; } let indicesRnAccessor ; const map = new Map ( ) ; if ( primitive . extensions ?. KHR_draco_mesh_compression ) { indicesRnAccessor = this . __decodeDraco ( primitive , rnBuffers , gltfModel , map ) ; if ( Is . not . exist ( indicesRnAccessor ) ) { break ; } } else { if ( Is . exist ( primitive . indices ) ) { indicesRnAccessor = this . __getRnAccessor ( primitive . indicesObject ! , rnBuffers [ primitive . indicesObject ! . bufferViewObject ! . buffer ! ] ) ; } for ( const attributeName in primitive . attributesObjects ! ) { const attributeAccessor = primitive . attributesObjects ! [ attributeName ] ; const attributeRnAccessor = this . __getRnAccessor ( attributeAccessor , rnBuffers [ ( attributeAccessor . bufferViewObject as RnM2BufferView ) . buffer ! ] ) ; if ( attributeAccessor . sparse ) { this . setSparseAccessor ( attributeAccessor , attributeRnAccessor ) ; } map . set ( VertexAttribute . fromString ( attributeAccessor . extras ! . attributeName ) , attributeRnAccessor ) ; } } rnPrimitive . setData ( map , rnPrimitiveMode , material , indicesRnAccessor ) ; if ( primitive . targets != null ) { let maxMorphTargetNumber = Config . maxMorphTargetNumber ; if ( rnLoaderOptions ?. maxMorphTargetNumber != null ) { maxMorphTargetNumber = rnLoaderOptions . maxMorphTargetNumber ; } const targets = [ ] ; for ( let i = 0 ; i < primitive . targetsObjects ! . length ; i ++ ) { if ( i >= maxMorphTargetNumber ) { break ; } const target = primitive . targetsObjects ! [ i ] ; const targetMap = new Map ( ) ; for ( const attributeName in target ) { const attributeAccessor = target [ attributeName ] ; const attributeRnAccessor = this . __getRnAccessor ( attributeAccessor , rnBuffers [ attributeAccessor . bufferViewObject ! . buffer ! ] ) ; const attributeRnAccessorInGPUVertexData = this . __copyRnAccessorAndBufferView ( attributeRnAccessor ) ; targetMap . set ( VertexAttribute . fromString ( attributeName ) , attributeRnAccessorInGPUVertexData ) ; } targets . push ( targetMap ) ; } rnPrimitive . setTargets ( targets ) ; } rnMesh . addPrimitive ( rnPrimitive ) ; } if ( mesh . weights ) { rnMesh . weights = mesh . weights ; } } meshComponent . setMesh ( rnMesh ) ; ( gltfModel . asset . extras as any ) . rnMeshesAtGltMeshIdx [ meshIndex ] = originalRnMesh ; return meshEntity ; } setSparseAccessor ( accessor , rnAccessor ) { const uint8Array = accessor . bufferViewObject ! . bufferObject ! . buffer ! ; const count = accessor . sparse ! . count ; const accessorIndices = accessor . sparse ! . indices ! ; const bufferViewIndices = accessorIndices . bufferViewObject ; const byteOffsetIndices = ( bufferViewIndices . byteOffset ?? 0 ) + ( accessorIndices . byteOffset ?? 0 ) ; const componentBytesIndices = this . _checkBytesPerComponent ( accessorIndices ) ; const byteLengthIndices = componentBytesIndices * count ; const dataViewIndices = new DataView ( uint8Array . buffer , byteOffsetIndices + uint8Array . byteOffset , byteLengthIndices ) ; const dataViewMethodIndices = this . _checkDataViewMethod ( accessorIndices ) ; const accessorValues = accessor . sparse ! . values ! ; const bufferViewValues = accessorValues . bufferViewObject ; const byteOffsetValues = ( bufferViewValues . byteOffset ?? 0 ) + ( accessorValues . byteOffset ?? 0 ) ; const componentBytesValues = this . _checkBytesPerComponent ( accessor ) ; const componentNValues = this . _checkComponentNumber ( accessor ) ; const byteLengthValues = componentBytesValues * componentNValues * count ; const dataViewValues = new DataView ( uint8Array . buffer , byteOffsetValues + uint8Array . byteOffset , byteLengthValues ) ; const dataViewMethodValues = this . _checkDataViewMethod ( accessor ) ; const typedArray = rnAccessor . getTypedArray ( ) ; const littleEndian = true ; for ( let i = 0 ; i < count ; i ++ ) { const index = dataViewIndices [ dataViewMethodIndices ] ( componentBytesIndices * i , littleEndian ) ; for ( let j = 0 ; j < componentNValues ; j ++ ) { const value = dataViewValues [ dataViewMethodValues ] ( componentBytesValues * componentNValues * i + componentBytesValues * j , littleEndian ) ; typedArray [ index * componentNValues + j ] = value ; } } } static setDefaultTextures ( material , gltfModel ) { if ( gltfModel . asset . extras ?. rnLoaderOptions ?. defaultTextures == null ) { return ; } const options = gltfModel . asset . extras . rnLoaderOptions ; const defaultTextures = gltfModel . asset . extras . rnLoaderOptions . defaultTextures ; const basePath = defaultTextures . basePath ; const textureInfos = defaultTextures . textureInfos ; for ( const textureInfo of textureInfos ) { const rnTexture = new Texture ( ) ; if ( textureInfo . shaderSemantics === ShaderSemantics . BaseColorTexture || textureInfo . shaderSemantics === ShaderSemantics . DiffuseColorTexture ) { rnTexture . autoDetectTransparency = options . autoDetectTextureTransparency === true ; } rnTexture . autoResize = options . autoResizeTexture === true ; const textureOption = { magFilter : Is . exist ( textureInfo . sampler ?. magFilter ) ? TextureParameter . from ( textureInfo . sampler ! . magFilter ) : TextureParameter . Linear , minFilter : Is . exist ( textureInfo . sampler ?. minFilter ) ? TextureParameter . from ( textureInfo . sampler ! . minFilter ) : TextureParameter . Linear , wrapS : Is . exist ( textureInfo . sampler ?. wrapS ) ? TextureParameter . from ( textureInfo . sampler ! . wrapS ) : TextureParameter . Repeat , wrapT : Is . exist ( textureInfo . sampler ?. wrapT ) ? TextureParameter . from ( textureInfo . sampler ! . wrapT ) : TextureParameter . Repeat , } ; const fileName = textureInfo . fileName ; const uri = basePath + fileName ; rnTexture . name = uri ; const image = textureInfo . image ; if ( image ?. image != null ) { const webglResourceRepository = CGAPIResourceRepository . getWebGLResourceRepository ( ) ; const isWebGL1 = ! webglResourceRepository . currentWebGLContextWrapper ?. isWebGL2 ; if ( isWebGL1 && ! this . __sizeIsPowerOfTwo ( image . image ) && this . __needResizeToPowerOfTwoOnWebGl1 ( textureOption ) ) { rnTexture . autoResize = true ; } rnTexture . generateTextureFromImage ( image . image , textureOption ) ; } else if ( image ?. basis != null ) { rnTexture . generateTextureFromBasis ( image . basis , textureOption ) ; } else if ( image ?. ktx2 != null ) { rnTexture . generateTextureFromKTX2 ( image . ktx2 , textureOption ) ; } else { console . warn ( 'default image not found' ) ; continue ; } const shaderSemantics = textureInfo . shaderSemantics ; material . setTextureParameter ( shaderSemantics , rnTexture ) ; } } private __setVRMMaterial ( rnPrimitive , node , gltfModel , primitive , materialJson , rnLoaderOptions ) { const VRMProperties = gltfModel . extensions . VRM ; const materialProperties = gltfModel . extensions . VRM . materialProperties [ primitive . material ! ] ; const shaderName = materialProperties . shader ; if ( shaderName === 'VRM/MToon' ) { const defaultMaterialHelperArgument = rnLoaderOptions . defaultMaterialHelperArgumentArray ! [ 0 ] ; const additionalName = defaultMaterialHelperArgument . additionalName ; const isMorphing = this . __isMorphing ( node , gltfModel ) ; const isSkinning = this . __isSkinning ( node , gltfModel ) ; const isLighting = this . __isLighting ( gltfModel , materialJson ) ; const useTangentAttribute = this . __useTangentAttribute ( gltfModel , primitive ) ; const textures = defaultMaterialHelperArgument . textures ; const debugMode = defaultMaterialHelperArgument . debugMode ; const maxInstancesNumber = defaultMaterialHelperArgument . maxInstancesNumber ; const makeOutputSrgb = this . __makeOutputSrgb ( gltfModel ) ; let renderPassOutline ; const rnExtension = VRMProperties . rnExtension ; if ( Is . exist ( rnExtension ) ) { renderPassOutline = rnExtension . renderPassOutline ; renderPassOutline . isVrRendering = true ; } if ( renderPassOutline != null ) { let outlineMaterial ; if ( materialProperties . floatProperties . _OutlineWidthMode !== 0 ) { outlineMaterial = MaterialHelper . createMToonMaterial ( { additionalName , isMorphing , isSkinning , isLighting , useTangentAttribute , isOutline : true , materialProperties , textures , debugMode , maxInstancesNumber , makeOutputSrgb , } ) ; } else { outlineMaterial = MaterialHelper . createEmptyMaterial ( ) ; } renderPassOutline . setMaterialForPrimitive ( outlineMaterial , rnPrimitive ) ; } const material = MaterialHelper . createMToonMaterial ( { additionalName , isMorphing , isSkinning , isLighting , useTangentAttribute , isOutline : false , materialProperties , textures , debugMode , maxInstancesNumber , makeOutputSrgb , } ) ; return material ; } else if ( rnLoaderOptions . defaultMaterialHelperArgumentArray ! [ 0 ] . isOutline ) { return MaterialHelper . createEmptyMaterial ( ) ; } return undefined ; } private __generateAppropriateMaterial ( rnPrimitive , node , gltfModel , primitive , materialJson ) { if ( gltfModel . asset . extras ?. rnLoaderOptions != null ) { const rnLoaderOptions = gltfModel . asset . extras . rnLoaderOptions ; if ( rnLoaderOptions ?. loaderExtension ?. isNeededToUseThisMaterial != null && rnLoaderOptions . loaderExtension . isNeededToUseThisMaterial ( gltfModel ) ) { const loaderExtension = gltfModel . asset . extras ?. rnLoaderOptions ?. loaderExtension ; if ( loaderExtension ?. generateMaterial != null ) { return loaderExtension . generateMaterial ( materialJson ) ; } } if ( rnLoaderOptions . isImportVRM ) { const material = this . __setVRMMaterial ( rnPrimitive , node , gltfModel , primitive , materialJson , rnLoaderOptions ) ; if ( material != null ) return material ; } const materialHelperName = rnLoaderOptions . defaultMaterialHelperName ; if ( materialHelperName != null ) { return ( MaterialHelper as any ) [ materialHelperName ] ( ... rnLoaderOptions . defaultMaterialHelperArgumentArray ! ) ; } } let maxMaterialInstanceNumber = Config . maxMaterialInstanceForEachType ; if ( gltfModel . meshes . length > Config . maxMaterialInstanceForEachType ) { maxMaterialInstanceNumber = gltfModel . meshes . length + Math . floor ( Config . maxMaterialInstanceForEachType / 2 ) ; } const isMorphing = this . __isMorphing ( node , gltfModel ) ; const isSkinning = this . __isSkinning ( node , gltfModel ) ; const isLighting = this . __isLighting ( gltfModel , materialJson ) ; const alphaMode = AlphaMode . fromGlTFString ( materialJson ?. alphaMode || 'OPAQUE' ) ; const additionalName = node . skin != null ? `skin${ node . skin ?? node . skinName ?? '' }` : void 0 ; if ( parseFloat ( gltfModel . asset ?. version ) >= 2 ) { const useTangentAttribute = this . __useTangentAttribute ( gltfModel , primitive ) ; const useNormalTexture = this . __useNormalTexture ( gltfModel ) ; const makeOutputSrgb = this . __makeOutputSrgb ( gltfModel ) ; return MaterialHelper . createPbrUberMaterial ( { isMorphing , isSkinning , isLighting , alphaMode , useTangentAttribute , useNormalTexture , additionalName : additionalName , maxInstancesNumber : maxMaterialInstanceNumber , makeOutputSrgb , } ) ; } else { return MaterialHelper . createClassicUberMaterial ( { isSkinning , isLighting , alphaMode , additionalName : additionalName , maxInstancesNumber : maxMaterialInstanceNumber , } ) ; } } private __isLighting ( gltfModel , materialJson ? ) { const argument = gltfModel ?. asset ?. extras ?. rnLoaderOptions ?. defaultMaterialHelperArgumentArray ! [ 0 ] ; if ( argument ?. isLighting != null ) { return argument . isLighting as boolean ; } else { return materialJson ?. extensions ?. KHR_materials_unlit != null ? false : true ; } } private __isSkinning ( node , gltfModel ) { const argument = gltfModel ?. asset ?. extras ?. rnLoaderOptions ?. defaultMaterialHelperArgumentArray ! [ 0 ] ; if ( argument ?. isSkinning === false ) { return false ; } else { return node . skin != null ; } } private __useTangentAttribute ( gltfModel , primitive ) { const tangentCalculationMode = gltfModel ?. asset ?. extras ?. rnLoaderOptions ?. tangentCalculationMode ; switch ( tangentCalculationMode ) { case 0 : return false ; case 1 : break ; case 2 : return true ; case 3 : return false ; case 4 : return true ; default : } for ( const attribute in primitive . attributes ) { if ( attribute === 'TANGENT' ) { return true ; } } return false ; } private __useNormalTexture ( gltfModel ) { const argument = gltfModel ?. asset ?. extras ?. rnLoaderOptions ?. defaultMaterialHelperArgumentArray ! [ 0 ] ; if ( argument ?. useNormalTexture === false ) { return false ; } else { return ( gltfModel ?. asset ?. extras ?. rnLoaderOptions ?. tangentCalculationMode !== 0 ) ; } } private __makeOutputSrgb ( gltfModel ) { const argument = gltfModel ?. asset ?. extras ?. rnLoaderOptions ?. defaultMaterialHelperArgumentArray ! [ 0 ] ; return argument ?. makeOutputSrgb as boolean | undefined ; } private __getMaterialHash ( node , gltfModel , primitive , materialJson ) { return ( primitive . material ! + '_isSkinning_' + this . __isSkinning ( node , gltfModel ) + '_isMorphing_' + this . __isMorphing ( node , gltfModel ) + '_isLighting_' + this . __isLighting ( gltfModel , materialJson ) + '_useTangentAttribute_' + this . __useTangentAttribute ( gltfModel , primitive ) ) ; } private __setupMaterial ( rnPrimitive , node , gltfModel , primitive , materialJson ) { const materialHash = this . __getMaterialHash ( node , gltfModel , primitive , materialJson ) ; let material = gltfModel . asset . extras ?. rnMaterials ! [ materialHash ] ; if ( material != null ) { return material ; } else { const newMaterial = this . __generateAppropriateMaterial ( rnPrimitive , node , gltfModel , primitive , materialJson ) ; gltfModel . asset . extras ! . rnMaterials ! [ materialHash ] = newMaterial ; material = newMaterial ; } if ( ! this . __needParameterInitialization ( materialJson , material . materialTypeName ) ) return material ; const options = gltfModel . asset . extras ! . rnLoaderOptions ; const pbrMetallicRoughness = materialJson . pbrMetallicRoughness ; if ( pbrMetallicRoughness != null ) { const baseColorFactor = pbrMetallicRoughness . baseColorFactor ; if ( baseColorFactor != null ) { material . setParameter ( ShaderSemantics . BaseColorFactor , Vector4 . fromCopyArray4 ( baseColorFactor ) ) ; } const baseColorTexture = pbrMetallicRoughness . baseColorTexture ; if ( baseColorTexture != null ) { const rnTexture = ModelConverter . _createTexture ( baseColorTexture . texture ! , gltfModel , { autoDetectTransparency : options ?. autoDetectTextureTransparency , } ) ; material . setTextureParameter ( ShaderSemantics . BaseColorTexture , rnTexture ) ; if ( baseColorTexture . texCoord != null ) { material . setParameter ( PbrShadingSingleMaterialNode . BaseColorTexcoordIndex , baseColorTexture . texCoord ) ; } } ModelConverter . _setupTextureTransform ( baseColorTexture ! , material , PbrShadingSingleMaterialNode . BaseColorTextureTransform , PbrShadingSingleMaterialNode . BaseColorTextureRotation ) ; const occlusionTexture = materialJson . occlusionTexture ; if ( occlusionTexture != null ) { const rnTexture = ModelConverter . _createTexture ( occlusionTexture . texture ! , gltfModel ) ; material . setTextureParameter ( ShaderSemantics . OcclusionTexture , rnTexture ) ; if ( occlusionTexture . texCoord != null ) { material . setParameter ( PbrShadingSingleMaterialNode . OcclusionTexcoordIndex , occlusionTexture . texCoord ) ; } if ( occlusionTexture . strength != null ) { material . setParameter ( PbrShadingSingleMaterialNode . OcclusionStrength , occlusionTexture . strength ) ; } } let metallicFactor = pbrMetallicRoughness . metallicFactor ; metallicFactor = metallicFactor ?? 1 ; let roughnessFactor = pbrMetallicRoughness . roughnessFactor ; roughnessFactor = roughnessFactor ?? 1 ; material . setParameter ( ShaderSemantics . MetallicRoughnessFactor , Vector2 . fromCopyArray2 ( [ metallicFactor , roughnessFactor ] ) ) ; const metallicRoughnessTexture = pbrMetallicRoughness . metallicRoughnessTexture ; if ( metallicRoughnessTexture != null ) { const rnTexture = ModelConverter . _createTexture ( metallicRoughnessTexture . texture ! , gltfModel ) ; material . setTextureParameter ( ShaderSemantics . MetallicRoughnessTexture , rnTexture ) ; if ( metallicRoughnessTexture . texCoord != null ) { material . setParameter ( PbrShadingSingleMaterialNode . MetallicRoughnessTexcoordIndex , metallicRoughnessTexture . texCoord ) ; } } ModelConverter . _setupTextureTransform ( metallicRoughnessTexture ! , material , PbrShadingSingleMaterialNode . MetallicRoughnessTextureTransform , PbrShadingSingleMaterialNode . MetallicRoughnessTextureRotation ) ; } else { let param = ShadingModel . Phong . index ; if ( materialJson . extras ?. technique ) { switch ( materialJson . extras . technique ) { case ShadingModel . Constant . str : param = ShadingModel . Constant . index ; break ; case ShadingModel . Lambert . str : param = ShadingModel . Lambert . index ; break ; case ShadingModel . BlinnPhong . str : param = ShadingModel . BlinnPhong . index ; break ; case ShadingModel . Phong . str : param = ShadingModel . Phong . index ; break ; } material . setParameter ( ShaderSemantics . ShadingModel , Scalar . fromCopyNumber ( param ) ) ; } } const emissiveTexture = materialJson . emissiveTexture ; if ( emissiveTexture != null ) { const rnTexture = ModelConverter . _createTexture ( emissiveTexture . texture ! , gltfModel ) ; material . setTextureParameter ( ShaderSemantics . EmissiveTexture , rnTexture ) ; if ( parseFloat ( gltfModel . asset ?. version ) >= 2 && emissiveTexture . texCoord != null ) { material . setParameter ( PbrShadingSingleMaterialNode . EmissiveTexcoordIndex , emissiveTexture . texCoord ) ; } } let alphaMode = materialJson . alphaMode ; if ( options ?. alphaMode ) { alphaMode = options . alphaMode ; } if ( alphaMode != null ) { material . alphaMode = AlphaMode . fromGlTFString ( alphaMode ) ! ; if ( material . alphaMode === AlphaMode . Mask && ! gltfModel . asset . extras ?. rnLoaderOptions ?. isImportVRM ) { material . setParameter ( ShaderSemantics . AlphaCutoff , Scalar . fromCopyNumber ( materialJson . alphaCutoff ?? 0.5 ) ) ; } } const doubleSided = materialJson . doubleSided ; if ( doubleSided != null ) { material . cullFace = ! doubleSided ; } if ( Is . exist ( ( materialJson as any ) . diffuseColorTexture ) ) { const diffuseColorTexture = ( materialJson as any ) . diffuseColorTexture as RnM2Texture ; const rnTexture = ModelConverter . _createTexture ( diffuseColorTexture , gltfModel , { autoDetectTransparency : options ?. autoDetectTextureTransparency , } ) ; material . setTextureParameter ( ShaderSemantics . DiffuseColorTexture , rnTexture ) ; if ( this . _checkRnGltfLoaderOptionsExist ( gltfModel ) && gltfModel . asset . extras ?. rnLoaderOptions ?. loaderExtension ) { const loaderExtension = gltfModel . asset . extras ! . rnLoaderOptions ! . loaderExtension as ILoaderExtension ; if ( loaderExtension . setUVTransformToTexture ) { loaderExtension . setUVTransformToTexture ( material , diffuseColorTexture . samplerObject ! ) ; } } } if ( Is . exist ( materialJson . diffuseColorFactor ) ) { const diffuseColorFactor = materialJson . diffuseColorFactor as Array4 < number > ; material . setParameter ( ShaderSemantics . DiffuseColorFactor , Vector4 . fromCopyArray4 ( diffuseColorFactor ) ) ; } const normalTexture = materialJson . normalTexture ; if ( normalTexture != null ) { const rnTexture = ModelConverter . _createTexture ( normalTexture . texture ! , gltfModel ) ; material . setTextureParameter ( ShaderSemantics . NormalTexture , rnTexture ) ; if ( parseFloat ( gltfModel . asset ?. version ) >= 2 ) { if ( normalTexture . texCoord != null ) { material . setParameter ( PbrShadingSingleMaterialNode . NormalTexcoordIndex , normalTexture . texCoord ) ; } if ( normalTexture . scale != null ) { material . setParameter ( PbrShadingSingleMaterialNode . NormalScale , normalTexture . scale ) ; } } } ModelConverter . _setupTextureTransform ( normalTexture ! , material , PbrShadingSingleMaterialNode . NormalTextureTransform , PbrShadingSingleMaterialNode . NormalTextureRotation ) ; if ( this . _checkRnGltfLoaderOptionsExist ( gltfModel ) ) { const loaderExtension = gltfModel . asset . extras ?. rnLoaderOptions ?. loaderExtension ; if ( loaderExtension ?. setupMaterial != null ) { loaderExtension . setupMaterial ( gltfModel , materialJson , material ) ; } } return material ; } static _createTexture ( texture , gltfModel , { autoDetectTransparency = false } = { } ) { const options = gltfModel . asset . extras ?. rnLoaderOptions ; const rnTexture = new Texture ( ) ; rnTexture . autoDetectTransparency = autoDetectTransparency ; rnTexture . autoResize = options ?. autoResizeTexture === true ; const textureOption = { magFilter : Is . exist ( texture . samplerObject ?. magFilter ) ? TextureParameter . from ( texture . samplerObject ! . magFilter ) : TextureParameter . Linear , minFilter : Is . exist ( texture . samplerObject ?. minFilter ) ? TextureParameter . from ( texture . samplerObject ! . minFilter ) : TextureParameter . Linear , wrapS : Is . exist ( texture . samplerObject ?. wrapS ) ? TextureParameter . from ( texture . samplerObject ! . wrapS ) : TextureParameter . Repeat , wrapT : Is . exist ( texture . samplerObject ?. wrapT ) ? TextureParameter . from ( texture . samplerObject ! . wrapT ) : TextureParameter . Repeat , } ; const image = texture . image as RnM2Image ; if ( image . image ) { const imageElem = image . image as HTMLImageElement ; const webglResourceRepository = CGAPIResourceRepository . getWebGLResourceRepository ( ) ; const isWebGL1 = ! webglResourceRepository . currentWebGLContextWrapper ?. isWebGL2 ; if ( isWebGL1 && ! this . __sizeIsPowerOfTwo ( imageElem ) && this . __needResizeToPowerOfTwoOnWebGl1 ( textureOption ) ) { rnTexture . autoResize = true ; } rnTexture . generateTextureFromImage ( imageElem , textureOption ) ; } else if ( image . basis ) { rnTexture . generateTextureFromBasis ( image . basis , textureOption ) ; } else if ( image . ktx2 ) { rnTexture . generateTextureFromKTX2 ( image . ktx2 , textureOption ) ; } if ( image . uri ) { rnTexture . name = image . uri ; } else { const ext = image . mimeType ?. split ( '/' ) [ 1 ] ; rnTexture . name = image . name + `.${ ext }` ; } return rnTexture ; } private static __needResizeToPowerOfTwoOnWebGl1 ( textureOption ) { if ( textureOption . wrapS !== TextureParameter . ClampToEdge || textureOption . wrapT !== TextureParameter . ClampToEdge || ( textureOption . minFilter !== TextureParameter . Linear && textureOption . minFilter !== TextureParameter . Nearest ) ) { return true ; } return false ; } private static __sizeIsPowerOfTwo ( image ) { const width = image . width ; const height = image . height ; if ( ( width & ( width - 1 ) ) === 0 && ( height & ( height - 1 ) ) === 0 ) { return true ; } else { return false ; } } private __needParameterInitialization ( materialJson , materialTypeName ) { if ( materialJson == null ) return false ; if ( materialTypeName . match ( /PbrUber/ ) != null || materialTypeName . match ( /ClassicUber/ ) != null ) { return true ; } else { return false ; } } private _checkRnGltfLoaderOptionsExist ( gltfModel ) { if ( gltfModel . asset . extras ?. rnLoaderOptions ) { return true ; } else { return false ; } } private __rewrapWithTypedArray ( typedArrayClass , uint8Array , byteOffset , length ) { return new typedArrayClass ( uint8Array . buffer , byteOffset + uint8Array . byteOffset , length ) ; } _checkBytesPerComponent ( accessor ) { let bytesPerComponent = 0 ; switch ( accessor . componentType ) { case 5120 : bytesPerComponent = 1 ; break ; case 5121 : bytesPerComponent = 1 ; break ; case 5122 : bytesPerComponent = 2 ; break ; case 5123 : bytesPerComponent = 2 ; break ; case 5124 : bytesPerComponent = 4 ; break ; case 5125 : bytesPerComponent = 4 ; break ; case 5126 : bytesPerComponent = 4 ; break ; default : break ; } return bytesPerComponent ; } _checkComponentNumber ( accessor ) { let componentN = 0 ; switch ( accessor . type ) { case 'SCALAR' : componentN = 1 ; break ; case 'VEC2' : componentN = 2 ; break ; case 'VEC3' : componentN = 3 ; break ; case 'VEC4' : componentN = 4 ; break ; case 'MAT4' : componentN = 16 ; break ; } return componentN ; } _checkDataViewMethod ( accessor ) { let dataViewMethod = '' ; switch ( accessor . componentType ) { case 5120 : dataViewMethod = 'getInt8' ; break ; case 5121 : dataViewMethod = 'getUint8' ; break ; case 5122 : dataViewMethod = 'getInt16' ; break ; case 5123 : dataViewMethod = 'getUint16' ; break ; case 5124 : dataViewMethod = 'getInt32' ; break ; case 5125 : dataViewMethod = 'getUint32' ; break ; case 5126 : dataViewMethod = 'getFloat32' ; break ; default : break ; } return dataViewMethod ; } static _isSystemLittleEndian ( ) { return ! ! new Uint8Array ( new Uint16Array ( [ 0x00ff ] ) . buffer ) [ 0 ] ; } _accessBinaryWithAccessor ( accessor ) { const bufferView = accessor . bufferViewObject ! ; const byteOffsetFromBuffer = ( bufferView . byteOffset ?? 0 ) + ( accessor . byteOffset ?? 0 ) ; const buffer = bufferView . bufferObject ! ; const uint8Array = buffer . buffer ! ; const componentN = this . _checkComponentNumber ( accessor ) ; const componentBytes = this . _checkBytesPerComponent ( accessor ) ; const dataViewMethod = this . _checkDataViewMethod ( accessor ) ; if ( Is . not . exist ( accessor . extras ) ) { accessor . extras = { attributeName : '' , toGetAsTypedArray : true , typedDataArray : new Float32Array ( ) , componentN : 0 , componentBytes : 4 , dataViewMethod : '' , } ; } accessor . extras . componentN = Is . exist ( accessor . extras ?. weightsArrayLength ) ? accessor . extras ! . weightsArrayLength : componentN ; accessor . extras . componentBytes = componentBytes ; accessor . extras . dataViewMethod = dataViewMethod ; const byteLength = componentBytes * componentN * accessor . count ; let float32Array = new Float32Array ( ) ; const numberArray = [ ] ; if ( ModelConverter . _isSystemLittleEndian ( ) ) { let typedDataArray = new Float32Array ( ) ; if ( dataViewMethod === 'getFloat32' ) { typedDataArray = this . __rewrapWithTypedArray ( Float32Array , uint8Array , byteOffsetFromBuffer , byteLength / componentBytes ) ; } else if ( dataViewMethod === 'getInt8' ) { typedDataArray = new Int8Array ( uint8Array , byteOffsetFromBuffer , byteLength / componentBytes ) ; } else if ( dataViewMethod === 'getUint8' ) { typedDataArray = new Uint8Array ( uint8Array , byteOffsetFromBuffer , byteLength / componentBytes ) ; } else if ( dataViewMethod === 'getInt16' ) { typedDataArray = this . __rewrapWithTypedArray ( Int16Array , uint8Array , byteOffsetFromBuffer , byteLength / componentBytes ) ; } else if ( dataViewMethod === 'getUint16' ) { typedDataArray = this . __rewrapWithTypedArray ( Uint16Array , uint8Array , byteOffsetFromBuffer , byteLength / componentBytes ) ; } else if ( dataViewMethod === 'getInt32' ) { typedDataArray = this . __rewrapWithTypedArray ( Int32Array , uint8Array , byteOffsetFromBuffer , byteLength / componentBytes ) ; } else if ( dataViewMethod === 'getUint32' ) { typedDataArray = this . __rewrapWithTypedArray ( Uint32Array , uint8Array , byteOffsetFromBuffer , byteLength / componentBytes ) ; } float32Array = this . __arrayToFloat32Array ( dataViewMethod , typedDataArray ) ; } else { const dataView = new DataView ( uint8Array . buffer , byteOffsetFromBuffer + uint8Array . byteOffset , byteLength ) ; const byteDelta = componentBytes * componentN ; const littleEndian = true ; for ( let pos = 0 ; pos < byteLength ; pos += byteDelta ) { switch ( accessor . type ) { case 'SCALAR' : numberArray . push ( dataView [ dataViewMethod ] ( pos , littleEndian ) ) ; break ; case 'VEC2' : numberArray . push ( dataView [ dataViewMethod ] ( pos , littleEndian ) ) ; numberArray . push ( dataView [ dataViewMethod ] ( pos + componentBytes , littleEndian ) ) ; break ; case 'VEC3' : numberArray . push ( dataView [ dataViewMethod ] ( pos , littleEndian ) ) ; numberArray . push ( dataView [ dataViewMethod ] ( pos + componentBytes , littleEndian ) ) ; numberArray . push ( dataView [ dataViewMethod ] ( pos + componentBytes * 2 , littleEndian ) ) ; break ; case 'VEC4' : for ( let i = 0 ; i < 4 ; i ++ ) { numberArray . push ( dataView [ dataViewMethod ] ( pos + componentBytes * i , littleEndian ) ) ; } break ; case 'MAT4' : for ( let i = 0 ; i < 16 ; i ++ ) { numberArray . push ( dataView [ dataViewMethod ] ( pos + componentBytes * i , littleEndian ) ) ; } break ; } } float32Array = this . __arrayToFloat32Array ( dataViewMethod , numberArray ) ; } accessor . extras ! . typedDataArray = float32Array ; return float32Array ; } private __arrayToFloat32Array ( dataViewMethod , numberArray ) { if ( dataViewMethod === 'getInt8' ) { return DataUtil . normalizedInt8ArrayToFloat32Array ( numberArray as unknown as Int8Array ) ; } else if ( dataViewMethod === 'getUint8' ) { return DataUtil . normalizedUint8ArrayToFloat32Array ( numberArray as unknown as Uint8Array ) ; } else if ( dataViewMethod === 'getInt16' ) { return DataUtil . normalizedInt16ArrayToFloat32Array ( numberArray as unknown as Int16Array ) ; } else if ( dataViewMethod === 'getUint16' ) { return DataUtil . normalizedUint16ArrayToFloat32Array ( numberArray as unknown as Uint16Array ) ; } else if ( dataViewMethod === 'getInt32' ) { console . error ( 'Not considered' ) ; return new Float32Array ( ) ; } else if ( dataViewMethod === 'getUint32' ) { console . error ( 'Not considered' ) ; return new Float32Array ( ) ; } else if ( dataViewMethod === 'getFloat32' ) { return new Float32Array ( numberArray ) ; } else { console . error ( 'Not considered' ) ; return new Float32Array ( ) ; } } private __addOffsetToIndices ( meshComponent ) { const primitiveNumber = meshComponent . mesh ! . getPrimitiveNumber ( ) ; let offsetSum = 0 ; for ( let i = 0 ; i < primitiveNumber ; i ++ ) { const primitive = meshComponent . mesh ! . getPrimitiveAt ( i ) ; const indicesAccessor = primitive . indicesAccessor ; if ( indicesAccessor ) { const elementNumber = indicesAccessor . elementCount ; for ( let j = 0 ; j < elementNumber ; j ++ ) { const index = indicesAccessor . getScalar ( j , { } ) ; indicesAccessor . setScalar ( j , index + offsetSum , { } ) ; } offsetSum += elementNumber ; } } } private __getRnAccessor ( accessor , rnBuffer ) { const bufferView = accessor . bufferViewObject ! ; const rnBufferView = rnBuffer . takeBufferViewWithByteOffset ( { byteLengthToNeed : bufferView . byteLength , byteStride : bufferView . byteStride ?? 0 , byteOffset : bufferView . byteOffset ?? 0 , } ) ; const rnAccessor = rnBufferView . takeAccessorWithByteOffset ( { compositionType : CompositionType . fromString ( accessor . type ) , componentType : ComponentType . from ( accessor . componentType ) , count : accessor . count , byteOffsetInBufferView : accessor . byteOffset ?? 0 , byteStride : accessor . byteStride , max : accessor . max , min : accessor . min , normalized : accessor . normalized , } ) ; return rnAccessor ; } private __copyRnAccessorAndBufferView ( srcRnAccessor ) { const byteSize = srcRnAccessor . elementCount * 3 * 4 ; const dstRnBuffer = MemoryManager . getInstance ( ) . createOrGetBuffer ( BufferUse . GPUVertexData ) ; const dstRnBufferView = dstRnBuffer . takeBufferView ( { byteLengthToNeed : byteSize , byteStride : 3 * 4 , } ) ; const dstRnAccessor = dstRnBufferView . takeAccessor ( { compositionType : CompositionType . Vec3 , componentType : ComponentType . Float , count : srcRnAccessor . elementCount , max : srcRnAccessor . max , min : srcRnAccessor . min , normalized : srcRnAccessor . normalized , } ) ; dstRnAccessor . copyBuffer ( srcRnAccessor ) ; return dstRnAccessor ; } private __createRnAccessor ( accessor , numOfAttributes , compositionNum , rnBuffer ) { const rnBufferView = rnBuffer . takeBufferView ( { byteLengthToNeed : numOfAttributes * compositionNum * 4 , byteStride : 0 , } ) ; const rnAccessor = rnBufferView . takeAccessorWithByteOffset ( { compositionType : CompositionType . fromString ( accessor . type ) , componentType : ComponentType . from ( accessor . componentType ) , count : numOfAttributes , byteStride : accessor . byteStride , byteOffsetInBufferView : accessor . byteOffset ?? 0 , max : accessor . max , min : accessor . min , normalized : accessor . normalized , } ) ; return rnAccessor ; } private __getRnBufferView ( bufferView , rnBuffer ) { const rnBufferView = rnBuffer . takeBufferViewWithByteOffset ( { byteLengthToNeed : bufferView . byteLength , byteStride : bufferView . byteStride ?? 0 , byteOffset : bufferView . byteOffset ?? 0 , } ) ; return rnBufferView ; } private __getGeometryFromDracoBuffer ( draco , decoder , arrayBuffer ) { const buffer = new draco . DecoderBuffer ( ) ; buffer . Init ( new Int8Array ( arrayBuffer ) , arrayBuffer . byteLength ) ; const geometryType = decoder . GetEncodedGeometryType ( buffer ) ; let dracoGeometry ; let decodingStatus ; if ( geometryType === draco . TRIANGULAR_MESH ) { dracoGeometry = new draco . Mesh ( ) ; decodingStatus = decoder . DecodeBufferToMesh ( buffer , dracoGeometry ) ; } else if ( geometryType === draco . POINT_CLOUD ) { dracoGeometry = new draco . PointCloud ( ) ; decodingStatus = decoder . DecodeBufferToPointCloud ( buffer , dracoGeometry ) ; } else { const errorMsg = 'Unknown geometry type.' ; console . error ( errorMsg ) ; } dracoGeometry . geometryType = geometryType ; if ( ! decodingStatus . ok ( ) || dracoGeometry . ptr === 0 ) { let errorMsg = 'Decoding failed: ' ; errorMsg += decodingStatus . error_msg ( ) ; console . error ( errorMsg ) ; draco . destroy ( decoder ) ; draco . destroy ( dracoGeometry ) ; return void 0 ; } draco . destroy ( buffer ) ; return dracoGeometry ; } __getIndicesFromDraco ( draco , decoder , dracoGeometry , triangleStripDrawMode ) { const geometryType = dracoGeometry . geometryType ; if ( geometryType !== draco . TRIANGULAR_MESH ) { return void 0 ; } let indices ; if ( triangleStripDrawMode ) { const stripsArray = new draco . DracoInt32Array ( ) ; decoder . GetTriangleStripsFromMesh ( dracoGeometry , stripsArray ) ; indices = new Uint32Array ( stripsArray . size ( ) ) ; for ( let i = 0 ; i < stripsArray . size ( ) ; ++ i ) { indices [ i ] = stripsArray . GetValue ( i ) ; } draco . destroy ( stripsArray ) ; } else { const numFaces = dracoGeometry . num_faces ( ) ; const numIndices = numFaces * 3 ; indices = new Uint32Array ( numIndices ) ; const ia = new draco . DracoInt32Array ( ) ; for ( let i = 0 ; i < numFaces ; ++ i ) { decoder . GetFaceFromMesh ( dracoGeometry , i , ia ) ; const index = i * 3 ; indices [ index ] = ia . GetValue ( 0 ) ; indices [ index + 1 ] = ia . GetValue ( 1 ) ; indices [ index + 2 ] = ia . GetValue ( 2 ) ; } draco . destroy ( ia ) ; } return indices ; } private __decodeDraco ( primitive , rnBuffers , gltfModel , map ) { const bufferView = gltfModel . bufferViews [ primitive . extensions . KHR_draco_mesh_compression . bufferView ] ; const rnBufferView = this . __getRnBufferView ( bufferView , rnBuffers [ bufferView . buffer ! ] ) ; const arraybufferOfBufferView = new Uint8Array ( rnBufferView . getUint8Array ( ) ) . buffer ; const draco = new DracoDecoderModule ( ) ; const decoder = new draco . Decoder ( ) ; const dracoGeometry = this . __getGeometryFromDracoBuffer ( draco , decoder , arraybufferOfBufferView ) ; if ( dracoGeometry == null ) { draco . destroy ( dracoGeometry ) ; draco . destroy ( decoder ) ; return void 0 ; } const numPoints = dracoGeometry . num_points ( ) ; const rnBufferForDraco = this . __createBufferForDecompressedData ( primitive , numPoints ) ; const primitiveMode = PrimitiveMode . from ( primitive . mode ! ) ; let isTriangleStrip = false ; if ( primitiveMode === PrimitiveMode . TriangleStrip ) { isTriangleStrip = true ; } const indices = this . __getIndicesFromDraco ( draco , decoder , dracoGeometry , isTriangleStrip ) ! ; const indicesRnAccessor = this . __createRnAccessor ( primitive . indicesObject ! , indices . length , 1 , rnBufferForDraco ) ; for ( let i = 0 ; i < indices . length ; i ++ ) { indicesRnAccessor . setScalar ( i , indices [ i ] , { } ) ; } for ( const attributeName in primitive . attributes ) { const dracoAttributeId = primitive . extensions . KHR_draco_mesh_compression . attributes [ attributeName ] ; const attributeGltf2Accessor = primitive . attributesObjects ! [ attributeName ] ; let attributeRnAccessor = undefined ; if ( Is . not . exist ( dracoAttributeId ) ) { attributeRnAccessor = this . __getRnAccessor ( attributeGltf2Accessor ! , rnBuffers [ attributeGltf2Accessor ! . bufferViewObject ! . buffer ! ] ) ; } else { const compositionNum = CompositionType . fromString ( attributeGltf2Accessor ! . type ) . getNumberOfComponents ( ) ; attributeRnAccessor = this . __createRnAccessor ( attributeGltf2Accessor ! , numPoints , compositionNum , rnBufferForDraco ) ; const dracoAttributePointer = decoder . GetAttributeByUniqueId ( dracoGeometry , dracoAttributeId ) ; const decompressedAttributeData = new draco . DracoFloat32Array ( ) ; decoder . GetAttributeFloatForAllPoints ( dracoGeometry , dracoAttributePointer , decompressedAttributeData ) ; for ( let i = 0 ; i < numPoints ; i ++ ) { if ( compositionNum === 1 ) { attributeRnAccessor . setScalar ( i , decompressedAttributeData . GetValue ( i * compositionNum ) , { } ) ; } else if ( compositionNum === 2 ) { attributeRnAccessor . setVec2 ( i , decompressedAttributeData . GetValue ( i * compositionNum ) , decompressedAttributeData . GetValue ( i * compositionNum + 1 ) , { } ) ; } else if ( compositionNum === 3 ) { attributeRnAccessor . setVec3 ( i , decompressedAttributeData . GetValue ( i * compositionNum ) , decompressedAttributeData . GetValue ( i * compositionNum + 1 ) , decompressedAttributeData . GetValue ( i * compositionNum + 2 ) , { } ) ; } else if ( compositionNum === 4 ) { attributeRnAccessor . setVec4 ( i , decompressedAttributeData . GetValue ( i * compositionNum ) , decompressedAttributeData . GetValue ( i * compositionNum + 1 ) , decompressedAttributeData . GetValue ( i * compositionNum + 2 ) , decompressedAttributeData . GetValue ( i * compositionNum + 3 ) , { } ) ; } } draco . destroy ( decompressedAttributeData ) ; } if ( Is . exist ( attributeGltf2Accessor ! . sparse ) ) { this . setSparseAccessor ( attributeGltf2Accessor ! , attributeRnAccessor ! ) ; } map . set ( VertexAttribute . fromString ( attributeGltf2Accessor ! . extras ! . attributeName ) , attributeRnAccessor ! ) ; } draco . destroy ( dracoGeometry ) ; draco . destroy ( decoder ) ; return indicesRnAccessor ; } static _setupTextureTransform ( textureJson , rnMaterial , textureTransformShaderSemantic , textureRotationShaderSemantic ) { if ( textureJson ?. extensions ?. KHR_texture_transform ) { const transform = MutableVector4 . fromCopyArray ( [ 1.0 , 1.0 , 0.0 , 0.0 ] ) ; let rotation = 0 ; const transformJson = textureJson . extensions . KHR_texture_transform ; if ( transformJson . scale != null ) { transform . x = transformJson . scale [ 0 ] ; transform . y = transformJson . scale [ 1 ] ; } if ( transformJson . offset != null ) { transform . z = transformJson . offset [ 0 ] ; transform . w = transformJson . offset [ 1 ] ; } if ( transformJson . rotation != null ) { rotation = transformJson . rotation ; } rnMaterial . setParameter ( textureTransformShaderSemantic , transform ) ; rnMaterial . setParameter ( textureRotationShaderSemantic , rotation ) ; } } private __createBufferForDecompressedData ( primitive , numPoints ) { let byteLengthOfBufferForDraco = 0 ; if ( Is . exist ( primitive . indices ) ) { const count = primitive . indicesObject ! . count ; byteLengthOfBufferForDraco += count * 4 ; } const drcAttributes = primitive . extensions . KHR_draco_mesh_compression . attributes ; for ( const attributeName in primitive . attributes ) { if ( drcAttributes [ attributeName ] == null ) { continue ; } const accessor = primitive . attributesObjects ! [ attributeName ] ; const compositionNum = CompositionType . fromString ( accessor ! . type ) . getNumberOfComponents ( ) ; const attributeByteLength = numPoints * compositionNum * 4 ; byteLengthOfBufferForDraco += attributeByteLength ; } return new Buffer ( { byteLength : byteLengthOfBufferForDraco , buffer : new ArrayBuffer ( byteLengthOfBufferForDraco ) , name : 'Draco' , byteAlign : 4 , } ) ; } }