Skip to content

Commit 522d058

Browse files
committed
[CORE] added mvx_convert_voxels_to_mesh function
1 parent 3ac1cc6 commit 522d058

2 files changed

Lines changed: 278 additions & 1 deletion

File tree

mvx.h

Lines changed: 215 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -300,7 +300,7 @@ MVX_API MVX_INLINE int mvx_triangle_box_overlap(
300300
float pmax = mvx_maxf(mvx_maxf(p0, p1), p2);
301301
float pmin = mvx_minf(mvx_minf(p0, p1), p2);
302302
float rad = boxhalf.y * f.z + boxhalf.z * f.y + SLOP;
303-
303+
304304
if (pmax < -rad || pmin > rad)
305305
{
306306
return 0;
@@ -575,6 +575,220 @@ MVX_API MVX_INLINE int mvx_voxelize_mesh(
575575
return 1;
576576
}
577577

578+
/* Get voxel value with boundary checks. */
579+
#define MVX_GET_VOXEL(voxels, x, y, z, gx, gy, gz) \
580+
(((x) >= 0 && (x) < (gx) && \
581+
(y) >= 0 && (y) < (gy) && \
582+
(z) >= 0 && (z) < (gz)) \
583+
? (voxels)[(x) + (y) * (gx) + (z) * (gx) * (gy)] \
584+
: 0)
585+
586+
MVX_API MVX_INLINE int mvx_convert_voxels_to_mesh(
587+
unsigned char *voxels,
588+
int grid_x,
589+
int grid_y,
590+
int grid_z,
591+
float voxel_size,
592+
float *out_vertices,
593+
unsigned long out_vertices_cap,
594+
unsigned long *out_vert_count,
595+
int *out_indices,
596+
unsigned long out_indices_cap,
597+
unsigned long *out_index_count)
598+
{
599+
long x, y, z;
600+
unsigned long current_vert_idx = 0;
601+
unsigned long current_index_idx = 0;
602+
float half_voxel_size = voxel_size * 0.5f;
603+
604+
/* A set of 4 vertices for each of the 6 faces.
605+
* The order of vertices is chosen to provide consistent winding. */
606+
float mvx_face_vertices[6][4][3] = {
607+
/* +Z face */
608+
{{-1.0f, -1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}, {1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}},
609+
/* -Z face */
610+
{{-1.0f, -1.0f, -1.0f}, {-1.0f, 1.0f, -1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}},
611+
/* +Y face */
612+
{{-1.0f, 1.0f, -1.0f}, {-1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, 1.0f, -1.0f}},
613+
/* -Y face */
614+
{{-1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, -1.0f}, {1.0f, -1.0f, 1.0f}, {-1.0f, -1.0f, 1.0f}},
615+
/* +X face */
616+
{{1.0f, -1.0f, -1.0f}, {1.0f, 1.0f, -1.0f}, {1.0f, 1.0f, 1.0f}, {1.0f, -1.0f, 1.0f}},
617+
/* -X face */
618+
{{-1.0f, -1.0f, -1.0f}, {-1.0f, -1.0f, 1.0f}, {-1.0f, 1.0f, 1.0f}, {-1.0f, 1.0f, -1.0f}}};
619+
620+
/* Indices for a quad (two triangles) from 4 vertices. */
621+
int mvx_face_indices[6] = {0, 1, 2, 0, 2, 3};
622+
623+
/* Check for invalid input pointers. */
624+
if (!voxels || !out_vertices || !out_indices || !out_vert_count || !out_index_count)
625+
{
626+
return 0;
627+
}
628+
629+
*out_vert_count = 0;
630+
*out_index_count = 0;
631+
632+
for (z = 0; z < grid_z; ++z)
633+
{
634+
for (y = 0; y < grid_y; ++y)
635+
{
636+
for (x = 0; x < grid_x; ++x)
637+
{
638+
long id = x + y * grid_x + z * grid_x * grid_y;
639+
640+
if (voxels[id] == 1)
641+
{
642+
/* Check for an empty neighbor in each direction. */
643+
644+
/* +X neighbor */
645+
if (MVX_GET_VOXEL(voxels, x + 1, y, z, grid_x, grid_y, grid_z) == 0)
646+
{
647+
int i;
648+
649+
if (current_vert_idx + 12 > out_vertices_cap || current_index_idx + 6 > out_indices_cap)
650+
{
651+
return 0;
652+
}
653+
654+
for (i = 0; i < 4; ++i)
655+
{
656+
out_vertices[current_vert_idx++] = (float)x * voxel_size + half_voxel_size + mvx_face_vertices[4][i][0] * half_voxel_size;
657+
out_vertices[current_vert_idx++] = (float)y * voxel_size + half_voxel_size + mvx_face_vertices[4][i][1] * half_voxel_size;
658+
out_vertices[current_vert_idx++] = (float)z * voxel_size + half_voxel_size + mvx_face_vertices[4][i][2] * half_voxel_size;
659+
}
660+
661+
for (i = 0; i < 6; ++i)
662+
{
663+
out_indices[current_index_idx++] = (int)((current_vert_idx / 3) - 4) + mvx_face_indices[i];
664+
}
665+
}
666+
667+
/* -X neighbor */
668+
if (MVX_GET_VOXEL(voxels, x - 1, y, z, grid_x, grid_y, grid_z) == 0)
669+
{
670+
int i;
671+
672+
if (current_vert_idx + 12 > out_vertices_cap || current_index_idx + 6 > out_indices_cap)
673+
{
674+
return 0;
675+
}
676+
677+
for (i = 0; i < 4; ++i)
678+
{
679+
out_vertices[current_vert_idx++] = (float)x * voxel_size + half_voxel_size + mvx_face_vertices[5][i][0] * half_voxel_size;
680+
out_vertices[current_vert_idx++] = (float)y * voxel_size + half_voxel_size + mvx_face_vertices[5][i][1] * half_voxel_size;
681+
out_vertices[current_vert_idx++] = (float)z * voxel_size + half_voxel_size + mvx_face_vertices[5][i][2] * half_voxel_size;
682+
}
683+
684+
for (i = 0; i < 6; ++i)
685+
{
686+
out_indices[current_index_idx++] = (int)((current_vert_idx / 3) - 4) + mvx_face_indices[i];
687+
}
688+
}
689+
690+
/* +Y neighbor */
691+
if (MVX_GET_VOXEL(voxels, x, y + 1, z, grid_x, grid_y, grid_z) == 0)
692+
{
693+
int i;
694+
695+
if (current_vert_idx + 12 > out_vertices_cap || current_index_idx + 6 > out_indices_cap)
696+
{
697+
return 0;
698+
}
699+
700+
for (i = 0; i < 4; ++i)
701+
{
702+
out_vertices[current_vert_idx++] = (float)x * voxel_size + half_voxel_size + mvx_face_vertices[2][i][0] * half_voxel_size;
703+
out_vertices[current_vert_idx++] = (float)y * voxel_size + half_voxel_size + mvx_face_vertices[2][i][1] * half_voxel_size;
704+
out_vertices[current_vert_idx++] = (float)z * voxel_size + half_voxel_size + mvx_face_vertices[2][i][2] * half_voxel_size;
705+
}
706+
707+
for (i = 0; i < 6; ++i)
708+
{
709+
out_indices[current_index_idx++] = (int)((current_vert_idx / 3) - 4) + mvx_face_indices[i];
710+
}
711+
}
712+
713+
/* -Y neighbor */
714+
if (MVX_GET_VOXEL(voxels, x, y - 1, z, grid_x, grid_y, grid_z) == 0)
715+
{
716+
int i;
717+
718+
if (current_vert_idx + 12 > out_vertices_cap || current_index_idx + 6 > out_indices_cap)
719+
{
720+
return 0;
721+
}
722+
723+
for (i = 0; i < 4; ++i)
724+
{
725+
out_vertices[current_vert_idx++] = (float)x * voxel_size + half_voxel_size + mvx_face_vertices[3][i][0] * half_voxel_size;
726+
out_vertices[current_vert_idx++] = (float)y * voxel_size + half_voxel_size + mvx_face_vertices[3][i][1] * half_voxel_size;
727+
out_vertices[current_vert_idx++] = (float)z * voxel_size + half_voxel_size + mvx_face_vertices[3][i][2] * half_voxel_size;
728+
}
729+
730+
for (i = 0; i < 6; ++i)
731+
{
732+
out_indices[current_index_idx++] = (int)((current_vert_idx / 3) - 4) + mvx_face_indices[i];
733+
}
734+
}
735+
736+
/* +Z neighbor */
737+
if (MVX_GET_VOXEL(voxels, x, y, z + 1, grid_x, grid_y, grid_z) == 0)
738+
{
739+
int i;
740+
741+
if (current_vert_idx + 12 > out_vertices_cap || current_index_idx + 6 > out_indices_cap)
742+
{
743+
return 0;
744+
}
745+
746+
for (i = 0; i < 4; ++i)
747+
{
748+
out_vertices[current_vert_idx++] = (float)x * voxel_size + half_voxel_size + mvx_face_vertices[0][i][0] * half_voxel_size;
749+
out_vertices[current_vert_idx++] = (float)y * voxel_size + half_voxel_size + mvx_face_vertices[0][i][1] * half_voxel_size;
750+
out_vertices[current_vert_idx++] = (float)z * voxel_size + half_voxel_size + mvx_face_vertices[0][i][2] * half_voxel_size;
751+
}
752+
753+
for (i = 0; i < 6; ++i)
754+
{
755+
out_indices[current_index_idx++] = (int)((current_vert_idx / 3) - 4) + mvx_face_indices[i];
756+
}
757+
}
758+
759+
/* -Z neighbor */
760+
if (MVX_GET_VOXEL(voxels, x, y, z - 1, grid_x, grid_y, grid_z) == 0)
761+
{
762+
int i;
763+
764+
if (current_vert_idx + 12 > out_vertices_cap || current_index_idx + 6 > out_indices_cap)
765+
{
766+
return 0;
767+
}
768+
769+
for (i = 0; i < 4; ++i)
770+
{
771+
out_vertices[current_vert_idx++] = (float)x * voxel_size + half_voxel_size + mvx_face_vertices[1][i][0] * half_voxel_size;
772+
out_vertices[current_vert_idx++] = (float)y * voxel_size + half_voxel_size + mvx_face_vertices[1][i][1] * half_voxel_size;
773+
out_vertices[current_vert_idx++] = (float)z * voxel_size + half_voxel_size + mvx_face_vertices[1][i][2] * half_voxel_size;
774+
}
775+
776+
for (i = 0; i < 6; ++i)
777+
{
778+
out_indices[current_index_idx++] = (int)((current_vert_idx / 3) - 4) + mvx_face_indices[i];
779+
}
780+
}
781+
}
782+
}
783+
}
784+
}
785+
786+
*out_vert_count = current_vert_idx;
787+
*out_index_count = current_index_idx;
788+
789+
return 1;
790+
}
791+
578792
#endif /* MVX_H */
579793

580794
/*

tests/mvx_test.c

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,74 @@ void mvx_test_voxelize_pyramid(void)
225225
mvx_test_print_voxels(voxels, py_grid_x, py_grid_y, py_grid_z);
226226
}
227227

228+
void mvx_test_convert_voxels_to_mesh(void)
229+
{
230+
/* Example: A unit cube mesh */
231+
float vertices[] = {
232+
0.0f, 0.0f, 0.0f,
233+
1.0f, 0.0f, 0.0f,
234+
1.0f, 1.0f, 0.0f,
235+
0.0f, 1.0f, 0.0f,
236+
0.0f, 0.0f, 1.0f,
237+
1.0f, 0.0f, 1.0f,
238+
1.0f, 1.0f, 1.0f,
239+
0.0f, 1.0f, 1.0f};
240+
241+
unsigned long vertices_size = sizeof(vertices) / sizeof(vertices[0]);
242+
243+
/* Example: A unit cube mesh indices (two per face) */
244+
int indices[] = {
245+
0, 1, 2, 0, 2, 3, /* bottom */
246+
4, 5, 6, 4, 6, 7, /* top */
247+
0, 1, 5, 0, 5, 4, /* front */
248+
1, 2, 6, 1, 6, 5, /* right */
249+
2, 3, 7, 2, 7, 6, /* back */
250+
3, 0, 4, 3, 4, 7 /* left */
251+
};
252+
253+
unsigned long indices_size = sizeof(indices) / sizeof(indices[0]);
254+
255+
/* Define a grid size where the voxelized mesh should fit into */
256+
#define grid_x 10
257+
#define grid_y 5
258+
#define grid_z 5
259+
unsigned char voxels[grid_x * grid_y * grid_z];
260+
261+
#define vertices_capacity 30000UL
262+
#define indices_capacity 30000UL
263+
float vox_vertices[vertices_capacity];
264+
int vox_indices[indices_capacity];
265+
unsigned long vox_vertices_size = 0;
266+
unsigned long vox_indices_size = 0;
267+
268+
/* Voxelize the mesh with 1 cell padding */
269+
mvx_voxelize_mesh(
270+
vertices, vertices_size, /* Mesh Vertices */
271+
indices, indices_size, /* Mesh Indices */
272+
grid_x, grid_y, grid_z, /* Grid Size */
273+
1, 1, 1, /* Grid Cell Padding */
274+
voxels /* Output Voxels */
275+
);
276+
277+
mvx_convert_voxels_to_mesh(voxels, grid_x, grid_y, grid_z, 1.0f, vox_vertices, vertices_capacity, &vox_vertices_size, vox_indices, indices_capacity, &vox_indices_size);
278+
279+
printf("vertices: %10lu\n", vox_vertices_size);
280+
printf(" indices: %10lu\n", vox_indices_size);
281+
282+
printf("vertex: %10.6f\n", (double)vox_vertices[0]);
283+
printf("vertex: %10.6f\n", (double)vox_vertices[1]);
284+
printf("vertex: %10.6f\n", (double)vox_vertices[2]);
285+
printf("vertex: %10.6f\n", (double)vox_vertices[4]);
286+
printf("vertex: %10.6f\n", (double)vox_vertices[5]);
287+
printf("vertex: %10.6f\n", (double)vox_vertices[6]);
288+
}
289+
228290
int main(void)
229291
{
230292
mvx_test_voxelize_cube();
231293
mvx_test_voxelize_icosphere();
232294
mvx_test_voxelize_pyramid();
295+
mvx_test_convert_voxels_to_mesh();
233296

234297
return 0;
235298
}

0 commit comments

Comments
 (0)