6 #include <unordered_map>
7 #include <unordered_set>
37 using std::make_unique;
40 using std::unique_ptr;
41 using std::unordered_map;
42 using std::unordered_set;
74 for (
auto i = 0; i < vertices.size(); i++) {
75 const auto& currentVertex = vertices[i];
76 const auto& nextVertex = vertices[(i + 1) % vertices.size()];
77 edgeSum += (nextVertex[0] - currentVertex[0]) * (nextVertex[1] - currentVertex[1]) * (nextVertex[2] - currentVertex[2]);
94 for (
const auto& [nodeId, node]: nodes) {
95 const auto& nodeVertices = node->getVertices();
96 const auto& nodeNormals = node->getNormals();
97 const auto& nodeTextureCoordinates = node->getTextureCoordinates();
98 const auto& nodeTangents = node->getTangents();
99 const auto& nodeBitangents = node->getBitangents();
100 const auto& nodeOrigins = node->getOrigins();
101 vector<int32_t> vertexMapping;
102 vector<Vector3> indexedVertices;
103 vector<Vector3> indexedNormals;
104 vector<Vector2> indexedTextureCoordinates;
105 vector<Vector3> indexedTangents;
106 vector<Vector3> indexedBitangents;
107 vector<Vector3> indexedOrigins;
109 auto preparedIndices = 0;
110 auto newFacesEntities = node->getFacesEntities();
111 for (
auto& newFacesEntity: newFacesEntities) {
112 auto newFaces = newFacesEntity.getFaces();
113 for (
auto& face: newFaces) {
114 auto faceVertexIndices = face.getVertexIndices();
115 auto faceNormalIndices = face.getNormalIndices();
116 auto faceTextureIndices = face.getTextureCoordinateIndices();
117 auto faceTangentIndices = face.getTangentIndices();
118 auto faceBitangentIndices = face.getBitangentIndices();
119 array<int32_t, 3> indexedFaceVertexIndices;
120 for (int16_t idx = 0; idx < 3; idx++) {
121 auto nodeVertexIndex = faceVertexIndices[idx];
122 auto nodeNormalIndex = faceNormalIndices[idx];
123 auto nodeTextureCoordinateIndex = faceTextureIndices[idx];
124 auto nodeTangentIndex = faceTangentIndices[idx];
125 auto nodeBitangentIndex = faceBitangentIndices[idx];
126 auto vertex = &nodeVertices[nodeVertexIndex];
127 auto normal = &nodeNormals[nodeNormalIndex];
128 auto textureCoordinate = nodeTextureCoordinates.size() > 0?&nodeTextureCoordinates[nodeTextureCoordinateIndex]:
static_cast<Vector2*
>(
nullptr);
129 auto tangent = nodeTangents.size() > 0 ? &nodeTangents[nodeTangentIndex] :
static_cast<Vector3*
>(
nullptr);
130 auto bitangent = nodeBitangents.size() > 0 ? &nodeBitangents[nodeBitangentIndex] :
static_cast<Vector3*
>(
nullptr);
131 auto origin = nodeOrigins.size() > 0 ? &nodeOrigins[nodeVertexIndex] :
static_cast<Vector3*
>(
nullptr);
132 auto newIndex = preparedIndices;
133 for (
auto i = 0; i < preparedIndices; i++)
134 if (indexedVertices[i].equals(*vertex) &&
135 indexedNormals[i].equals(*normal) &&
136 (textureCoordinate ==
nullptr || indexedTextureCoordinates[i].equals(*textureCoordinate)) &&
137 (tangent ==
nullptr || indexedTangents[i].equals(*tangent)) &&
138 (bitangent ==
nullptr || indexedBitangents[i].equals(*bitangent))) {
142 if (newIndex == preparedIndices) {
143 vertexMapping.push_back(nodeVertexIndex);
144 indexedVertices.push_back(*vertex);
145 indexedNormals.push_back(*normal);
146 if (textureCoordinate !=
nullptr) indexedTextureCoordinates.push_back(*textureCoordinate);
147 if (tangent !=
nullptr) indexedTangents.push_back(*tangent);
148 if (bitangent !=
nullptr) indexedBitangents.push_back(*bitangent);
149 if (origin !=
nullptr) indexedOrigins.push_back(*origin);
152 indexedFaceVertexIndices[idx] = newIndex;
154 face.setIndexedRenderingIndices(indexedFaceVertexIndices);
156 newFacesEntity.setFaces(newFaces);
158 node->setFacesEntities(newFacesEntities);
160 auto skinning = node->getSkinning();
161 if (skinning !=
nullptr) {
164 node->setVertices(indexedVertices);
165 node->setNormals(indexedNormals);
166 if (nodeTextureCoordinates.size() > 0) {
167 node->setTextureCoordinates(indexedTextureCoordinates);
169 node->setTangents(indexedTangents);
170 node->setBitangents(indexedBitangents);
171 if (nodeOrigins.size() > 0) {
172 node->setOrigins(indexedOrigins);
182 vector<vector<JointWeight>> verticesJointsWeights;
183 verticesJointsWeights.resize(vertices);
184 for (
auto i = 0; i < vertices; i++) {
185 auto vertexOriginalMappedToIdx = vertexMapping[i];
186 verticesJointsWeights[i].resize(originalVerticesJointsWeights[vertexOriginalMappedToIdx].size());
187 for (
auto j = 0; j < verticesJointsWeights[i].size(); j++) {
188 verticesJointsWeights[i][j] = originalVerticesJointsWeights[vertexOriginalMappedToIdx][j];
198 for (
const auto& [nodeId, node]: nodes) {
199 auto skinning = node->getSkinning();
201 if (skinning !=
nullptr) {
203 for (
const auto& joint : skinning->getJoints()) {
204 auto jointNodeIt = nodes.find(joint.getNodeId());
205 if (jointNodeIt != nodes.end()) {
216 for (
const auto& [subNodeId, subNode]: root->
getSubNodes()) {
225 if (defaultAnimation !=
nullptr) {
226 for (
const auto& [subNodeId, subNode]: model->
getSubNodes()) {
235 if (animation !=
nullptr) {
236 vector<Matrix4x4> newTransformMatrices;
238 auto animation = make_unique<Animation>();
239 newTransformMatrices.resize(frames);
240 for (
auto i = 0; i < frames; i++) {
241 if (i < oldTransformMatrices.size()) {
242 newTransformMatrices[i] = oldTransformMatrices[i];
244 newTransformMatrices[i].identity();
247 animation->setTransformMatrices(newTransformMatrices);
250 for (
const auto& [subNodeId, subNode]: root->
getSubNodes()) {
263 if (defaultAnimation ==
nullptr) {
267 if (defaultAnimation->getStartFrame() != 0 || defaultAnimation->getEndFrame() != frames - 1) {
270 if (frames - 1 > defaultAnimation->getEndFrame()) {
271 Console::println(
string(
"Warning: default animation mismatch, will be fixed"));
278 auto clonedMaterial = make_unique<Material>(
id.empty()?material->
getId():
id);
280 if (specularMaterialProperties !=
nullptr) {
281 auto clonedSpecularMaterialProperties = make_unique<SpecularMaterialProperties>();
282 clonedSpecularMaterialProperties->setAmbientColor(specularMaterialProperties->getAmbientColor());
283 clonedSpecularMaterialProperties->setDiffuseColor(specularMaterialProperties->getDiffuseColor());
284 clonedSpecularMaterialProperties->setEmissionColor(specularMaterialProperties->getEmissionColor());
285 clonedSpecularMaterialProperties->setSpecularColor(specularMaterialProperties->getSpecularColor());
286 clonedSpecularMaterialProperties->setShininess(specularMaterialProperties->getShininess());
287 clonedSpecularMaterialProperties->setTextureAtlasSize(specularMaterialProperties->getTextureAtlasSize());
288 auto clonedSpecularMaterialPropertiesDiffuseTexture = specularMaterialProperties->getDiffuseTexture();
289 if (clonedSpecularMaterialPropertiesDiffuseTexture !=
nullptr) {
290 clonedSpecularMaterialPropertiesDiffuseTexture->acquireReference();
291 clonedSpecularMaterialProperties->setDiffuseTexture(clonedSpecularMaterialPropertiesDiffuseTexture);
292 clonedSpecularMaterialProperties->setDiffuseTexturePathName(specularMaterialProperties->getDiffuseTexturePathName());
293 clonedSpecularMaterialProperties->setDiffuseTextureFileName(specularMaterialProperties->getDiffuseTextureFileName());
295 clonedSpecularMaterialProperties->setDiffuseTextureTransparency(specularMaterialProperties->hasDiffuseTextureTransparency());
296 clonedSpecularMaterialProperties->setDiffuseTextureMaskedTransparency(specularMaterialProperties->hasDiffuseTextureMaskedTransparency());
297 clonedSpecularMaterialProperties->setDiffuseTextureMaskedTransparencyThreshold(specularMaterialProperties->getDiffuseTextureMaskedTransparencyThreshold());
298 auto clonedSpecularMaterialPropertiesSpecularTexture = specularMaterialProperties->getSpecularTexture();
299 if (clonedSpecularMaterialPropertiesSpecularTexture !=
nullptr) {
300 clonedSpecularMaterialPropertiesSpecularTexture->acquireReference();
301 clonedSpecularMaterialProperties->setSpecularTexture(clonedSpecularMaterialPropertiesSpecularTexture);
302 clonedSpecularMaterialProperties->setSpecularTexturePathName(specularMaterialProperties->getSpecularTexturePathName());
303 clonedSpecularMaterialProperties->setSpecularTextureFileName(specularMaterialProperties->getSpecularTextureFileName());
305 auto clonedSpecularMaterialPropertiesNormalTexture = specularMaterialProperties->getNormalTexture();
306 if (clonedSpecularMaterialPropertiesNormalTexture !=
nullptr) {
307 clonedSpecularMaterialPropertiesNormalTexture->acquireReference();
308 clonedSpecularMaterialProperties->setNormalTexture(clonedSpecularMaterialPropertiesNormalTexture);
309 clonedSpecularMaterialProperties->setNormalTexturePathName(specularMaterialProperties->getNormalTexturePathName());
310 clonedSpecularMaterialProperties->setNormalTextureFileName(specularMaterialProperties->getNormalTextureFileName());
312 clonedMaterial->setSpecularMaterialProperties(clonedSpecularMaterialProperties.release());
314 return clonedMaterial.release();
318 auto clonedNode = make_unique<Node>(targetModel, targetParentNode, sourceNode->
getId(), sourceNode->
getName());
320 clonedNode->setJoint(sourceNode->
isJoint());
321 if (cloneMesh ==
true) {
322 clonedNode->setVertices(sourceNode->
getVertices());
323 clonedNode->setNormals(sourceNode->
getNormals());
325 clonedNode->setTangents(sourceNode->
getTangents());
327 clonedNode->setOrigins(sourceNode->
getOrigins());
328 auto facesEntities = clonedNode->getFacesEntities();
330 if (facesEntity.getMaterial() ==
nullptr)
continue;
332 auto materialIt = targetModel->
getMaterials().find(facesEntity.getMaterial()->getId());
334 auto newMaterial = unique_ptr<Material>(
cloneMaterial(facesEntity.getMaterial()));
336 material = newMaterial.release();
338 material = materialIt->second;
340 auto clonedFacesEntity =
FacesEntity(clonedNode.get(), facesEntity.getId());
341 clonedFacesEntity.setMaterial(material);
342 clonedFacesEntity.setFaces(facesEntity.getFaces());
343 facesEntities.push_back(clonedFacesEntity);
345 clonedNode->setFacesEntities(facesEntities);
348 auto clonedAnimation = make_unique<Animation>();
350 clonedNode->setAnimation(clonedAnimation.release());
352 targetModel->
getNodes()[clonedNode->getId()] = clonedNode.get();
353 if (targetParentNode ==
nullptr) {
354 targetModel->
getSubNodes()[clonedNode->getId()] = clonedNode.get();
356 targetParentNode->
getSubNodes()[clonedNode->getId()] = clonedNode.get();
358 auto newTargetParentNode = clonedNode.release();
359 for (
const auto& [sourceSubNodeId, sourceSubNode]: sourceNode->
getSubNodes()) {
360 cloneNode(sourceSubNode, targetModel, newTargetParentNode, cloneMesh);
370 transformMatrix.
multiply(parentTransformMatrix);
404 unordered_map<string, Node*> partitionModelNodes;
407 unordered_map<string, vector<Vector3>> partitionModelNodesVertices;
408 unordered_map<string, vector<Vector3>> partitionModelNodesNormals;
409 unordered_map<string, vector<Vector2>> partitionModelNodesTextureCoordinates;
410 unordered_map<string, vector<Vector3>> partitionModelNodesTangents;
411 unordered_map<string, vector<Vector3>> partitionModelNodesBitangents;
412 unordered_map<string, vector<FacesEntity>> partitionModelNodesFacesEntities;
415 bool haveTextureCoordinates = facesEntity.isTextureCoordinatesAvailable();
416 bool haveTangentsBitangents = facesEntity.isTangentBitangentAvailable();
417 for (
const auto& face: facesEntity.getFaces()) {
419 const auto& vertexIndices = face.getVertexIndices();
420 const auto& normalIndices = face.getNormalIndices();
421 const auto& textureCoordinatesIndices = face.getTextureCoordinateIndices();
422 const auto& tangentIndices = face.getTangentIndices();
423 const auto& bitangentIndices = face.getBitangentIndices();
430 if (haveTextureCoordinates ==
true) {
435 if (haveTangentsBitangents ==
true) {
445 vertex0Transformed = transformMatrix.
multiply(vertex0);
446 vertex1Transformed = transformMatrix.
multiply(vertex1);
447 vertex2Transformed = transformMatrix.
multiply(vertex2);
448 faceCenter.
set(vertex0Transformed);
449 faceCenter.
add(vertex1Transformed);
450 faceCenter.
add(vertex2Transformed);
451 faceCenter.
scale(1.0f / 3.0f);
452 auto minX = Math::min(Math::min(vertex0Transformed.
getX(), vertex1Transformed.
getX()), vertex2Transformed.
getX());
453 auto minY = Math::min(Math::min(vertex0Transformed.
getY(), vertex1Transformed.
getY()), vertex2Transformed.
getY());
454 auto minZ = Math::min(Math::min(vertex0Transformed.
getZ(), vertex1Transformed.
getZ()), vertex2Transformed.
getZ());
455 auto partitionX = (int)(minX / 64.0f);
456 auto partitionY = (int)(minY / 64.0f);
457 auto partitionZ = (int)(minZ / 64.0f);
460 string partitionModelKey =
461 to_string(partitionX) +
"," +
462 to_string(partitionY) +
"," +
463 to_string(partitionZ);
466 auto partitionModel = modelsByPartition[partitionModelKey];
467 if (partitionModel ==
nullptr) {
468 auto newPartitionModel = make_unique<Model>(
469 sourceNodeId +
"." + partitionModelKey,
470 sourceNodeName +
"." + partitionModelKey,
475 modelsByPartition[partitionModelKey] = newPartitionModel.get();
476 modelsPosition[partitionModelKey].set(partitionX * 64.0f, partitionY * 64.0f, partitionZ * 64.0f);
477 partitionModel = newPartitionModel.release();
481 auto partitionModelNode = partitionModelNodes[partitionModelKey];
482 partitionModelNode = partitionModel->getNodeById(sourceNode->
getId());
483 if (partitionModelNode ==
nullptr) {
484 auto newPartitionModelNode = make_unique<Node>(
492 partitionModel->getSubNodes()[newPartitionModelNode->getId()] = newPartitionModelNode.get();
494 newPartitionModelNode->getParentNode()->getSubNodes()[newPartitionModelNode->getId()] = newPartitionModelNode.get();
496 partitionModel->getNodes()[newPartitionModelNode->getId()] = newPartitionModelNode.get();
497 partitionModelNodes[partitionModelKey] = newPartitionModelNode.get();
498 partitionModelNode = newPartitionModelNode.release();
502 FacesEntity* partitionModelNodeFacesEntity =
nullptr;
503 for (
auto& partitionModelNodeFacesEntityExisting: partitionModelNodesFacesEntities[partitionModelKey]) {
504 if (partitionModelNodeFacesEntityExisting.getId() == facesEntity.getId()) {
505 partitionModelNodeFacesEntity = &partitionModelNodeFacesEntityExisting;
508 if (partitionModelNodeFacesEntity ==
nullptr) {
513 partitionModelNodesFacesEntities[partitionModelKey].push_back(newFacesEntity);
514 partitionModelNodeFacesEntity = &newFacesEntity;
515 auto partitionModelNodeFacesEntityMaterial = partitionModel->getMaterials()[facesEntity.getMaterial()->getId()];
516 if (partitionModelNodeFacesEntityMaterial ==
nullptr) {
517 partitionModelNodeFacesEntityMaterial =
cloneMaterial(facesEntity.getMaterial());
518 partitionModel->getMaterials()[facesEntity.getMaterial()->getId()] = partitionModelNodeFacesEntityMaterial;
520 partitionModelNodeFacesEntity->
setMaterial(partitionModelNodeFacesEntityMaterial);
523 auto faces = partitionModelNodeFacesEntity->
getFaces();
526 auto verticesIdx = partitionModelNodesVertices[partitionModelKey].size();
527 partitionModelNodesVertices[partitionModelKey].push_back(vertex0);
528 partitionModelNodesVertices[partitionModelKey].push_back(vertex1);
529 partitionModelNodesVertices[partitionModelKey].push_back(vertex2);
530 partitionModelNodesNormals[partitionModelKey].push_back(normal0);
531 partitionModelNodesNormals[partitionModelKey].push_back(normal1);
532 partitionModelNodesNormals[partitionModelKey].push_back(normal2);
533 if (haveTextureCoordinates ==
true) {
534 partitionModelNodesTextureCoordinates[partitionModelKey].push_back(textureCoordinate0);
535 partitionModelNodesTextureCoordinates[partitionModelKey].push_back(textureCoordinate1);
536 partitionModelNodesTextureCoordinates[partitionModelKey].push_back(textureCoordinate2);
538 if (haveTangentsBitangents ==
true) {
539 partitionModelNodesTangents[partitionModelKey].push_back(tangent0);
540 partitionModelNodesTangents[partitionModelKey].push_back(tangent1);
541 partitionModelNodesTangents[partitionModelKey].push_back(tangent2);
542 partitionModelNodesBitangents[partitionModelKey].push_back(bitangent0);
543 partitionModelNodesBitangents[partitionModelKey].push_back(bitangent1);
544 partitionModelNodesBitangents[partitionModelKey].push_back(bitangent2);
556 if (haveTextureCoordinates ==
true) {
563 if (haveTangentsBitangents ==
true) {
575 faces.push_back(newFace);
576 partitionModelNodeFacesEntity->
setFaces(faces);
581 for (
const auto& [partitionModelKey, model]: modelsByPartition) {
582 if (partitionModelNodes[partitionModelKey] ==
nullptr)
continue;
583 partitionModelNodes[partitionModelKey]->setVertices(partitionModelNodesVertices[partitionModelKey]);
584 partitionModelNodes[partitionModelKey]->setNormals(partitionModelNodesNormals[partitionModelKey]);
585 partitionModelNodes[partitionModelKey]->setTextureCoordinates(partitionModelNodesTextureCoordinates[partitionModelKey]);
586 partitionModelNodes[partitionModelKey]->setTangents(partitionModelNodesTangents[partitionModelKey]);
587 partitionModelNodes[partitionModelKey]->setBitangents(partitionModelNodesBitangents[partitionModelKey]);
588 partitionModelNodes[partitionModelKey]->setFacesEntities(partitionModelNodesFacesEntities[partitionModelKey]);
592 for (
const auto& [sourceNodeId, sourceNode]: sourceNode->
getSubNodes()) {
593 partitionNode(sourceNode, modelsByPartition, modelsPosition, transformMatrix);
601 for (
const auto& [subNodeId, subNode]: model->
getSubNodes()) {
602 partitionNode(subNode, modelsByPartition, modelsPosition, transformMatrix);
604 for (
const auto& [partitionKey, partitionModel]: modelsByPartition) {
635 for (
const auto& [subNodeId, subNode]: model->
getSubNodes()) {
642 array<Vector3, 3> vertices;
644 auto facesEntityProcessed = 0;
645 vector<Vector3> normals;
647 for (
auto& facesEntity: facesEntities) {
648 auto faces = facesEntity.getFaces();
649 for (
auto& face: faces) {
650 for (
auto i = 0; i < vertices.size(); i++) {
651 vertices[i] = node->
getVertices()[face.getVertexIndices()[i]];
654 face.setNormalIndices(normals.size(), normals.size() + 1, normals.size() + 2);
655 normals.push_back(normal);
656 normals.push_back(normal);
657 normals.push_back(normal);
658 if (progressCallback !=
nullptr) {
659 progress+= incrementPerFace / 2.0f;
660 if (facesEntityProcessed == 0 || facesEntityProcessed % 1000 == 0) progressCallback->
progress(progress);
661 facesEntityProcessed++;
664 facesEntity.setFaces(faces);
667 facesEntityProcessed = 0;
669 for (
const auto& face: facesEntity.getFaces()) {
670 for (
auto i = 0; i < vertices.size(); i++) {
672 normals[face.getNormalIndices()[i]].set(normal);
675 if (progressCallback !=
nullptr) {
676 progress+= incrementPerFace / 2.0f;
677 if (facesEntityProcessed == 0 || facesEntityProcessed % 1000 == 0) progressCallback->
progress(progress);
678 facesEntityProcessed++;
683 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
684 progress =
computeNormals(subNode, progressCallback, incrementPerFace, progress);
690 auto progessCallbackPtr = unique_ptr<ProgressCallback>(progressCallback);
692 for (
const auto& [subNodeId, subNode]: model->
getSubNodes()) {
695 for (
const auto& [subNodeId, subNode]: model->
getSubNodes()) {
696 computeNormals(subNode, progessCallbackPtr.get(), 1.0f /
static_cast<float>(faceCount), 0.0f);
699 if (progessCallbackPtr !=
nullptr) {
700 progessCallbackPtr->progress(1.0f);
707 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
714 if (shader ==
"foliage" || shader ==
"pbr-foliage" || shader ==
"tree" || shader ==
"pbr-tree") {
729 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
739 for (
auto& vertex: vertices) {
740 vertex = transformMatrix.multiply(vertex);
746 for (
auto& normal: normals) {
747 normal = transformMatrix.multiplyNoTranslation(normal);
754 for (
auto& tangent: tangents) {
755 tangent = transformMatrix.multiplyNoTranslation(tangent);
762 for (
auto& bitangent: bitangents) {
763 bitangent = transformMatrix.multiplyNoTranslation(bitangent);
764 bitangent.normalize();
773 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
787 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
794 vector<Vector3> objectOrigins;
799 for (
auto& vertex: vertices) {
800 vertex = transformMatrix.multiply(vertex);
801 if (shader ==
"tree" || shader ==
"pbr-tree") objectOrigins[vertexIdx].set(0.0f, vertex.getY(), 0.0f);
808 for (
auto& normal: normals) {
809 normal = transformMatrix.multiplyNoTranslation(normal);
816 for (
auto& tangent: tangents) {
817 tangent = transformMatrix.multiplyNoTranslation(tangent);
824 for (
auto& bitangent: bitangents) {
825 bitangent = transformMatrix.multiplyNoTranslation(bitangent);
826 bitangent.normalize();
836 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
843 if (node->
isJoint() ==
true)
return;
847 if (facesEntity.getMaterial() ==
nullptr)
continue;
848 bool excludeDiffuseTexture =
false;
849 for (
const auto& excludeDiffuseTextureFileNamePattern: excludeDiffuseTextureFileNamePatterns) {
850 if (
StringTools::startsWith(facesEntity.getMaterial()->getSpecularMaterialProperties()->getDiffuseTextureFileName(), excludeDiffuseTextureFileNamePattern) ==
true) {
851 excludeDiffuseTexture =
true;
855 if (excludeDiffuseTexture ==
true) {
858 materialUseCount[facesEntity.getMaterial()->getId()]++;
865 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
872 if (node->
isJoint() ==
true)
return;
881 for (
auto& vertex: vertices) {
882 vertex = transformMatrix.multiply(vertex);
888 for (
auto& normal: normals) {
889 normal = transformMatrix.multiplyNoTranslation(normal);
896 for (
auto& tangent: tangents) {
897 tangent = transformMatrix.multiplyNoTranslation(tangent);
904 for (
auto& bitangent: bitangents) {
905 bitangent = transformMatrix.multiplyNoTranslation(bitangent);
906 bitangent.normalize();
915 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
920 void ModelTools::optimizeNode(
Node* sourceNode,
Model* targetModel,
int diffuseTextureAtlasSize,
const unordered_map<string, int>& diffuseTextureAtlasIndices,
const vector<string>& excludeDiffuseTextureFileNamePatterns) {
922 unordered_set<int> processedTextureCoordinates;
923 const auto& sourceVertices = sourceNode->
getVertices();
924 const auto& sourceNormals = sourceNode->
getNormals();
925 const auto& sourceTangents = sourceNode->
getTangents();
928 const auto& sourceOrigins = sourceNode->
getOrigins();
929 auto targetNode = targetModel->
getNodes()[
"tdme.node.optimized"];
930 auto targetVertices = targetNode->getVertices();
931 auto targetNormals = targetNode->getNormals();
932 auto targetTangents = targetNode->getTangents();
933 auto targetBitangents = targetNode->getBitangents();
934 auto targetTextureCoordinates = targetNode->getTextureCoordinates();
935 auto targetOrigins = targetNode->getOrigins();
936 auto targetOffset = targetVertices.size();
937 for (
const auto& v: sourceVertices) targetVertices.push_back(v);
938 for (
const auto& v: sourceNormals) targetNormals.push_back(v);
939 for (
const auto& v: sourceTangents) targetTangents.push_back(v);
940 for (
const auto& v: sourceBitangents) targetBitangents.push_back(v);
941 for (
const auto& v: sourceTextureCoordinates) targetTextureCoordinates.push_back(v);
942 for (
const auto& v: sourceOrigins) targetOrigins.push_back(v);
943 targetNode->setVertices(targetVertices);
944 targetNode->setNormals(targetNormals);
945 targetNode->setTangents(targetTangents);
946 targetNode->setBitangents(targetBitangents);
947 targetNode->setOrigins(targetOrigins);
948 vector<FacesEntity> targetFacesEntitiesKeptMaterials;
949 for (
auto& targetFacesEntity: targetNode->getFacesEntities()) {
951 targetFacesEntitiesKeptMaterials.push_back(targetFacesEntity);
954 auto targetFaces = (tmpFacesEntity = targetNode->getFacesEntity(
"tdme.facesentity.optimized")) !=
nullptr?tmpFacesEntity->
getFaces():vector<Face>();
955 auto targetFacesMaskedTransparency = (tmpFacesEntity = targetNode->getFacesEntity(
"tdme.facesentity.optimized.maskedtransparency")) !=
nullptr?tmpFacesEntity->
getFaces():vector<Face>();
956 auto targetFacesTransparency = (tmpFacesEntity = targetNode->getFacesEntity(
"tdme.facesentity.optimized.transparency")) !=
nullptr?tmpFacesEntity->
getFaces():vector<Face>();
958 auto material = sourceFacesEntity.getMaterial();
961 string keptMaterialId;
962 for (
const auto& excludeDiffuseTextureFileNamePattern: excludeDiffuseTextureFileNamePatterns) {
963 if (
StringTools::startsWith(sourceFacesEntity.getMaterial()->getSpecularMaterialProperties()->getDiffuseTextureFileName(), excludeDiffuseTextureFileNamePattern) ==
true) {
964 keptMaterialId = sourceFacesEntity.getMaterial()->getId();
968 auto targetFacesKeptMaterial = (tmpFacesEntity = targetNode->getFacesEntity(
"tdme.facesentity.kept." + keptMaterialId)) !=
nullptr?tmpFacesEntity->
getFaces():vector<Face>();
970 auto diffuseTextureAtlasIndexIt = diffuseTextureAtlasIndices.find(material->getId());
971 auto diffuseTextureAtlasIndex = -1;
972 if (diffuseTextureAtlasIndexIt != diffuseTextureAtlasIndices.end()) {
973 diffuseTextureAtlasIndex = diffuseTextureAtlasIndices.find(material->getId())->second;
975 auto textureXOffset = 0.0f;
976 auto textureYOffset = 0.0f;
977 auto textureXScale = 1.0f;
978 auto textureYScale = 1.0f;
979 if (diffuseTextureAtlasIndex != -1) {
980 textureXOffset = diffuseTextureAtlasSize == 0?0.0f:
static_cast<float>(diffuseTextureAtlasIndex % diffuseTextureAtlasSize) * 1000.0f + 500.0f;
981 textureYOffset = diffuseTextureAtlasSize == 0?0.0f:
static_cast<float>(diffuseTextureAtlasIndex / diffuseTextureAtlasSize) * 1000.0f + 500.0f;
982 textureXScale = diffuseTextureAtlasSize == 0?1.0f:1.0f;
983 textureYScale = diffuseTextureAtlasSize == 0?1.0f:1.0f;
985 for (
const auto& face: sourceFacesEntity.getFaces()) {
986 auto sourceVertexIndices = face.getVertexIndices();
987 auto sourceNormalIndices = face.getNormalIndices();
988 auto sourceTangentIndices = face.getTangentIndices();
989 auto sourceBitangentIndices = face.getBitangentIndices();
990 auto sourceTextureCoordinateIndices = face.getTextureCoordinateIndices();
992 for (
auto i = 0; i < sourceTextureCoordinateIndices.size(); i++) {
993 if (sourceTextureCoordinateIndices[i] != -1 &&
994 sourceTextureCoordinates.size() > 0 &&
995 processedTextureCoordinates.find(sourceTextureCoordinateIndices[i]) == processedTextureCoordinates.end()) {
996 auto textureCoordinateArray = sourceTextureCoordinates[sourceTextureCoordinateIndices[i]].getArray();
997 textureCoordinateArray[0]*= textureXScale;
998 textureCoordinateArray[0]+= textureXOffset;
999 textureCoordinateArray[1]*= textureYScale;
1000 textureCoordinateArray[1]+= textureYOffset;
1001 targetTextureCoordinates[sourceTextureCoordinateIndices[i] + targetOffset] =
Vector2(textureCoordinateArray);
1002 processedTextureCoordinates.insert(sourceTextureCoordinateIndices[i]);
1005 if (keptMaterialId.empty() ==
false) {
1006 targetFacesKeptMaterial.push_back(
1009 sourceVertexIndices[0] + targetOffset,
1010 sourceVertexIndices[1] + targetOffset,
1011 sourceVertexIndices[2] + targetOffset,
1012 sourceNormalIndices[0] + targetOffset,
1013 sourceNormalIndices[1] + targetOffset,
1014 sourceNormalIndices[2] + targetOffset,
1015 sourceTextureCoordinateIndices[0] + targetOffset,
1016 sourceTextureCoordinateIndices[1] + targetOffset,
1017 sourceTextureCoordinateIndices[2] + targetOffset
1021 if (material->getSpecularMaterialProperties()->hasDiffuseTextureTransparency() ==
true) {
1022 if (material->getSpecularMaterialProperties()->hasDiffuseTextureMaskedTransparency() ==
true) {
1023 targetFacesMaskedTransparency.push_back(
1026 sourceVertexIndices[0] + targetOffset,
1027 sourceVertexIndices[1] + targetOffset,
1028 sourceVertexIndices[2] + targetOffset,
1029 sourceNormalIndices[0] + targetOffset,
1030 sourceNormalIndices[1] + targetOffset,
1031 sourceNormalIndices[2] + targetOffset,
1032 sourceTextureCoordinateIndices[0] + targetOffset,
1033 sourceTextureCoordinateIndices[1] + targetOffset,
1034 sourceTextureCoordinateIndices[2] + targetOffset
1038 targetFacesTransparency.push_back(
1041 sourceVertexIndices[0] + targetOffset,
1042 sourceVertexIndices[1] + targetOffset,
1043 sourceVertexIndices[2] + targetOffset,
1044 sourceNormalIndices[0] + targetOffset,
1045 sourceNormalIndices[1] + targetOffset,
1046 sourceNormalIndices[2] + targetOffset,
1047 sourceTextureCoordinateIndices[0] + targetOffset,
1048 sourceTextureCoordinateIndices[1] + targetOffset,
1049 sourceTextureCoordinateIndices[2] + targetOffset
1054 targetFaces.push_back(
1057 sourceVertexIndices[0] + targetOffset,
1058 sourceVertexIndices[1] + targetOffset,
1059 sourceVertexIndices[2] + targetOffset,
1060 sourceNormalIndices[0] + targetOffset,
1061 sourceNormalIndices[1] + targetOffset,
1062 sourceNormalIndices[2] + targetOffset,
1063 sourceTextureCoordinateIndices[0] + targetOffset,
1064 sourceTextureCoordinateIndices[1] + targetOffset,
1065 sourceTextureCoordinateIndices[2] + targetOffset
1070 if (targetFacesKeptMaterial.size() > 0) {
1072 for (
auto& targetFacesEntityKeptMaterial: targetFacesEntitiesKeptMaterials) {
1073 if (targetFacesEntityKeptMaterial.getId() ==
"tdme.facesentity.kept." + keptMaterialId) {
1074 facesEntity = &targetFacesEntityKeptMaterial;
1078 if (facesEntity ==
nullptr) {
1079 targetFacesEntitiesKeptMaterials.push_back(
FacesEntity(targetNode,
"tdme.facesentity.kept." + keptMaterialId));
1080 facesEntity = &targetFacesEntitiesKeptMaterials[targetFacesEntitiesKeptMaterials.size() - 1];
1082 facesEntity->
setFaces(targetFacesKeptMaterial);
1086 targetNode->setTextureCoordinates(targetTextureCoordinates);
1087 vector<FacesEntity> targetFacesEntities;
1088 if (targetFaces.size() > 0) {
1089 targetFacesEntities.push_back(
FacesEntity(targetNode,
"tdme.facesentity.optimized"));
1090 targetFacesEntities[targetFacesEntities.size() - 1].setFaces(targetFaces);
1092 if (targetFacesMaskedTransparency.size() > 0) {
1093 targetFacesEntities.push_back(
FacesEntity(targetNode,
"tdme.facesentity.optimized.maskedtransparency"));
1094 targetFacesEntities[targetFacesEntities.size() - 1].setFaces(targetFacesMaskedTransparency);
1096 if (targetFacesTransparency.size() > 0) {
1097 targetFacesEntities.push_back(
FacesEntity(targetNode,
"tdme.facesentity.optimized.transparency"));
1098 targetFacesEntities[targetFacesEntities.size() - 1].setFaces(targetFacesTransparency);
1100 for (
const auto& targetFacesEntityKeptMaterial: targetFacesEntitiesKeptMaterials) {
1101 targetFacesEntities.push_back(targetFacesEntityKeptMaterial);
1103 targetNode->setFacesEntities(targetFacesEntities);
1105 for (
const auto& [subNodeId, subNode]: sourceNode->
getSubNodes()) {
1106 optimizeNode(subNode, targetModel, diffuseTextureAtlasSize, diffuseTextureAtlasIndices, excludeDiffuseTextureFileNamePatterns);
1111 return model->
getNodes()[
"tdme.node.optimized"] !=
nullptr;
1115 auto modelPtr = unique_ptr<Model>(model);
1121 unordered_map<string, int> materialUseCount;
1122 for (
const auto& [subNodeId, subNode]: modelPtr->getSubNodes()) {
1126 excludeDiffuseTextureFileNamePatterns
1134 auto diffuseTextureCount = 0;
1135 unordered_map<string, int> diffuseTextureAtlasIndices;
1136 unordered_map<string, Material*> atlasMaterials;
1137 for (
const auto& [materialName, materialCount]: materialUseCount) {
1138 auto material = modelPtr->getMaterials().find(materialName)->second;
1139 auto diffuseTexture = material->getSpecularMaterialProperties()->getDiffuseTexture();
1140 if (diffuseTexture !=
nullptr) {
1141 diffuseTextureAtlasIndices[material->getId()] = diffuseAtlas.
addTexture(diffuseTexture);
1142 diffuseTextureCount++;
1143 atlasMaterials[material->getId()] = material;
1148 if (diffuseTextureCount < 2)
return modelPtr.release();
1151 for (
const auto& [subNodeId, subNode]: modelPtr->getSubNodes()) {
1162 auto optimizedModelPtr = make_unique<Model>(modelPtr->getId() +
".optimized", modelPtr->getName() +
".optimized", modelPtr->getUpVector(), modelPtr->getRotationOrder(), make_unique<BoundingBox>(modelPtr->getBoundingBox()).release(), modelPtr->getAuthoringTool());
1163 optimizedModelPtr->setImportTransformMatrix(modelPtr->getImportTransformMatrix());
1164 optimizedModelPtr->setEmbedSpecularTextures(
true);
1165 optimizedModelPtr->setEmbedPBRTextures(
true);
1166 auto optimizedNode = make_unique<Node>(optimizedModelPtr.get(),
nullptr,
"tdme.node.optimized",
"tdme.node.optimized");
1167 optimizedModelPtr->getNodes()[
"tdme.node.optimized"] = optimizedNode.get();
1168 optimizedModelPtr->getSubNodes()[
"tdme.node.optimized"] = optimizedNode.get();
1169 optimizedNode.release();
1172 for (
const auto& [materialId, material]: modelPtr->getMaterials()) {
1173 bool keepDiffuseTexture =
false;
1174 for (
const auto& excludeDiffuseTextureFileNamePattern: excludeDiffuseTextureFileNamePatterns) {
1175 if (
StringTools::startsWith(material->getSpecularMaterialProperties()->getDiffuseTextureFileName(), excludeDiffuseTextureFileNamePattern) ==
true) {
1176 keepDiffuseTexture =
true;
1180 if (keepDiffuseTexture ==
false)
continue;
1181 optimizedModelPtr->getMaterials()[material->getId()] =
cloneMaterial(material);
1185 auto optimizedMaterial = make_unique<Material>(
"tdme.material.optimized");
1188 optimizedMaterial->getSpecularMaterialProperties()->setDiffuseTexture(diffuseAtlas.
getAtlasTexture());
1190 optimizedMaterial->getSpecularMaterialProperties()->setDiffuseTextureTransparency(
false);
1191 optimizedMaterial->getSpecularMaterialProperties()->setDiffuseTextureMaskedTransparency(
false);
1192 Vector4 optimizedMaterialEmission(0.0f, 0.0f, 0.0f, 0.0f);
1193 Vector4 optimizedMaterialAmbient(0.0f, 0.0f, 0.0f, 0.0f);
1194 Vector4 optimizedMaterialDiffuse(0.0f, 0.0f, 0.0f, 0.0f);
1195 Vector4 optimizedMaterialSpecular(0.0f, 0.0f, 0.0f, 0.0f);
1196 float optimizedMaterialShininess = 0.0f;
1197 for (
const auto& [atlasMaterialsId, material]: atlasMaterials) {
1198 optimizedMaterialEmission+=
Vector4(material->getSpecularMaterialProperties()->getEmissionColor().getArray());
1199 optimizedMaterialAmbient+=
Vector4(material->getSpecularMaterialProperties()->getAmbientColor().getArray());
1200 optimizedMaterialDiffuse+=
Vector4(material->getSpecularMaterialProperties()->getDiffuseColor().getArray());
1201 optimizedMaterialSpecular+=
Vector4(material->getSpecularMaterialProperties()->getSpecularColor().getArray());
1202 optimizedMaterialShininess+= material->getSpecularMaterialProperties()->getShininess();
1204 optimizedMaterialEmission/=
static_cast<float>(atlasMaterials.size());
1205 optimizedMaterialAmbient/=
static_cast<float>(atlasMaterials.size());
1206 optimizedMaterialDiffuse/=
static_cast<float>(atlasMaterials.size());
1207 optimizedMaterialSpecular/=
static_cast<float>(atlasMaterials.size());
1208 optimizedMaterialShininess/=
static_cast<float>(atlasMaterials.size());
1209 optimizedMaterial->getSpecularMaterialProperties()->setEmissionColor(
Color4(optimizedMaterialEmission.
getArray()));
1210 optimizedMaterial->getSpecularMaterialProperties()->setAmbientColor(
Color4(optimizedMaterialAmbient.
getArray()));
1211 optimizedMaterial->getSpecularMaterialProperties()->setDiffuseColor(
Color4(optimizedMaterialDiffuse.
getArray()));
1212 optimizedMaterial->getSpecularMaterialProperties()->setSpecularColor(
Color4(optimizedMaterialSpecular.
getArray()));
1213 optimizedMaterial->getSpecularMaterialProperties()->setShininess(optimizedMaterialShininess);
1217 auto optimizedMaterialMaskedTransparency = unique_ptr<Material>(
cloneMaterial(optimizedMaterial.get(),
"tdme.material.optimized.maskedtransparency"));
1218 optimizedMaterialMaskedTransparency->getSpecularMaterialProperties()->setDiffuseTextureTransparency(
true);
1219 optimizedMaterialMaskedTransparency->getSpecularMaterialProperties()->setDiffuseTextureMaskedTransparency(
true);
1222 auto optimizedMaterialTransparency = unique_ptr<Material>(
cloneMaterial(optimizedMaterial.get(),
"tdme.material.optimized.transparency"));
1223 optimizedMaterialTransparency->getSpecularMaterialProperties()->setDiffuseTextureTransparency(
true);
1226 for (
const auto& [subNodeId, subNode]: modelPtr->getSubNodes()) {
1227 if ((modelPtr->hasSkinning() ==
true && subNode->getSkinning() !=
nullptr) ||
1228 (modelPtr->hasSkinning() ==
false && subNode->isJoint() ==
false)) {
1230 if (modelPtr->hasSkinning() ==
true) {
1231 auto skinning = subNode->getSkinning();
1232 auto optimizedSkinning = make_unique<Skinning>();
1233 optimizedSkinning->setWeights(skinning->getWeights());
1234 optimizedSkinning->setJoints(skinning->getJoints());
1235 optimizedSkinning->setVerticesJointsWeights(skinning->getVerticesJointsWeights());
1236 optimizedModelPtr->getNodes()[
"tdme.node.optimized"]->setSkinning(optimizedSkinning.release());
1239 cloneNode(subNode, optimizedModelPtr.get(),
nullptr,
false);
1244 auto optimizedFacesEntity = optimizedModelPtr->getNodes()[
"tdme.node.optimized"]->getFacesEntity(
"tdme.facesentity.optimized");
1245 if (optimizedFacesEntity !=
nullptr) {
1246 optimizedModelPtr->getMaterials()[optimizedMaterial->getId()] = optimizedMaterial.get();
1247 optimizedFacesEntity->setMaterial(optimizedMaterial.release());
1251 auto optimizedFacesEntityMaskedTransparency = optimizedModelPtr->getNodes()[
"tdme.node.optimized"]->getFacesEntity(
"tdme.facesentity.optimized.maskedtransparency");
1252 if (optimizedFacesEntityMaskedTransparency !=
nullptr) {
1253 optimizedModelPtr->getMaterials()[optimizedMaterialMaskedTransparency->getId()] = optimizedMaterialMaskedTransparency.get();
1254 optimizedFacesEntityMaskedTransparency->setMaterial(optimizedMaterialMaskedTransparency.release());
1258 auto optimizedFacesEntityTransparency = optimizedModelPtr->getNodes()[
"tdme.node.optimized"]->getFacesEntity(
"tdme.facesentity.optimized.transparency");
1259 if (optimizedFacesEntityTransparency !=
nullptr) {
1260 optimizedModelPtr->getMaterials()[optimizedMaterialTransparency->getId()] = optimizedMaterialTransparency.get();
1261 optimizedFacesEntityTransparency->setMaterial(optimizedMaterialTransparency.release());
1266 for (
const auto& [animationSetupId, animationSetup]: modelPtr->getAnimationSetups()) {
1267 if (animationSetup->getOverlayFromNodeId().empty() ==
false) {
1268 optimizedModelPtr->addOverlayAnimationSetup(
1269 animationSetup->getId(),
1270 animationSetup->getOverlayFromNodeId(),
1271 animationSetup->getStartFrame(),
1272 animationSetup->getEndFrame(),
1273 animationSetup->isLoop(),
1274 animationSetup->getSpeed()
1277 optimizedModelPtr->addAnimationSetup(
1278 animationSetup->getId(),
1279 animationSetup->getStartFrame(),
1280 animationSetup->getEndFrame(),
1281 animationSetup->isLoop(),
1282 animationSetup->getSpeed()
1288 return optimizedModelPtr.release();
1295 Console::println(
"ModelTools::computeTangentsAndBitangents(): " + node->
getId() +
": No texture coordinates");
1300 vector<Vector3> tangents;
1301 vector<Vector3> bitangents;
1315 for (
auto& faceEntity: facesEntities) {
1316 auto faces = faceEntity.getFaces();
1317 for (
auto& face: faces) {
1319 auto verticesIndexes = face.getVertexIndices();
1320 auto v0 = vertices[verticesIndexes[0]];
1321 auto v1 = vertices[verticesIndexes[1]];
1322 auto v2 = vertices[verticesIndexes[2]];
1324 auto textureCoordinatesIndexes = face.getTextureCoordinateIndices();
1325 uv0.
set(textureCoordinates[textureCoordinatesIndexes[0]].getArray());
1327 uv1.
set(textureCoordinates[textureCoordinatesIndexes[1]].getArray());
1329 uv2.
set(textureCoordinates[textureCoordinatesIndexes[2]].getArray());
1332 deltaPos1.
set(v1).
sub(v0);
1333 deltaPos2.
set(v2).
sub(v0);
1335 deltaUV1.
set(uv1).
sub(uv0);
1336 deltaUV2.
set(uv2).
sub(uv0);
1338 auto r = 1.0f / (deltaUV1.
getX() * deltaUV2.
getY() - deltaUV1.
getY() * deltaUV2.
getX());
1342 face.setTangentIndices(tangents.size() + 0, tangents.size() + 1, tangents.size() + 2);
1344 face.setBitangentIndices(bitangents.size() + 0, bitangents.size() + 1, bitangents.size() + 2);
1346 tangents.push_back(tangent);
1347 tangents.push_back(tangent);
1348 tangents.push_back(tangent);
1349 bitangents.push_back(bitangent);
1350 bitangents.push_back(bitangent);
1351 bitangents.push_back(bitangent);
1353 faceEntity.setFaces(faces);
1358 if (tangents.size() > 0 && bitangents.size() > 0) {
1361 for (
auto& faceEntity: facesEntities) {
1362 auto faces = faceEntity.getFaces();
1363 for (
auto& face: faces) {
1364 for (
auto i = 0; i < 3; i++) {
1365 auto normal = normals[face.getNormalIndices()[i]];
1366 auto& tangent = tangents[face.getTangentIndices()[i]];
1367 auto& bitangent = bitangents[face.getBitangentIndices()[i]];
1368 tangent.sub(normal.clone().scale(Vector3::computeDotProduct(normal, tangent))).normalize();
1369 if (Vector3::computeDotProduct(Vector3::computeCrossProduct(normal, tangent), bitangent) < 0.0f) {
1370 tangent.scale(-1.0f);
1372 bitangent.normalize();
1375 faceEntity.setFaces(faces);
1386 for (
auto& facesEntity: facesEntities) {
1387 auto faces = facesEntity.getFaces();
1388 for (
auto& face: faces) face.changeFrontFace();
1389 facesEntity.setFaces(faces);
1392 if (applyToSubNodes ==
true) {
1393 for (
const auto& [subNodeId, subNode]: node->
getSubNodes()) {
1400 for (
const auto& [subNodeId, subNode]: model->
getSubNodes()) {
Color 4 definition class.
uint16_t getAtlasSize() const
const vector< Matrix4x4 > & getTransformMatrices() const
Returns transform matrices.
Represents a model face, consisting of vertex, normal, tangent and bitangent vectors,...
void setTextureCoordinateIndices(int32_t vt0, int32_t vt1, int32_t vt2)
Set up optional texture coordinate indices.
void setTangentIndices(int32_t ti0, int32_t ti1, int32_t ti2)
Set tangent indices.
void setBitangentIndices(int32_t bi0, int32_t bi1, int32_t bi2)
Set bitangent indices.
Node faces entity A node can have multiple entities containing faces and a applied material.
const vector< Face > & getFaces() const
void setMaterial(Material *material)
Set up the entity's material.
void setFaces(const vector< Face > &faces)
Set up entity's faces.
const SpecularMaterialProperties * getSpecularMaterialProperties() const
const string & getId() const
Representation of a 3D model.
unordered_map< string, Node * > & getSubNodes()
Returns object's sub nodes.
unordered_map< string, Material * > & getMaterials()
Returns all object materials.
void setImportTransformMatrix(const Matrix4x4 &importTransformMatrix)
Set import transform matrix.
void clearAnimationSetups()
Clear animation setups.
RotationOrder * getRotationOrder()
AnimationSetup * getAnimationSetup(const string &id)
const Matrix4x4 & getImportTransformMatrix()
void setUpVector(UpVector *upVector)
Set up vector.
unordered_map< string, Node * > & getNodes()
Returns all object's nodes.
AnimationSetup * addAnimationSetup(const string &id, int32_t startFrame, int32_t endFrame, bool loop, float speed=1.0f)
Adds an base animation setup.
const vector< Vector3 > & getBitangents() const
int32_t getFaceCount() const
unordered_map< string, Node * > & getSubNodes()
void setAnimation(Animation *animation)
Sets animation object.
void setOrigins(const vector< Vector3 > &origins)
Set origins.
void setVertices(const vector< Vector3 > &vertices)
Set vertices.
const vector< Vector3 > & getTangents() const
void setFacesEntities(const vector< FacesEntity > &facesEntities)
Set up faces entities.
const vector< Vector3 > & getOrigins() const
void setTransformMatrix(const Matrix4x4 &transformMatrix)
Animation * getAnimation()
void setJoint(bool isJoint)
Sets up if this node is a joint or not.
const vector< Vector3 > & getVertices() const
const vector< Vector3 > & getNormals() const
const vector< Vector2 > & getTextureCoordinates() const
void setNormals(const vector< Vector3 > &normals)
Set normals.
const string & getId()
Returns id.
void setBitangents(const vector< Vector3 > &bitangents)
Set bitangents.
const vector< FacesEntity > & getFacesEntities() const
void setTangents(const vector< Vector3 > &tangents)
Set tangents.
const Matrix4x4 & getTransformMatrix() const
Skinning definition for nodes.
const vector< vector< JointWeight > > & getVerticesJointsWeights()
void setVerticesJointsWeights(const vector< vector< JointWeight >> &verticesJointsWeights)
Sets up vertices joints weights.
Represents specular material properties.
Axis aligned bounding box used for frustum, this is not directly connectable with physics engine.
Matrix4x4 class representing matrix4x4 mathematical structure and operations for 3d space.
Matrix4x4 clone() const
Clones this matrix.
Vector3 multiply(const Vector3 &vector3) const
Multiplies this matrix with vector3.
Matrix4x4 & set(float r0c0, float r0c1, float r0c2, float r0c3, float r1c0, float r1c1, float r1c2, float r1c3, float r2c0, float r2c1, float r2c2, float r2c3, float r3c0, float r3c1, float r3c2, float r3c3)
Sets this matrix by its components.
Vector2 class representing vector2 mathematical structure and operations with x, y components.
Vector2 & sub(float scalar)
Subtracts a scalar.
Vector2 & setY(float y)
Sets y component.
Vector2 & set(float x, float y)
Sets this vector2 by its components.
Vector3 class representing vector3 mathematical structure and operations with x, y,...
Vector3 & add(float scalar)
Adds a scalar.
Vector3 clone() const
Clones this vector3.
Vector3 & sub(float scalar)
Subtracts a scalar.
Vector3 & scale(float scalar)
Scales by scalar.
Vector3 & set(float x, float y, float z)
Sets this vector3 by its components.
Vector4 class representing vector4 mathematical structure and operations with x, y,...
const array< float, 4 > & getArray() const
static void println()
Print new line to console.
virtual void acquireReference()
Acquires a reference, incrementing the counter.
int addTexture(Texture *texture)
Add texture.
void update()
Update texture atlas.
Texture * getAtlasTexture()
virtual void progress(float value)=0
Perform action.