Reworked SkeletalMesh class
It now uses a VertexBuffer Former-commit-id: 81d5db90d9eb8a097342a1ae613468edcae730a6
This commit is contained in:
parent
d636174c04
commit
af1d2d9146
|
|
@ -11,54 +11,37 @@
|
||||||
#include <Nazara/Utility/Mesh.hpp>
|
#include <Nazara/Utility/Mesh.hpp>
|
||||||
#include <Nazara/Utility/SubMesh.hpp>
|
#include <Nazara/Utility/SubMesh.hpp>
|
||||||
|
|
||||||
class NzSkeleton;
|
|
||||||
|
|
||||||
struct NzVertexWeight
|
|
||||||
{
|
|
||||||
std::vector<unsigned int> weights; ///FIXME: Niveau fragmentation mémoire ça doit pas être génial
|
|
||||||
};
|
|
||||||
|
|
||||||
struct NzWeight
|
|
||||||
{
|
|
||||||
float weight;
|
|
||||||
unsigned int jointIndex;
|
|
||||||
};
|
|
||||||
|
|
||||||
class NzSkeletalMesh;
|
class NzSkeletalMesh;
|
||||||
|
|
||||||
using NzSkeletalMeshConstRef = NzResourceRef<const NzSkeletalMesh>;
|
using NzSkeletalMeshConstRef = NzResourceRef<const NzSkeletalMesh>;
|
||||||
using NzSkeletalMeshRef = NzResourceRef<NzSkeletalMesh>;
|
using NzSkeletalMeshRef = NzResourceRef<NzSkeletalMesh>;
|
||||||
|
|
||||||
struct NzSkeletalMeshImpl;
|
|
||||||
|
|
||||||
class NAZARA_API NzSkeletalMesh final : public NzSubMesh
|
class NAZARA_API NzSkeletalMesh final : public NzSubMesh
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
NzSkeletalMesh(const NzMesh* parent);
|
NzSkeletalMesh(const NzMesh* parent);
|
||||||
virtual ~NzSkeletalMesh();
|
~NzSkeletalMesh();
|
||||||
|
|
||||||
bool Create(unsigned int vertexCount, unsigned int weightCount);
|
bool Create(NzVertexBuffer* vertexBuffer);
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
||||||
const NzBoxf& GetAABB() const;
|
const NzBoxf& GetAABB() const override;
|
||||||
nzAnimationType GetAnimationType() const final;
|
nzAnimationType GetAnimationType() const final;
|
||||||
NzMeshVertex* GetBindPoseBuffer();
|
|
||||||
const NzMeshVertex* GetBindPoseBuffer() const;
|
|
||||||
const NzIndexBuffer* GetIndexBuffer() const override;
|
const NzIndexBuffer* GetIndexBuffer() const override;
|
||||||
|
NzVertexBuffer* GetVertexBuffer();
|
||||||
|
const NzVertexBuffer* GetVertexBuffer() const;
|
||||||
unsigned int GetVertexCount() const override;
|
unsigned int GetVertexCount() const override;
|
||||||
NzVertexWeight* GetVertexWeight(unsigned int vertexIndex = 0);
|
|
||||||
const NzVertexWeight* GetVertexWeight(unsigned int vertexIndex = 0) const;
|
|
||||||
NzWeight* GetWeight(unsigned int weightIndex = 0);
|
|
||||||
const NzWeight* GetWeight(unsigned int weightIndex = 0) const;
|
|
||||||
unsigned int GetWeightCount() const;
|
|
||||||
|
|
||||||
bool IsAnimated() const final;
|
bool IsAnimated() const final;
|
||||||
bool IsValid() const;
|
bool IsValid() const;
|
||||||
|
|
||||||
|
void SetAABB(const NzBoxf& aabb);
|
||||||
void SetIndexBuffer(const NzIndexBuffer* indexBuffer);
|
void SetIndexBuffer(const NzIndexBuffer* indexBuffer);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
NzSkeletalMeshImpl* m_impl = nullptr;
|
NzBoxf m_aabb;
|
||||||
|
NzIndexBufferConstRef m_indexBuffer = nullptr;
|
||||||
|
NzVertexBufferRef m_vertexBuffer = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // NAZARA_SKELETALMESH_HPP
|
#endif // NAZARA_SKELETALMESH_HPP
|
||||||
|
|
|
||||||
|
|
@ -195,12 +195,16 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh)
|
||||||
|
|
||||||
unsigned int indexCount = md5Mesh.triangles.size()*3;
|
unsigned int indexCount = md5Mesh.triangles.size()*3;
|
||||||
unsigned int vertexCount = md5Mesh.vertices.size();
|
unsigned int vertexCount = md5Mesh.vertices.size();
|
||||||
unsigned int weightCount = md5Mesh.weights.size();
|
|
||||||
|
|
||||||
// Index buffer
|
|
||||||
bool largeIndices = (vertexCount > std::numeric_limits<nzUInt16>::max());
|
bool largeIndices = (vertexCount > std::numeric_limits<nzUInt16>::max());
|
||||||
|
|
||||||
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(largeIndices, indexCount, m_parameters.storage));
|
std::unique_ptr<NzIndexBuffer> indexBuffer(new NzIndexBuffer(largeIndices, indexCount, m_parameters.storage));
|
||||||
|
indexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
std::unique_ptr<NzVertexBuffer> vertexBuffer(new NzVertexBuffer(NzVertexDeclaration::Get(nzVertexLayout_XYZ_Normal_UV_Tangent_Skinning), vertexCount, m_parameters.storage, nzBufferUsage_Static));
|
||||||
|
vertexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
// Index buffer
|
||||||
NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_DiscardAndWrite);
|
NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_DiscardAndWrite);
|
||||||
|
|
||||||
unsigned int index = 0;
|
unsigned int index = 0;
|
||||||
|
|
@ -214,53 +218,99 @@ bool NzMD5MeshParser::Parse(NzMesh* mesh)
|
||||||
|
|
||||||
indexMapper.Unmap();
|
indexMapper.Unmap();
|
||||||
|
|
||||||
std::unique_ptr<NzSkeletalMesh> subMesh(new NzSkeletalMesh(mesh));
|
// Vertex buffer
|
||||||
if (!subMesh->Create(vertexCount, weightCount))
|
struct Weight
|
||||||
{
|
{
|
||||||
NazaraError("Failed to create skeletal mesh");
|
float bias;
|
||||||
continue;
|
unsigned int jointIndex;
|
||||||
}
|
};
|
||||||
|
|
||||||
subMesh->SetIndexBuffer(indexBuffer.get());
|
std::vector<Weight> tempWeights(NAZARA_UTILITY_SKINNING_MAX_WEIGHTS);
|
||||||
indexBuffer->SetPersistent(false);
|
|
||||||
indexBuffer.release();
|
|
||||||
|
|
||||||
NzWeight* weights = subMesh->GetWeight();
|
NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
for (unsigned int j = 0; j < weightCount; ++j)
|
NzSkeletalMeshVertex* vertices = static_cast<NzSkeletalMeshVertex*>(vertexMapper.GetPointer());
|
||||||
{
|
|
||||||
weights->jointIndex = md5Mesh.weights[j].joint;
|
|
||||||
weights->weight = md5Mesh.weights[j].bias;
|
|
||||||
weights++;
|
|
||||||
}
|
|
||||||
|
|
||||||
NzMeshVertex* bindPosVertex = reinterpret_cast<NzMeshVertex*>(subMesh->GetBindPoseBuffer());
|
|
||||||
NzVertexWeight* vertexWeight = subMesh->GetVertexWeight();
|
|
||||||
for (const Mesh::Vertex& vertex : md5Mesh.vertices)
|
for (const Mesh::Vertex& vertex : md5Mesh.vertices)
|
||||||
{
|
{
|
||||||
// Skinning MD5 (Formule d'Id Tech)
|
// Skinning MD5 (Formule d'Id Tech)
|
||||||
NzVector3f finalPos(NzVector3f::Zero());
|
NzVector3f finalPos(NzVector3f::Zero());
|
||||||
|
|
||||||
vertexWeight->weights.resize(vertex.weightCount);
|
tempWeights.resize(vertex.weightCount);
|
||||||
for (unsigned int j = 0; j < vertex.weightCount; ++j)
|
for (unsigned int j = 0; j < vertex.weightCount; ++j)
|
||||||
{
|
{
|
||||||
const Mesh::Weight& weight = md5Mesh.weights[vertex.startWeight + j];
|
const Mesh::Weight& weight = md5Mesh.weights[vertex.startWeight + j];
|
||||||
const Joint& joint = m_joints[weight.joint];
|
const Joint& joint = m_joints[weight.joint];
|
||||||
|
|
||||||
finalPos += (joint.bindPos + joint.bindOrient*weight.pos) * weight.bias;
|
finalPos += (joint.bindPos + joint.bindOrient*weight.pos) * weight.bias;
|
||||||
vertexWeight->weights[j] = vertex.startWeight + j;
|
|
||||||
|
// Avant d'ajouter les poids, il faut s'assurer qu'il n'y en ait pas plus que le maximum supporté
|
||||||
|
// et dans le cas contraire, garder les poids les plus importants et les renormaliser
|
||||||
|
tempWeights[j] = {weight.bias, weight.joint};
|
||||||
}
|
}
|
||||||
|
|
||||||
bindPosVertex->position = finalPos;
|
unsigned int weightCount = vertex.weightCount;
|
||||||
bindPosVertex->uv.Set(vertex.uv.x, 1.f-vertex.uv.y);
|
if (weightCount > NAZARA_UTILITY_SKINNING_MAX_WEIGHTS)
|
||||||
bindPosVertex++;
|
{
|
||||||
vertexWeight++;
|
// Pour augmenter la qualité du skinning tout en ne gardant que X poids, on ne garde que les poids
|
||||||
|
// les plus importants, ayant le plus d'impact sur le sommet final
|
||||||
|
std::sort(tempWeights.begin(), tempWeights.end(), [] (const Weight& a, const Weight& b) -> bool {
|
||||||
|
return a.bias > b.bias;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Sans oublier bien sûr de renormaliser les poids (que leur somme soit 1)
|
||||||
|
float weightSum = 0.f;
|
||||||
|
for (unsigned int j = 0; j < NAZARA_UTILITY_SKINNING_MAX_WEIGHTS; ++j)
|
||||||
|
weightSum += tempWeights[j].bias;
|
||||||
|
|
||||||
|
for (unsigned int j = 0; j < NAZARA_UTILITY_SKINNING_MAX_WEIGHTS; ++j)
|
||||||
|
tempWeights[j].bias /= weightSum;
|
||||||
|
|
||||||
|
weightCount = NAZARA_UTILITY_SKINNING_MAX_WEIGHTS;
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices->weightCount = weightCount;
|
||||||
|
for (unsigned int j = 0; j < NAZARA_UTILITY_SKINNING_MAX_WEIGHTS; ++j)
|
||||||
|
{
|
||||||
|
// On donne une valeur aux poids présents, et 0 pour les autres (nécessaire pour le GPU Skinning)
|
||||||
|
if (j < weightCount)
|
||||||
|
{
|
||||||
|
vertices->weights[j] = tempWeights[j].bias;
|
||||||
|
vertices->jointIndexes[j] = tempWeights[j].jointIndex;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
vertices->weights[j] = 0.f;
|
||||||
|
vertices->jointIndexes[j] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
vertices->position = finalPos;
|
||||||
|
vertices->uv.Set(vertex.uv.x, 1.f-vertex.uv.y);
|
||||||
|
vertices++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
vertexMapper.Unmap();
|
||||||
|
|
||||||
// Material
|
// Material
|
||||||
mesh->SetMaterial(i, baseDir + md5Mesh.shader);
|
mesh->SetMaterial(i, baseDir + md5Mesh.shader);
|
||||||
|
|
||||||
|
// Submesh
|
||||||
|
std::unique_ptr<NzSkeletalMesh> subMesh(new NzSkeletalMesh(mesh));
|
||||||
|
if (!subMesh->Create(vertexBuffer.get()))
|
||||||
|
{
|
||||||
|
NazaraError("Failed to create skeletal mesh");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
vertexBuffer.release();
|
||||||
|
|
||||||
|
if (m_parameters.optimizeIndexBuffers)
|
||||||
|
indexBuffer->Optimize();
|
||||||
|
|
||||||
|
subMesh->SetIndexBuffer(indexBuffer.get());
|
||||||
|
indexBuffer.release();
|
||||||
|
|
||||||
subMesh->GenerateNormalsAndTangents();
|
subMesh->GenerateNormalsAndTangents();
|
||||||
subMesh->SetMaterialIndex(i);
|
subMesh->SetMaterialIndex(i);
|
||||||
|
subMesh->SetPrimitiveMode(nzPrimitiveMode_TriangleList);
|
||||||
|
|
||||||
mesh->AddSubMesh(subMesh.get());
|
mesh->AddSubMesh(subMesh.get());
|
||||||
subMesh.release();
|
subMesh.release();
|
||||||
|
|
|
||||||
|
|
@ -9,16 +9,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <Nazara/Utility/Debug.hpp>
|
#include <Nazara/Utility/Debug.hpp>
|
||||||
|
|
||||||
struct NzSkeletalMeshImpl
|
|
||||||
{
|
|
||||||
std::unique_ptr<NzMeshVertex[]> bindPoseBuffer;
|
|
||||||
std::vector<NzVertexWeight> vertexWeights;
|
|
||||||
std::vector<NzWeight> weights;
|
|
||||||
NzBoxf aabb;
|
|
||||||
NzIndexBufferConstRef indexBuffer;
|
|
||||||
unsigned int vertexCount;
|
|
||||||
};
|
|
||||||
|
|
||||||
NzSkeletalMesh::NzSkeletalMesh(const NzMesh* parent) :
|
NzSkeletalMesh::NzSkeletalMesh(const NzMesh* parent) :
|
||||||
NzSubMesh(parent)
|
NzSubMesh(parent)
|
||||||
{
|
{
|
||||||
|
|
@ -29,57 +19,36 @@ NzSkeletalMesh::~NzSkeletalMesh()
|
||||||
Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NzSkeletalMesh::Create(unsigned int vertexCount, unsigned int weightCount)
|
bool NzSkeletalMesh::Create(NzVertexBuffer* vertexBuffer)
|
||||||
{
|
{
|
||||||
Destroy();
|
Destroy();
|
||||||
|
|
||||||
#if NAZARA_UTILITY_SAFE
|
#if NAZARA_UTILITY_SAFE
|
||||||
if (vertexCount == 0)
|
if (!vertexBuffer)
|
||||||
{
|
{
|
||||||
NazaraError("Vertex count must be over 0");
|
NazaraError("Invalid vertex buffer");
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (weightCount == 0)
|
|
||||||
{
|
|
||||||
NazaraError("Weight count must be over 0");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
m_impl = new NzSkeletalMeshImpl;
|
m_vertexBuffer = vertexBuffer;
|
||||||
m_impl->bindPoseBuffer.reset(new NzMeshVertex[vertexCount]);
|
|
||||||
m_impl->vertexCount = vertexCount;
|
|
||||||
m_impl->vertexWeights.resize(vertexCount);
|
|
||||||
m_impl->weights.resize(weightCount);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NzSkeletalMesh::Destroy()
|
void NzSkeletalMesh::Destroy()
|
||||||
{
|
{
|
||||||
if (m_impl)
|
if (m_vertexBuffer)
|
||||||
{
|
{
|
||||||
NotifyDestroy();
|
NotifyDestroy();
|
||||||
|
|
||||||
delete m_impl;
|
m_indexBuffer.Reset();
|
||||||
m_impl = nullptr;
|
m_vertexBuffer.Reset();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const NzBoxf& NzSkeletalMesh::GetAABB() const
|
const NzBoxf& NzSkeletalMesh::GetAABB() const
|
||||||
{
|
{
|
||||||
#if NAZARA_UTILITY_SAFE
|
return m_aabb;
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
|
|
||||||
static NzBoxf dummy;
|
|
||||||
return dummy;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m_impl->aabb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
nzAnimationType NzSkeletalMesh::GetAnimationType() const
|
nzAnimationType NzSkeletalMesh::GetAnimationType() const
|
||||||
|
|
@ -87,121 +56,24 @@ nzAnimationType NzSkeletalMesh::GetAnimationType() const
|
||||||
return nzAnimationType_Skeletal;
|
return nzAnimationType_Skeletal;
|
||||||
}
|
}
|
||||||
|
|
||||||
NzMeshVertex* NzSkeletalMesh::GetBindPoseBuffer()
|
|
||||||
{
|
|
||||||
#if NAZARA_UTILITY_SAFE
|
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m_impl->bindPoseBuffer.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const NzMeshVertex* NzSkeletalMesh::GetBindPoseBuffer() const
|
|
||||||
{
|
|
||||||
#if NAZARA_UTILITY_SAFE
|
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m_impl->bindPoseBuffer.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
const NzIndexBuffer* NzSkeletalMesh::GetIndexBuffer() const
|
const NzIndexBuffer* NzSkeletalMesh::GetIndexBuffer() const
|
||||||
{
|
{
|
||||||
#if NAZARA_UTILITY_SAFE
|
return m_indexBuffer;
|
||||||
if (!m_impl)
|
}
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m_impl->indexBuffer;
|
NzVertexBuffer* NzSkeletalMesh::GetVertexBuffer()
|
||||||
|
{
|
||||||
|
return m_vertexBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NzVertexBuffer* NzSkeletalMesh::GetVertexBuffer() const
|
||||||
|
{
|
||||||
|
return m_vertexBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int NzSkeletalMesh::GetVertexCount() const
|
unsigned int NzSkeletalMesh::GetVertexCount() const
|
||||||
{
|
{
|
||||||
#if NAZARA_UTILITY_SAFE
|
return m_vertexBuffer->GetVertexCount();
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m_impl->vertexCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
NzVertexWeight* NzSkeletalMesh::GetVertexWeight(unsigned int vertexIndex)
|
|
||||||
{
|
|
||||||
#if NAZARA_UTILITY_SAFE
|
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return &m_impl->vertexWeights[vertexIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
const NzVertexWeight* NzSkeletalMesh::GetVertexWeight(unsigned int vertexIndex) const
|
|
||||||
{
|
|
||||||
#if NAZARA_UTILITY_SAFE
|
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return &m_impl->vertexWeights[vertexIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
NzWeight* NzSkeletalMesh::GetWeight(unsigned int weightIndex)
|
|
||||||
{
|
|
||||||
#if NAZARA_UTILITY_SAFE
|
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return &m_impl->weights[weightIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
const NzWeight* NzSkeletalMesh::GetWeight(unsigned int weightIndex) const
|
|
||||||
{
|
|
||||||
#if NAZARA_UTILITY_SAFE
|
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return &m_impl->weights[weightIndex];
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int NzSkeletalMesh::GetWeightCount() const
|
|
||||||
{
|
|
||||||
#if NAZARA_UTILITY_SAFE
|
|
||||||
if (!m_impl)
|
|
||||||
{
|
|
||||||
NazaraError("Skeletal mesh not created");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return m_impl->weights.size();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NzSkeletalMesh::IsAnimated() const
|
bool NzSkeletalMesh::IsAnimated() const
|
||||||
|
|
@ -211,10 +83,15 @@ bool NzSkeletalMesh::IsAnimated() const
|
||||||
|
|
||||||
bool NzSkeletalMesh::IsValid() const
|
bool NzSkeletalMesh::IsValid() const
|
||||||
{
|
{
|
||||||
return m_impl != nullptr;
|
return m_vertexBuffer != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzSkeletalMesh::SetAABB(const NzBoxf& aabb)
|
||||||
|
{
|
||||||
|
m_aabb = aabb;
|
||||||
}
|
}
|
||||||
|
|
||||||
void NzSkeletalMesh::SetIndexBuffer(const NzIndexBuffer* indexBuffer)
|
void NzSkeletalMesh::SetIndexBuffer(const NzIndexBuffer* indexBuffer)
|
||||||
{
|
{
|
||||||
m_impl->indexBuffer = indexBuffer;
|
m_indexBuffer = indexBuffer;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue