Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat request / question : exporting optimized meshes with no redundant vertices (possible workaround via Blender) #387

Open
sleeptightAnsiC opened this issue Aug 8, 2024 · 4 comments

Comments

@sleeptightAnsiC
Copy link

sleeptightAnsiC commented Aug 8, 2024

Hey yet again,

Right away, I'm just gonna say this is most likely a dupe of #315
I opened a new ticket as the other one is pretty lengthy already and mine will be too.

I'm looking for a way to export meshes that are "kinda production-ready", with as little amount of vertices as possible and with colors included. As I understand the problem with colors is well known (e.g. #203) and solvable depending on the format of exported file. The problem with vertices is a bit bigger though.

There are two issues with vertices (mostly tested with .gltf and .obj):

  1. Duplicate vertices at the edge of each voxel - because of this voxels aren't connected
  2. Despite that voxels create a simple 2D plane in most places, there are still redundant vertices on them (mesh is simply not optimized)
2024-08-08_18-27-52.mp4

So, I solved both those issues via Blender.
Pasting instructions here in case someone has a similar problem:

  1. Edit Mode > select whole mesh [A] > RMB at mesh > Merge Vertices > By Distance - https://docs.blender.org/manual/en/latest/modeling/meshes/editing/mesh/merge.html
  2. Object Mode > Modifiers > Add Modifier > Generate > Decimate > Planar > Apply - https://docs.blender.org/manual/en/latest/modeling/modifiers/generate/decimate.html
2024-08-08_18-57-23.mp4

However, my solution isn't perfect. I already noticed that depending on which step is applied as the first one, this can either mess the colors (as seen on video above) or leave the vertices inside of geometry. I'm still looking for something better and will try to automate it at some point.

Is there a way to export meshes without those problems?
Is there any better workaround to the one I use?

Thanks

