2024-12-09 20:22:47 +00:00
/*
Open Asset Import Library ( assimp )
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
2026-06-09 12:46:56 -05:00
Copyright ( c ) 2006 - 2026 , assimp team
2024-12-09 20:22:47 +00:00
All rights reserved .
Redistribution and use of this software in source and binary forms ,
with or without modification , are permitted provided that the
following conditions are met :
* Redistributions of source code must retain the above
copyright notice , this list of conditions and the
following disclaimer .
* Redistributions in binary form must reproduce the above
copyright notice , this list of conditions and the
following disclaimer in the documentation and / or other
materials provided with the distribution .
* Neither the name of the assimp team , nor the names of its
contributors may be used to endorse or promote products
derived from this software without specific prior
written permission of the assimp team .
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
" AS IS " AND ANY EXPRESS OR IMPLIED WARRANTIES , INCLUDING , BUT NOT
LIMITED TO , THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED . IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT , INDIRECT , INCIDENTAL ,
SPECIAL , EXEMPLARY , OR CONSEQUENTIAL DAMAGES ( INCLUDING , BUT NOT
LIMITED TO , PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES ; LOSS OF USE ,
DATA , OR PROFITS ; OR BUSINESS INTERRUPTION ) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY , WHETHER IN CONTRACT , STRICT LIABILITY , OR TORT
( INCLUDING NEGLIGENCE OR OTHERWISE ) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE , EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE .
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
/** @file USDLoader.cpp
* @ brief Implementation of the USD importer class
*/
# ifndef ASSIMP_BUILD_NO_USD_IMPORTER
2026-06-09 12:46:56 -05:00
# include "USDLoaderImplTinyusdz.h"
# include "USDLoaderImplTinyusdzHelper.h"
# include "USDLoaderUtil.h"
# include "USDPreprocessor.h"
# include "io-util.hh" // namespace tinyusdz::io
# include "tydra/scene-access.hh"
# include "tydra/shader-network.hh"
2024-12-09 20:22:47 +00:00
# include <memory>
# include <sstream>
// internal headers
2026-06-09 12:46:56 -05:00
# include "assimp/MemoryIOWrapper.h"
2024-12-09 20:22:47 +00:00
# include <assimp/CreateAnimMesh.h>
# include <assimp/DefaultIOSystem.h>
2026-06-09 12:46:56 -05:00
# include <assimp/IOStreamBuffer.h>
# include <assimp/StreamReader.h>
# include <assimp/StringUtils.h>
# include <assimp/ai_assert.h>
# include <assimp/anim.h>
2024-12-09 20:22:47 +00:00
# include <assimp/fast_atof.h>
# include <assimp/importerdesc.h>
2026-06-09 12:46:56 -05:00
# include <assimp/DefaultLogger.hpp>
2024-12-09 20:22:47 +00:00
# include <assimp/IOSystem.hpp>
2026-06-09 12:46:56 -05:00
# include <assimp/Importer.hpp>
2024-12-09 20:22:47 +00:00
# include "../../../contrib/tinyusdz/assimp_tinyusdz_logging.inc"
namespace {
static constexpr char TAG [ ] = " tinyusdz loader " ;
}
namespace Assimp {
2026-06-09 12:46:56 -05:00
using Assimp : : tinyUsdzMat4ToAiMat4 ;
using Assimp : : tinyusdzNodeTypeFor ;
using tinyusdz : : tydra : : NodeType ;
using namespace tinyusdz : : tydra ;
void USDImporterImplTinyusdz : : InternReadFile ( const std : : string & pFile , aiScene * pScene , IOSystem * pIOHandler ) {
2024-12-09 20:22:47 +00:00
// Grab filename for logging purposes
size_t pos = pFile . find_last_of ( ' / ' ) ;
2026-06-09 12:46:56 -05:00
std : : string basePath = pFile . substr ( 0 , pos ) ;
std : : string nameWExt = pFile . substr ( pos + 1 ) ;
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
ss < < " InternReadFile(): model " < < nameWExt ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
bool is_load_from_mem { pFile . substr ( 0 , AI_MEMORYIO_MAGIC_FILENAME_LENGTH ) = = AI_MEMORYIO_MAGIC_FILENAME } ;
std : : vector < uint8_t > in_mem_data ;
if ( is_load_from_mem ) {
auto stream_closer = [ pIOHandler ] ( IOStream * pStream ) {
pIOHandler - > Close ( pStream ) ;
} ;
std : : unique_ptr < IOStream , decltype ( stream_closer ) > file_stream ( pIOHandler - > Open ( pFile , " rb " ) , stream_closer ) ;
if ( ! file_stream ) {
throw DeadlyImportError ( " Failed to open file " , pFile , " . " ) ;
}
size_t file_size { file_stream - > FileSize ( ) } ;
in_mem_data . resize ( file_size ) ;
file_stream - > Read ( in_mem_data . data ( ) , 1 , file_size ) ;
}
bool ret { false } ;
tinyusdz : : USDLoadOptions options ;
tinyusdz : : Stage stage ;
std : : string warn , err ;
bool is_usdz { false } ;
if ( isUsdc ( pFile ) ) {
ret = is_load_from_mem ? LoadUSDCFromMemory ( in_mem_data . data ( ) , in_mem_data . size ( ) , pFile , & stage , & warn , & err , options ) :
LoadUSDCFromFile ( pFile , & stage , & warn , & err , options ) ;
ss . str ( " " ) ;
ss < < " InternReadFile(): LoadUSDCFromFile() result: " < < ret ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
} else if ( isUsda ( pFile ) ) {
ret = is_load_from_mem ? LoadUSDAFromMemory ( in_mem_data . data ( ) , in_mem_data . size ( ) , pFile , & stage , & warn , & err , options ) :
LoadUSDAFromFile ( pFile , & stage , & warn , & err , options ) ;
ss . str ( " " ) ;
ss < < " InternReadFile(): LoadUSDAFromFile() result: " < < ret ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
} else if ( isUsdz ( pFile ) ) {
ret = is_load_from_mem ? LoadUSDZFromMemory ( in_mem_data . data ( ) , in_mem_data . size ( ) , pFile , & stage , & warn , & err , options ) :
LoadUSDZFromFile ( pFile , & stage , & warn , & err , options ) ;
is_usdz = true ;
ss . str ( " " ) ;
ss < < " InternReadFile(): LoadUSDZFromFile() result: " < < ret ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
} else if ( isUsd ( pFile ) ) {
ret = is_load_from_mem ? LoadUSDFromMemory ( in_mem_data . data ( ) , in_mem_data . size ( ) , pFile , & stage , & warn , & err , options ) :
LoadUSDFromFile ( pFile , & stage , & warn , & err , options ) ;
ss . str ( " " ) ;
ss < < " InternReadFile(): LoadUSDFromFile() result: " < < ret ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
}
if ( warn . empty ( ) & & err . empty ( ) ) {
ss . str ( " " ) ;
ss < < " InternReadFile(): load free of warnings/errors " ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
} else {
if ( ! warn . empty ( ) ) {
ss . str ( " " ) ;
ss < < " InternReadFile(): WARNING reported: " < < warn ;
TINYUSDZLOGW ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
}
if ( ! err . empty ( ) ) {
ss . str ( " " ) ;
ss < < " InternReadFile(): ERROR reported: " < < err ;
TINYUSDZLOGE ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
}
}
if ( ! ret ) {
ss . str ( " " ) ;
ss < < " InternReadFile(): ERROR: load failed! ret: " < < ret ;
TINYUSDZLOGE ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
return ;
}
2026-06-09 12:46:56 -05:00
RenderScene render_scene ;
RenderSceneConverter converter ;
RenderSceneConverterEnv env ( stage ) ;
2024-12-09 20:22:47 +00:00
std : : string usd_basedir = tinyusdz : : io : : GetBaseDir ( pFile ) ;
env . set_search_paths ( { usd_basedir } ) ; // {} needed to convert to vector of char
// NOTE: Pointer address of usdz_asset must be valid until the call of RenderSceneConverter::ConvertToRenderScene.
tinyusdz : : USDZAsset usdz_asset ;
if ( is_usdz ) {
bool is_read_USDZ_asset = is_load_from_mem ? tinyusdz : : ReadUSDZAssetInfoFromMemory ( in_mem_data . data ( ) , in_mem_data . size ( ) , false , & usdz_asset , & warn , & err ) :
tinyusdz : : ReadUSDZAssetInfoFromFile ( pFile , & usdz_asset , & warn , & err ) ;
if ( ! is_read_USDZ_asset ) {
if ( ! warn . empty ( ) ) {
ss . str ( " " ) ;
ss < < " InternReadFile(): ReadUSDZAssetInfoFromFile: WARNING reported: " < < warn ;
TINYUSDZLOGW ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
}
if ( ! err . empty ( ) ) {
ss . str ( " " ) ;
ss < < " InternReadFile(): ReadUSDZAssetInfoFromFile: ERROR reported: " < < err ;
TINYUSDZLOGE ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
}
ss . str ( " " ) ;
ss < < " InternReadFile(): ReadUSDZAssetInfoFromFile: ERROR! " ;
TINYUSDZLOGE ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
} else {
ss . str ( " " ) ;
ss < < " InternReadFile(): ReadUSDZAssetInfoFromFile: OK " ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
}
tinyusdz : : AssetResolutionResolver arr ;
if ( ! tinyusdz : : SetupUSDZAssetResolution ( arr , & usdz_asset ) ) {
ss . str ( " " ) ;
ss < < " InternReadFile(): SetupUSDZAssetResolution: ERROR: load failed! ret: " < < ret ;
TINYUSDZLOGE ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
} else {
ss . str ( " " ) ;
ss < < " InternReadFile(): SetupUSDZAssetResolution: OK " ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
env . asset_resolver = arr ;
}
}
ret = converter . ConvertToRenderScene ( env , & render_scene ) ;
if ( ! ret ) {
ss . str ( " " ) ;
ss < < " InternReadFile(): ConvertToRenderScene() failed! " ;
TINYUSDZLOGE ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
return ;
}
// sanityCheckNodesRecursive(pScene->mRootNode);
animations ( render_scene , pScene ) ;
meshes ( render_scene , pScene , nameWExt ) ;
materials ( render_scene , pScene , nameWExt ) ;
textures ( render_scene , pScene , nameWExt ) ;
textureImages ( render_scene , pScene , nameWExt ) ;
buffers ( render_scene , pScene , nameWExt ) ;
2026-06-09 12:46:56 -05:00
pScene - > mRootNode = nodesRecursive ( nullptr , render_scene . nodes [ 0 ] , render_scene . skeletons ) ;
2024-12-09 20:22:47 +00:00
setupBlendShapes ( render_scene , pScene , nameWExt ) ;
}
2026-06-09 12:46:56 -05:00
void USDImporterImplTinyusdz : : animations ( const tinyusdz : : tydra : : RenderScene & render_scene , aiScene * pScene ) {
2024-12-09 20:22:47 +00:00
if ( render_scene . animations . empty ( ) ) {
return ;
}
2026-06-09 12:46:56 -05:00
pScene - > mNumAnimations = unsigned ( render_scene . animations . size ( ) ) ;
2024-12-09 20:22:47 +00:00
pScene - > mAnimations = new aiAnimation * [ pScene - > mNumAnimations ] ;
2026-06-09 12:46:56 -05:00
for ( unsigned animationIndex = 0 ; animationIndex < pScene - > mNumAnimations ; + + animationIndex ) {
2024-12-09 20:22:47 +00:00
const auto & animation = render_scene . animations [ animationIndex ] ;
auto newAiAnimation = new aiAnimation ( ) ;
pScene - > mAnimations [ animationIndex ] = newAiAnimation ;
newAiAnimation - > mName = animation . abs_path ;
if ( animation . channels_map . empty ( ) ) {
newAiAnimation - > mNumChannels = 0 ;
continue ;
}
// each channel affects a node (joint)
2026-06-09 12:46:56 -05:00
newAiAnimation - > mTicksPerSecond = render_scene . meta . framesPerSecond ;
newAiAnimation - > mNumChannels = unsigned ( animation . channels_map . size ( ) ) ;
2024-12-09 20:22:47 +00:00
newAiAnimation - > mChannels = new aiNodeAnim * [ newAiAnimation - > mNumChannels ] ;
int channelIndex = 0 ;
for ( const auto & [ jointName , animationChannelMap ] : animation . channels_map ) {
auto newAiNodeAnim = new aiNodeAnim ( ) ;
newAiAnimation - > mChannels [ channelIndex ] = newAiNodeAnim ;
newAiNodeAnim - > mNodeName = jointName ;
newAiAnimation - > mDuration = 0 ;
std : : vector < aiVectorKey > positionKeys ;
std : : vector < aiQuatKey > rotationKeys ;
std : : vector < aiVectorKey > scalingKeys ;
for ( const auto & [ channelType , animChannel ] : animationChannelMap ) {
switch ( channelType ) {
2026-06-09 12:46:56 -05:00
case AnimationChannel : : ChannelType : : Rotation :
2024-12-09 20:22:47 +00:00
if ( animChannel . rotations . static_value . has_value ( ) ) {
rotationKeys . emplace_back ( 0 , tinyUsdzQuatToAiQuat ( animChannel . rotations . static_value . value ( ) ) ) ;
}
for ( const auto & rotationAnimSampler : animChannel . rotations . samples ) {
if ( rotationAnimSampler . t > newAiAnimation - > mDuration ) {
newAiAnimation - > mDuration = rotationAnimSampler . t ;
}
rotationKeys . emplace_back ( rotationAnimSampler . t , tinyUsdzQuatToAiQuat ( rotationAnimSampler . value ) ) ;
}
break ;
2026-06-09 12:46:56 -05:00
case AnimationChannel : : ChannelType : : Scale :
2024-12-09 20:22:47 +00:00
if ( animChannel . scales . static_value . has_value ( ) ) {
scalingKeys . emplace_back ( 0 , tinyUsdzScaleOrPosToAssimp ( animChannel . scales . static_value . value ( ) ) ) ;
}
for ( const auto & scaleAnimSampler : animChannel . scales . samples ) {
if ( scaleAnimSampler . t > newAiAnimation - > mDuration ) {
newAiAnimation - > mDuration = scaleAnimSampler . t ;
}
scalingKeys . emplace_back ( scaleAnimSampler . t , tinyUsdzScaleOrPosToAssimp ( scaleAnimSampler . value ) ) ;
}
break ;
2026-06-09 12:46:56 -05:00
case AnimationChannel : : ChannelType : : Transform :
2024-12-09 20:22:47 +00:00
if ( animChannel . transforms . static_value . has_value ( ) ) {
aiVector3D position ;
aiVector3D scale ;
aiQuaternion rotation ;
tinyUsdzMat4ToAiMat4 ( animChannel . transforms . static_value . value ( ) . m ) . Decompose ( scale , rotation , position ) ;
positionKeys . emplace_back ( 0 , position ) ;
scalingKeys . emplace_back ( 0 , scale ) ;
rotationKeys . emplace_back ( 0 , rotation ) ;
}
for ( const auto & transformAnimSampler : animChannel . transforms . samples ) {
if ( transformAnimSampler . t > newAiAnimation - > mDuration ) {
newAiAnimation - > mDuration = transformAnimSampler . t ;
}
aiVector3D position ;
aiVector3D scale ;
aiQuaternion rotation ;
tinyUsdzMat4ToAiMat4 ( transformAnimSampler . value . m ) . Decompose ( scale , rotation , position ) ;
positionKeys . emplace_back ( transformAnimSampler . t , position ) ;
scalingKeys . emplace_back ( transformAnimSampler . t , scale ) ;
rotationKeys . emplace_back ( transformAnimSampler . t , rotation ) ;
}
break ;
2026-06-09 12:46:56 -05:00
case AnimationChannel : : ChannelType : : Translation :
2024-12-09 20:22:47 +00:00
if ( animChannel . translations . static_value . has_value ( ) ) {
positionKeys . emplace_back ( 0 , tinyUsdzScaleOrPosToAssimp ( animChannel . translations . static_value . value ( ) ) ) ;
}
for ( const auto & translationAnimSampler : animChannel . translations . samples ) {
if ( translationAnimSampler . t > newAiAnimation - > mDuration ) {
newAiAnimation - > mDuration = translationAnimSampler . t ;
}
positionKeys . emplace_back ( translationAnimSampler . t , tinyUsdzScaleOrPosToAssimp ( translationAnimSampler . value ) ) ;
}
break ;
default :
TINYUSDZLOGW ( TAG , " Unsupported animation channel type (%s). Please update the USD importer to support this animation channel. " , tinyusdzAnimChannelTypeFor ( channelType ) . c_str ( ) ) ;
}
}
2026-06-09 12:46:56 -05:00
newAiNodeAnim - > mNumPositionKeys = unsigned ( positionKeys . size ( ) ) ;
2024-12-09 20:22:47 +00:00
newAiNodeAnim - > mPositionKeys = new aiVectorKey [ newAiNodeAnim - > mNumPositionKeys ] ;
std : : move ( positionKeys . begin ( ) , positionKeys . end ( ) , newAiNodeAnim - > mPositionKeys ) ;
2026-06-09 12:46:56 -05:00
newAiNodeAnim - > mNumRotationKeys = unsigned ( rotationKeys . size ( ) ) ;
2024-12-09 20:22:47 +00:00
newAiNodeAnim - > mRotationKeys = new aiQuatKey [ newAiNodeAnim - > mNumRotationKeys ] ;
std : : move ( rotationKeys . begin ( ) , rotationKeys . end ( ) , newAiNodeAnim - > mRotationKeys ) ;
2026-06-09 12:46:56 -05:00
newAiNodeAnim - > mNumScalingKeys = unsigned ( scalingKeys . size ( ) ) ;
2024-12-09 20:22:47 +00:00
newAiNodeAnim - > mScalingKeys = new aiVectorKey [ newAiNodeAnim - > mNumScalingKeys ] ;
std : : move ( scalingKeys . begin ( ) , scalingKeys . end ( ) , newAiNodeAnim - > mScalingKeys ) ;
+ + channelIndex ;
}
}
}
void USDImporterImplTinyusdz : : meshes (
const tinyusdz : : tydra : : RenderScene & render_scene ,
aiScene * pScene ,
const std : : string & nameWExt ) {
2026-06-09 12:46:56 -05:00
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
pScene - > mNumMeshes = static_cast < unsigned int > ( render_scene . meshes . size ( ) ) ;
pScene - > mMeshes = new aiMesh * [ pScene - > mNumMeshes ] ( ) ;
ss . str ( " " ) ;
ss < < " meshes(): pScene->mNumMeshes: " < < pScene - > mNumMeshes ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
// Export meshes
for ( size_t meshIdx = 0 ; meshIdx < pScene - > mNumMeshes ; meshIdx + + ) {
pScene - > mMeshes [ meshIdx ] = new aiMesh ( ) ;
pScene - > mMeshes [ meshIdx ] - > mName . Set ( render_scene . meshes [ meshIdx ] . prim_name ) ;
ss . str ( " " ) ;
2026-06-09 12:46:56 -05:00
ss < < " mesh[ " < < meshIdx < < " ]: " < < render_scene . meshes [ meshIdx ] . joint_and_weights . jointIndices . size ( ) < < " jointIndices, " < < render_scene . meshes [ meshIdx ] . joint_and_weights . jointWeights . size ( ) < < " jointWeights, elementSize: " < < render_scene . meshes [ meshIdx ] . joint_and_weights . elementSize ;
2024-12-09 20:22:47 +00:00
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
ss . str ( " " ) ;
ss < < " skel_id: " < < render_scene . meshes [ meshIdx ] . skel_id ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
if ( render_scene . meshes [ meshIdx ] . material_id > - 1 ) {
pScene - > mMeshes [ meshIdx ] - > mMaterialIndex = render_scene . meshes [ meshIdx ] . material_id ;
}
verticesForMesh ( render_scene , pScene , meshIdx , nameWExt ) ;
facesForMesh ( render_scene , pScene , meshIdx , nameWExt ) ;
// Some models infer normals from faces, but others need them e.g.
// - apple "toy car" canopy normals will be wrong
// - human "untitled" model (tinyusdz issue #115) will be "splotchy"
normalsForMesh ( render_scene , pScene , meshIdx , nameWExt ) ;
materialsForMesh ( render_scene , pScene , meshIdx , nameWExt ) ;
uvsForMesh ( render_scene , pScene , meshIdx , nameWExt ) ;
}
}
2026-06-09 12:46:56 -05:00
void USDImporterImplTinyusdz : : verticesForMesh ( const tinyusdz : : tydra : : RenderScene & render_scene ,
aiScene * pScene , size_t meshIdx , const std : : string & ) {
2024-12-09 20:22:47 +00:00
const auto numVertices = static_cast < unsigned int > ( render_scene . meshes [ meshIdx ] . points . size ( ) ) ;
pScene - > mMeshes [ meshIdx ] - > mNumVertices = numVertices ;
pScene - > mMeshes [ meshIdx ] - > mVertices = new aiVector3D [ pScene - > mMeshes [ meshIdx ] - > mNumVertices ] ;
// Check if this is a skinned mesh
if ( int skeleton_id = render_scene . meshes [ meshIdx ] . skel_id ; skeleton_id > - 1 ) {
// Recursively iterate to collect all the joints in the hierarchy into a flattened array
std : : vector < const tinyusdz : : tydra : : SkelNode * > skeletonNodes ;
skeletonNodes . push_back ( & render_scene . skeletons [ skeleton_id ] . root_node ) ;
for ( int i = 0 ; i < skeletonNodes . size ( ) ; + + i ) {
for ( const auto & child : skeletonNodes [ i ] - > children ) {
skeletonNodes . push_back ( & child ) ;
}
}
// Convert USD skeleton joints to Assimp bones
2026-06-09 12:46:56 -05:00
const unsigned int numBones = unsigned ( skeletonNodes . size ( ) ) ;
2024-12-09 20:22:47 +00:00
pScene - > mMeshes [ meshIdx ] - > mNumBones = numBones ;
pScene - > mMeshes [ meshIdx ] - > mBones = new aiBone * [ numBones ] ;
for ( unsigned int i = 0 ; i < numBones ; + + i ) {
const tinyusdz : : tydra : : SkelNode * skeletonNode = skeletonNodes [ i ] ;
const int boneIndex = skeletonNode - > joint_id ;
// Sorted so that Assimp bone ids align with USD joint id
auto outputBone = new aiBone ( ) ;
outputBone - > mName = aiString ( skeletonNode - > joint_name ) ;
outputBone - > mOffsetMatrix = tinyUsdzMat4ToAiMat4 ( skeletonNode - > bind_transform . m ) . Inverse ( ) ;
pScene - > mMeshes [ meshIdx ] - > mBones [ boneIndex ] = outputBone ;
}
// Vertex weights
std : : vector < std : : vector < aiVertexWeight > > aiBonesVertexWeights ;
aiBonesVertexWeights . resize ( numBones ) ;
const std : : vector < int > & jointIndices = render_scene . meshes [ meshIdx ] . joint_and_weights . jointIndices ;
const std : : vector < float > & jointWeightIndices = render_scene . meshes [ meshIdx ] . joint_and_weights . jointWeights ;
const int numWeightsPerVertex = render_scene . meshes [ meshIdx ] . joint_and_weights . elementSize ;
for ( unsigned int vertexIndex = 0 ; vertexIndex < numVertices ; + + vertexIndex ) {
for ( int weightIndex = 0 ; weightIndex < numWeightsPerVertex ; + + weightIndex ) {
const unsigned int index = vertexIndex * numWeightsPerVertex + weightIndex ;
const float jointWeight = jointWeightIndices [ index ] ;
if ( jointWeight > 0 ) {
const int jointIndex = jointIndices [ index ] ;
aiBonesVertexWeights [ jointIndex ] . emplace_back ( vertexIndex , jointWeight ) ;
}
}
}
2026-06-09 12:46:56 -05:00
for ( unsigned boneIndex = 0 ; boneIndex < numBones ; + + boneIndex ) {
const auto numWeightsForBone = unsigned ( aiBonesVertexWeights [ boneIndex ] . size ( ) ) ;
2024-12-09 20:22:47 +00:00
pScene - > mMeshes [ meshIdx ] - > mBones [ boneIndex ] - > mWeights = new aiVertexWeight [ numWeightsForBone ] ;
pScene - > mMeshes [ meshIdx ] - > mBones [ boneIndex ] - > mNumWeights = numWeightsForBone ;
std : : swap_ranges ( aiBonesVertexWeights [ boneIndex ] . begin ( ) , aiBonesVertexWeights [ boneIndex ] . end ( ) , pScene - > mMeshes [ meshIdx ] - > mBones [ boneIndex ] - > mWeights ) ;
}
2026-06-09 12:46:56 -05:00
} // Skinned mesh end
2024-12-09 20:22:47 +00:00
for ( size_t j = 0 ; j < pScene - > mMeshes [ meshIdx ] - > mNumVertices ; + + j ) {
pScene - > mMeshes [ meshIdx ] - > mVertices [ j ] . x = render_scene . meshes [ meshIdx ] . points [ j ] [ 0 ] ;
pScene - > mMeshes [ meshIdx ] - > mVertices [ j ] . y = render_scene . meshes [ meshIdx ] . points [ j ] [ 1 ] ;
pScene - > mMeshes [ meshIdx ] - > mVertices [ j ] . z = render_scene . meshes [ meshIdx ] . points [ j ] [ 2 ] ;
}
}
2026-06-09 12:46:56 -05:00
void USDImporterImplTinyusdz : : facesForMesh ( const RenderScene & render_scene , aiScene * pScene ,
size_t meshIdx , const std : : string & ) {
2024-12-09 20:22:47 +00:00
pScene - > mMeshes [ meshIdx ] - > mNumFaces = static_cast < unsigned int > ( render_scene . meshes [ meshIdx ] . faceVertexCounts ( ) . size ( ) ) ;
pScene - > mMeshes [ meshIdx ] - > mFaces = new aiFace [ pScene - > mMeshes [ meshIdx ] - > mNumFaces ] ( ) ;
size_t faceVertIdxOffset = 0 ;
for ( size_t faceIdx = 0 ; faceIdx < pScene - > mMeshes [ meshIdx ] - > mNumFaces ; + + faceIdx ) {
pScene - > mMeshes [ meshIdx ] - > mFaces [ faceIdx ] . mNumIndices = render_scene . meshes [ meshIdx ] . faceVertexCounts ( ) [ faceIdx ] ;
pScene - > mMeshes [ meshIdx ] - > mFaces [ faceIdx ] . mIndices = new unsigned int [ pScene - > mMeshes [ meshIdx ] - > mFaces [ faceIdx ] . mNumIndices ] ;
for ( size_t j = 0 ; j < pScene - > mMeshes [ meshIdx ] - > mFaces [ faceIdx ] . mNumIndices ; + + j ) {
pScene - > mMeshes [ meshIdx ] - > mFaces [ faceIdx ] . mIndices [ j ] =
render_scene . meshes [ meshIdx ] . faceVertexIndices ( ) [ j + faceVertIdxOffset ] ;
}
faceVertIdxOffset + = pScene - > mMeshes [ meshIdx ] - > mFaces [ faceIdx ] . mNumIndices ;
}
}
2026-06-09 12:46:56 -05:00
void USDImporterImplTinyusdz : : normalsForMesh ( const RenderScene & render_scene , aiScene * pScene ,
size_t meshIdx , const std : : string & ) {
2024-12-09 20:22:47 +00:00
pScene - > mMeshes [ meshIdx ] - > mNormals = new aiVector3D [ pScene - > mMeshes [ meshIdx ] - > mNumVertices ] ;
const float * floatPtr = reinterpret_cast < const float * > ( render_scene . meshes [ meshIdx ] . normals . get_data ( ) . data ( ) ) ;
for ( size_t vertIdx = 0 , fpj = 0 ; vertIdx < pScene - > mMeshes [ meshIdx ] - > mNumVertices ; + + vertIdx , fpj + = 3 ) {
pScene - > mMeshes [ meshIdx ] - > mNormals [ vertIdx ] . x = floatPtr [ fpj ] ;
pScene - > mMeshes [ meshIdx ] - > mNormals [ vertIdx ] . y = floatPtr [ fpj + 1 ] ;
pScene - > mMeshes [ meshIdx ] - > mNormals [ vertIdx ] . z = floatPtr [ fpj + 2 ] ;
}
}
2026-06-09 12:46:56 -05:00
void USDImporterImplTinyusdz : : materialsForMesh ( const RenderScene & , aiScene * ,
size_t , const std : : string & ) {
// todo
2024-12-09 20:22:47 +00:00
}
void USDImporterImplTinyusdz : : uvsForMesh (
const tinyusdz : : tydra : : RenderScene & render_scene ,
aiScene * pScene ,
size_t meshIdx ,
2026-06-09 12:46:56 -05:00
const std : : string & ) {
2024-12-09 20:22:47 +00:00
const size_t uvSlotsCount = render_scene . meshes [ meshIdx ] . texcoords . size ( ) ;
if ( uvSlotsCount < 1 ) {
return ;
}
pScene - > mMeshes [ meshIdx ] - > mTextureCoords [ 0 ] = new aiVector3D [ pScene - > mMeshes [ meshIdx ] - > mNumVertices ] ;
pScene - > mMeshes [ meshIdx ] - > mNumUVComponents [ 0 ] = 2 ; // U and V stored in "x", "y" of aiVector3D.
for ( unsigned int uvSlotIdx = 0 ; uvSlotIdx < uvSlotsCount ; + + uvSlotIdx ) {
const auto uvsForSlot = render_scene . meshes [ meshIdx ] . texcoords . at ( uvSlotIdx ) ;
if ( uvsForSlot . get_data ( ) . size ( ) = = 0 ) {
continue ;
}
const float * floatPtr = reinterpret_cast < const float * > ( uvsForSlot . get_data ( ) . data ( ) ) ;
for ( size_t vertIdx = 0 , fpj = 0 ; vertIdx < pScene - > mMeshes [ meshIdx ] - > mNumVertices ; + + vertIdx , fpj + = 2 ) {
pScene - > mMeshes [ meshIdx ] - > mTextureCoords [ uvSlotIdx ] [ vertIdx ] . x = floatPtr [ fpj ] ;
pScene - > mMeshes [ meshIdx ] - > mTextureCoords [ uvSlotIdx ] [ vertIdx ] . y = floatPtr [ fpj + 1 ] ;
}
}
}
2026-06-09 12:46:56 -05:00
static std : : string nameForTextureWithId ( const RenderScene & render_scene , const int targetId ) {
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
std : : string texName ;
for ( const auto & image : render_scene . images ) {
if ( image . buffer_id = = targetId ) {
texName = image . asset_identifier ;
ss . str ( " " ) ;
ss < < " nameForTextureWithId(): found texture " < < texName < < " with target id " < < targetId ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
break ;
}
}
ss . str ( " " ) ;
ss < < " nameForTextureWithId(): ERROR! Failed to find texture with target id " < < targetId ;
TINYUSDZLOGE ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
return texName ;
}
static void assignTexture (
2026-06-09 12:46:56 -05:00
const RenderScene & render_scene ,
const RenderMaterial & ,
2024-12-09 20:22:47 +00:00
aiMaterial * mat ,
const int textureId ,
const int aiTextureType ) {
std : : string name = nameForTextureWithId ( render_scene , textureId ) ;
2026-06-09 12:46:56 -05:00
aiString texName ;
texName . Set ( name ) ;
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
ss < < " assignTexture(): name: " < < name ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
// TODO: verify hard-coded '0' index is correct
2026-06-09 12:46:56 -05:00
mat - > AddProperty ( & texName , _AI_MATKEY_TEXTURE_BASE , aiTextureType , 0 ) ;
2024-12-09 20:22:47 +00:00
}
void USDImporterImplTinyusdz : : materials (
const tinyusdz : : tydra : : RenderScene & render_scene ,
aiScene * pScene ,
const std : : string & nameWExt ) {
2026-06-09 12:46:56 -05:00
const size_t numMaterials { render_scene . materials . size ( ) } ;
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
ss < < " materials(): model " < < nameWExt < < " , numMaterials: " < < numMaterials ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
pScene - > mNumMaterials = 0 ;
if ( render_scene . materials . empty ( ) ) {
return ;
}
2026-06-09 12:46:56 -05:00
2024-12-09 20:22:47 +00:00
pScene - > mMaterials = new aiMaterial * [ render_scene . materials . size ( ) ] ;
for ( const auto & material : render_scene . materials ) {
ss . str ( " " ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: name: | " < < material . name < < " |, disp name: | " < < material . display_name < < " | " ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
aiMaterial * mat = new aiMaterial ;
2026-06-09 12:46:56 -05:00
aiString materialName ;
materialName . Set ( material . name ) ;
2024-12-09 20:22:47 +00:00
mat - > AddProperty ( materialName , AI_MATKEY_NAME ) ;
mat - > AddProperty (
2026-06-09 12:46:56 -05:00
reinterpret_cast < const aiColor3D * > ( material . surfaceShader . diffuseColor . value . data ( ) ) ,
2024-12-09 20:22:47 +00:00
1 , AI_MATKEY_COLOR_DIFFUSE ) ;
mat - > AddProperty (
2026-06-09 12:46:56 -05:00
reinterpret_cast < const aiColor3D * > ( material . surfaceShader . specularColor . value . data ( ) ) ,
2024-12-09 20:22:47 +00:00
1 , AI_MATKEY_COLOR_SPECULAR ) ;
mat - > AddProperty (
2026-06-09 12:46:56 -05:00
reinterpret_cast < const aiColor3D * > ( material . surfaceShader . emissiveColor . value . data ( ) ) ,
2024-12-09 20:22:47 +00:00
1 , AI_MATKEY_COLOR_EMISSIVE ) ;
ss . str ( " " ) ;
if ( material . surfaceShader . diffuseColor . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . diffuseColor . texture_id , aiTextureType_DIFFUSE ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: diff tex id " < < material . surfaceShader . diffuseColor . texture_id < < " \n " ;
}
if ( material . surfaceShader . specularColor . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . specularColor . texture_id , aiTextureType_SPECULAR ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: spec tex id " < < material . surfaceShader . specularColor . texture_id < < " \n " ;
}
if ( material . surfaceShader . normal . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . normal . texture_id , aiTextureType_NORMALS ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: normal tex id " < < material . surfaceShader . normal . texture_id < < " \n " ;
}
if ( material . surfaceShader . emissiveColor . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . emissiveColor . texture_id , aiTextureType_EMISSIVE ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: emissive tex id " < < material . surfaceShader . emissiveColor . texture_id < < " \n " ;
}
if ( material . surfaceShader . occlusion . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . occlusion . texture_id , aiTextureType_LIGHTMAP ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: lightmap (occlusion) tex id " < < material . surfaceShader . occlusion . texture_id < < " \n " ;
}
if ( material . surfaceShader . metallic . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . metallic . texture_id , aiTextureType_METALNESS ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: metallic tex id " < < material . surfaceShader . metallic . texture_id < < " \n " ;
}
if ( material . surfaceShader . roughness . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . roughness . texture_id , aiTextureType_DIFFUSE_ROUGHNESS ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: roughness tex id " < < material . surfaceShader . roughness . texture_id < < " \n " ;
}
if ( material . surfaceShader . clearcoat . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . clearcoat . texture_id , aiTextureType_CLEARCOAT ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: clearcoat tex id " < < material . surfaceShader . clearcoat . texture_id < < " \n " ;
}
if ( material . surfaceShader . opacity . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . opacity . texture_id , aiTextureType_OPACITY ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: opacity tex id " < < material . surfaceShader . opacity . texture_id < < " \n " ;
}
if ( material . surfaceShader . displacement . is_texture ( ) ) {
assignTexture ( render_scene , material , mat , material . surfaceShader . displacement . texture_id , aiTextureType_DISPLACEMENT ) ;
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: displacement tex id " < < material . surfaceShader . displacement . texture_id < < " \n " ;
}
if ( material . surfaceShader . clearcoatRoughness . is_texture ( ) ) {
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: clearcoatRoughness tex id " < < material . surfaceShader . clearcoatRoughness . texture_id < < " \n " ;
}
if ( material . surfaceShader . opacityThreshold . is_texture ( ) ) {
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: opacityThreshold tex id " < < material . surfaceShader . opacityThreshold . texture_id < < " \n " ;
}
if ( material . surfaceShader . ior . is_texture ( ) ) {
ss < < " material[ " < < pScene - > mNumMaterials < < " ]: ior tex id " < < material . surfaceShader . ior . texture_id < < " \n " ;
}
if ( ! ss . str ( ) . empty ( ) ) {
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
}
pScene - > mMaterials [ pScene - > mNumMaterials ] = mat ;
+ + pScene - > mNumMaterials ;
}
}
void USDImporterImplTinyusdz : : textures (
const tinyusdz : : tydra : : RenderScene & render_scene ,
2026-06-09 12:46:56 -05:00
aiScene * ,
2024-12-09 20:22:47 +00:00
const std : : string & nameWExt ) {
2026-06-09 12:46:56 -05:00
const size_t numTextures { render_scene . textures . size ( ) } ;
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
ss < < " textures(): model " < < nameWExt < < " , numTextures: " < < numTextures ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
2026-06-09 12:46:56 -05:00
size_t i { 0 } ;
2024-12-09 20:22:47 +00:00
for ( const auto & texture : render_scene . textures ) {
ss . str ( " " ) ;
2026-06-09 12:46:56 -05:00
ss < < " texture[ " < < i < < " ]: id: " < < texture . texture_image_id < < " , disp name: | " < < texture . display_name < < " |, varname_uv: " < < texture . varname_uv < < " , prim_name: | " < < texture . prim_name < < " |, abs_path: | " < < texture . abs_path < < " | " ;
2024-12-09 20:22:47 +00:00
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
+ + i ;
}
}
/**
* " owned " as in , used " new " to allocate and aiScene now responsible for " delete "
*
* @ param render_scene renderScene object
* @ param image textureImage object
* @ param nameWExt filename w / ext ( use to extract file type hint )
* @ return aiTexture ptr
*/
2026-06-09 12:46:56 -05:00
static aiTexture * ownedEmbeddedTextureFor ( const RenderScene & render_scene , const TextureImage & image ,
const std : : string & ) {
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
aiTexture * tex = new aiTexture ( ) ;
size_t pos = image . asset_identifier . find_last_of ( ' / ' ) ;
2026-06-09 12:46:56 -05:00
std : : string embTexName { image . asset_identifier . substr ( pos + 1 ) } ;
2024-12-09 20:22:47 +00:00
tex - > mFilename . Set ( image . asset_identifier . c_str ( ) ) ;
tex - > mHeight = image . height ;
2026-06-09 12:46:56 -05:00
2024-12-09 20:22:47 +00:00
tex - > mWidth = image . width ;
if ( tex - > mHeight = = 0 ) {
pos = embTexName . find_last_of ( ' . ' ) ;
strncpy ( tex - > achFormatHint , embTexName . substr ( pos + 1 ) . c_str ( ) , 3 ) ;
2026-06-09 12:46:56 -05:00
const size_t imageBytesCount { render_scene . buffers [ image . buffer_id ] . data . size ( ) } ;
tex - > pcData = ( aiTexel * ) new char [ imageBytesCount ] ;
2024-12-09 20:22:47 +00:00
memcpy ( tex - > pcData , & render_scene . buffers [ image . buffer_id ] . data [ 0 ] , imageBytesCount ) ;
} else {
2026-06-09 12:46:56 -05:00
std : : string formatHint { " rgba8888 " } ;
2024-12-09 20:22:47 +00:00
strncpy ( tex - > achFormatHint , formatHint . c_str ( ) , 8 ) ;
2026-06-09 12:46:56 -05:00
const size_t imageTexelsCount { tex - > mWidth * tex - > mHeight } ;
tex - > pcData = ( aiTexel * ) new char [ imageTexelsCount * image . channels ] ;
2024-12-09 20:22:47 +00:00
const float * floatPtr = reinterpret_cast < const float * > ( & render_scene . buffers [ image . buffer_id ] . data [ 0 ] ) ;
ss . str ( " " ) ;
ss < < " ownedEmbeddedTextureFor(): manual fill... " ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
for ( size_t i = 0 , fpi = 0 ; i < imageTexelsCount ; + + i , fpi + = 4 ) {
2026-06-09 12:46:56 -05:00
tex - > pcData [ i ] . b = static_cast < uint8_t > ( floatPtr [ fpi ] * 255 ) ;
2024-12-09 20:22:47 +00:00
tex - > pcData [ i ] . g = static_cast < uint8_t > ( floatPtr [ fpi + 1 ] * 255 ) ;
tex - > pcData [ i ] . r = static_cast < uint8_t > ( floatPtr [ fpi + 2 ] * 255 ) ;
tex - > pcData [ i ] . a = static_cast < uint8_t > ( floatPtr [ fpi + 3 ] * 255 ) ;
}
ss . str ( " " ) ;
ss < < " ownedEmbeddedTextureFor(): imageTexelsCount: " < < imageTexelsCount < < " , channels: " < < image . channels ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
}
return tex ;
}
2026-06-09 12:46:56 -05:00
void USDImporterImplTinyusdz : : textureImages ( const RenderScene & render_scene , aiScene * pScene , const std : : string & nameWExt ) {
std : : stringstream ss ;
const size_t numTextureImages { render_scene . images . size ( ) } ;
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
ss < < " textureImages(): model " < < nameWExt < < " , numTextureImages: " < < numTextureImages ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
pScene - > mTextures = nullptr ; // Need to iterate over images before knowing if valid textures available
pScene - > mNumTextures = 0 ;
for ( const auto & image : render_scene . images ) {
ss . str ( " " ) ;
2026-06-09 12:46:56 -05:00
ss < < " image[ " < < pScene - > mNumTextures < < " ]: | " < < image . asset_identifier < < " | w: "
< < image . width < < " , h: " < < image . height < < " , channels: " < < image . channels < < " , miplevel: "
< < image . miplevel < < " , buffer id: " < < image . buffer_id < < " \n "
< < " buffers.size(): " < < render_scene . buffers . size ( ) < < " , data empty? "
< < render_scene . buffers [ image . buffer_id ] . data . empty ( ) ;
2024-12-09 20:22:47 +00:00
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
if ( image . buffer_id > - 1 & &
2026-06-09 12:46:56 -05:00
image . buffer_id < static_cast < long int > ( render_scene . buffers . size ( ) ) & &
! render_scene . buffers [ image . buffer_id ] . data . empty ( ) ) {
2024-12-09 20:22:47 +00:00
aiTexture * tex = ownedEmbeddedTextureFor (
render_scene ,
image ,
nameWExt ) ;
if ( pScene - > mTextures = = nullptr ) {
ss . str ( " " ) ;
ss < < " Init pScene->mTextures[ " < < render_scene . images . size ( ) < < " ] " ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
pScene - > mTextures = new aiTexture * [ render_scene . images . size ( ) ] ;
}
ss . str ( " " ) ;
2026-06-09 12:46:56 -05:00
ss < < " pScene->mTextures[ " < < pScene - > mNumTextures < < " ] name: | " < < tex - > mFilename . C_Str ( )
< < " |, w: " < < tex - > mWidth < < " , h: " < < tex - > mHeight < < " , hint: " < < tex - > achFormatHint ;
2024-12-09 20:22:47 +00:00
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
pScene - > mTextures [ pScene - > mNumTextures + + ] = tex ;
}
}
}
void USDImporterImplTinyusdz : : buffers (
2026-06-09 12:46:56 -05:00
const RenderScene & render_scene , aiScene * , const std : : string & nameWExt ) {
const size_t numBuffers { render_scene . buffers . size ( ) } ;
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
ss < < " buffers(): model " < < nameWExt < < " , numBuffers: " < < numBuffers ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
size_t i = 0 ;
for ( const auto & buffer : render_scene . buffers ) {
ss . str ( " " ) ;
ss < < " buffer[ " < < i < < " ]: count: " < < buffer . data . size ( ) < < " , type: " < < to_string ( buffer . componentType ) ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
+ + i ;
}
}
2026-06-09 12:46:56 -05:00
aiNode * USDImporterImplTinyusdz : : nodesRecursive ( aiNode * pNodeParent , const tinyusdz : : tydra : : Node & node ,
const std : : vector < SkelHierarchy > & skeletons ) {
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
aiNode * cNode = new aiNode ( ) ;
cNode - > mParent = pNodeParent ;
cNode - > mName . Set ( node . prim_name ) ;
cNode - > mTransformation = tinyUsdzMat4ToAiMat4 ( node . local_matrix . m ) ;
2026-06-09 12:46:56 -05:00
if ( node . nodeType = = NodeType : : Mesh ) {
cNode - > mNumMeshes = 1 ;
cNode - > mMeshes = new unsigned int [ cNode - > mNumMeshes ] ;
cNode - > mMeshes [ 0 ] = node . id ;
}
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
2026-06-09 12:46:56 -05:00
ss < < " nodesRecursive(): node " < < cNode - > mName . C_Str ( ) < < " type: | "
< < tinyusdzNodeTypeFor ( node . nodeType )
< < " |, disp " < < node . display_name < < " , abs " < < node . abs_path ;
2024-12-09 20:22:47 +00:00
if ( cNode - > mParent ! = nullptr ) {
ss < < " (parent " < < cNode - > mParent - > mName . C_Str ( ) < < " ) " ;
}
ss < < " has " < < node . children . size ( ) < < " children " ;
2026-06-09 12:46:56 -05:00
if ( node . nodeType = = NodeType : : Mesh ) {
2024-12-09 20:22:47 +00:00
ss < < " \n node mesh id: " < < node . id < < " (node type: " < < tinyusdzNodeTypeFor ( node . nodeType ) < < " ) " ;
}
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
2026-06-09 12:46:56 -05:00
unsigned int numChildren = unsigned ( node . children . size ( ) ) ;
2024-12-09 20:22:47 +00:00
// Find any tinyusdz skeletons which might begin at this node
// Add the skeleton bones as child nodes
const tinyusdz : : tydra : : SkelNode * skelNode = nullptr ;
for ( const auto & skeleton : skeletons ) {
if ( skeleton . abs_path = = node . abs_path ) {
// Add this skeleton's bones as child nodes
+ + numChildren ;
skelNode = & skeleton . root_node ;
break ;
}
}
cNode - > mNumChildren = numChildren ;
// Done. No more children.
if ( numChildren = = 0 ) {
return cNode ;
}
cNode - > mChildren = new aiNode * [ cNode - > mNumChildren ] ;
size_t i { 0 } ;
for ( const auto & childNode : node . children ) {
cNode - > mChildren [ i ] = nodesRecursive ( cNode , childNode , skeletons ) ;
+ + i ;
}
if ( skelNode ! = nullptr ) {
// Convert USD skeleton into an Assimp node and make it the last child
2026-06-09 12:46:56 -05:00
cNode - > mChildren [ cNode - > mNumChildren - 1 ] = skeletonNodesRecursive ( cNode , * skelNode ) ;
2024-12-09 20:22:47 +00:00
}
return cNode ;
}
aiNode * USDImporterImplTinyusdz : : skeletonNodesRecursive (
2026-06-09 12:46:56 -05:00
aiNode * pNodeParent ,
const SkelNode & joint ) {
2024-12-09 20:22:47 +00:00
auto * cNode = new aiNode ( joint . joint_path ) ;
cNode - > mParent = pNodeParent ;
cNode - > mNumMeshes = 0 ; // not a mesh node
cNode - > mTransformation = tinyUsdzMat4ToAiMat4 ( joint . rest_transform . m ) ;
// Done. No more children.
if ( joint . children . empty ( ) ) {
return cNode ;
}
cNode - > mNumChildren = static_cast < unsigned int > ( joint . children . size ( ) ) ;
cNode - > mChildren = new aiNode * [ cNode - > mNumChildren ] ;
2026-06-09 12:46:56 -05:00
for ( unsigned i = 0 ; i < cNode - > mNumChildren ; + + i ) {
const SkelNode & childJoint = joint . children [ i ] ;
2024-12-09 20:22:47 +00:00
cNode - > mChildren [ i ] = skeletonNodesRecursive ( cNode , childJoint ) ;
}
return cNode ;
}
void USDImporterImplTinyusdz : : sanityCheckNodesRecursive (
aiNode * cNode ) {
2026-06-09 12:46:56 -05:00
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
ss < < " sanityCheckNodesRecursive(): node " < < cNode - > mName . C_Str ( ) ;
if ( cNode - > mParent ! = nullptr ) {
ss < < " (parent " < < cNode - > mParent - > mName . C_Str ( ) < < " ) " ;
}
ss < < " has " < < cNode - > mNumChildren < < " children " ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
for ( size_t i = 0 ; i < cNode - > mNumChildren ; + + i ) {
sanityCheckNodesRecursive ( cNode - > mChildren [ i ] ) ;
}
}
2026-06-09 12:46:56 -05:00
void USDImporterImplTinyusdz : : setupBlendShapes ( const RenderScene & render_scene , aiScene * pScene ,
2024-12-09 20:22:47 +00:00
const std : : string & nameWExt ) {
2026-06-09 12:46:56 -05:00
std : : stringstream ss ;
2024-12-09 20:22:47 +00:00
ss . str ( " " ) ;
ss < < " setupBlendShapes(): iterating over " < < pScene - > mNumMeshes < < " meshes for model " < < nameWExt ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
for ( size_t meshIdx = 0 ; meshIdx < pScene - > mNumMeshes ; meshIdx + + ) {
2026-06-09 12:46:56 -05:00
blendShapesForMesh ( render_scene , pScene , meshIdx , nameWExt ) ;
2024-12-09 20:22:47 +00:00
}
}
void USDImporterImplTinyusdz : : blendShapesForMesh (
const tinyusdz : : tydra : : RenderScene & render_scene ,
aiScene * pScene ,
size_t meshIdx ,
2026-06-09 12:46:56 -05:00
const std : : string & ) {
std : : stringstream ss ;
const unsigned int numBlendShapeTargets { static_cast < unsigned int > ( render_scene . meshes [ meshIdx ] . targets . size ( ) ) } ;
2024-12-09 20:22:47 +00:00
UNUSED ( numBlendShapeTargets ) ; // Ignore unused variable when -Werror enabled
ss . str ( " " ) ;
ss < < " blendShapesForMesh(): mesh[ " < < meshIdx < < " ], numBlendShapeTargets: " < < numBlendShapeTargets ;
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
if ( numBlendShapeTargets > 0 ) {
pScene - > mMeshes [ meshIdx ] - > mNumAnimMeshes = numBlendShapeTargets ;
pScene - > mMeshes [ meshIdx ] - > mAnimMeshes = new aiAnimMesh * [ pScene - > mMeshes [ meshIdx ] - > mNumAnimMeshes ] ;
}
auto mapIter = render_scene . meshes [ meshIdx ] . targets . begin ( ) ;
2026-06-09 12:46:56 -05:00
size_t animMeshIdx { 0 } ;
2024-12-09 20:22:47 +00:00
for ( ; mapIter ! = render_scene . meshes [ meshIdx ] . targets . end ( ) ; + + mapIter ) {
2026-06-09 12:46:56 -05:00
const std : : string name { mapIter - > first } ;
const tinyusdz : : tydra : : ShapeTarget shapeTarget { mapIter - > second } ;
2024-12-09 20:22:47 +00:00
pScene - > mMeshes [ meshIdx ] - > mAnimMeshes [ animMeshIdx ] = aiCreateAnimMesh ( pScene - > mMeshes [ meshIdx ] ) ;
ss . str ( " " ) ;
2026-06-09 12:46:56 -05:00
ss < < " mAnimMeshes[ " < < animMeshIdx < < " ]: mNumVertices: " < < pScene - > mMeshes [ meshIdx ] - > mAnimMeshes [ animMeshIdx ] - > mNumVertices < < " , target: " < < shapeTarget . pointIndices . size ( ) < < " pointIndices, " < < shapeTarget . pointOffsets . size ( ) < < " pointOffsets, " < < shapeTarget . normalOffsets . size ( ) < < " normalOffsets " ;
2024-12-09 20:22:47 +00:00
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
for ( size_t iVert = 0 ; iVert < shapeTarget . pointOffsets . size ( ) ; + + iVert ) {
pScene - > mMeshes [ meshIdx ] - > mAnimMeshes [ animMeshIdx ] - > mVertices [ shapeTarget . pointIndices [ iVert ] ] + =
tinyUsdzScaleOrPosToAssimp ( shapeTarget . pointOffsets [ iVert ] ) ;
}
for ( size_t iVert = 0 ; iVert < shapeTarget . normalOffsets . size ( ) ; + + iVert ) {
pScene - > mMeshes [ meshIdx ] - > mAnimMeshes [ animMeshIdx ] - > mNormals [ shapeTarget . pointIndices [ iVert ] ] + =
tinyUsdzScaleOrPosToAssimp ( shapeTarget . normalOffsets [ iVert ] ) ;
}
ss . str ( " " ) ;
2026-06-09 12:46:56 -05:00
ss < < " target[ " < < animMeshIdx < < " ]: name: " < < name < < " , prim_name: " < < shapeTarget . prim_name < < " , abs_path: " < < shapeTarget . abs_path < < " , display_name: " < < shapeTarget . display_name < < " , " < < shapeTarget . pointIndices . size ( ) < < " pointIndices, " < < shapeTarget . pointOffsets . size ( ) < < " pointOffsets, " < < shapeTarget . normalOffsets . size ( ) < < " normalOffsets, " < < shapeTarget . inbetweens . size ( ) < < " inbetweens " ;
2024-12-09 20:22:47 +00:00
TINYUSDZLOGD ( TAG , " %s " , ss . str ( ) . c_str ( ) ) ;
+ + animMeshIdx ;
}
}
} // namespace Assimp
# endif // !! ASSIMP_BUILD_NO_USD_IMPORTER