1 #define _USE_MATH_DEFINES
4 #include "primitivebuilder.h"
12 UvSphereBuilder::UvSphereBuilder(float r, unsigned s, unsigned n):
21 rings = (segments+1)/2;
26 void UvSphereBuilder::build(PrimitiveBuilder &builder) const
28 float u_scale = 1.0f/segments;
29 float v_scale = 1.0f/rings;
30 adjust_texture_scale(u_scale, v_scale, radius*M_PI*2, radius*M_PI);
32 for(unsigned i=0; i<=rings; ++i)
34 float av = i*M_PI/rings-M_PI/2;
38 for(unsigned j=0; j<=segments; ++j)
40 float au = j*M_PI*2/segments;
44 builder.normal(cv*cu, cv*su, sv);
45 builder.texcoord(j*u_scale, i*v_scale);
48 builder.tangent(-su, cu, 0);
49 builder.binormal(-sv*cu, -sv*su, cv);
51 builder.vertex(cv*cu*radius, cv*su*radius, sv*radius);
55 builder.begin(TRIANGLES);
56 for(unsigned j=0; j<segments; ++j)
59 builder.element(segments+2+j);
60 builder.element(segments+1+j);
62 unsigned top = (rings+1)*(segments+1)-1;
63 for(unsigned j=0; j<segments; ++j)
65 builder.element(top-j);
66 builder.element(top-(segments+2+j));
67 builder.element(top-(segments+1+j));
71 for(unsigned i=1; i<rings; ++i)
73 builder.begin(TRIANGLE_STRIP);
74 unsigned base = i*(segments+1);
75 for(unsigned j=0; j<=segments; ++j)
77 builder.element(base+segments+1+j);
78 builder.element(base+j);
85 // https://en.wikipedia.org/wiki/Regular_icosahedron#Cartesian_coordinates
86 float IcoSphereBuilder::base_vertices[12*3] =
88 0.0f, -0.5257311f, -0.8506508f,
89 0.0f, 0.5257311f, -0.8506508f,
90 0.0f, -0.5257311f, 0.8506508f,
91 0.0f, 0.5257311f, 0.8506508f,
92 -0.8506508f, 0.0f, -0.5257311f,
93 -0.8506508f, 0.0f, 0.5257311f,
94 0.8506508f, 0.0f, -0.5257311f,
95 0.8506508f, 0.0f, 0.5257311f,
96 -0.5257311f, -0.8506508f, 0.0f,
97 0.5257311f, -0.8506508f, 0.0f,
98 -0.5257311f, 0.8506508f, 0.0f,
99 0.5257311f, 0.8506508f, 0.0f
102 unsigned IcoSphereBuilder::base_triangles[20*3] =
126 unsigned IcoSphereBuilder::base_edges[30*2] = { 0, 0 };
127 unsigned IcoSphereBuilder::base_tri_edges[20*3] = { 0, 0, 0 };
129 IcoSphereBuilder::IcoSphereBuilder(float r, unsigned s):
133 if(base_edges[0]==base_edges[1])
137 void IcoSphereBuilder::initialize_edges()
139 vector<int> edge_map(12*12, -1);
140 unsigned next_edge = 0;
141 for(unsigned i=0; i<20; ++i)
142 for(unsigned j=0; j<3; ++j)
144 unsigned v1 = base_triangles[i*3+j];
145 unsigned v2 = base_triangles[i*3+(j+1)%3];
146 int e = edge_map[v1*12+v2];
150 base_edges[e*2] = v1;
151 base_edges[e*2+1] = v2;
152 // The other triangle using this edge will have the vertices swapped
153 edge_map[v2*12+v1] = e|32;
155 base_tri_edges[i*3+j] = e;
159 void IcoSphereBuilder::build(PrimitiveBuilder &bld) const
161 for(unsigned i=0; i<12; ++i)
163 const float *v = base_vertices+i*3;
164 bld.normal(v[0], v[1], v[2]);
165 bld.vertex(v[0]*radius, v[1]*radius, v[2]*radius);
170 vector<Vector3> edge_subdiv(30*(subdivision+1));
171 for(unsigned i=0; i<30; ++i)
173 Vector3 v1(base_vertices+base_edges[i*2]*3);
174 Vector3 v2(base_vertices+base_edges[i*2+1]*3);
175 for(unsigned j=1; j<subdivision; ++j)
177 float t = static_cast<float>(j)/subdivision;
178 Vector3 v = v1*(1.0f-t)+v2*t;
179 edge_subdiv[i*(subdivision-1)+j-1] = v;
182 bld.vertex(v*radius);
186 for(unsigned i=0; i<20; ++i)
187 for(unsigned j=1; j<subdivision; ++j)
189 unsigned e = base_tri_edges[i*3];
190 Vector3 v1 = edge_subdiv[edge_vertex(e, subdivision-j)];
191 e = base_tri_edges[i*3+1];
192 Vector3 v2 = edge_subdiv[edge_vertex(e, j)];
193 for(unsigned k=1; k<j; ++k)
195 float t = static_cast<float>(k)/j;
196 Vector3 v = normalize(v1*(1.0f-t)+v2*t);
198 bld.vertex(v*radius);
202 for(unsigned i=0; i<20; ++i)
204 unsigned mid = 12+30*(subdivision-1)+i*(subdivision-1)*(subdivision-2)/2;
205 for(unsigned j=1; j<=subdivision; ++j)
207 bld.begin(TRIANGLE_STRIP);
209 bld.element(base_triangles[i*3]);
211 bld.element(12+edge_vertex(base_tri_edges[i*3], subdivision-j));
215 bld.element(base_triangles[i*3+1]);
216 bld.element(12+edge_vertex(base_tri_edges[i*3+1], j));
220 bld.element(12+edge_vertex(base_tri_edges[i*3], subdivision-j+1));
223 bld.element(12+edge_vertex(base_tri_edges[i*3+2], subdivision-1));
225 bld.element(mid+(j-1)*(j-2)/2);
227 for(unsigned k=2; k<j; ++k)
229 bld.element(mid+(j-2)*(j-3)/2+k-2);
231 bld.element(12+edge_vertex(base_tri_edges[i*3+2], subdivision-k));
233 bld.element(mid+(j-1)*(j-2)/2+k-1);
236 bld.element(12+edge_vertex(base_tri_edges[i*3+1], j-1));
238 bld.element(base_triangles[i*3+2]);
240 bld.element(12+edge_vertex(base_tri_edges[i*3+1], j));
248 bld.begin(TRIANGLES);
249 for(unsigned i=0; i<20*3; ++i)
250 bld.element(base_triangles[i]);
255 unsigned IcoSphereBuilder::edge_vertex(unsigned e, unsigned i) const
257 return (e&31)*(subdivision-1)+((e&32)?subdivision-i:i)-1;