5 // -------- sphere --------
7 #define SURAD(u) ((u) * 2.0 * M_PI)
8 #define SVRAD(v) ((v) * M_PI)
10 static Vec3 sphvec(float theta, float phi)
12 return Vec3(sin(theta) * sin(phi),
14 cos(theta) * sin(phi));
17 void gen_sphere(Mesh *mesh, float rad, int usub, int vsub, float urange, float vrange)
19 if(usub < 4) usub = 4;
20 if(vsub < 2) vsub = 2;
22 int uverts = usub + 1;
23 int vverts = vsub + 1;
25 int num_verts = uverts * vverts;
26 int num_quads = usub * vsub;
27 int num_tri = num_quads * 2;
30 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
31 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
32 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
33 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
34 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
36 float du = urange / (float)(uverts - 1);
37 float dv = vrange / (float)(vverts - 1);
40 for(int i=0; i<uverts; i++) {
41 float theta = u * 2.0 * M_PI;
44 for(int j=0; j<vverts; j++) {
47 Vec3 pos = sphvec(theta, phi);
51 *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f));
52 *uvarr++ = Vec2(u * urange, v * vrange);
54 if(i < usub && j < vsub) {
55 int idx = i * vverts + j;
58 *idxarr++ = idx + vverts + 1;
61 *idxarr++ = idx + vverts + 1;
62 *idxarr++ = idx + vverts;
71 // ------ geosphere ------
74 static Vec3 icosa_pt[] = {
88 enum { P11, P12, P13, P14, P21, P22, P23, P24, P31, P32, P33, P34 };
89 static int icosa_idx[] = {
115 static void geosphere(std::vector<Vec3> *verts, const Vec3 &v1, const Vec3 &v2, const Vec3 &v3, int iter)
118 verts->push_back(v1);
119 verts->push_back(v2);
120 verts->push_back(v3);
124 Vec3 v12 = normalize(v1 + v2);
125 Vec3 v23 = normalize(v2 + v3);
126 Vec3 v31 = normalize(v3 + v1);
128 geosphere(verts, v1, v12, v31, iter - 1);
129 geosphere(verts, v2, v23, v12, iter - 1);
130 geosphere(verts, v3, v31, v23, iter - 1);
131 geosphere(verts, v12, v23, v31, iter - 1);
134 void gen_geosphere(Mesh *mesh, float rad, int subdiv, bool hemi)
136 int num_tri = (sizeof icosa_idx / sizeof *icosa_idx) / 3;
138 std::vector<Vec3> verts;
139 for(int i=0; i<num_tri; i++) {
142 for(int j=0; j<3; j++) {
143 int vidx = icosa_idx[i * 3 + j];
144 v[j] = normalize(icosa_pt[vidx]);
147 if(hemi && (v[0].y < 0.0 || v[1].y < 0.0 || v[2].y < 0.0)) {
151 geosphere(&verts, v[0], v[1], v[2], subdiv);
154 int num_verts = (int)verts.size();
157 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
158 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
159 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
160 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
162 for(int i=0; i<num_verts; i++) {
163 *varr++ = verts[i] * rad;
166 float theta = atan2(verts[i].z, verts[i].x);
167 float phi = acos(verts[i].y);
169 *tarr++ = normalize(sphvec(theta + 0.1f, (float)M_PI / 2.0f) - sphvec(theta - 0.1f, (float)M_PI / 2.0f));
171 float u = 0.5 * theta / M_PI + 0.5;
172 float v = phi / M_PI;
173 *uvarr++ = Vec2(u, v);
177 // -------- torus -----------
178 static Vec3 torusvec(float theta, float phi, float mr, float rr)
182 float rx = -cos(phi) * rr + mr;
183 float ry = sin(phi) * rr;
186 float x = rx * sin(theta) + rz * cos(theta);
188 float z = -rx * cos(theta) + rz * sin(theta);
190 return Vec3(x, y, z);
193 void gen_torus(Mesh *mesh, float mainrad, float ringrad, int usub, int vsub, float urange, float vrange)
195 if(usub < 4) usub = 4;
196 if(vsub < 2) vsub = 2;
198 int uverts = usub + 1;
199 int vverts = vsub + 1;
201 int num_verts = uverts * vverts;
202 int num_quads = usub * vsub;
203 int num_tri = num_quads * 2;
206 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
207 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
208 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
209 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
210 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
212 float du = urange / (float)(uverts - 1);
213 float dv = vrange / (float)(vverts - 1);
216 for(int i=0; i<uverts; i++) {
217 float theta = u * 2.0 * M_PI;
220 for(int j=0; j<vverts; j++) {
221 float phi = v * 2.0 * M_PI;
223 Vec3 pos = torusvec(theta, phi, mainrad, ringrad);
224 Vec3 cent = torusvec(theta, phi, mainrad, 0.0);
227 *narr++ = (pos - cent) / ringrad;
229 Vec3 pprev = torusvec(theta - 0.1f, phi, mainrad, ringrad);
230 Vec3 pnext = torusvec(theta + 0.1f, phi, mainrad, ringrad);
232 *tarr++ = normalize(pnext - pprev);
233 *uvarr++ = Vec2(u * urange, v * vrange);
235 if(i < usub && j < vsub) {
236 int idx = i * vverts + j;
239 *idxarr++ = idx + vverts + 1;
242 *idxarr++ = idx + vverts + 1;
243 *idxarr++ = idx + vverts;
253 // -------- cylinder --------
255 static Vec3 cylvec(float theta, float height)
257 return Vec3(sin(theta), height, cos(theta));
260 void gen_cylinder(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
262 if(usub < 4) usub = 4;
263 if(vsub < 1) vsub = 1;
265 int uverts = usub + 1;
266 int vverts = vsub + 1;
268 int num_body_verts = uverts * vverts;
269 int num_body_quads = usub * vsub;
270 int num_body_tri = num_body_quads * 2;
272 int capvverts = capsub ? capsub + 1 : 0;
273 int num_cap_verts = uverts * capvverts;
274 int num_cap_quads = usub * capsub;
275 int num_cap_tri = num_cap_quads * 2;
277 int num_verts = num_body_verts + num_cap_verts * 2;
278 int num_tri = num_body_tri + num_cap_tri * 2;
281 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
282 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
283 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
284 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
285 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
287 float du = urange / (float)(uverts - 1);
288 float dv = vrange / (float)(vverts - 1);
291 for(int i=0; i<uverts; i++) {
292 float theta = SURAD(u);
295 for(int j=0; j<vverts; j++) {
296 float y = (v - 0.5) * height;
297 Vec3 pos = cylvec(theta, y);
299 *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad);
300 *narr++ = Vec3(pos.x, 0.0, pos.z);
301 *tarr++ = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
302 *uvarr++ = Vec2(u * urange, v * vrange);
304 if(i < usub && j < vsub) {
305 int idx = i * vverts + j;
308 *idxarr++ = idx + vverts + 1;
312 *idxarr++ = idx + vverts;
313 *idxarr++ = idx + vverts + 1;
327 dv = 1.0 / (float)(capvverts - 1);
330 for(int i=0; i<uverts; i++) {
331 float theta = SURAD(u);
334 for(int j=0; j<capvverts; j++) {
337 Vec3 pos = cylvec(theta, height / 2.0) * r;
338 pos.y = height / 2.0;
339 Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
342 *narr++ = Vec3(0, 1, 0);
344 *uvarr++ = Vec2(u * urange, v);
346 pos.y = -height / 2.0;
348 *narr++ = Vec3(0, -1, 0);
350 *uvarr++ = Vec2(u * urange, v);
352 if(i < usub && j < capsub) {
353 unsigned int idx = num_body_verts + (i * capvverts + j) * 2;
355 unsigned int vidx[4] = {
358 idx + (capvverts + 1) * 2,
369 *idxarr++ = vidx[0] + 1;
370 *idxarr++ = vidx[1] + 1;
371 *idxarr++ = vidx[2] + 1;
372 *idxarr++ = vidx[0] + 1;
373 *idxarr++ = vidx[2] + 1;
374 *idxarr++ = vidx[3] + 1;
383 // -------- cone --------
385 static Vec3 conevec(float theta, float y, float height)
387 float scale = 1.0 - y / height;
388 return Vec3(sin(theta) * scale, y, cos(theta) * scale);
391 void gen_cone(Mesh *mesh, float rad, float height, int usub, int vsub, int capsub, float urange, float vrange)
393 if(usub < 4) usub = 4;
394 if(vsub < 1) vsub = 1;
396 int uverts = usub + 1;
397 int vverts = vsub + 1;
399 int num_body_verts = uverts * vverts;
400 int num_body_quads = usub * vsub;
401 int num_body_tri = num_body_quads * 2;
403 int capvverts = capsub ? capsub + 1 : 0;
404 int num_cap_verts = uverts * capvverts;
405 int num_cap_quads = usub * capsub;
406 int num_cap_tri = num_cap_quads * 2;
408 int num_verts = num_body_verts + num_cap_verts;
409 int num_tri = num_body_tri + num_cap_tri;
412 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
413 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
414 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
415 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
416 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
418 float du = urange / (float)(uverts - 1);
419 float dv = vrange / (float)(vverts - 1);
422 for(int i=0; i<uverts; i++) {
423 float theta = SURAD(u);
426 for(int j=0; j<vverts; j++) {
427 float y = v * height;
428 Vec3 pos = conevec(theta, y, height);
430 Vec3 tang = normalize(conevec(theta + 0.1, 0.0, height) - conevec(theta - 0.1, 0.0, height));
431 Vec3 bitang = normalize(conevec(theta, y + 0.1, height) - pos);
433 *varr++ = Vec3(pos.x * rad, pos.y, pos.z * rad);
434 *narr++ = cross(tang, bitang);
436 *uvarr++ = Vec2(u * urange, v * vrange);
438 if(i < usub && j < vsub) {
439 int idx = i * vverts + j;
442 *idxarr++ = idx + vverts + 1;
446 *idxarr++ = idx + vverts;
447 *idxarr++ = idx + vverts + 1;
456 // now the bottom cap!
461 dv = 1.0 / (float)(capvverts - 1);
464 for(int i=0; i<uverts; i++) {
465 float theta = SURAD(u);
468 for(int j=0; j<capvverts; j++) {
471 Vec3 pos = conevec(theta, 0.0, height) * r;
472 Vec3 tang = normalize(cylvec(theta + 0.1, 0.0) - cylvec(theta - 0.1, 0.0));
475 *narr++ = Vec3(0, -1, 0);
477 *uvarr++ = Vec2(u * urange, v);
479 if(i < usub && j < capsub) {
480 unsigned int idx = num_body_verts + i * capvverts + j;
482 unsigned int vidx[4] = {
485 idx + (capvverts + 1),
504 // -------- plane --------
506 void gen_plane(Mesh *mesh, float width, float height, int usub, int vsub)
508 gen_heightmap(mesh, width, height, usub, vsub, 0);
512 // ----- heightmap ------
514 void gen_heightmap(Mesh *mesh, float width, float height, int usub, int vsub, float (*hf)(float, float, void*), void *hfdata)
516 if(usub < 1) usub = 1;
517 if(vsub < 1) vsub = 1;
521 int uverts = usub + 1;
522 int vverts = vsub + 1;
523 int num_verts = uverts * vverts;
525 int num_quads = usub * vsub;
526 int num_tri = num_quads * 2;
528 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
529 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
530 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
531 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
532 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
534 float du = 1.0 / (float)usub;
535 float dv = 1.0 / (float)vsub;
538 for(int i=0; i<uverts; i++) {
540 for(int j=0; j<vverts; j++) {
541 float x = (u - 0.5) * width;
542 float y = (v - 0.5) * height;
543 float z = hf ? hf(u, v, hfdata) : 0.0;
545 Vec3 normal = Vec3(0, 0, 1);
547 float u1z = hf(u + du, v, hfdata);
548 float v1z = hf(u, v + dv, hfdata);
550 Vec3 tang = Vec3(du * width, 0, u1z - z);
551 Vec3 bitan = Vec3(0, dv * height, v1z - z);
552 normal = normalize(cross(tang, bitan));
555 *varr++ = Vec3(x, y, z);
557 *tarr++ = Vec3(1, 0, 0);
558 *uvarr++ = Vec2(u, v);
560 if(i < usub && j < vsub) {
561 int idx = i * vverts + j;
564 *idxarr++ = idx + vverts + 1;
568 *idxarr++ = idx + vverts;
569 *idxarr++ = idx + vverts + 1;
579 void gen_box(Mesh *mesh, float xsz, float ysz, float zsz, int usub, int vsub)
581 static const float face_angles[][2] = {
585 {3.0 * M_PI / 2.0, 0},
590 if(usub < 1) usub = 1;
591 if(vsub < 1) vsub = 1;
595 for(int i=0; i<6; i++) {
596 Mat4 xform, dir_xform;
599 gen_plane(&m, 1, 1, usub, vsub);
600 xform.rotate(Vec3(face_angles[i][1], face_angles[i][0], 0));
602 xform.translate(Vec3(0, 0, 0.5));
603 m.apply_xform(xform, dir_xform);
609 scale.scaling(xsz, ysz, zsz);
610 mesh->apply_xform(scale, Mat4::identity);
614 void gen_box(Mesh *mesh, float xsz, float ysz, float zsz)
618 const int num_faces = 6;
619 int num_verts = num_faces * 4;
620 int num_tri = num_faces * 2;
626 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
627 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
628 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
629 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
630 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
632 static const Vec2 uv[] = { Vec2(0, 0), Vec2(1, 0), Vec2(1, 1), Vec2(0, 1) };
635 for(int i=0; i<4; i++) {
636 *narr++ = Vec3(0, 0, 1);
637 *tarr++ = Vec3(1, 0, 0);
640 *varr++ = Vec3(-x, -y, z);
641 *varr++ = Vec3(x, -y, z);
642 *varr++ = Vec3(x, y, z);
643 *varr++ = Vec3(-x, y, z);
645 for(int i=0; i<4; i++) {
646 *narr++ = Vec3(1, 0, 0);
647 *tarr++ = Vec3(0, 0, -1);
650 *varr++ = Vec3(x, -y, z);
651 *varr++ = Vec3(x, -y, -z);
652 *varr++ = Vec3(x, y, -z);
653 *varr++ = Vec3(x, y, z);
655 for(int i=0; i<4; i++) {
656 *narr++ = Vec3(0, 0, -1);
657 *tarr++ = Vec3(-1, 0, 0);
660 *varr++ = Vec3(x, -y, -z);
661 *varr++ = Vec3(-x, -y, -z);
662 *varr++ = Vec3(-x, y, -z);
663 *varr++ = Vec3(x, y, -z);
665 for(int i=0; i<4; i++) {
666 *narr++ = Vec3(-1, 0, 0);
667 *tarr++ = Vec3(0, 0, 1);
670 *varr++ = Vec3(-x, -y, -z);
671 *varr++ = Vec3(-x, -y, z);
672 *varr++ = Vec3(-x, y, z);
673 *varr++ = Vec3(-x, y, -z);
675 for(int i=0; i<4; i++) {
676 *narr++ = Vec3(0, 1, 0);
677 *tarr++ = Vec3(1, 0, 0);
680 *varr++ = Vec3(-x, y, z);
681 *varr++ = Vec3(x, y, z);
682 *varr++ = Vec3(x, y, -z);
683 *varr++ = Vec3(-x, y, -z);
685 for(int i=0; i<4; i++) {
686 *narr++ = Vec3(0, -1, 0);
687 *tarr++ = Vec3(1, 0, 0);
690 *varr++ = Vec3(-x, -y, -z);
691 *varr++ = Vec3(x, -y, -z);
692 *varr++ = Vec3(x, -y, z);
693 *varr++ = Vec3(-x, -y, z);
696 static const int faceidx[] = {0, 1, 2, 0, 2, 3};
697 for(int i=0; i<num_faces; i++) {
698 for(int j=0; j<6; j++) {
699 *idxarr++ = faceidx[j] + i * 4;
705 static inline Vec3 rev_vert(float u, float v, Vec2 (*rf)(float, float, void*), void *cls)
707 Vec2 pos = rf(u, v, cls);
709 float angle = u * 2.0 * M_PI;
710 float x = pos.x * cos(angle);
712 float z = pos.x * sin(angle);
714 return Vec3(x, y, z);
717 // ------ surface of revolution -------
718 void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*), void *cls)
720 gen_revol(mesh, usub, vsub, rfunc, 0, cls);
723 void gen_revol(Mesh *mesh, int usub, int vsub, Vec2 (*rfunc)(float, float, void*),
724 Vec2 (*nfunc)(float, float, void*), void *cls)
727 if(usub < 3) usub = 3;
728 if(vsub < 1) vsub = 1;
732 int uverts = usub + 1;
733 int vverts = vsub + 1;
734 int num_verts = uverts * vverts;
736 int num_quads = usub * vsub;
737 int num_tri = num_quads * 2;
739 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
740 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
741 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
742 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
743 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
745 float du = 1.0 / (float)(uverts - 1);
746 float dv = 1.0 / (float)(vverts - 1);
749 for(int i=0; i<uverts; i++) {
751 for(int j=0; j<vverts; j++) {
752 Vec3 pos = rev_vert(u, v, rfunc, cls);
754 Vec3 nextu = rev_vert(fmod(u + du, 1.0), v, rfunc, cls);
755 Vec3 tang = nextu - pos;
756 if(length_sq(tang) < 1e-6) {
757 float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
758 nextu = rev_vert(fmod(u + du, 1.0), new_v, rfunc, cls);
764 normal = rev_vert(u, v, nfunc, cls);
766 Vec3 nextv = rev_vert(u, v + dv, rfunc, cls);
767 Vec3 bitan = nextv - pos;
768 if(length_sq(bitan) < 1e-6) {
769 nextv = rev_vert(u, v - dv, rfunc, cls);
773 normal = cross(tang, bitan);
777 *narr++ = normalize(normal);
778 *tarr++ = normalize(tang);
779 *uvarr++ = Vec2(u, v);
781 if(i < usub && j < vsub) {
782 int idx = i * vverts + j;
785 *idxarr++ = idx + vverts + 1;
789 *idxarr++ = idx + vverts;
790 *idxarr++ = idx + vverts + 1;
800 static inline Vec3 sweep_vert(float u, float v, float height, Vec2 (*sf)(float, float, void*), void *cls)
802 Vec2 pos = sf(u, v, cls);
805 float y = v * height;
808 return Vec3(x, y, z);
811 // ---- sweep shape along a path ----
812 void gen_sweep(Mesh *mesh, float height, int usub, int vsub, Vec2 (*sfunc)(float, float, void*), void *cls)
815 if(usub < 3) usub = 3;
816 if(vsub < 1) vsub = 1;
820 int uverts = usub + 1;
821 int vverts = vsub + 1;
822 int num_verts = uverts * vverts;
824 int num_quads = usub * vsub;
825 int num_tri = num_quads * 2;
827 Vec3 *varr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_VERTEX, 3, num_verts, 0);
828 Vec3 *narr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_NORMAL, 3, num_verts, 0);
829 Vec3 *tarr = (Vec3*)mesh->set_attrib_data(MESH_ATTR_TANGENT, 3, num_verts, 0);
830 Vec2 *uvarr = (Vec2*)mesh->set_attrib_data(MESH_ATTR_TEXCOORD, 2, num_verts, 0);
831 unsigned int *idxarr = mesh->set_index_data(num_tri * 3, 0);
833 float du = 1.0 / (float)(uverts - 1);
834 float dv = 1.0 / (float)(vverts - 1);
837 for(int i=0; i<uverts; i++) {
839 for(int j=0; j<vverts; j++) {
840 Vec3 pos = sweep_vert(u, v, height, sfunc, cls);
842 Vec3 nextu = sweep_vert(fmod(u + du, 1.0), v, height, sfunc, cls);
843 Vec3 tang = nextu - pos;
844 if(length_sq(tang) < 1e-6) {
845 float new_v = v > 0.5 ? v - dv * 0.25 : v + dv * 0.25;
846 nextu = sweep_vert(fmod(u + du, 1.0), new_v, height, sfunc, cls);
851 Vec3 nextv = sweep_vert(u, v + dv, height, sfunc, cls);
852 Vec3 bitan = nextv - pos;
853 if(length_sq(bitan) < 1e-6) {
854 nextv = sweep_vert(u, v - dv, height, sfunc, cls);
858 normal = cross(tang, bitan);
861 *narr++ = normalize(normal);
862 *tarr++ = normalize(tang);
863 *uvarr++ = Vec2(u, v);
865 if(i < usub && j < vsub) {
866 int idx = i * vverts + j;
869 *idxarr++ = idx + vverts + 1;
873 *idxarr++ = idx + vverts;
874 *idxarr++ = idx + vverts + 1;