@sleeptightAnsiC sleeptightAnsiC changed the title feat request: exporting optimized meshes with as little vertices as possible (with Blender workaround feat request / question : exporting optimized meshes with no redundant vertices (possible workaround via Blender) Aug 8, 2024
@guillaumechereau
Copy link
Owner

Thanks for the detailed explanation.

Currently goxel uses meshoptimzer [1] to simplify the meshes before glTF export. Maybe there are better alternatives? Or the options I used are not optimal. I am not too sure about that.

[1] https://github.com/zeux/meshoptimizer

@sleeptightAnsiC
Copy link
Author

sleeptightAnsiC commented Aug 13, 2024

NOTEs

the code making it happen is here

static void optimize_mesh(volume_mesh_t *mesh, float simplify)
{
unsigned int *remap;
unsigned int *tmp_indices;
typeof(*mesh->vertices) *tmp_vertices;
size_t vertices_count;
size_t indices_count;
int target_index_count;
float target_error = 1e-2f;
// Merge duplicated vertices.
remap = calloc(mesh->vertices_count, sizeof(unsigned int));
vertices_count = meshopt_generateVertexRemap(
remap, mesh->indices, mesh->indices_count, mesh->vertices,
mesh->vertices_count, sizeof(*mesh->vertices));
tmp_indices = malloc(mesh->indices_count * sizeof(*tmp_indices));
meshopt_remapIndexBuffer(
tmp_indices, mesh->indices, mesh->indices_count, remap);
tmp_vertices = malloc(vertices_count * sizeof(*mesh->vertices));
meshopt_remapVertexBuffer(
tmp_vertices, mesh->vertices, mesh->vertices_count,
sizeof(*mesh->vertices), remap);
free(remap);
SWAP(mesh->vertices, tmp_vertices);
SWAP(mesh->indices, tmp_indices);
mesh->vertices_count = vertices_count;
// Also simplify the mesh if required.
target_index_count = (int)(mesh->indices_count * (1 - simplify));
target_index_count = fmax(target_index_count, 1);
if (target_index_count < mesh->indices_count) {
indices_count = meshopt_simplify(
tmp_indices, mesh->indices, mesh->indices_count,
(const float*)mesh->vertices, mesh->vertices_count,
sizeof(*mesh->vertices), target_index_count, target_error,
0, NULL);
vertices_count = meshopt_optimizeVertexFetch(
tmp_vertices, tmp_indices, indices_count,
mesh->vertices, mesh->vertices_count, sizeof(*mesh->vertices));
SWAP(mesh->vertices, tmp_vertices);
SWAP(mesh->indices, tmp_indices);
mesh->vertices_count = vertices_count;
mesh->indices_count = indices_count;
}
free(tmp_vertices);
free(tmp_indices);
}

it uses this struct

goxel/src/volume_utils.h

Lines 74 to 92 in 292588c

typedef struct volume_mesh
{
int vertices_count;
struct {
float pos[3];
float normal[3];
// Note: we lose some space here.
union {
float color[4];
float texcoord[2];
};
} *vertices;
int indices_count;
unsigned int *indices;
float pos_min[3];
float pos_max[3];
} volume_mesh_t;

and is being called from there

volume_mesh_t *volume_generate_mesh(
const volume_t *volume, int effects, const palette_t *palette,
float simplify)
{
volume_iterator_t iter;
int bpos[3];
voxel_vertex_t *verts;
int i, nb, size, subdivide;
volume_mesh_t *mesh = calloc(1, sizeof(*mesh));
verts = calloc(N * N * N * 6 * 4, sizeof(*verts));
iter = volume_get_iterator(volume,
VOLUME_ITER_TILES | VOLUME_ITER_INCLUDES_NEIGHBORS);
while (volume_iter(&iter, bpos)) {
nb = volume_generate_vertices(volume, bpos, effects, verts,
&size, &subdivide);
if (nb == 0) continue;
fill_mesh(mesh, verts, nb, size, subdivide, bpos, palette);
}
free(verts);
optimize_mesh(mesh, simplify);
mesh->pos_min[0] = +FLT_MAX;
mesh->pos_min[1] = +FLT_MAX;
mesh->pos_min[2] = +FLT_MAX;
mesh->pos_max[0] = -FLT_MAX;
mesh->pos_max[1] = -FLT_MAX;
mesh->pos_max[2] = -FLT_MAX;
for (i = 0; i < mesh->vertices_count; i++) {
mesh->pos_min[0] = min(mesh->vertices[i].pos[0], mesh->pos_min[0]);
mesh->pos_min[1] = min(mesh->vertices[i].pos[1], mesh->pos_min[1]);
mesh->pos_min[2] = min(mesh->vertices[i].pos[2], mesh->pos_min[2]);
mesh->pos_max[0] = max(mesh->vertices[i].pos[0], mesh->pos_max[0]);
mesh->pos_max[1] = max(mesh->vertices[i].pos[1], mesh->pos_max[1]);
mesh->pos_max[2] = max(mesh->vertices[i].pos[2], mesh->pos_max[2]);
}
return mesh;
}

@guillaumechereau a question:
Is meshoptimizer being used or will be used in any other file than volume_to_vertices.c ?

I have a feeling it might be easier to just implement the algorithm from scratch, instead of messing with the general purpose library. I may give it a try.

@420noscope-exe
Copy link

420noscope-exe commented Aug 18, 2024

I'm having a problem with this too. Im trying to bring this rather large model into unity.

2024-08-18.14-20-43.mp4

It has way to many verticies.

I tried goxel's simplifiy gltf feature to 1.0. It doesn't simplifiy as much as blender's decimate option, and it turns smaller voxel features into triangles. I think this is the issue from #315 that wasn't reproducing.

Goxel gltf simplify:
image
image

Blender Decimate (No simplifiy on export):
image
image
image

However, my solution isn't perfect. I already noticed that depending on which step is applied as the first one, this can either mess the colors (as seen on video above) or leave the vertices inside of geometry.

Yes, Blender seems to "decimate" the colors too lol. Jokes aside, thank you these videos are helpful, it gives me a starting point

@420noscope-exe
Copy link

420noscope-exe commented Aug 18, 2024

So, I solved both those issues via Blender. Pasting instructions here in case someone has a similar problem:

  1. Edit Mode > select whole mesh [A] > RMB at mesh > Merge Vertices > By Distance - https://docs.blender.org/manual/en/latest/modeling/meshes/editing/mesh/merge.html
  2. Object Mode > Modifiers > Add Modifier > Generate > Decimate > Planar > Apply - https://docs.blender.org/manual/en/latest/modeling/modifiers/generate/decimate.html

I've figured it out! You were right on track! You actually need to select Delimit UVs!

  1. Edit Mode > select whole mesh [A] > RMB at mesh > Merge Vertices > By Distance - https://docs.blender.org/manual/en/latest/modeling/meshes/editing/mesh/merge.html
  2. Object Mode > Modifiers > Add Modifier > Generate > Decimate > Planar > Delimit UVs > Apply - https://docs.blender.org/manual/en/latest/modeling/modifiers/generate/decimate.html
2024-08-18.15-22-41.mp4

I don't know if I can be of any help in regards to re writing the algo. But it seems that it needs to focus on grouping voxels of like colors on surfaces and taking those into account before simplifying vertices. Maybe some code from the magic wand tool with the color option can be re-used?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants