Export toolpaths to obj -> Reduced size of output

This commit is contained in:
Enrico Turri 2019-08-27 16:05:38 +02:00
parent 80490550b5
commit 97473439cf

View file

@ -906,13 +906,14 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
return; return;
// collect color information to generate materials // collect color information to generate materials
std::set<std::array<float, 4>> colors; typedef std::array<float, 4> Color;
std::set<Color> colors;
for (const GLVolume* volume : this->volumes) for (const GLVolume* volume : this->volumes)
{ {
if (!can_export_to_obj(*volume)) if (!can_export_to_obj(*volume))
continue; continue;
std::array<float, 4> color; Color color;
::memcpy((void*)color.data(), (const void*)volume->color, 4 * sizeof(float)); ::memcpy((void*)color.data(), (const void*)volume->color, 4 * sizeof(float));
colors.insert(color); colors.insert(color);
} }
@ -930,7 +931,7 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
fprintf(fp, "# Generated by %s based on Slic3r\n", SLIC3R_BUILD_ID); fprintf(fp, "# Generated by %s based on Slic3r\n", SLIC3R_BUILD_ID);
unsigned int colors_count = 1; unsigned int colors_count = 1;
for (const std::array<float, 4>& color : colors) for (const Color& color : colors)
{ {
fprintf(fp, "\nnewmtl material_%d\n", colors_count++); fprintf(fp, "\nnewmtl material_%d\n", colors_count++);
fprintf(fp, "Ka 1 1 1\n"); fprintf(fp, "Ka 1 1 1\n");
@ -952,6 +953,7 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
fprintf(fp, "\nmtllib ./%s\n", mat_filename.filename().string().c_str()); fprintf(fp, "\nmtllib ./%s\n", mat_filename.filename().string().c_str());
unsigned int vertices_count = 0; unsigned int vertices_count = 0;
unsigned int normals_count = 0;
unsigned int volumes_count = 0; unsigned int volumes_count = 0;
for (const GLVolume* volume : this->volumes) for (const GLVolume* volume : this->volumes)
@ -959,20 +961,20 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
if (!can_export_to_obj(*volume)) if (!can_export_to_obj(*volume))
continue; continue;
std::vector<float> vertices_and_normals_interleaved; std::vector<float> src_vertices_and_normals_interleaved;
std::vector<int> triangle_indices; std::vector<int> src_triangle_indices;
std::vector<int> quad_indices; std::vector<int> src_quad_indices;
if (!volume->indexed_vertex_array.vertices_and_normals_interleaved.empty()) if (!volume->indexed_vertex_array.vertices_and_normals_interleaved.empty())
// data are in CPU memory // data are in CPU memory
vertices_and_normals_interleaved = volume->indexed_vertex_array.vertices_and_normals_interleaved; src_vertices_and_normals_interleaved = volume->indexed_vertex_array.vertices_and_normals_interleaved;
else if ((volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id != 0) && (volume->indexed_vertex_array.vertices_and_normals_interleaved_size != 0)) else if ((volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id != 0) && (volume->indexed_vertex_array.vertices_and_normals_interleaved_size != 0))
{ {
// data are in GPU memory // data are in GPU memory
vertices_and_normals_interleaved = std::vector<float>(volume->indexed_vertex_array.vertices_and_normals_interleaved_size, 0.0f); src_vertices_and_normals_interleaved = std::vector<float>(volume->indexed_vertex_array.vertices_and_normals_interleaved_size, 0.0f);
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, volume->indexed_vertex_array.vertices_and_normals_interleaved_VBO_id));
glsafe(::glGetBufferSubData(GL_ARRAY_BUFFER, 0, vertices_and_normals_interleaved.size() * sizeof(float), vertices_and_normals_interleaved.data())); glsafe(::glGetBufferSubData(GL_ARRAY_BUFFER, 0, src_vertices_and_normals_interleaved.size() * sizeof(float), src_vertices_and_normals_interleaved.data()));
glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ARRAY_BUFFER, 0));
} }
else else
@ -986,7 +988,7 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
{ {
std::vector<int>::const_iterator it_begin = volume->indexed_vertex_array.triangle_indices.begin() + volume->tverts_range.first; std::vector<int>::const_iterator it_begin = volume->indexed_vertex_array.triangle_indices.begin() + volume->tverts_range.first;
std::vector<int>::const_iterator it_end = volume->indexed_vertex_array.triangle_indices.begin() + volume->tverts_range.first + size; std::vector<int>::const_iterator it_end = volume->indexed_vertex_array.triangle_indices.begin() + volume->tverts_range.first + size;
std::copy(it_begin, it_end, std::back_inserter(triangle_indices)); std::copy(it_begin, it_end, std::back_inserter(src_triangle_indices));
} }
} }
else if ((volume->indexed_vertex_array.triangle_indices_VBO_id != 0) && (volume->indexed_vertex_array.triangle_indices_size != 0)) else if ((volume->indexed_vertex_array.triangle_indices_VBO_id != 0) && (volume->indexed_vertex_array.triangle_indices_size != 0))
@ -995,10 +997,10 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
size_t size = std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first); size_t size = std::min(volume->indexed_vertex_array.triangle_indices_size, volume->tverts_range.second - volume->tverts_range.first);
if (size != 0) if (size != 0)
{ {
triangle_indices = std::vector<int>(size, 0); src_triangle_indices = std::vector<int>(size, 0);
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.triangle_indices_VBO_id)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.triangle_indices_VBO_id));
glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, volume->tverts_range.first * sizeof(int), size * sizeof(int), triangle_indices.data())); glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, volume->tverts_range.first * sizeof(int), size * sizeof(int), src_triangle_indices.data()));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
} }
} }
@ -1011,7 +1013,7 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
{ {
std::vector<int>::const_iterator it_begin = volume->indexed_vertex_array.quad_indices.begin() + volume->qverts_range.first; std::vector<int>::const_iterator it_begin = volume->indexed_vertex_array.quad_indices.begin() + volume->qverts_range.first;
std::vector<int>::const_iterator it_end = volume->indexed_vertex_array.quad_indices.begin() + volume->qverts_range.first + size; std::vector<int>::const_iterator it_end = volume->indexed_vertex_array.quad_indices.begin() + volume->qverts_range.first + size;
std::copy(it_begin, it_end, std::back_inserter(quad_indices)); std::copy(it_begin, it_end, std::back_inserter(src_quad_indices));
} }
} }
else if ((volume->indexed_vertex_array.quad_indices_VBO_id != 0) && (volume->indexed_vertex_array.quad_indices_size != 0)) else if ((volume->indexed_vertex_array.quad_indices_VBO_id != 0) && (volume->indexed_vertex_array.quad_indices_size != 0))
@ -1020,56 +1022,158 @@ void GLVolumeCollection::export_toolpaths_to_obj(const char* filename) const
size_t size = std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first); size_t size = std::min(volume->indexed_vertex_array.quad_indices_size, volume->qverts_range.second - volume->qverts_range.first);
if (size != 0) if (size != 0)
{ {
quad_indices = std::vector<int>(size, 0); src_quad_indices = std::vector<int>(size, 0);
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.quad_indices_VBO_id)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, volume->indexed_vertex_array.quad_indices_VBO_id));
glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, volume->qverts_range.first * sizeof(int), size * sizeof(int), quad_indices.data())); glsafe(::glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, volume->qverts_range.first * sizeof(int), size * sizeof(int), src_quad_indices.data()));
glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0)); glsafe(::glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
} }
} }
if (triangle_indices.empty() && quad_indices.empty()) if (src_triangle_indices.empty() && src_quad_indices.empty())
continue; continue;
fprintf(fp, "\n# vertices volume %d\n", volumes_count); ++volumes_count;
for (unsigned int i = 0; i < vertices_and_normals_interleaved.size(); i += 6)
// reduce output size by keeping only used vertices and normals
struct Vector
{ {
fprintf(fp, "v %f %f %f\n", vertices_and_normals_interleaved[i + 3], vertices_and_normals_interleaved[i + 4], vertices_and_normals_interleaved[i + 5]); std::array<coord_t, 3> vector;
explicit Vector(float* ptr)
{
vector[0] = scale_(*(ptr + 0));
vector[1] = scale_(*(ptr + 1));
vector[2] = scale_(*(ptr + 2));
}
};
typedef std::vector<Vector> Vectors;
auto vector_less = [](const Vector& v1, const Vector& v2)->bool {
return v1.vector < v2.vector;
};
auto vector_equal = [](const Vector& v1, const Vector& v2)->bool {
return (v1.vector[0] == v2.vector[0]) && (v1.vector[1] == v2.vector[1]) && (v1.vector[2] == v2.vector[2]);
};
// copy used vertices and normals data
Vectors dst_normals;
Vectors dst_vertices;
unsigned int src_triangle_indices_size = (unsigned int)src_triangle_indices.size();
for (unsigned int i = 0; i < src_triangle_indices_size; ++i)
{
float* src_ptr = src_vertices_and_normals_interleaved.data() + src_triangle_indices[i] * 6;
dst_normals.emplace_back(src_ptr + 0);
dst_vertices.emplace_back(src_ptr + 3);
}
unsigned int src_quad_indices_size = (unsigned int)src_quad_indices.size();
for (unsigned int i = 0; i < src_quad_indices_size; ++i)
{
float* src_ptr = src_vertices_and_normals_interleaved.data() + src_quad_indices[i] * 6;
dst_normals.emplace_back(src_ptr + 0);
dst_vertices.emplace_back(src_ptr + 3);
}
// sort vertices and normals
std::sort(dst_normals.begin(), dst_normals.end(), vector_less);
std::sort(dst_vertices.begin(), dst_vertices.end(), vector_less);
// remove duplicated vertices and normals
dst_normals.erase(std::unique(dst_normals.begin(), dst_normals.end(), vector_equal), dst_normals.end());
dst_vertices.erase(std::unique(dst_vertices.begin(), dst_vertices.end(), vector_equal), dst_vertices.end());
// reindex triangles and quads
struct IndicesPair
{
int vertex;
int normal;
IndicesPair(int vertex, int normal) : vertex(vertex), normal(normal) {}
};
typedef std::vector<IndicesPair> Indices;
unsigned int src_vertices_count = (unsigned int)src_vertices_and_normals_interleaved.size() / 6;
std::vector<int> src_dst_vertex_indices_map(src_vertices_count, -1);
std::vector<int> src_dst_normal_indices_map(src_vertices_count, -1);
for (unsigned int i = 0; i < src_vertices_count; ++i)
{
float* src_ptr = src_vertices_and_normals_interleaved.data() + i * 6;
src_dst_normal_indices_map[i] = std::distance(dst_normals.begin(), std::lower_bound(dst_normals.begin(), dst_normals.end(), Vector(src_ptr + 0), vector_less));
src_dst_vertex_indices_map[i] = std::distance(dst_vertices.begin(), std::lower_bound(dst_vertices.begin(), dst_vertices.end(), Vector(src_ptr + 3), vector_less));
}
Indices dst_triangle_indices;
if (src_triangle_indices_size > 0)
dst_triangle_indices.reserve(src_triangle_indices_size);
for (unsigned int i = 0; i < src_triangle_indices_size; ++i)
{
int id = src_triangle_indices[i];
dst_triangle_indices.emplace_back(src_dst_vertex_indices_map[id], src_dst_normal_indices_map[id]);
}
Indices dst_quad_indices;
if (src_quad_indices_size > 0)
dst_quad_indices.reserve(src_quad_indices_size);
for (unsigned int i = 0; i < src_quad_indices_size; ++i)
{
int id = src_quad_indices[i];
dst_quad_indices.emplace_back(src_dst_vertex_indices_map[id], src_dst_normal_indices_map[id]);
}
// save to file
fprintf(fp, "\n# vertices volume %d\n", volumes_count);
for (const Vector& v : dst_vertices)
{
fprintf(fp, "v %f %f %f\n", unscale<float>(v.vector[0]), unscale<float>(v.vector[1]), unscale<float>(v.vector[2]));
} }
fprintf(fp, "\n# normals volume %d\n", volumes_count); fprintf(fp, "\n# normals volume %d\n", volumes_count);
for (unsigned int i = 0; i < vertices_and_normals_interleaved.size(); i += 6) for (const Vector& n : dst_normals)
{ {
fprintf(fp, "vn %f %f %f\n", vertices_and_normals_interleaved[i + 0], vertices_and_normals_interleaved[i + 1], vertices_and_normals_interleaved[i + 2]); fprintf(fp, "vn %f %f %f\n", unscale<float>(n.vector[0]), unscale<float>(n.vector[1]), unscale<float>(n.vector[2]));
} }
std::array<float, 4> color; Color color;
::memcpy((void*)color.data(), (const void*)volume->color, 4 * sizeof(float)); ::memcpy((void*)color.data(), (const void*)volume->color, 4 * sizeof(float));
colors.insert(color);
fprintf(fp, "\n# material volume %d\n", volumes_count); fprintf(fp, "\n# material volume %d\n", volumes_count);
fprintf(fp, "usemtl material_%lld\n", 1 + std::distance(colors.begin(), colors.find(color))); fprintf(fp, "usemtl material_%lld\n", 1 + std::distance(colors.begin(), colors.find(color)));
int base_vertex_id = vertices_count + 1;
int base_normal_id = normals_count + 1;
if (!dst_triangle_indices.empty())
{
fprintf(fp, "\n# triangular facets volume %d\n", volumes_count); fprintf(fp, "\n# triangular facets volume %d\n", volumes_count);
for (unsigned int i = 0; i < triangle_indices.size(); i += 3) for (unsigned int i = 0; i < (unsigned int)dst_triangle_indices.size(); i += 3)
{ {
int id_v1 = vertices_count + 1 + triangle_indices[i + 0]; fprintf(fp, "f %d//%d %d//%d %d//%d\n",
int id_v2 = vertices_count + 1 + triangle_indices[i + 1]; base_vertex_id + dst_triangle_indices[i + 0].vertex, base_normal_id + dst_triangle_indices[i + 0].normal,
int id_v3 = vertices_count + 1 + triangle_indices[i + 2]; base_vertex_id + dst_triangle_indices[i + 1].vertex, base_normal_id + dst_triangle_indices[i + 1].normal,
fprintf(fp, "f %d//%d %d//%d %d//%d\n", id_v1, id_v1, id_v2, id_v2, id_v3, id_v3); base_vertex_id + dst_triangle_indices[i + 2].vertex, base_normal_id + dst_triangle_indices[i + 2].normal);
}
} }
if (!dst_quad_indices.empty())
{
fprintf(fp, "\n# quadrangular facets volume %d\n", volumes_count); fprintf(fp, "\n# quadrangular facets volume %d\n", volumes_count);
for (unsigned int i = 0; i < quad_indices.size(); i += 4) for (unsigned int i = 0; i < (unsigned int)src_quad_indices.size(); i += 4)
{ {
int id_v1 = vertices_count + 1 + quad_indices[i + 0]; fprintf(fp, "f %d//%d %d//%d %d//%d %d//%d\n",
int id_v2 = vertices_count + 1 + quad_indices[i + 1]; base_vertex_id + dst_quad_indices[i + 0].vertex, base_normal_id + dst_quad_indices[i + 0].normal,
int id_v3 = vertices_count + 1 + quad_indices[i + 2]; base_vertex_id + dst_quad_indices[i + 1].vertex, base_normal_id + dst_quad_indices[i + 1].normal,
int id_v4 = vertices_count + 1 + quad_indices[i + 3]; base_vertex_id + dst_quad_indices[i + 2].vertex, base_normal_id + dst_quad_indices[i + 2].normal,
fprintf(fp, "f %d//%d %d//%d %d//%d %d//%d\n", id_v1, id_v1, id_v2, id_v2, id_v3, id_v3, id_v4, id_v4); base_vertex_id + dst_quad_indices[i + 3].vertex, base_normal_id + dst_quad_indices[i + 3].normal);
}
} }
++volumes_count; vertices_count += (unsigned int)dst_vertices.size();
vertices_count += vertices_and_normals_interleaved.size() / 6; normals_count += (unsigned int)dst_normals.size();
} }
fclose(fp); fclose(fp);