Added mesh generator functions
Added Mesh::Build Former-commit-id: dcfc6587b67ab4ec350ab7ca04ae7f45475f6b1b
This commit is contained in:
parent
65c08442ce
commit
714e3e01bc
|
|
@ -0,0 +1,34 @@
|
||||||
|
// Copyright (C) 2013 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifndef NAZARA_ALGORITHM_UTILITY_HPP
|
||||||
|
#define NAZARA_ALGORITHM_UTILITY_HPP
|
||||||
|
|
||||||
|
#include <Nazara/Prerequesites.hpp>
|
||||||
|
#include <Nazara/Math/Matrix4.hpp>
|
||||||
|
#include <Nazara/Math/Vector2.hpp>
|
||||||
|
#include <Nazara/Math/Vector3.hpp>
|
||||||
|
#include <Nazara/Utility/Mesh.hpp>
|
||||||
|
|
||||||
|
NAZARA_API void NzComputeCubeIndexVertexCount(const NzVector3ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount);
|
||||||
|
NAZARA_API void NzComputeCubicSphereIndexVertexCount(unsigned int subdivision, unsigned int* indexCount, unsigned int* vertexCount);
|
||||||
|
NAZARA_API void NzComputeIcoSphereIndexVertexCount(unsigned int recursionLevel, unsigned int* indexCount, unsigned int* vertexCount);
|
||||||
|
NAZARA_API void NzComputePlaneIndexVertexCount(const NzVector2ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount);
|
||||||
|
NAZARA_API void NzComputeUvSphereIndexVertexCount(unsigned int sliceCount, unsigned int stackCount, unsigned int* indexCount, unsigned int* vertexCount);
|
||||||
|
|
||||||
|
///TODO: Itérateur sur les indices
|
||||||
|
NAZARA_API void NzGenerateCube(const NzCubef& cube, const NzVector3ui& subdivision, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0);
|
||||||
|
NAZARA_API void NzGenerateCubicSphere(float size, unsigned int subdivision, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0);
|
||||||
|
NAZARA_API void NzGenerateIcoSphere(float size, unsigned int recursionLevel, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0);
|
||||||
|
NAZARA_API void NzGeneratePlane(const NzVector2ui& subdivision, const NzVector3f& position, const NzVector3f& normal, const NzVector2f& size, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0);
|
||||||
|
NAZARA_API void NzGenerateUvSphere(float size, unsigned int sliceCount, unsigned int stackCount, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb = nullptr, unsigned int indexOffset = 0);
|
||||||
|
|
||||||
|
inline void NzTransformVertex(NzMeshVertex* vertex, const NzMatrix4f& matrix);
|
||||||
|
inline void NzTransformVertices(NzMeshVertex* vertices, unsigned int vertexCount, const NzMatrix4f& matrix);
|
||||||
|
|
||||||
|
#include <Nazara/Utility/Algorithm.inl>
|
||||||
|
|
||||||
|
#endif // NAZARA_ALGORITHM_UTILITY_HPP
|
||||||
|
|
@ -0,0 +1,24 @@
|
||||||
|
// Copyright (C) 2013 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Utility/Debug.hpp>
|
||||||
|
|
||||||
|
void NzTransformVertex(NzMeshVertex* vertex, const NzMatrix4f& matrix)
|
||||||
|
{
|
||||||
|
vertex->normal = matrix.Transform(vertex->normal, 0.f);
|
||||||
|
vertex->position = matrix.Transform(vertex->position);
|
||||||
|
vertex->tangent = matrix.Transform(vertex->tangent, 0.f);
|
||||||
|
vertex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzTransformVertices(NzMeshVertex* vertices, unsigned int vertexCount, const NzMatrix4f& matrix)
|
||||||
|
{
|
||||||
|
if (matrix.IsIdentity())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < vertexCount; ++i)
|
||||||
|
NzTransformVertex(vertices++, matrix);
|
||||||
|
}
|
||||||
|
|
||||||
|
#include <Nazara/Utility/DebugOff.hpp>
|
||||||
|
|
@ -33,6 +33,7 @@ struct NAZARA_API NzMeshParams
|
||||||
};
|
};
|
||||||
|
|
||||||
class NzAnimation;
|
class NzAnimation;
|
||||||
|
class NzPrimitiveList;
|
||||||
class NzMesh;
|
class NzMesh;
|
||||||
|
|
||||||
typedef NzVertexStruct_XYZ_Normal_UV_Tangent NzMeshVertex;
|
typedef NzVertexStruct_XYZ_Normal_UV_Tangent NzMeshVertex;
|
||||||
|
|
@ -54,6 +55,8 @@ class NAZARA_API NzMesh : public NzResource, NzResourceListener
|
||||||
bool AddSubMesh(NzSubMesh* subMesh);
|
bool AddSubMesh(NzSubMesh* subMesh);
|
||||||
bool AddSubMesh(const NzString& identifier, NzSubMesh* subMesh);
|
bool AddSubMesh(const NzString& identifier, NzSubMesh* subMesh);
|
||||||
|
|
||||||
|
void Build(const NzPrimitiveList& list, const NzMeshParams& params = NzMeshParams());
|
||||||
|
|
||||||
bool CreateSkeletal(unsigned int jointCount);
|
bool CreateSkeletal(unsigned int jointCount);
|
||||||
bool CreateStatic();
|
bool CreateStatic();
|
||||||
void Destroy();
|
void Destroy();
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,396 @@
|
||||||
|
// Copyright (C) 2013 Jérôme Leclercq
|
||||||
|
// This file is part of the "Nazara Engine - Utility module"
|
||||||
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
|
#include <Nazara/Utility/Algorithm.hpp>
|
||||||
|
#include <Nazara/Math/Basic.hpp>
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <Nazara/Utility/Debug.hpp>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
class IcoSphereBuilder
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
IcoSphereBuilder(const NzMatrix4f& matrix) :
|
||||||
|
m_matrix(matrix)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Generate(float size, unsigned int recursionLevel, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset)
|
||||||
|
{
|
||||||
|
// Grandement inspiré de http://blog.andreaskahler.com/2009/06/creating-icosphere-mesh-in-code.html
|
||||||
|
const float t = (1.f + 2.236067f)/2.f;
|
||||||
|
|
||||||
|
m_cache.clear();
|
||||||
|
m_size = size;
|
||||||
|
m_vertices = vertices;
|
||||||
|
m_vertexIndex = 0;
|
||||||
|
|
||||||
|
// Sommets de base
|
||||||
|
AddVertex({-1.f, t, 0.f});
|
||||||
|
AddVertex({ 1.f, t, 0.f});
|
||||||
|
AddVertex({-1.f, -t, 0.f});
|
||||||
|
AddVertex({ 1.f, -t, 0.f});
|
||||||
|
|
||||||
|
AddVertex({0.f, -1.f, t});
|
||||||
|
AddVertex({0.f, 1.f, t});
|
||||||
|
AddVertex({0.f, -1.f, -t});
|
||||||
|
AddVertex({0.f, 1.f, -t});
|
||||||
|
|
||||||
|
AddVertex({ t, 0.f, -1.f});
|
||||||
|
AddVertex({ t, 0.f, 1.f});
|
||||||
|
AddVertex({-t, 0.f, -1.f});
|
||||||
|
AddVertex({-t, 0.f, 1.f});
|
||||||
|
|
||||||
|
std::vector<NzVector3ui> triangles;
|
||||||
|
triangles.reserve(20 * NzIntegralPow(4, recursionLevel));
|
||||||
|
|
||||||
|
// Cinq triangles autour du premier point
|
||||||
|
triangles.push_back({0, 11, 5});
|
||||||
|
triangles.push_back({0, 5, 1});
|
||||||
|
triangles.push_back({0, 1, 7});
|
||||||
|
triangles.push_back({0, 7, 10});
|
||||||
|
triangles.push_back({0, 10, 11});
|
||||||
|
|
||||||
|
// Cinq faces adjaçentes
|
||||||
|
triangles.push_back({ 1, 5, 9});
|
||||||
|
triangles.push_back({ 5, 11, 4});
|
||||||
|
triangles.push_back({11, 10, 2});
|
||||||
|
triangles.push_back({10, 7, 6});
|
||||||
|
triangles.push_back({ 7, 1, 8});
|
||||||
|
|
||||||
|
// Cinq triangles autour du troisième point
|
||||||
|
triangles.push_back({3, 9, 4});
|
||||||
|
triangles.push_back({3, 4, 2});
|
||||||
|
triangles.push_back({3, 2, 6});
|
||||||
|
triangles.push_back({3, 6, 8});
|
||||||
|
triangles.push_back({3, 8, 9});
|
||||||
|
|
||||||
|
// Cinq faces adjaçentes
|
||||||
|
triangles.push_back({4, 9, 5});
|
||||||
|
triangles.push_back({2, 4, 11});
|
||||||
|
triangles.push_back({6, 2, 10});
|
||||||
|
triangles.push_back({8, 6, 7});
|
||||||
|
triangles.push_back({9, 8, 1});
|
||||||
|
|
||||||
|
// Et maintenant on affine la sphère
|
||||||
|
for (unsigned int i = 0; i < recursionLevel; ++i)
|
||||||
|
{
|
||||||
|
for (NzVector3ui& triangle : triangles)
|
||||||
|
{
|
||||||
|
unsigned int a = GetMiddleVertex(triangle.x, triangle.y);
|
||||||
|
unsigned int b = GetMiddleVertex(triangle.y, triangle.z);
|
||||||
|
unsigned int c = GetMiddleVertex(triangle.z, triangle.x);
|
||||||
|
|
||||||
|
triangles.push_back({triangle.x, a, c});
|
||||||
|
triangles.push_back({triangle.y, b, a});
|
||||||
|
triangles.push_back({triangle.z, c, b});
|
||||||
|
|
||||||
|
triangle.Set(a, b, c); // Réutilisation du triangle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const NzVector3ui& triangle : triangles)
|
||||||
|
{
|
||||||
|
*indices++ = triangle.x + indexOffset;
|
||||||
|
*indices++ = triangle.y + indexOffset;
|
||||||
|
*indices++ = triangle.z + indexOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aabb)
|
||||||
|
{
|
||||||
|
NzVector3f totalSize = size * m_matrix.GetScale();
|
||||||
|
aabb->Set(-totalSize, totalSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int AddVertex(const NzVector3f& position)
|
||||||
|
{
|
||||||
|
NzMeshVertex& vertex = m_vertices[m_vertexIndex];
|
||||||
|
|
||||||
|
vertex.normal = NzVector3f::Normalize(m_matrix.Transform(position, 0.f));
|
||||||
|
vertex.position = m_matrix.Transform(m_size * position.GetNormal());
|
||||||
|
|
||||||
|
return m_vertexIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int GetMiddleVertex(unsigned int index1, unsigned int index2)
|
||||||
|
{
|
||||||
|
nzUInt64 key = (static_cast<nzUInt64>(std::min(index1, index2)) << 32) + static_cast<nzUInt32>(std::max(index1, index2));
|
||||||
|
auto it = m_cache.find(key);
|
||||||
|
if (it != m_cache.end())
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
NzVector3f middle = NzVector3f::Lerp(m_vertices[index1].position, m_vertices[index2].position, 0.5f);
|
||||||
|
|
||||||
|
unsigned int index = AddVertex(middle);
|
||||||
|
m_cache[key] = index;
|
||||||
|
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::unordered_map<nzUInt64, unsigned int> m_cache;
|
||||||
|
const NzMatrix4f& m_matrix;
|
||||||
|
NzMeshVertex* m_vertices;
|
||||||
|
float m_size;
|
||||||
|
unsigned int m_vertexIndex;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzComputeCubeIndexVertexCount(const NzVector3ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount)
|
||||||
|
{
|
||||||
|
unsigned int xIndexCount, yIndexCount, zIndexCount;
|
||||||
|
unsigned int xVertexCount, yVertexCount, zVertexCount;
|
||||||
|
|
||||||
|
NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.y, subdivision.z), &xIndexCount, &xVertexCount);
|
||||||
|
NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.x, subdivision.z), &yIndexCount, &yVertexCount);
|
||||||
|
NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.x, subdivision.y), &zIndexCount, &zVertexCount);
|
||||||
|
|
||||||
|
if (indexCount)
|
||||||
|
*indexCount = xIndexCount*2 + yIndexCount*2 + zIndexCount*2;
|
||||||
|
|
||||||
|
if (vertexCount)
|
||||||
|
*vertexCount = xVertexCount*2 + yVertexCount*2 + zVertexCount*2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzComputeCubicSphereIndexVertexCount(unsigned int subdivision, unsigned int* indexCount, unsigned int* vertexCount)
|
||||||
|
{
|
||||||
|
// Comme tous nos plans sont identiques, on peut optimiser un peu
|
||||||
|
NzComputePlaneIndexVertexCount(NzVector2ui(subdivision), indexCount, vertexCount);
|
||||||
|
|
||||||
|
if (indexCount)
|
||||||
|
*indexCount *= 6;
|
||||||
|
|
||||||
|
if (vertexCount)
|
||||||
|
*vertexCount *= 6;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzComputeIcoSphereIndexVertexCount(unsigned int recursionLevel, unsigned int* indexCount, unsigned int* vertexCount)
|
||||||
|
{
|
||||||
|
if (indexCount)
|
||||||
|
*indexCount = 3 * 20 * NzIntegralPow(4, recursionLevel);
|
||||||
|
|
||||||
|
if (vertexCount)
|
||||||
|
*vertexCount = NzIntegralPow(4, recursionLevel)*10 + 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzComputePlaneIndexVertexCount(const NzVector2ui& subdivision, unsigned int* indexCount, unsigned int* vertexCount)
|
||||||
|
{
|
||||||
|
// Le nombre de faces appartenant à un axe est équivalent à 2 exposant la subdivision (2,3,5,9,17,33,...)
|
||||||
|
unsigned int horizontalFaceCount = (1 << subdivision.x);
|
||||||
|
unsigned int verticalFaceCount = (1 << subdivision.y);
|
||||||
|
|
||||||
|
// Et le nombre de sommets est ce nombre ajouté de 1
|
||||||
|
unsigned int horizontalVertexCount = horizontalFaceCount + 1;
|
||||||
|
unsigned int verticalVertexCount = verticalFaceCount + 1;
|
||||||
|
|
||||||
|
if (indexCount)
|
||||||
|
*indexCount = horizontalFaceCount*verticalFaceCount*6;
|
||||||
|
|
||||||
|
if (vertexCount)
|
||||||
|
*vertexCount = horizontalVertexCount*verticalVertexCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzComputeUvSphereIndexVertexCount(unsigned int sliceCount, unsigned int stackCount, unsigned int* indexCount, unsigned int* vertexCount)
|
||||||
|
{
|
||||||
|
if (indexCount)
|
||||||
|
*indexCount = (sliceCount-1) * (stackCount-1) * 6;
|
||||||
|
|
||||||
|
if (vertexCount)
|
||||||
|
*vertexCount = sliceCount * stackCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzGenerateCube(const NzCubef& cube, const NzVector3ui& subdivision, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset)
|
||||||
|
{
|
||||||
|
unsigned int xIndexCount, yIndexCount, zIndexCount;
|
||||||
|
unsigned int xVertexCount, yVertexCount, zVertexCount;
|
||||||
|
|
||||||
|
NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.y, subdivision.z), &xIndexCount, &xVertexCount);
|
||||||
|
NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.x, subdivision.z), &yIndexCount, &yVertexCount);
|
||||||
|
NzComputePlaneIndexVertexCount(NzVector2ui(subdivision.x, subdivision.y), &zIndexCount, &zVertexCount);
|
||||||
|
|
||||||
|
NzMeshVertex* oldVertices = vertices;
|
||||||
|
|
||||||
|
// Face +X
|
||||||
|
NzGeneratePlane(NzVector2ui(subdivision.y, subdivision.z), cube.GetPosition() + NzVector3f::UnitX() * cube.width/2.f, NzVector3f::UnitX(), NzVector2f(cube.height, cube.depth), vertices, indices, nullptr, indexOffset);
|
||||||
|
indexOffset += xVertexCount;
|
||||||
|
indices += xIndexCount;
|
||||||
|
vertices += xVertexCount;
|
||||||
|
|
||||||
|
// Face +Y
|
||||||
|
NzGeneratePlane(NzVector2ui(subdivision.x, subdivision.z), cube.GetPosition() + NzVector3f::UnitY() * cube.height/2.f, NzVector3f::UnitY(), NzVector2f(cube.width, cube.depth), vertices, indices, nullptr, indexOffset);
|
||||||
|
indexOffset += yVertexCount;
|
||||||
|
indices += yIndexCount;
|
||||||
|
vertices += yVertexCount;
|
||||||
|
|
||||||
|
// Face +Z
|
||||||
|
NzGeneratePlane(NzVector2ui(subdivision.x, subdivision.y), cube.GetPosition() + NzVector3f::UnitZ() * cube.depth/2.f, NzVector3f::UnitZ(), NzVector2f(cube.width, cube.height), vertices, indices, nullptr, indexOffset);
|
||||||
|
indexOffset += zVertexCount;
|
||||||
|
indices += zIndexCount;
|
||||||
|
vertices += zVertexCount;
|
||||||
|
|
||||||
|
// Face -X
|
||||||
|
NzGeneratePlane(NzVector2ui(subdivision.y, subdivision.z), cube.GetPosition() - NzVector3f::UnitX() * cube.width/2.f, -NzVector3f::UnitX(), NzVector2f(cube.height, cube.depth), vertices, indices, nullptr, indexOffset);
|
||||||
|
indexOffset += xVertexCount;
|
||||||
|
indices += xIndexCount;
|
||||||
|
vertices += xVertexCount;
|
||||||
|
|
||||||
|
// Face -Y
|
||||||
|
NzGeneratePlane(NzVector2ui(subdivision.x, subdivision.z), cube.GetPosition() - NzVector3f::UnitY() * cube.height/2.f, -NzVector3f::UnitY(), NzVector2f(cube.width, cube.depth), vertices, indices, nullptr, indexOffset);
|
||||||
|
indexOffset += yVertexCount;
|
||||||
|
indices += yIndexCount;
|
||||||
|
vertices += yVertexCount;
|
||||||
|
|
||||||
|
// Face -Z
|
||||||
|
NzGeneratePlane(NzVector2ui(subdivision.x, subdivision.y), cube.GetPosition() - NzVector3f::UnitZ() * cube.depth/2.f, -NzVector3f::UnitZ(), NzVector2f(cube.width, cube.height), vertices, indices, nullptr, indexOffset);
|
||||||
|
indexOffset += zVertexCount;
|
||||||
|
indices += zIndexCount;
|
||||||
|
vertices += zVertexCount;
|
||||||
|
|
||||||
|
NzTransformVertices(oldVertices, vertices-oldVertices, matrix);
|
||||||
|
|
||||||
|
if (aabb)
|
||||||
|
{
|
||||||
|
aabb->Set(NzVector3f::Unit());
|
||||||
|
aabb->Transform(matrix, 0.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzGenerateCubicSphere(float size, unsigned int subdivision, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset)
|
||||||
|
{
|
||||||
|
unsigned int vertexCount;
|
||||||
|
NzComputeCubeIndexVertexCount(NzVector3ui(subdivision), nullptr, &vertexCount);
|
||||||
|
|
||||||
|
// On envoie une matrice identité de sorte à ce que le cube ne subisse aucune transformation (rendant plus facile l'étape suivante)
|
||||||
|
NzGenerateCube(NzCubef(size, size, size), NzVector3ui(subdivision), NzMatrix4f::Identity(), vertices, indices, nullptr, indexOffset);
|
||||||
|
|
||||||
|
if (aabb)
|
||||||
|
{
|
||||||
|
NzVector3f totalSize = size * matrix.GetScale();
|
||||||
|
aabb->Set(-totalSize, totalSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < vertexCount; ++i)
|
||||||
|
{
|
||||||
|
vertices->normal = vertices->position.GetNormal();
|
||||||
|
vertices->position = matrix.Transform(size * vertices->normal);
|
||||||
|
//vertices->tangent = ???
|
||||||
|
vertices++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzGenerateIcoSphere(float size, unsigned int recursionLevel, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset)
|
||||||
|
{
|
||||||
|
IcoSphereBuilder builder(matrix);
|
||||||
|
builder.Generate(size, recursionLevel, vertices, indices, aabb, indexOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzGeneratePlane(const NzVector2ui& subdivision, const NzVector3f& position, const NzVector3f& normal, const NzVector2f& size, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset)
|
||||||
|
{
|
||||||
|
// Le nombre de faces appartenant à un axe est équivalent à 2 exposant la subdivision (2,3,5,9,17,33,...)
|
||||||
|
unsigned int horizontalFaceCount = (1 << subdivision.x);
|
||||||
|
unsigned int verticalFaceCount = (1 << subdivision.y);
|
||||||
|
|
||||||
|
// Et le nombre de sommets est ce nombre ajouté de 1
|
||||||
|
unsigned int horizontalVertexCount = horizontalFaceCount + 1;
|
||||||
|
unsigned int verticalVertexCount = verticalFaceCount + 1;
|
||||||
|
|
||||||
|
// Pour plus de facilité, on va construire notre plan en considérant que la normale est de 0,1,0
|
||||||
|
// et on va construire un quaternion représentant la rotation de cette normale à la normale demandée par l'utilisateur.
|
||||||
|
// Celui-ci, combiné avec la position, va former une transformation qu'il suffira d'appliquer aux sommets
|
||||||
|
NzQuaternionf rotation;
|
||||||
|
rotation.MakeRotationBetween(NzVector3f::UnitY(), normal);
|
||||||
|
|
||||||
|
NzMatrix4f transform;
|
||||||
|
transform.MakeTransform(position, rotation);
|
||||||
|
|
||||||
|
///FIXME: Vérifier les tangentes
|
||||||
|
NzVector3f tangent(1.f, 1.f, 0.f);
|
||||||
|
tangent = rotation * tangent;
|
||||||
|
tangent.Normalize();
|
||||||
|
|
||||||
|
float halfSizeX = size.x / 2.f;
|
||||||
|
float halfSizeY = size.y / 2.f;
|
||||||
|
|
||||||
|
float invHorizontalVertexCount = 1.f/(horizontalVertexCount-1);
|
||||||
|
float invVerticalVertexCount = 1.f/(verticalVertexCount-1);
|
||||||
|
for (unsigned int x = 0; x < horizontalVertexCount; ++x)
|
||||||
|
{
|
||||||
|
for (unsigned int y = 0; y < verticalVertexCount; ++y)
|
||||||
|
{
|
||||||
|
NzVector3f localPos((2.f*x*invHorizontalVertexCount - 1.f) * halfSizeX, 0.f, (2.f*y*invVerticalVertexCount - 1.f) * halfSizeY);
|
||||||
|
vertices->position = transform * localPos;
|
||||||
|
vertices->uv.Set(x*invHorizontalVertexCount, y*invVerticalVertexCount);
|
||||||
|
vertices->normal = normal;
|
||||||
|
vertices->tangent = tangent;
|
||||||
|
vertices++;
|
||||||
|
|
||||||
|
if (x != horizontalVertexCount-1 && y != verticalVertexCount-1)
|
||||||
|
{
|
||||||
|
*indices++ = (x+0)*verticalVertexCount + y + 0 + indexOffset;
|
||||||
|
*indices++ = (x+0)*verticalVertexCount + y + 1 + indexOffset;
|
||||||
|
*indices++ = (x+1)*verticalVertexCount + y + 0 + indexOffset;
|
||||||
|
|
||||||
|
*indices++ = (x+1)*verticalVertexCount + y + 0 + indexOffset;
|
||||||
|
*indices++ = (x+0)*verticalVertexCount + y + 1 + indexOffset;
|
||||||
|
*indices++ = (x+1)*verticalVertexCount + y + 1 + indexOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aabb)
|
||||||
|
aabb->Set(rotation * NzVector3f(-halfSizeX, 0.f, -halfSizeY), rotation * NzVector3f(halfSizeX, 0.f, halfSizeY));
|
||||||
|
}
|
||||||
|
|
||||||
|
void NzGenerateUvSphere(float size, unsigned int sliceCount, unsigned int stackCount, const NzMatrix4f& matrix, NzMeshVertex* vertices, nzUInt32* indices, NzCubef* aabb, unsigned int indexOffset)
|
||||||
|
{
|
||||||
|
// http://stackoverflow.com/questions/14080932/implementing-opengl-sphere-example-code
|
||||||
|
float invSliceCount = 1.f / (sliceCount-1);
|
||||||
|
float invStackCount = 1.f / (stackCount-1);
|
||||||
|
|
||||||
|
const float pi = M_PI; // Pour éviter toute promotion en double
|
||||||
|
const float pi2 = pi * 2.f;
|
||||||
|
const float pi_2 = pi / 2.f;
|
||||||
|
|
||||||
|
for (unsigned int stack = 0; stack < stackCount; ++stack)
|
||||||
|
{
|
||||||
|
float stackVal = stack * invStackCount;
|
||||||
|
float stackValPi = stackVal * pi;
|
||||||
|
float sinStackValPi = std::sin(stackValPi);
|
||||||
|
|
||||||
|
for (unsigned int slice = 0; slice < sliceCount; ++slice)
|
||||||
|
{
|
||||||
|
float sliceVal = slice * invSliceCount;
|
||||||
|
float sliceValPi2 = sliceVal * pi2;
|
||||||
|
|
||||||
|
NzVector3f normal;
|
||||||
|
normal.y = std::sin(-pi_2 + stackValPi);
|
||||||
|
normal.x = std::cos(sliceValPi2) * sinStackValPi;
|
||||||
|
normal.z = std::sin(sliceValPi2) * sinStackValPi;
|
||||||
|
|
||||||
|
vertices->position = matrix.Transform(size * normal);
|
||||||
|
vertices->normal = matrix.Transform(normal, 0.f);
|
||||||
|
vertices->uv.Set(1.f - sliceVal, stackVal);
|
||||||
|
vertices++;
|
||||||
|
|
||||||
|
if (stack != stackCount-1 && slice != sliceCount-1)
|
||||||
|
{
|
||||||
|
*indices++ = (stack+0)*sliceCount + (slice+0) + indexOffset;
|
||||||
|
*indices++ = (stack+1)*sliceCount + (slice+0) + indexOffset;
|
||||||
|
*indices++ = (stack+0)*sliceCount + (slice+1) + indexOffset;
|
||||||
|
|
||||||
|
*indices++ = (stack+0)*sliceCount + (slice+1) + indexOffset;
|
||||||
|
*indices++ = (stack+1)*sliceCount + (slice+0) + indexOffset;
|
||||||
|
*indices++ = (stack+1)*sliceCount + (slice+1) + indexOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aabb)
|
||||||
|
{
|
||||||
|
NzVector3f totalSize = size * matrix.GetScale();
|
||||||
|
aabb->Set(-totalSize, totalSize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,16 +3,24 @@
|
||||||
// For conditions of distribution and use, see copyright notice in Config.hpp
|
// For conditions of distribution and use, see copyright notice in Config.hpp
|
||||||
|
|
||||||
#include <Nazara/Utility/Mesh.hpp>
|
#include <Nazara/Utility/Mesh.hpp>
|
||||||
|
#include <Nazara/Core/Enums.hpp>
|
||||||
#include <Nazara/Core/Error.hpp>
|
#include <Nazara/Core/Error.hpp>
|
||||||
|
#include <Nazara/Core/PrimitiveList.hpp>
|
||||||
|
#include <Nazara/Math/Basic.hpp>
|
||||||
|
#include <Nazara/Utility/Algorithm.hpp>
|
||||||
#include <Nazara/Utility/Animation.hpp>
|
#include <Nazara/Utility/Animation.hpp>
|
||||||
#include <Nazara/Utility/Buffer.hpp>
|
#include <Nazara/Utility/Buffer.hpp>
|
||||||
|
#include <Nazara/Utility/BufferMapper.hpp>
|
||||||
#include <Nazara/Utility/Config.hpp>
|
#include <Nazara/Utility/Config.hpp>
|
||||||
|
#include <Nazara/Utility/IndexMapper.hpp>
|
||||||
#include <Nazara/Utility/SkeletalMesh.hpp>
|
#include <Nazara/Utility/SkeletalMesh.hpp>
|
||||||
#include <Nazara/Utility/Skeleton.hpp>
|
#include <Nazara/Utility/Skeleton.hpp>
|
||||||
|
#include <Nazara/Utility/StaticMesh.hpp>
|
||||||
#include <Nazara/Utility/SubMesh.hpp>
|
#include <Nazara/Utility/SubMesh.hpp>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <deque>
|
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
#include <limits>
|
||||||
#include <Nazara/Utility/Debug.hpp>
|
#include <Nazara/Utility/Debug.hpp>
|
||||||
|
|
||||||
NzMeshParams::NzMeshParams()
|
NzMeshParams::NzMeshParams()
|
||||||
|
|
@ -126,6 +134,218 @@ bool NzMesh::AddSubMesh(const NzString& identifier, NzSubMesh* subMesh)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void NzMesh::Build(const NzPrimitiveList& list, const NzMeshParams& params)
|
||||||
|
{
|
||||||
|
#if NAZARA_UTILITY_SAFE
|
||||||
|
if (!m_impl)
|
||||||
|
{
|
||||||
|
NazaraError("Mesh not created");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_impl->animationType != nzAnimationType_Static)
|
||||||
|
{
|
||||||
|
NazaraError("Mesh must be static");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned int primitiveCount = list.GetSize();
|
||||||
|
|
||||||
|
#if NAZARA_UTILITY_SAFE
|
||||||
|
if (primitiveCount == 0)
|
||||||
|
{
|
||||||
|
NazaraError("GeomBuilder has no primitive");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params.IsValid())
|
||||||
|
{
|
||||||
|
NazaraError("Parameters must be valid");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
for (unsigned int p = 0; p < primitiveCount; ++p)
|
||||||
|
{
|
||||||
|
NzCubef aabb;
|
||||||
|
std::unique_ptr<NzIndexBuffer> indexBuffer;
|
||||||
|
std::unique_ptr<NzVertexBuffer> vertexBuffer;
|
||||||
|
|
||||||
|
const NzPrimitive& primitive = list.GetPrimitive(p);
|
||||||
|
|
||||||
|
switch (primitive.type)
|
||||||
|
{
|
||||||
|
case nzPrimitiveType_Cube:
|
||||||
|
{
|
||||||
|
unsigned int indexCount;
|
||||||
|
unsigned int vertexCount;
|
||||||
|
NzComputeCubeIndexVertexCount(primitive.cube.subdivision, &indexCount, &vertexCount);
|
||||||
|
|
||||||
|
indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits<nzUInt16>::max(), params.storage, nzBufferUsage_Static));
|
||||||
|
indexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static));
|
||||||
|
vertexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
///TODO: Remplacer par un itérateur sur les indices
|
||||||
|
std::vector<nzUInt32> indices;
|
||||||
|
indices.resize(indexCount);
|
||||||
|
|
||||||
|
NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
NzGenerateCube(primitive.cube.cube, primitive.cube.subdivision, primitive.cube.matrix, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), &indices[0], &aabb);
|
||||||
|
vertexMapper.Unmap();
|
||||||
|
|
||||||
|
NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < indexCount; ++i)
|
||||||
|
indexMapper.Set(i, indices[i]);
|
||||||
|
|
||||||
|
indexMapper.Unmap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case nzPrimitiveType_Plane:
|
||||||
|
{
|
||||||
|
unsigned int indexCount;
|
||||||
|
unsigned int vertexCount;
|
||||||
|
NzComputePlaneIndexVertexCount(primitive.plane.subdivision, &indexCount, &vertexCount);
|
||||||
|
|
||||||
|
indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits<nzUInt16>::max(), params.storage, nzBufferUsage_Static));
|
||||||
|
indexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static));
|
||||||
|
vertexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
///TODO: Remplacer par un itérateur sur les indices
|
||||||
|
std::vector<nzUInt32> indices;
|
||||||
|
indices.resize(indexCount);
|
||||||
|
|
||||||
|
NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
NzGeneratePlane(primitive.plane.subdivision, primitive.plane.position, primitive.plane.normal, primitive.plane.size, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), &indices[0], &aabb);
|
||||||
|
vertexMapper.Unmap();
|
||||||
|
|
||||||
|
NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < indexCount; ++i)
|
||||||
|
indexMapper.Set(i, indices[i]);
|
||||||
|
|
||||||
|
indexMapper.Unmap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case nzPrimitiveType_Sphere:
|
||||||
|
{
|
||||||
|
switch (primitive.sphere.type)
|
||||||
|
{
|
||||||
|
case nzSphereType_Cubic:
|
||||||
|
{
|
||||||
|
unsigned int indexCount;
|
||||||
|
unsigned int vertexCount;
|
||||||
|
NzComputeCubicSphereIndexVertexCount(primitive.sphere.cubic.subdivision, &indexCount, &vertexCount);
|
||||||
|
|
||||||
|
indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits<nzUInt16>::max(), params.storage, nzBufferUsage_Static));
|
||||||
|
indexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static));
|
||||||
|
vertexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
///TODO: Remplacer par un itérateur sur les indices
|
||||||
|
std::vector<nzUInt32> indices;
|
||||||
|
indices.resize(indexCount);
|
||||||
|
|
||||||
|
NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
NzGenerateCubicSphere(primitive.sphere.size, primitive.sphere.cubic.subdivision, primitive.sphere.matrix, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), &indices[0], &aabb);
|
||||||
|
vertexMapper.Unmap();
|
||||||
|
|
||||||
|
NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < indexCount; ++i)
|
||||||
|
indexMapper.Set(i, indices[i]);
|
||||||
|
|
||||||
|
indexMapper.Unmap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case nzSphereType_Ico:
|
||||||
|
{
|
||||||
|
unsigned int indexCount;
|
||||||
|
unsigned int vertexCount;
|
||||||
|
NzComputeIcoSphereIndexVertexCount(primitive.sphere.ico.recursionLevel, &indexCount, &vertexCount);
|
||||||
|
|
||||||
|
indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits<nzUInt16>::max(), params.storage, nzBufferUsage_Static));
|
||||||
|
indexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static));
|
||||||
|
vertexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
///TODO: Remplacer par un itérateur sur les indices
|
||||||
|
std::vector<nzUInt32> indices;
|
||||||
|
indices.resize(indexCount);
|
||||||
|
|
||||||
|
NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
NzGenerateIcoSphere(primitive.sphere.size, primitive.sphere.ico.recursionLevel, primitive.sphere.matrix, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), &indices[0], &aabb);
|
||||||
|
vertexMapper.Unmap();
|
||||||
|
|
||||||
|
NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < indexCount; ++i)
|
||||||
|
indexMapper.Set(i, indices[i]);
|
||||||
|
|
||||||
|
indexMapper.Unmap();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case nzSphereType_UV:
|
||||||
|
{
|
||||||
|
unsigned int indexCount;
|
||||||
|
unsigned int vertexCount;
|
||||||
|
NzComputeUvSphereIndexVertexCount(primitive.sphere.uv.slices, primitive.sphere.uv.stacks, &indexCount, &vertexCount);
|
||||||
|
|
||||||
|
indexBuffer.reset(new NzIndexBuffer(indexCount, vertexCount > std::numeric_limits<nzUInt16>::max(), params.storage, nzBufferUsage_Static));
|
||||||
|
indexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
vertexBuffer.reset(new NzVertexBuffer(GetDeclaration(), vertexCount, params.storage, nzBufferUsage_Static));
|
||||||
|
vertexBuffer->SetPersistent(false);
|
||||||
|
|
||||||
|
///TODO: Remplacer par un itérateur sur les indices
|
||||||
|
std::vector<nzUInt32> indices;
|
||||||
|
indices.resize(indexCount);
|
||||||
|
|
||||||
|
NzBufferMapper<NzVertexBuffer> vertexMapper(vertexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
NzGenerateUvSphere(primitive.sphere.size, primitive.sphere.uv.slices, primitive.sphere.uv.stacks, primitive.sphere.matrix, static_cast<NzMeshVertex*>(vertexMapper.GetPointer()), &indices[0], &aabb);
|
||||||
|
vertexMapper.Unmap();
|
||||||
|
|
||||||
|
NzIndexMapper indexMapper(indexBuffer.get(), nzBufferAccess_WriteOnly);
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < indexCount; ++i)
|
||||||
|
indexMapper.Set(i, indices[i]);
|
||||||
|
|
||||||
|
indexMapper.Unmap();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<NzStaticMesh> subMesh(new NzStaticMesh(this));
|
||||||
|
if (!subMesh->Create(vertexBuffer.get()))
|
||||||
|
{
|
||||||
|
NazaraError("Failed to create StaticMesh");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
vertexBuffer.release();
|
||||||
|
|
||||||
|
subMesh->SetIndexBuffer(indexBuffer.get());
|
||||||
|
indexBuffer.release();
|
||||||
|
|
||||||
|
subMesh->SetAABB(aabb);
|
||||||
|
|
||||||
|
if (AddSubMesh(subMesh.get()))
|
||||||
|
subMesh.release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool NzMesh::CreateSkeletal(unsigned int jointCount)
|
bool NzMesh::CreateSkeletal(unsigned int jointCount)
|
||||||
{
|
{
|
||||||
Destroy();
|
Destroy();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue