2
0

USDLoaderImplTinyusdz.cpp 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925
  1. /*
  2. Open Asset Import Library (assimp)
  3. ----------------------------------------------------------------------
  4. Copyright (c) 2006-2025, assimp team
  5. All rights reserved.
  6. Redistribution and use of this software in source and binary forms,
  7. with or without modification, are permitted provided that the
  8. following conditions are met:
  9. * Redistributions of source code must retain the above
  10. copyright notice, this list of conditions and the
  11. following disclaimer.
  12. * Redistributions in binary form must reproduce the above
  13. copyright notice, this list of conditions and the
  14. following disclaimer in the documentation and/or other
  15. materials provided with the distribution.
  16. * Neither the name of the assimp team, nor the names of its
  17. contributors may be used to endorse or promote products
  18. derived from this software without specific prior
  19. written permission of the assimp team.
  20. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  21. "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  23. A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  24. OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  25. SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  26. LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  27. DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  28. THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  29. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  30. OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  31. ----------------------------------------------------------------------
  32. */
  33. /** @file USDLoader.cpp
  34. * @brief Implementation of the USD importer class
  35. */
  36. #ifndef ASSIMP_BUILD_NO_USD_IMPORTER
  37. #include "USDLoaderImplTinyusdz.h"
  38. #include "USDLoaderImplTinyusdzHelper.h"
  39. #include "USDLoaderUtil.h"
  40. #include "USDPreprocessor.h"
  41. #include "io-util.hh" // namespace tinyusdz::io
  42. #include "tydra/scene-access.hh"
  43. #include "tydra/shader-network.hh"
  44. #include <memory>
  45. #include <sstream>
  46. // internal headers
  47. #include "assimp/MemoryIOWrapper.h"
  48. #include <assimp/CreateAnimMesh.h>
  49. #include <assimp/DefaultIOSystem.h>
  50. #include <assimp/IOStreamBuffer.h>
  51. #include <assimp/StreamReader.h>
  52. #include <assimp/StringUtils.h>
  53. #include <assimp/ai_assert.h>
  54. #include <assimp/anim.h>
  55. #include <assimp/fast_atof.h>
  56. #include <assimp/importerdesc.h>
  57. #include <assimp/DefaultLogger.hpp>
  58. #include <assimp/IOSystem.hpp>
  59. #include <assimp/Importer.hpp>
  60. #include "../../../contrib/tinyusdz/assimp_tinyusdz_logging.inc"
  61. namespace {
  62. static constexpr char TAG[] = "tinyusdz loader";
  63. }
  64. namespace Assimp {
  65. using Assimp::tinyUsdzMat4ToAiMat4;
  66. using Assimp::tinyusdzNodeTypeFor;
  67. using tinyusdz::tydra::NodeType;
  68. using namespace tinyusdz::tydra;
  69. void USDImporterImplTinyusdz::InternReadFile(const std::string &pFile, aiScene *pScene, IOSystem *pIOHandler) {
  70. // Grab filename for logging purposes
  71. size_t pos = pFile.find_last_of('/');
  72. std::string basePath = pFile.substr(0, pos);
  73. std::string nameWExt = pFile.substr(pos + 1);
  74. std::stringstream ss;
  75. ss.str("");
  76. ss << "InternReadFile(): model" << nameWExt;
  77. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  78. bool is_load_from_mem{ pFile.substr(0, AI_MEMORYIO_MAGIC_FILENAME_LENGTH) == AI_MEMORYIO_MAGIC_FILENAME };
  79. std::vector<uint8_t> in_mem_data;
  80. if (is_load_from_mem) {
  81. auto stream_closer = [pIOHandler](IOStream *pStream) {
  82. pIOHandler->Close(pStream);
  83. };
  84. std::unique_ptr<IOStream, decltype(stream_closer)> file_stream(pIOHandler->Open(pFile, "rb"), stream_closer);
  85. if (!file_stream) {
  86. throw DeadlyImportError("Failed to open file ", pFile, ".");
  87. }
  88. size_t file_size{ file_stream->FileSize() };
  89. in_mem_data.resize(file_size);
  90. file_stream->Read(in_mem_data.data(), 1, file_size);
  91. }
  92. bool ret{ false };
  93. tinyusdz::USDLoadOptions options;
  94. tinyusdz::Stage stage;
  95. std::string warn, err;
  96. bool is_usdz{ false };
  97. if (isUsdc(pFile)) {
  98. ret = is_load_from_mem ? LoadUSDCFromMemory(in_mem_data.data(), in_mem_data.size(), pFile, &stage, &warn, &err, options) :
  99. LoadUSDCFromFile(pFile, &stage, &warn, &err, options);
  100. ss.str("");
  101. ss << "InternReadFile(): LoadUSDCFromFile() result: " << ret;
  102. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  103. } else if (isUsda(pFile)) {
  104. ret = is_load_from_mem ? LoadUSDAFromMemory(in_mem_data.data(), in_mem_data.size(), pFile, &stage, &warn, &err, options) :
  105. LoadUSDAFromFile(pFile, &stage, &warn, &err, options);
  106. ss.str("");
  107. ss << "InternReadFile(): LoadUSDAFromFile() result: " << ret;
  108. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  109. } else if (isUsdz(pFile)) {
  110. ret = is_load_from_mem ? LoadUSDZFromMemory(in_mem_data.data(), in_mem_data.size(), pFile, &stage, &warn, &err, options) :
  111. LoadUSDZFromFile(pFile, &stage, &warn, &err, options);
  112. is_usdz = true;
  113. ss.str("");
  114. ss << "InternReadFile(): LoadUSDZFromFile() result: " << ret;
  115. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  116. } else if (isUsd(pFile)) {
  117. ret = is_load_from_mem ? LoadUSDFromMemory(in_mem_data.data(), in_mem_data.size(), pFile, &stage, &warn, &err, options) :
  118. LoadUSDFromFile(pFile, &stage, &warn, &err, options);
  119. ss.str("");
  120. ss << "InternReadFile(): LoadUSDFromFile() result: " << ret;
  121. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  122. }
  123. if (warn.empty() && err.empty()) {
  124. ss.str("");
  125. ss << "InternReadFile(): load free of warnings/errors";
  126. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  127. } else {
  128. if (!warn.empty()) {
  129. ss.str("");
  130. ss << "InternReadFile(): WARNING reported: " << warn;
  131. TINYUSDZLOGW(TAG, "%s", ss.str().c_str());
  132. }
  133. if (!err.empty()) {
  134. ss.str("");
  135. ss << "InternReadFile(): ERROR reported: " << err;
  136. TINYUSDZLOGE(TAG, "%s", ss.str().c_str());
  137. }
  138. }
  139. if (!ret) {
  140. ss.str("");
  141. ss << "InternReadFile(): ERROR: load failed! ret: " << ret;
  142. TINYUSDZLOGE(TAG, "%s", ss.str().c_str());
  143. return;
  144. }
  145. RenderScene render_scene;
  146. RenderSceneConverter converter;
  147. RenderSceneConverterEnv env(stage);
  148. std::string usd_basedir = tinyusdz::io::GetBaseDir(pFile);
  149. env.set_search_paths({ usd_basedir }); // {} needed to convert to vector of char
  150. // NOTE: Pointer address of usdz_asset must be valid until the call of RenderSceneConverter::ConvertToRenderScene.
  151. tinyusdz::USDZAsset usdz_asset;
  152. if (is_usdz) {
  153. bool is_read_USDZ_asset = is_load_from_mem ? tinyusdz::ReadUSDZAssetInfoFromMemory(in_mem_data.data(), in_mem_data.size(), false, &usdz_asset, &warn, &err) :
  154. tinyusdz::ReadUSDZAssetInfoFromFile(pFile, &usdz_asset, &warn, &err);
  155. if (!is_read_USDZ_asset) {
  156. if (!warn.empty()) {
  157. ss.str("");
  158. ss << "InternReadFile(): ReadUSDZAssetInfoFromFile: WARNING reported: " << warn;
  159. TINYUSDZLOGW(TAG, "%s", ss.str().c_str());
  160. }
  161. if (!err.empty()) {
  162. ss.str("");
  163. ss << "InternReadFile(): ReadUSDZAssetInfoFromFile: ERROR reported: " << err;
  164. TINYUSDZLOGE(TAG, "%s", ss.str().c_str());
  165. }
  166. ss.str("");
  167. ss << "InternReadFile(): ReadUSDZAssetInfoFromFile: ERROR!";
  168. TINYUSDZLOGE(TAG, "%s", ss.str().c_str());
  169. } else {
  170. ss.str("");
  171. ss << "InternReadFile(): ReadUSDZAssetInfoFromFile: OK";
  172. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  173. }
  174. tinyusdz::AssetResolutionResolver arr;
  175. if (!tinyusdz::SetupUSDZAssetResolution(arr, &usdz_asset)) {
  176. ss.str("");
  177. ss << "InternReadFile(): SetupUSDZAssetResolution: ERROR: load failed! ret: " << ret;
  178. TINYUSDZLOGE(TAG, "%s", ss.str().c_str());
  179. } else {
  180. ss.str("");
  181. ss << "InternReadFile(): SetupUSDZAssetResolution: OK";
  182. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  183. env.asset_resolver = arr;
  184. }
  185. }
  186. ret = converter.ConvertToRenderScene(env, &render_scene);
  187. if (!ret) {
  188. ss.str("");
  189. ss << "InternReadFile(): ConvertToRenderScene() failed!";
  190. TINYUSDZLOGE(TAG, "%s", ss.str().c_str());
  191. return;
  192. }
  193. // sanityCheckNodesRecursive(pScene->mRootNode);
  194. animations(render_scene, pScene);
  195. meshes(render_scene, pScene, nameWExt);
  196. materials(render_scene, pScene, nameWExt);
  197. textures(render_scene, pScene, nameWExt);
  198. textureImages(render_scene, pScene, nameWExt);
  199. buffers(render_scene, pScene, nameWExt);
  200. pScene->mRootNode = nodesRecursive(nullptr, render_scene.nodes[0], render_scene.skeletons);
  201. setupBlendShapes(render_scene, pScene, nameWExt);
  202. }
  203. void USDImporterImplTinyusdz::animations(const tinyusdz::tydra::RenderScene &render_scene, aiScene *pScene) {
  204. if (render_scene.animations.empty()) {
  205. return;
  206. }
  207. pScene->mNumAnimations = unsigned(render_scene.animations.size());
  208. pScene->mAnimations = new aiAnimation *[pScene->mNumAnimations];
  209. for (unsigned animationIndex = 0; animationIndex < pScene->mNumAnimations; ++animationIndex) {
  210. const auto &animation = render_scene.animations[animationIndex];
  211. auto newAiAnimation = new aiAnimation();
  212. pScene->mAnimations[animationIndex] = newAiAnimation;
  213. newAiAnimation->mName = animation.abs_path;
  214. if (animation.channels_map.empty()) {
  215. newAiAnimation->mNumChannels = 0;
  216. continue;
  217. }
  218. // each channel affects a node (joint)
  219. newAiAnimation->mTicksPerSecond = render_scene.meta.framesPerSecond;
  220. newAiAnimation->mNumChannels = unsigned(animation.channels_map.size());
  221. newAiAnimation->mChannels = new aiNodeAnim *[newAiAnimation->mNumChannels];
  222. int channelIndex = 0;
  223. for (const auto &[jointName, animationChannelMap] : animation.channels_map) {
  224. auto newAiNodeAnim = new aiNodeAnim();
  225. newAiAnimation->mChannels[channelIndex] = newAiNodeAnim;
  226. newAiNodeAnim->mNodeName = jointName;
  227. newAiAnimation->mDuration = 0;
  228. std::vector<aiVectorKey> positionKeys;
  229. std::vector<aiQuatKey> rotationKeys;
  230. std::vector<aiVectorKey> scalingKeys;
  231. for (const auto &[channelType, animChannel] : animationChannelMap) {
  232. switch (channelType) {
  233. case AnimationChannel::ChannelType::Rotation:
  234. if (animChannel.rotations.static_value.has_value()) {
  235. rotationKeys.emplace_back(0, tinyUsdzQuatToAiQuat(animChannel.rotations.static_value.value()));
  236. }
  237. for (const auto &rotationAnimSampler : animChannel.rotations.samples) {
  238. if (rotationAnimSampler.t > newAiAnimation->mDuration) {
  239. newAiAnimation->mDuration = rotationAnimSampler.t;
  240. }
  241. rotationKeys.emplace_back(rotationAnimSampler.t, tinyUsdzQuatToAiQuat(rotationAnimSampler.value));
  242. }
  243. break;
  244. case AnimationChannel::ChannelType::Scale:
  245. if (animChannel.scales.static_value.has_value()) {
  246. scalingKeys.emplace_back(0, tinyUsdzScaleOrPosToAssimp(animChannel.scales.static_value.value()));
  247. }
  248. for (const auto &scaleAnimSampler : animChannel.scales.samples) {
  249. if (scaleAnimSampler.t > newAiAnimation->mDuration) {
  250. newAiAnimation->mDuration = scaleAnimSampler.t;
  251. }
  252. scalingKeys.emplace_back(scaleAnimSampler.t, tinyUsdzScaleOrPosToAssimp(scaleAnimSampler.value));
  253. }
  254. break;
  255. case AnimationChannel::ChannelType::Transform:
  256. if (animChannel.transforms.static_value.has_value()) {
  257. aiVector3D position;
  258. aiVector3D scale;
  259. aiQuaternion rotation;
  260. tinyUsdzMat4ToAiMat4(animChannel.transforms.static_value.value().m).Decompose(scale, rotation, position);
  261. positionKeys.emplace_back(0, position);
  262. scalingKeys.emplace_back(0, scale);
  263. rotationKeys.emplace_back(0, rotation);
  264. }
  265. for (const auto &transformAnimSampler : animChannel.transforms.samples) {
  266. if (transformAnimSampler.t > newAiAnimation->mDuration) {
  267. newAiAnimation->mDuration = transformAnimSampler.t;
  268. }
  269. aiVector3D position;
  270. aiVector3D scale;
  271. aiQuaternion rotation;
  272. tinyUsdzMat4ToAiMat4(transformAnimSampler.value.m).Decompose(scale, rotation, position);
  273. positionKeys.emplace_back(transformAnimSampler.t, position);
  274. scalingKeys.emplace_back(transformAnimSampler.t, scale);
  275. rotationKeys.emplace_back(transformAnimSampler.t, rotation);
  276. }
  277. break;
  278. case AnimationChannel::ChannelType::Translation:
  279. if (animChannel.translations.static_value.has_value()) {
  280. positionKeys.emplace_back(0, tinyUsdzScaleOrPosToAssimp(animChannel.translations.static_value.value()));
  281. }
  282. for (const auto &translationAnimSampler : animChannel.translations.samples) {
  283. if (translationAnimSampler.t > newAiAnimation->mDuration) {
  284. newAiAnimation->mDuration = translationAnimSampler.t;
  285. }
  286. positionKeys.emplace_back(translationAnimSampler.t, tinyUsdzScaleOrPosToAssimp(translationAnimSampler.value));
  287. }
  288. break;
  289. default:
  290. TINYUSDZLOGW(TAG, "Unsupported animation channel type (%s). Please update the USD importer to support this animation channel.", tinyusdzAnimChannelTypeFor(channelType).c_str());
  291. }
  292. }
  293. newAiNodeAnim->mNumPositionKeys = unsigned(positionKeys.size());
  294. newAiNodeAnim->mPositionKeys = new aiVectorKey[newAiNodeAnim->mNumPositionKeys];
  295. std::move(positionKeys.begin(), positionKeys.end(), newAiNodeAnim->mPositionKeys);
  296. newAiNodeAnim->mNumRotationKeys = unsigned(rotationKeys.size());
  297. newAiNodeAnim->mRotationKeys = new aiQuatKey[newAiNodeAnim->mNumRotationKeys];
  298. std::move(rotationKeys.begin(), rotationKeys.end(), newAiNodeAnim->mRotationKeys);
  299. newAiNodeAnim->mNumScalingKeys = unsigned(scalingKeys.size());
  300. newAiNodeAnim->mScalingKeys = new aiVectorKey[newAiNodeAnim->mNumScalingKeys];
  301. std::move(scalingKeys.begin(), scalingKeys.end(), newAiNodeAnim->mScalingKeys);
  302. ++channelIndex;
  303. }
  304. }
  305. }
  306. void USDImporterImplTinyusdz::meshes(
  307. const tinyusdz::tydra::RenderScene &render_scene,
  308. aiScene *pScene,
  309. const std::string &nameWExt) {
  310. std::stringstream ss;
  311. pScene->mNumMeshes = static_cast<unsigned int>(render_scene.meshes.size());
  312. pScene->mMeshes = new aiMesh *[pScene->mNumMeshes]();
  313. ss.str("");
  314. ss << "meshes(): pScene->mNumMeshes: " << pScene->mNumMeshes;
  315. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  316. // Export meshes
  317. for (size_t meshIdx = 0; meshIdx < pScene->mNumMeshes; meshIdx++) {
  318. pScene->mMeshes[meshIdx] = new aiMesh();
  319. pScene->mMeshes[meshIdx]->mName.Set(render_scene.meshes[meshIdx].prim_name);
  320. ss.str("");
  321. 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;
  322. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  323. ss.str("");
  324. ss << " skel_id: " << render_scene.meshes[meshIdx].skel_id;
  325. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  326. if (render_scene.meshes[meshIdx].material_id > -1) {
  327. pScene->mMeshes[meshIdx]->mMaterialIndex = render_scene.meshes[meshIdx].material_id;
  328. }
  329. verticesForMesh(render_scene, pScene, meshIdx, nameWExt);
  330. facesForMesh(render_scene, pScene, meshIdx, nameWExt);
  331. // Some models infer normals from faces, but others need them e.g.
  332. // - apple "toy car" canopy normals will be wrong
  333. // - human "untitled" model (tinyusdz issue #115) will be "splotchy"
  334. normalsForMesh(render_scene, pScene, meshIdx, nameWExt);
  335. materialsForMesh(render_scene, pScene, meshIdx, nameWExt);
  336. uvsForMesh(render_scene, pScene, meshIdx, nameWExt);
  337. }
  338. }
  339. void USDImporterImplTinyusdz::verticesForMesh(const tinyusdz::tydra::RenderScene &render_scene,
  340. aiScene *pScene, size_t meshIdx, const std::string &) {
  341. const auto numVertices = static_cast<unsigned int>(render_scene.meshes[meshIdx].points.size());
  342. pScene->mMeshes[meshIdx]->mNumVertices = numVertices;
  343. pScene->mMeshes[meshIdx]->mVertices = new aiVector3D[pScene->mMeshes[meshIdx]->mNumVertices];
  344. // Check if this is a skinned mesh
  345. if (int skeleton_id = render_scene.meshes[meshIdx].skel_id; skeleton_id > -1) {
  346. // Recursively iterate to collect all the joints in the hierarchy into a flattened array
  347. std::vector<const tinyusdz::tydra::SkelNode *> skeletonNodes;
  348. skeletonNodes.push_back(&render_scene.skeletons[skeleton_id].root_node);
  349. for (int i = 0; i < skeletonNodes.size(); ++i) {
  350. for (const auto &child : skeletonNodes[i]->children) {
  351. skeletonNodes.push_back(&child);
  352. }
  353. }
  354. // Convert USD skeleton joints to Assimp bones
  355. const unsigned int numBones = unsigned(skeletonNodes.size());
  356. pScene->mMeshes[meshIdx]->mNumBones = numBones;
  357. pScene->mMeshes[meshIdx]->mBones = new aiBone *[numBones];
  358. for (unsigned int i = 0; i < numBones; ++i) {
  359. const tinyusdz::tydra::SkelNode *skeletonNode = skeletonNodes[i];
  360. const int boneIndex = skeletonNode->joint_id;
  361. // Sorted so that Assimp bone ids align with USD joint id
  362. auto outputBone = new aiBone();
  363. outputBone->mName = aiString(skeletonNode->joint_name);
  364. outputBone->mOffsetMatrix = tinyUsdzMat4ToAiMat4(skeletonNode->bind_transform.m).Inverse();
  365. pScene->mMeshes[meshIdx]->mBones[boneIndex] = outputBone;
  366. }
  367. // Vertex weights
  368. std::vector<std::vector<aiVertexWeight>> aiBonesVertexWeights;
  369. aiBonesVertexWeights.resize(numBones);
  370. const std::vector<int> &jointIndices = render_scene.meshes[meshIdx].joint_and_weights.jointIndices;
  371. const std::vector<float> &jointWeightIndices = render_scene.meshes[meshIdx].joint_and_weights.jointWeights;
  372. const int numWeightsPerVertex = render_scene.meshes[meshIdx].joint_and_weights.elementSize;
  373. for (unsigned int vertexIndex = 0; vertexIndex < numVertices; ++vertexIndex) {
  374. for (int weightIndex = 0; weightIndex < numWeightsPerVertex; ++weightIndex) {
  375. const unsigned int index = vertexIndex * numWeightsPerVertex + weightIndex;
  376. const float jointWeight = jointWeightIndices[index];
  377. if (jointWeight > 0) {
  378. const int jointIndex = jointIndices[index];
  379. aiBonesVertexWeights[jointIndex].emplace_back(vertexIndex, jointWeight);
  380. }
  381. }
  382. }
  383. for (unsigned boneIndex = 0; boneIndex < numBones; ++boneIndex) {
  384. const auto numWeightsForBone = unsigned(aiBonesVertexWeights[boneIndex].size());
  385. pScene->mMeshes[meshIdx]->mBones[boneIndex]->mWeights = new aiVertexWeight[numWeightsForBone];
  386. pScene->mMeshes[meshIdx]->mBones[boneIndex]->mNumWeights = numWeightsForBone;
  387. std::swap_ranges(aiBonesVertexWeights[boneIndex].begin(), aiBonesVertexWeights[boneIndex].end(), pScene->mMeshes[meshIdx]->mBones[boneIndex]->mWeights);
  388. }
  389. } // Skinned mesh end
  390. for (size_t j = 0; j < pScene->mMeshes[meshIdx]->mNumVertices; ++j) {
  391. pScene->mMeshes[meshIdx]->mVertices[j].x = render_scene.meshes[meshIdx].points[j][0];
  392. pScene->mMeshes[meshIdx]->mVertices[j].y = render_scene.meshes[meshIdx].points[j][1];
  393. pScene->mMeshes[meshIdx]->mVertices[j].z = render_scene.meshes[meshIdx].points[j][2];
  394. }
  395. }
  396. void USDImporterImplTinyusdz::facesForMesh(const RenderScene &render_scene, aiScene *pScene,
  397. size_t meshIdx, const std::string &) {
  398. pScene->mMeshes[meshIdx]->mNumFaces = static_cast<unsigned int>(render_scene.meshes[meshIdx].faceVertexCounts().size());
  399. pScene->mMeshes[meshIdx]->mFaces = new aiFace[pScene->mMeshes[meshIdx]->mNumFaces]();
  400. size_t faceVertIdxOffset = 0;
  401. for (size_t faceIdx = 0; faceIdx < pScene->mMeshes[meshIdx]->mNumFaces; ++faceIdx) {
  402. pScene->mMeshes[meshIdx]->mFaces[faceIdx].mNumIndices = render_scene.meshes[meshIdx].faceVertexCounts()[faceIdx];
  403. pScene->mMeshes[meshIdx]->mFaces[faceIdx].mIndices = new unsigned int[pScene->mMeshes[meshIdx]->mFaces[faceIdx].mNumIndices];
  404. for (size_t j = 0; j < pScene->mMeshes[meshIdx]->mFaces[faceIdx].mNumIndices; ++j) {
  405. pScene->mMeshes[meshIdx]->mFaces[faceIdx].mIndices[j] =
  406. render_scene.meshes[meshIdx].faceVertexIndices()[j + faceVertIdxOffset];
  407. }
  408. faceVertIdxOffset += pScene->mMeshes[meshIdx]->mFaces[faceIdx].mNumIndices;
  409. }
  410. }
  411. void USDImporterImplTinyusdz::normalsForMesh(const RenderScene &render_scene, aiScene *pScene,
  412. size_t meshIdx, const std::string &) {
  413. pScene->mMeshes[meshIdx]->mNormals = new aiVector3D[pScene->mMeshes[meshIdx]->mNumVertices];
  414. const float *floatPtr = reinterpret_cast<const float *>(render_scene.meshes[meshIdx].normals.get_data().data());
  415. for (size_t vertIdx = 0, fpj = 0; vertIdx < pScene->mMeshes[meshIdx]->mNumVertices; ++vertIdx, fpj += 3) {
  416. pScene->mMeshes[meshIdx]->mNormals[vertIdx].x = floatPtr[fpj];
  417. pScene->mMeshes[meshIdx]->mNormals[vertIdx].y = floatPtr[fpj + 1];
  418. pScene->mMeshes[meshIdx]->mNormals[vertIdx].z = floatPtr[fpj + 2];
  419. }
  420. }
  421. void USDImporterImplTinyusdz::materialsForMesh(const RenderScene&, aiScene*,
  422. size_t, const std::string&) {
  423. // todo
  424. }
  425. void USDImporterImplTinyusdz::uvsForMesh(
  426. const tinyusdz::tydra::RenderScene &render_scene,
  427. aiScene *pScene,
  428. size_t meshIdx,
  429. const std::string&) {
  430. const size_t uvSlotsCount = render_scene.meshes[meshIdx].texcoords.size();
  431. if (uvSlotsCount < 1) {
  432. return;
  433. }
  434. pScene->mMeshes[meshIdx]->mTextureCoords[0] = new aiVector3D[pScene->mMeshes[meshIdx]->mNumVertices];
  435. pScene->mMeshes[meshIdx]->mNumUVComponents[0] = 2; // U and V stored in "x", "y" of aiVector3D.
  436. for (unsigned int uvSlotIdx = 0; uvSlotIdx < uvSlotsCount; ++uvSlotIdx) {
  437. const auto uvsForSlot = render_scene.meshes[meshIdx].texcoords.at(uvSlotIdx);
  438. if (uvsForSlot.get_data().size() == 0) {
  439. continue;
  440. }
  441. const float *floatPtr = reinterpret_cast<const float *>(uvsForSlot.get_data().data());
  442. for (size_t vertIdx = 0, fpj = 0; vertIdx < pScene->mMeshes[meshIdx]->mNumVertices; ++vertIdx, fpj += 2) {
  443. pScene->mMeshes[meshIdx]->mTextureCoords[uvSlotIdx][vertIdx].x = floatPtr[fpj];
  444. pScene->mMeshes[meshIdx]->mTextureCoords[uvSlotIdx][vertIdx].y = floatPtr[fpj + 1];
  445. }
  446. }
  447. }
  448. static aiColor3D *ownedColorPtrFor(const std::array<float, 3> &color) {
  449. aiColor3D *colorPtr = new aiColor3D();
  450. colorPtr->r = color[0];
  451. colorPtr->g = color[1];
  452. colorPtr->b = color[2];
  453. return colorPtr;
  454. }
  455. static std::string nameForTextureWithId(const RenderScene &render_scene, const int targetId) {
  456. std::stringstream ss;
  457. std::string texName;
  458. for (const auto &image : render_scene.images) {
  459. if (image.buffer_id == targetId) {
  460. texName = image.asset_identifier;
  461. ss.str("");
  462. ss << "nameForTextureWithId(): found texture " << texName << " with target id " << targetId;
  463. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  464. break;
  465. }
  466. }
  467. ss.str("");
  468. ss << "nameForTextureWithId(): ERROR! Failed to find texture with target id " << targetId;
  469. TINYUSDZLOGE(TAG, "%s", ss.str().c_str());
  470. return texName;
  471. }
  472. static void assignTexture(
  473. const RenderScene &render_scene,
  474. const RenderMaterial &,
  475. aiMaterial *mat,
  476. const int textureId,
  477. const int aiTextureType) {
  478. std::string name = nameForTextureWithId(render_scene, textureId);
  479. aiString *texName = new aiString();
  480. texName->Set(name);
  481. std::stringstream ss;
  482. ss.str("");
  483. ss << "assignTexture(): name: " << name;
  484. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  485. // TODO: verify hard-coded '0' index is correct
  486. mat->AddProperty(texName, _AI_MATKEY_TEXTURE_BASE, aiTextureType, 0);
  487. }
  488. void USDImporterImplTinyusdz::materials(
  489. const tinyusdz::tydra::RenderScene &render_scene,
  490. aiScene *pScene,
  491. const std::string &nameWExt) {
  492. const size_t numMaterials{ render_scene.materials.size() };
  493. std::stringstream ss;
  494. ss.str("");
  495. ss << "materials(): model" << nameWExt << ", numMaterials: " << numMaterials;
  496. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  497. pScene->mNumMaterials = 0;
  498. if (render_scene.materials.empty()) {
  499. return;
  500. }
  501. pScene->mMaterials = new aiMaterial *[render_scene.materials.size()];
  502. for (const auto &material : render_scene.materials) {
  503. ss.str("");
  504. ss << " material[" << pScene->mNumMaterials << "]: name: |" << material.name << "|, disp name: |" << material.display_name << "|";
  505. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  506. aiMaterial *mat = new aiMaterial;
  507. aiString *materialName = new aiString();
  508. materialName->Set(material.name);
  509. mat->AddProperty(materialName, AI_MATKEY_NAME);
  510. mat->AddProperty(
  511. ownedColorPtrFor(material.surfaceShader.diffuseColor.value),
  512. 1, AI_MATKEY_COLOR_DIFFUSE);
  513. mat->AddProperty(
  514. ownedColorPtrFor(material.surfaceShader.specularColor.value),
  515. 1, AI_MATKEY_COLOR_SPECULAR);
  516. mat->AddProperty(
  517. ownedColorPtrFor(material.surfaceShader.emissiveColor.value),
  518. 1, AI_MATKEY_COLOR_EMISSIVE);
  519. ss.str("");
  520. if (material.surfaceShader.diffuseColor.is_texture()) {
  521. assignTexture(render_scene, material, mat, material.surfaceShader.diffuseColor.texture_id, aiTextureType_DIFFUSE);
  522. ss << " material[" << pScene->mNumMaterials << "]: diff tex id " << material.surfaceShader.diffuseColor.texture_id << "\n";
  523. }
  524. if (material.surfaceShader.specularColor.is_texture()) {
  525. assignTexture(render_scene, material, mat, material.surfaceShader.specularColor.texture_id, aiTextureType_SPECULAR);
  526. ss << " material[" << pScene->mNumMaterials << "]: spec tex id " << material.surfaceShader.specularColor.texture_id << "\n";
  527. }
  528. if (material.surfaceShader.normal.is_texture()) {
  529. assignTexture(render_scene, material, mat, material.surfaceShader.normal.texture_id, aiTextureType_NORMALS);
  530. ss << " material[" << pScene->mNumMaterials << "]: normal tex id " << material.surfaceShader.normal.texture_id << "\n";
  531. }
  532. if (material.surfaceShader.emissiveColor.is_texture()) {
  533. assignTexture(render_scene, material, mat, material.surfaceShader.emissiveColor.texture_id, aiTextureType_EMISSIVE);
  534. ss << " material[" << pScene->mNumMaterials << "]: emissive tex id " << material.surfaceShader.emissiveColor.texture_id << "\n";
  535. }
  536. if (material.surfaceShader.occlusion.is_texture()) {
  537. assignTexture(render_scene, material, mat, material.surfaceShader.occlusion.texture_id, aiTextureType_LIGHTMAP);
  538. ss << " material[" << pScene->mNumMaterials << "]: lightmap (occlusion) tex id " << material.surfaceShader.occlusion.texture_id << "\n";
  539. }
  540. if (material.surfaceShader.metallic.is_texture()) {
  541. assignTexture(render_scene, material, mat, material.surfaceShader.metallic.texture_id, aiTextureType_METALNESS);
  542. ss << " material[" << pScene->mNumMaterials << "]: metallic tex id " << material.surfaceShader.metallic.texture_id << "\n";
  543. }
  544. if (material.surfaceShader.roughness.is_texture()) {
  545. assignTexture(render_scene, material, mat, material.surfaceShader.roughness.texture_id, aiTextureType_DIFFUSE_ROUGHNESS);
  546. ss << " material[" << pScene->mNumMaterials << "]: roughness tex id " << material.surfaceShader.roughness.texture_id << "\n";
  547. }
  548. if (material.surfaceShader.clearcoat.is_texture()) {
  549. assignTexture(render_scene, material, mat, material.surfaceShader.clearcoat.texture_id, aiTextureType_CLEARCOAT);
  550. ss << " material[" << pScene->mNumMaterials << "]: clearcoat tex id " << material.surfaceShader.clearcoat.texture_id << "\n";
  551. }
  552. if (material.surfaceShader.opacity.is_texture()) {
  553. assignTexture(render_scene, material, mat, material.surfaceShader.opacity.texture_id, aiTextureType_OPACITY);
  554. ss << " material[" << pScene->mNumMaterials << "]: opacity tex id " << material.surfaceShader.opacity.texture_id << "\n";
  555. }
  556. if (material.surfaceShader.displacement.is_texture()) {
  557. assignTexture(render_scene, material, mat, material.surfaceShader.displacement.texture_id, aiTextureType_DISPLACEMENT);
  558. ss << " material[" << pScene->mNumMaterials << "]: displacement tex id " << material.surfaceShader.displacement.texture_id << "\n";
  559. }
  560. if (material.surfaceShader.clearcoatRoughness.is_texture()) {
  561. ss << " material[" << pScene->mNumMaterials << "]: clearcoatRoughness tex id " << material.surfaceShader.clearcoatRoughness.texture_id << "\n";
  562. }
  563. if (material.surfaceShader.opacityThreshold.is_texture()) {
  564. ss << " material[" << pScene->mNumMaterials << "]: opacityThreshold tex id " << material.surfaceShader.opacityThreshold.texture_id << "\n";
  565. }
  566. if (material.surfaceShader.ior.is_texture()) {
  567. ss << " material[" << pScene->mNumMaterials << "]: ior tex id " << material.surfaceShader.ior.texture_id << "\n";
  568. }
  569. if (!ss.str().empty()) {
  570. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  571. }
  572. pScene->mMaterials[pScene->mNumMaterials] = mat;
  573. ++pScene->mNumMaterials;
  574. }
  575. }
  576. void USDImporterImplTinyusdz::textures(
  577. const tinyusdz::tydra::RenderScene &render_scene,
  578. aiScene*,
  579. const std::string &nameWExt) {
  580. const size_t numTextures{ render_scene.textures.size() };
  581. std::stringstream ss;
  582. ss.str("");
  583. ss << "textures(): model" << nameWExt << ", numTextures: " << numTextures;
  584. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  585. size_t i{ 0 };
  586. for (const auto &texture : render_scene.textures) {
  587. ss.str("");
  588. 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 << "|";
  589. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  590. ++i;
  591. }
  592. }
  593. /**
  594. * "owned" as in, used "new" to allocate and aiScene now responsible for "delete"
  595. *
  596. * @param render_scene renderScene object
  597. * @param image textureImage object
  598. * @param nameWExt filename w/ext (use to extract file type hint)
  599. * @return aiTexture ptr
  600. */
  601. static aiTexture *ownedEmbeddedTextureFor(const RenderScene &render_scene, const TextureImage &image,
  602. const std::string&) {
  603. std::stringstream ss;
  604. aiTexture *tex = new aiTexture();
  605. size_t pos = image.asset_identifier.find_last_of('/');
  606. std::string embTexName{ image.asset_identifier.substr(pos + 1) };
  607. tex->mFilename.Set(image.asset_identifier.c_str());
  608. tex->mHeight = image.height;
  609. tex->mWidth = image.width;
  610. if (tex->mHeight == 0) {
  611. pos = embTexName.find_last_of('.');
  612. strncpy(tex->achFormatHint, embTexName.substr(pos + 1).c_str(), 3);
  613. const size_t imageBytesCount{ render_scene.buffers[image.buffer_id].data.size() };
  614. tex->pcData = (aiTexel *)new char[imageBytesCount];
  615. memcpy(tex->pcData, &render_scene.buffers[image.buffer_id].data[0], imageBytesCount);
  616. } else {
  617. std::string formatHint{ "rgba8888" };
  618. strncpy(tex->achFormatHint, formatHint.c_str(), 8);
  619. const size_t imageTexelsCount{ tex->mWidth * tex->mHeight };
  620. tex->pcData = (aiTexel *)new char[imageTexelsCount * image.channels];
  621. const float *floatPtr = reinterpret_cast<const float *>(&render_scene.buffers[image.buffer_id].data[0]);
  622. ss.str("");
  623. ss << "ownedEmbeddedTextureFor(): manual fill...";
  624. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  625. for (size_t i = 0, fpi = 0; i < imageTexelsCount; ++i, fpi += 4) {
  626. tex->pcData[i].b = static_cast<uint8_t>(floatPtr[fpi] * 255);
  627. tex->pcData[i].g = static_cast<uint8_t>(floatPtr[fpi + 1] * 255);
  628. tex->pcData[i].r = static_cast<uint8_t>(floatPtr[fpi + 2] * 255);
  629. tex->pcData[i].a = static_cast<uint8_t>(floatPtr[fpi + 3] * 255);
  630. }
  631. ss.str("");
  632. ss << "ownedEmbeddedTextureFor(): imageTexelsCount: " << imageTexelsCount << ", channels: " << image.channels;
  633. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  634. }
  635. return tex;
  636. }
  637. void USDImporterImplTinyusdz::textureImages(const RenderScene &render_scene, aiScene *pScene, const std::string &nameWExt) {
  638. std::stringstream ss;
  639. const size_t numTextureImages{ render_scene.images.size() };
  640. ss.str("");
  641. ss << "textureImages(): model" << nameWExt << ", numTextureImages: " << numTextureImages;
  642. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  643. pScene->mTextures = nullptr; // Need to iterate over images before knowing if valid textures available
  644. pScene->mNumTextures = 0;
  645. for (const auto &image : render_scene.images) {
  646. ss.str("");
  647. ss << " image[" << pScene->mNumTextures << "]: |" << image.asset_identifier << "| w: "
  648. << image.width << ", h: " << image.height << ", channels: " << image.channels << ", miplevel: "
  649. << image.miplevel << ", buffer id: " << image.buffer_id << "\n"
  650. << " buffers.size(): " << render_scene.buffers.size() << ", data empty? "
  651. << render_scene.buffers[image.buffer_id].data.empty();
  652. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  653. if (image.buffer_id > -1 &&
  654. image.buffer_id < static_cast<long int>(render_scene.buffers.size()) &&
  655. !render_scene.buffers[image.buffer_id].data.empty()) {
  656. aiTexture *tex = ownedEmbeddedTextureFor(
  657. render_scene,
  658. image,
  659. nameWExt);
  660. if (pScene->mTextures == nullptr) {
  661. ss.str("");
  662. ss << " Init pScene->mTextures[" << render_scene.images.size() << "]";
  663. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  664. pScene->mTextures = new aiTexture *[render_scene.images.size()];
  665. }
  666. ss.str("");
  667. ss << " pScene->mTextures[" << pScene->mNumTextures << "] name: |" << tex->mFilename.C_Str()
  668. << "|, w: " << tex->mWidth << ", h: " << tex->mHeight << ", hint: " << tex->achFormatHint;
  669. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  670. pScene->mTextures[pScene->mNumTextures++] = tex;
  671. }
  672. }
  673. }
  674. void USDImporterImplTinyusdz::buffers(
  675. const RenderScene &render_scene, aiScene*, const std::string &nameWExt) {
  676. const size_t numBuffers{ render_scene.buffers.size() };
  677. std::stringstream ss;
  678. ss.str("");
  679. ss << "buffers(): model" << nameWExt << ", numBuffers: " << numBuffers;
  680. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  681. size_t i = 0;
  682. for (const auto &buffer : render_scene.buffers) {
  683. ss.str("");
  684. ss << " buffer[" << i << "]: count: " << buffer.data.size() << ", type: " << to_string(buffer.componentType);
  685. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  686. ++i;
  687. }
  688. }
  689. aiNode *USDImporterImplTinyusdz::nodesRecursive(aiNode *pNodeParent, const tinyusdz::tydra::Node &node,
  690. const std::vector<SkelHierarchy> &skeletons) {
  691. std::stringstream ss;
  692. aiNode *cNode = new aiNode();
  693. cNode->mParent = pNodeParent;
  694. cNode->mName.Set(node.prim_name);
  695. cNode->mTransformation = tinyUsdzMat4ToAiMat4(node.local_matrix.m);
  696. if (node.nodeType == NodeType::Mesh) {
  697. cNode->mNumMeshes = 1;
  698. cNode->mMeshes = new unsigned int[cNode->mNumMeshes];
  699. cNode->mMeshes[0] = node.id;
  700. }
  701. ss.str("");
  702. ss << "nodesRecursive(): node " << cNode->mName.C_Str() << " type: |"
  703. << tinyusdzNodeTypeFor(node.nodeType)
  704. << "|, disp " << node.display_name << ", abs " << node.abs_path;
  705. if (cNode->mParent != nullptr) {
  706. ss << " (parent " << cNode->mParent->mName.C_Str() << ")";
  707. }
  708. ss << " has " << node.children.size() << " children";
  709. if (node.nodeType == NodeType::Mesh) {
  710. ss << "\n node mesh id: " << node.id << " (node type: " << tinyusdzNodeTypeFor(node.nodeType) << ")";
  711. }
  712. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  713. unsigned int numChildren = unsigned(node.children.size());
  714. // Find any tinyusdz skeletons which might begin at this node
  715. // Add the skeleton bones as child nodes
  716. const tinyusdz::tydra::SkelNode *skelNode = nullptr;
  717. for (const auto &skeleton : skeletons) {
  718. if (skeleton.abs_path == node.abs_path) {
  719. // Add this skeleton's bones as child nodes
  720. ++numChildren;
  721. skelNode = &skeleton.root_node;
  722. break;
  723. }
  724. }
  725. cNode->mNumChildren = numChildren;
  726. // Done. No more children.
  727. if (numChildren == 0) {
  728. return cNode;
  729. }
  730. cNode->mChildren = new aiNode *[cNode->mNumChildren];
  731. size_t i{ 0 };
  732. for (const auto &childNode : node.children) {
  733. cNode->mChildren[i] = nodesRecursive(cNode, childNode, skeletons);
  734. ++i;
  735. }
  736. if (skelNode != nullptr) {
  737. // Convert USD skeleton into an Assimp node and make it the last child
  738. cNode->mChildren[cNode->mNumChildren - 1] = skeletonNodesRecursive(cNode, *skelNode);
  739. }
  740. return cNode;
  741. }
  742. aiNode *USDImporterImplTinyusdz::skeletonNodesRecursive(
  743. aiNode *pNodeParent,
  744. const SkelNode &joint) {
  745. auto *cNode = new aiNode(joint.joint_path);
  746. cNode->mParent = pNodeParent;
  747. cNode->mNumMeshes = 0; // not a mesh node
  748. cNode->mTransformation = tinyUsdzMat4ToAiMat4(joint.rest_transform.m);
  749. // Done. No more children.
  750. if (joint.children.empty()) {
  751. return cNode;
  752. }
  753. cNode->mNumChildren = static_cast<unsigned int>(joint.children.size());
  754. cNode->mChildren = new aiNode *[cNode->mNumChildren];
  755. for (unsigned i = 0; i < cNode->mNumChildren; ++i) {
  756. const SkelNode &childJoint = joint.children[i];
  757. cNode->mChildren[i] = skeletonNodesRecursive(cNode, childJoint);
  758. }
  759. return cNode;
  760. }
  761. void USDImporterImplTinyusdz::sanityCheckNodesRecursive(
  762. aiNode *cNode) {
  763. std::stringstream ss;
  764. ss.str("");
  765. ss << "sanityCheckNodesRecursive(): node " << cNode->mName.C_Str();
  766. if (cNode->mParent != nullptr) {
  767. ss << " (parent " << cNode->mParent->mName.C_Str() << ")";
  768. }
  769. ss << " has " << cNode->mNumChildren << " children";
  770. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  771. for (size_t i = 0; i < cNode->mNumChildren; ++i) {
  772. sanityCheckNodesRecursive(cNode->mChildren[i]);
  773. }
  774. }
  775. void USDImporterImplTinyusdz::setupBlendShapes(const RenderScene &render_scene, aiScene *pScene,
  776. const std::string &nameWExt) {
  777. std::stringstream ss;
  778. ss.str("");
  779. ss << "setupBlendShapes(): iterating over " << pScene->mNumMeshes << " meshes for model" << nameWExt;
  780. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  781. for (size_t meshIdx = 0; meshIdx < pScene->mNumMeshes; meshIdx++) {
  782. blendShapesForMesh(render_scene, pScene, meshIdx, nameWExt);
  783. }
  784. }
  785. void USDImporterImplTinyusdz::blendShapesForMesh(
  786. const tinyusdz::tydra::RenderScene &render_scene,
  787. aiScene *pScene,
  788. size_t meshIdx,
  789. const std::string &) {
  790. std::stringstream ss;
  791. const unsigned int numBlendShapeTargets{ static_cast<unsigned int>(render_scene.meshes[meshIdx].targets.size()) };
  792. UNUSED(numBlendShapeTargets); // Ignore unused variable when -Werror enabled
  793. ss.str("");
  794. ss << " blendShapesForMesh(): mesh[" << meshIdx << "], numBlendShapeTargets: " << numBlendShapeTargets;
  795. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  796. if (numBlendShapeTargets > 0) {
  797. pScene->mMeshes[meshIdx]->mNumAnimMeshes = numBlendShapeTargets;
  798. pScene->mMeshes[meshIdx]->mAnimMeshes = new aiAnimMesh *[pScene->mMeshes[meshIdx]->mNumAnimMeshes];
  799. }
  800. auto mapIter = render_scene.meshes[meshIdx].targets.begin();
  801. size_t animMeshIdx{ 0 };
  802. for (; mapIter != render_scene.meshes[meshIdx].targets.end(); ++mapIter) {
  803. const std::string name{ mapIter->first };
  804. const tinyusdz::tydra::ShapeTarget shapeTarget{ mapIter->second };
  805. pScene->mMeshes[meshIdx]->mAnimMeshes[animMeshIdx] = aiCreateAnimMesh(pScene->mMeshes[meshIdx]);
  806. ss.str("");
  807. ss << " mAnimMeshes[" << animMeshIdx << "]: mNumVertices: " << pScene->mMeshes[meshIdx]->mAnimMeshes[animMeshIdx]->mNumVertices << ", target: " << shapeTarget.pointIndices.size() << " pointIndices, " << shapeTarget.pointOffsets.size() << " pointOffsets, " << shapeTarget.normalOffsets.size() << " normalOffsets";
  808. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  809. for (size_t iVert = 0; iVert < shapeTarget.pointOffsets.size(); ++iVert) {
  810. pScene->mMeshes[meshIdx]->mAnimMeshes[animMeshIdx]->mVertices[shapeTarget.pointIndices[iVert]] +=
  811. tinyUsdzScaleOrPosToAssimp(shapeTarget.pointOffsets[iVert]);
  812. }
  813. for (size_t iVert = 0; iVert < shapeTarget.normalOffsets.size(); ++iVert) {
  814. pScene->mMeshes[meshIdx]->mAnimMeshes[animMeshIdx]->mNormals[shapeTarget.pointIndices[iVert]] +=
  815. tinyUsdzScaleOrPosToAssimp(shapeTarget.normalOffsets[iVert]);
  816. }
  817. ss.str("");
  818. 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";
  819. TINYUSDZLOGD(TAG, "%s", ss.str().c_str());
  820. ++animMeshIdx;
  821. }
  822. }
  823. } // namespace Assimp
  824. #endif // !! ASSIMP_BUILD_NO_USD_IMPORTER