Cogs.Core
MeshGeneratorSphere.h
1#pragma once
2
3#include "MeshGeneratorCommon.h"
4
5namespace
6{
7 template<ShapeType subtype>
8 void sphereFactoryHelper(std::vector<PositionNormalTexVertex>& V,
9 std::vector<uint32_t>& I,
10 const glm::vec3& p001,
11 const glm::vec3& p010,
12 const glm::vec3& p100,
13 uint32_t samples)
14 {
15 // sample triangular grid
16 int N = samples + 1;
17 for (int j = 0; j < N; j++) {
18 float v = float(j) / float(N - 1);
19 //float w0 = std::sin(glm::half_pi<float>()*(1.f - v));
20 //float w1 = std::sin(glm::half_pi<float>()*v);
21 for (int i = 0; i < (N - j - (j == 0 ? 1 : 0)); i++) { // note that we omit final element when j==0, see below
22 float u = float(i) / float(N - 1);
23
24 // sphere position
25 glm::vec3 P = glm::normalize(v*p010 + u*p001 + (1.f - u - v)*p100);
26
27 // texcoords
28 float t = 1.f / std::sqrt(1.f - P.z*P.z);
29 float t_u = float(0.5 * glm::one_over_pi<float>())*std::acos(std::min(1.f, P.y*t));
30 float t_v = subtype == ShapeType::SphereGeoTexSph
31 ? glm::one_over_pi<float>() * std::acos(-P.z)
32 : 0.5f + 0.5f*P.z;
33 V.push_back({ P, P, glm::vec2(t_u, t_v) });
34 }
35 if (j == 0) {
36 // final element when j==0 has texture parameterization pole degeneracy; needs some extra care.
37 V.push_back({ p001, p001, glm::vec2(0.125f, 1.f) });
38 }
39 }
40
41 // triangulate grid samples
42 uint32_t k = 0;
43 for (uint32_t j = 0; j < samples; j++) {
44 for (uint32_t i = 0; i < samples - j; i++) {
45 I.push_back(j + k);
46 I.push_back(j + k + samples - j + 1);
47 I.push_back(j + k + 1);
48 if (i < samples - j - 1) {
49 I.push_back(j + k + samples - j + 1);
50 I.push_back(j + k + samples - j + 2);
51 I.push_back(j + k + 1);
52 }
53 k++;
54 }
55 }
56 }
57
58 /*
59 Creates a transformed copy of the mesh in V_t/I_t and pushes it into V/I
60 */
61 void sphereFactoryCloneOctant(std::vector<PositionNormalTexVertex>& V,
62 std::vector<uint32_t>& I,
63 const std::vector<PositionNormalTexVertex>& V_t,
64 const std::vector<uint32_t>& I_t,
65 const glm::vec3& P100,
66 const glm::vec3& P010,
67 const glm::vec3& P001,
68 const glm::vec2& transform_u,
69 const glm::vec2& transform_v,
70 uint32_t samples)
71 {
72 uint32_t offset = uint32_t(V.size());
73 int Vn = ((samples + 1)*(samples + 2)) / 2;
74 for (int i = 0; i < Vn; i++) {
75 glm::vec3 pw = V_t[i].position;
76 glm::vec3 p = P001 * pw.x + P010*pw.y + P100*pw.z;
77 glm::vec2 tw = V_t[i].tex;
78 glm::vec2 t = glm::vec2(transform_u.x*tw.x + transform_u.y,
79 transform_v.x*tw.y + transform_v.y);
80 V.push_back({ p, p, t });
81 }
82
83 int In = ((3 * samples*(samples + 1)) / 2 + (3 * (samples - 1)*samples) / 2);
84 for (int i = 0; i < In; i++) {
85 I.push_back(offset + I_t[i]);
86 }
87 }
88
89 template<ShapeType subtype>
90 void sphereGeoTexSphFactory(Mesh * m, const ShapeDefinition & definition, int kRefinementLevels, int kMaxSamples)
91 {
92 int n = (samplesFromLevel(definition.refinement, kRefinementLevels, kMaxSamples) + 3) / 4;
93
94 std::vector<PositionNormalTexVertex> V_t;
95 V_t.reserve(((n + 1)*(n + 2)) / 2);
96
97 std::vector<uint32_t> I_t;
98 I_t.reserve(((3 * n*(n + 1)) / 2 + (3 * (n - 1)*n) / 2));
99
100 //FIXME: a bit wasteful to create the "template" separately, but it was easier to get scaling correct like this.
101 //We could consider caching the templates for the most recently used n values for efficency
102 sphereFactoryHelper<subtype>(V_t, I_t, glm::vec3(0.f, 0.f, 1), glm::vec3(0.f, 1, 0.f), glm::vec3(1, 0.f, 0.f), n);
103
104 std::vector<PositionNormalTexVertex> V;
105 V.reserve(8 * ((n + 1)*(n + 2)) / 2);
106
107 std::vector<uint32_t> I;
108 I.reserve(8 * ((3 * n*(n + 1)) / 2 + (3 * (n - 1)*n) / 2));
109
110 //Uses X dimension for radius, ignores Y and Z
111 //I feel like "spheroid" would be a better name if we were to allow non-uniform sizing - wiesener
112 auto & r = definition.size.x;
113
114 sphereFactoryCloneOctant(V, I, V_t, I_t, glm::vec3(0.f, 0.f, r), glm::vec3( r, 0.f, 0.f), glm::vec3(0.f, -r, 0.f), glm::vec2( 1.f, 0.25f), glm::vec2( 1.f, 0.f), n);
115 sphereFactoryCloneOctant(V, I, V_t, I_t, glm::vec3(0.f, 0.f, r), glm::vec3(0.f, -r, 0.f), glm::vec3( -r, 0.f, 0.f), glm::vec2( 1.f, 0.50f), glm::vec2( 1.f, 0.f), n);
116 sphereFactoryCloneOctant(V, I, V_t, I_t, glm::vec3(0.f, 0.f, r), glm::vec3( -r, 0.f, 0.f), glm::vec3(0.f, r, 0.f), glm::vec2( 1.f, 0.75f), glm::vec2( 1.f, 0.f), n);
117 sphereFactoryCloneOctant(V, I, V_t, I_t, glm::vec3(0.f, 0.f, r), glm::vec3(0.f, r, 0.f), glm::vec3( r, 0.f, 0.f), glm::vec2( 1.f, 0.0f ), glm::vec2( 1.f, 0.f), n);
118
119 sphereFactoryCloneOctant(V, I, V_t, I_t, glm::vec3(0.f, 0.f, -r), glm::vec3( r, 0.f, 0.f), glm::vec3(0.f, r, 0.f), glm::vec2(-1.f, 0.25f), glm::vec2(-1.f, 1.0f), n);
120 sphereFactoryCloneOctant(V, I, V_t, I_t, glm::vec3(0.f, 0.f, -r), glm::vec3(0.f, -r, 0.f), glm::vec3( r, 0.f, 0.f), glm::vec2(-1.f, 0.50f), glm::vec2(-1.f, 1.0f), n);
121 sphereFactoryCloneOctant(V, I, V_t, I_t, glm::vec3(0.f, 0.f, -r), glm::vec3( -r, 0.f, 0.f), glm::vec3(0.f, -r, 0.f), glm::vec2(-1.f, 0.75f), glm::vec2(-1.f, 1.0f), n);
122 sphereFactoryCloneOctant(V, I, V_t, I_t, glm::vec3(0.f, 0.f, -r), glm::vec3(0.f, r, 0.f), glm::vec3( -r, 0.f, 0.f), glm::vec2(-1.f, 1.0f ), glm::vec2(-1.f, 1.0f), n);
123
124 m->setVertexData(V.data(), V.size());
125 m->setIndexData(I.data(), I.size());
126 m->setBounds(computeBoundingBoxFromVertexFormat(V.begin(), V.end()));
127 }
128}
Meshes contain streams of vertex data in addition to index data and options defining geometry used fo...
Definition: Mesh.h:265
void setIndexData(const uint32_t *data, size_t count)
Convenience method for setting index data from a raw pointer to data and count number of elements.
Definition: Mesh.h:705
void setBounds(Geometry::BoundingBox box)
Set custom bounds for the mesh.
Definition: Mesh.h:298
void setVertexData(Element *elements, size_t count)
Set vertex data.
Definition: Mesh.h:754
Defines creation values for a unique shape.
Definition: ShapeType.h:74