From d41476226c3be318fe70fec7018bc37648e599b6 Mon Sep 17 00:00:00 2001 From: Anselme Date: Tue, 26 Apr 2016 12:08:26 +0200 Subject: [PATCH] updated parametric mesh --- src/parametricmesh.cpp | 138 ++++++++++++++++++++--------------------- src/parametricmesh.h | 78 +++++++++++++++++++---- 2 files changed, 131 insertions(+), 85 deletions(-) diff --git a/src/parametricmesh.cpp b/src/parametricmesh.cpp index 0ce7b18..67116cf 100644 --- a/src/parametricmesh.cpp +++ b/src/parametricmesh.cpp @@ -5,11 +5,50 @@ #define M_PI 3.14159265358979323846 #define MAGIC_RATIO 0.37139f -Sphere::Sphere(Material* mat, int n, float myRadius) : - radius(myRadius) +Mesh* MeshGenerator::generateParametricMesh(Material* mat, int width, int height, float size, bool alternate) { - setMaterial(mat); + m_size = size; + m_mesh = new Mesh(); + m_mesh->setMaterial(mat); + + for(int i=0; i<=width; ++i) + { + for(int j=0; j<=height; ++j) + { + createVertex(float(i)/float(width), float(j)/float(height)); + if(i > 0 && j > 0) + { + if(alternate && (i+j)%2) + { + m_mesh->addTriangle(getVertexId(i, j, height), + getVertexId(i, j-1, height), + getVertexId(i-1, j, height)); + m_mesh->addTriangle(getVertexId(i-1, j-1, height), + getVertexId(i-1, j, height), + getVertexId(i, j-1, height)); + } + else + { + m_mesh->addTriangle(getVertexId(i, j, height), + getVertexId(i-1, j-1, height), + getVertexId(i-1, j, height)); + m_mesh->addTriangle(getVertexId(i, j, height), + getVertexId(i, j-1, height), + getVertexId(i-1, j-1, height)); + } + } + } + } + + return m_mesh; +} +Mesh* MeshGenerator::generateGeodesicMesh(Material* mat, int n, float size) +{ + m_size = size; + m_mesh = new Mesh(); + m_mesh->setMaterial(mat); + // icosahedron : // top cap @@ -28,23 +67,27 @@ Sphere::Sphere(Material* mat, int n, float myRadius) : int bottom = 7; int offset = (i+1)%5; // top cap - addTriangle(0, top+i, top+offset); + m_mesh->addTriangle(0, top+i, top+offset); // bottom cap - addTriangle(6, bottom+offset, bottom+i); + m_mesh->addTriangle(6, bottom+offset, bottom+i); // middle ribbon - addTriangle(top+i, bottom+i, top+offset); - addTriangle(top+offset, bottom+i, bottom+offset); + m_mesh->addTriangle(top+i, bottom+i, top+offset); + m_mesh->addTriangle(top+offset, bottom+i, bottom+offset); } // geodesic subdivisions : for(int i=0; iaddVertex(evalUV(u, v)*m_size, glm::vec2(u, v)); +} + +int MeshGenerator::getEdge(int a, int b) { Edge* current = edges+a; int vid = -1; @@ -54,16 +97,14 @@ int Sphere::getEdge(int a, int b) vid = current->vertex; else if(current->next == NULL) { - vid = positions3D.size(); + vid = m_mesh->positions3D.size(); // creating subdivision vertex - glm::vec3 pos = glm::normalize(positions3D[a] + positions3D[b] / 2.f); - addPosition(pos); - addNormal(pos); + glm::vec3 pos = glm::normalize(m_mesh->positions3D[a] + m_mesh->positions3D[b] / 2.f); // u/v sphériques, cohérents sur toute la sphère sauf des artefacts au niveau des u==0 float newU = (pos.x < 0 ? 1.5f : 1.f) + atan(pos.z/pos.x)/(2*M_PI); float newV = acos(pos.y)/M_PI; - addTexCoord(newU - floor(newU), newV); + createVertex(newU - floor(newU), newV); // alternative, u/v moyennés : //v.texCoord = (v0.texCoord + v1.texCoord)/2.f; @@ -82,77 +123,30 @@ int Sphere::getEdge(int a, int b) return vid; } -void Sphere::subdivide() +void MeshGenerator::subdivide() { - edges = new Edge[positions3D.size()-1]; - int nb_triangles = indices.size()/3; + edges = new Edge[m_mesh->positions3D.size()-1]; + int nb_triangles = m_mesh->indices.size()/3; for(int j=0; jindices[j*3 + k]; + int idB = m_mesh->indices[j*3 + (k+1)%3]; int a = idA < idB ? idA : idB; int b = idA > idB ? idA : idB; vid[k] = getEdge(a, b); } for(int k=0; k<3; k++) - addTriangle(indices[j*3 + k], vid[k], vid[(k+2)%3]); - addTriangle(vid[0], vid[1], vid[2]); + m_mesh->addTriangle(m_mesh->indices[j*3 + k], vid[k], vid[(k+2)%3]); + m_mesh->addTriangle(vid[0], vid[1], vid[2]); } delete[](edges); - indices.erase(indices.begin(), indices.begin()+nb_triangles*3); + m_mesh->indices.erase(m_mesh->indices.begin(), m_mesh->indices.begin()+nb_triangles*3); } -void Sphere::createVertex(float u, float v) -{ - glm::vec3 pos(cos(u*2*M_PI)*sin(v*M_PI), - cos(v*M_PI), - sin(u*2*M_PI)*sin(v*M_PI)); - addPosition(pos); - addNormal(pos); - addTexCoord(u, v); -} - -GridMesh::GridMesh(Material* mat, int width, int height, bool alternate) -{ - setMaterial(mat); - for(int i=0; i<=width; ++i) - { - for(int j=0; j<=height; ++j) - { - float x = (float)i/(float)width; - float y = (float)j/(float)height; - addPosition(x-0.5f, 0, y-0.5f); - addNormal(0, 1, 0); - addTexCoord(x, y); - if(i > 0 && j > 0) - { - if(alternate && (i+j)%2) - { - addTriangle(getVertexId(i, j, height), - getVertexId(i, j-1, height), - getVertexId(i-1, j, height)); - addTriangle(getVertexId(i-1, j-1, height), - getVertexId(i-1, j, height), - getVertexId(i, j-1, height)); - } - else - { - addTriangle(getVertexId(i, j, height), - getVertexId(i-1, j-1, height), - getVertexId(i-1, j, height)); - addTriangle(getVertexId(i, j, height), - getVertexId(i, j-1, height), - getVertexId(i-1, j-1, height)); - } - } - } - } -} - -int GridMesh::getVertexId(int i, int j, int height) +int MeshGenerator::getVertexId(int i, int j, int height) { return i*(height+1) + j; } diff --git a/src/parametricmesh.h b/src/parametricmesh.h index 27e1d83..707d36d 100644 --- a/src/parametricmesh.h +++ b/src/parametricmesh.h @@ -1,11 +1,27 @@ #ifndef PARAMETRIC_MESH_H #define PARAMETRIC_MESH_H -#include "meshbuilder.h" +#include "mesh.h" -class Sphere : public MeshBuilder +class MeshGenerator { +public: + virtual glm::vec3 evalUV(float u, float v) = 0; + + /** + * @brief generateParametricMesh creates a mesh from a rectangular grid of size width:height + */ + Mesh* generateParametricMesh(Material* mat, int width = 10, int height = 10, float size = 1, bool alternate = true); + + /** + * @brief generateGeodesicMesh creates a closed mesh from an icosahedron subdivided n times + */ + Mesh* generateGeodesicMesh(Material* mat, int n = 0, float size = 1); private: + float m_size; + Mesh *m_mesh; + + // geodesic methods class Edge{ public: int b; @@ -20,23 +36,59 @@ private: }; Edge* edges; - float radius; int getEdge(int a, int b); void createVertex(float u, float v); void subdivide(); -public: - Sphere(Material* mat, int n = 0, float myRadius = 1.f); -}; - -class GridMesh : public MeshBuilder -{ -public: - GridMesh(Material* mat, int width, int height, bool alternate = true); -private: + + // parametric methods int getVertexId(int i, int j, int height); }; -// TODO TextMesh (with glyph map) +// here are some basic implementations of parametric mesh generators + +/** + * @brief The GridGenerator class is the simplest parametric mesh, a uniform mapped grid + */ +class GridGenerator : public MeshGenerator +{ +public: + virtual glm::vec3 evalUV(float u, float v) + {return glm::vec3(u-0.5f, 0, v-0.5f);} +}; + +/** + * @brief The CylinderGenerator class creates a vertical open cylinder + */ +class CylinderGenerator : public MeshGenerator +{ +public: + virtual glm::vec3 evalUV(float u, float v) + {return glm::vec3(cos(u*6.2832f), v-0.5f, sin(u*6.2832f));} +}; + +/** + * @brief The ConeGenerator class creates an open cone pointing down + */ +class ConeGenerator : public MeshGenerator +{ +public: + virtual glm::vec3 evalUV(float u, float v) + {return glm::vec3(cos(u*6.2832f)*v, v, sin(u*6.2832f)*v);} +}; + +/** + * @brief The SphereGenerator class creates a sphere uv-mapped like a planisphere + * it is recommended to use a grid where the width value is twice the value of height + */ +class SphereGenerator : public MeshGenerator +{ +public: + virtual glm::vec3 evalUV(float u, float v) + { + float r = sin(v*3.1416f); + return glm::vec3(cos(u*6.2832f)*r, cos(v*3.1416f), sin(u*6.2832f)*r); + } +}; #endif // PARAMETRIC_MESH_H