forked from blender/blender
Implemented feedback from Hans #1
@ -181,8 +181,7 @@ void WM_OT_ply_export(struct wmOperatorType *ot)
|
||||
FILE_SORT_DEFAULT);
|
||||
|
||||
/* Object transform options. */
|
||||
prop = RNA_def_enum(
|
||||
ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
|
||||
prop = RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
|
||||
RNA_def_property_update_runtime(prop, (void *)forward_axis_update);
|
||||
prop = RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
|
||||
RNA_def_property_update_runtime(prop, (void *)up_axis_update);
|
||||
@ -205,12 +204,14 @@ void WM_OT_ply_export(struct wmOperatorType *ot)
|
||||
"Export Selected Objects",
|
||||
"Export only selected objects instead of all supported objects");
|
||||
RNA_def_boolean(ot->srna, "export_uv", false, "Export UVs", "");
|
||||
RNA_def_boolean(ot->srna,
|
||||
RNA_def_boolean(
|
||||
ot->srna,
|
||||
"export_normals",
|
||||
false,
|
||||
"Export Vertex Normals",
|
||||
"Export specific vertex normals if available, export calculated normals otherwise");
|
||||
RNA_def_boolean(ot->srna, "export_colors", true, "Export Vertex Colors", "Export per-vertex colors");
|
||||
RNA_def_boolean(
|
||||
ot->srna, "export_colors", true, "Export Vertex Colors", "Export per-vertex colors");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"export_triangulated_mesh",
|
||||
false,
|
||||
@ -241,7 +242,6 @@ static int wm_ply_import_execute(bContext *C, wmOperator *op)
|
||||
params.up_axis = RNA_enum_get(op->ptr, "up_axis");
|
||||
params.use_scene_unit = RNA_boolean_get(op->ptr, "use_scene_unit");
|
||||
params.global_scale = RNA_float_get(op->ptr, "global_scale");
|
||||
params.import_normals_as_attribute = RNA_boolean_get(op->ptr, "import_normals_as_attribute");
|
||||
params.merge_verts = RNA_boolean_get(op->ptr, "merge_verts");
|
||||
|
||||
int files_len = RNA_collection_length(op->ptr, "files");
|
||||
@ -321,16 +321,7 @@ void WM_OT_ply_import(struct wmOperatorType *ot)
|
||||
"Apply current scene's unit (as defined by unit scale) to imported data");
|
||||
RNA_def_enum(ot->srna, "forward_axis", io_transform_axis, IO_AXIS_Y, "Forward Axis", "");
|
||||
RNA_def_enum(ot->srna, "up_axis", io_transform_axis, IO_AXIS_Z, "Up Axis", "");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"import_normals_as_attribute",
|
||||
false,
|
||||
"Normals As Attribute",
|
||||
"Sets the vertex normal data as a vertex attribute");
|
||||
RNA_def_boolean(ot->srna,
|
||||
"merge_verts",
|
||||
false,
|
||||
"Merge Vertices",
|
||||
"Merges vertices by distance");
|
||||
RNA_def_boolean(ot->srna, "merge_verts", false, "Merge Vertices", "Merges vertices by distance");
|
||||
|
||||
/* Only show .ply files by default. */
|
||||
prop = RNA_def_string(ot->srna, "filter_glob", "*.ply", 0, "Extension Filter", "");
|
||||
|
@ -11,13 +11,13 @@
|
||||
#include "ply_export.hh"
|
||||
#include "ply_import.hh"
|
||||
|
||||
void PLY_export(bContext *C, const struct PLYExportParams *export_params)
|
||||
void PLY_export(bContext *C, const PLYExportParams *export_params)
|
||||
{
|
||||
SCOPED_TIMER("PLY Export");
|
||||
blender::io::ply::exporter_main(C, *export_params);
|
||||
}
|
||||
|
||||
void PLY_import(bContext *C, const struct PLYImportParams *import_params, wmOperator *op)
|
||||
void PLY_import(bContext *C, const PLYImportParams *import_params, wmOperator *op)
|
||||
{
|
||||
SCOPED_TIMER("PLY Import");
|
||||
blender::io::ply::importer_main(C, *import_params, op);
|
||||
|
@ -49,7 +49,6 @@ struct PLYImportParams {
|
||||
eIOAxis up_axis;
|
||||
bool use_scene_unit;
|
||||
float global_scale;
|
||||
bool import_normals_as_attribute;
|
||||
bool merge_verts;
|
||||
};
|
||||
|
||||
|
@ -50,16 +50,16 @@ void exporter_main(Main *bmain,
|
||||
}
|
||||
|
||||
/* Generate and write header. */
|
||||
write_header(buffer, plyData, export_params);
|
||||
write_header(*buffer.get(), *plyData.get(), export_params);
|
||||
|
||||
/* Generate and write vertices. */
|
||||
write_vertices(buffer, plyData);
|
||||
write_vertices(*buffer.get(), *plyData.get());
|
||||
|
||||
/* Generate and write faces. */
|
||||
write_faces(buffer, plyData);
|
||||
write_faces(*buffer.get(), *plyData.get());
|
||||
|
||||
/* Generate and write edges. */
|
||||
write_edges(buffer, plyData);
|
||||
write_edges(*buffer.get(), *plyData.get());
|
||||
|
||||
/* Clean up. */
|
||||
buffer->close_file();
|
||||
|
@ -3,48 +3,49 @@
|
||||
/** \file
|
||||
* \ingroup ply
|
||||
*/
|
||||
#include "BLI_array.hh"
|
||||
|
||||
#include "ply_data.hh"
|
||||
#include "ply_file_buffer.hh"
|
||||
|
||||
namespace blender::io::ply {
|
||||
|
||||
void write_vertices(std::unique_ptr<FileBuffer> &buffer, std::unique_ptr<PlyData> &plyData)
|
||||
void write_vertices(FileBuffer &buffer, const PlyData &ply_data)
|
||||
{
|
||||
for (int i = 0; i < plyData->vertices.size(); i++) {
|
||||
buffer->write_vertex(plyData->vertices[i].x, plyData->vertices[i].y, plyData->vertices[i].z);
|
||||
for (int i = 0; i < ply_data.vertices.size(); i++) {
|
||||
buffer.write_vertex(ply_data.vertices[i].x, ply_data.vertices[i].y, ply_data.vertices[i].z);
|
||||
|
||||
if (!plyData->vertex_normals.is_empty())
|
||||
buffer->write_vertex_normal(plyData->vertex_normals[i].x,
|
||||
plyData->vertex_normals[i].y,
|
||||
plyData->vertex_normals[i].z);
|
||||
if (!ply_data.vertex_normals.is_empty())
|
||||
buffer.write_vertex_normal(ply_data.vertex_normals[i].x,
|
||||
ply_data.vertex_normals[i].y,
|
||||
ply_data.vertex_normals[i].z);
|
||||
|
||||
if (!plyData->vertex_colors.is_empty())
|
||||
buffer->write_vertex_color(uchar(plyData->vertex_colors[i].x * 255),
|
||||
uchar(plyData->vertex_colors[i].y * 255),
|
||||
uchar(plyData->vertex_colors[i].z * 255),
|
||||
uchar(plyData->vertex_colors[i].w * 255));
|
||||
if (!ply_data.vertex_colors.is_empty())
|
||||
buffer.write_vertex_color(uchar(ply_data.vertex_colors[i].x * 255),
|
||||
uchar(ply_data.vertex_colors[i].y * 255),
|
||||
uchar(ply_data.vertex_colors[i].z * 255),
|
||||
uchar(ply_data.vertex_colors[i].w * 255));
|
||||
|
||||
if (!plyData->UV_coordinates.is_empty())
|
||||
buffer->write_UV(plyData->UV_coordinates[i].x, plyData->UV_coordinates[i].y);
|
||||
if (!ply_data.UV_coordinates.is_empty())
|
||||
buffer.write_UV(ply_data.UV_coordinates[i].x, ply_data.UV_coordinates[i].y);
|
||||
|
||||
buffer->write_vertex_end();
|
||||
buffer.write_vertex_end();
|
||||
}
|
||||
buffer->write_to_file();
|
||||
buffer.write_to_file();
|
||||
}
|
||||
|
||||
void write_faces(std::unique_ptr<FileBuffer> &buffer, std::unique_ptr<PlyData> &plyData)
|
||||
void write_faces(FileBuffer &buffer, const PlyData &ply_data)
|
||||
{
|
||||
for (const Vector<uint32_t> &face : plyData->faces) {
|
||||
buffer->write_face(char(face.size()), face);
|
||||
for (const Array<uint32_t> &face : ply_data.faces) {
|
||||
buffer.write_face(char(face.size()), face);
|
||||
}
|
||||
buffer->write_to_file();
|
||||
buffer.write_to_file();
|
||||
}
|
||||
void write_edges(std::unique_ptr<FileBuffer> &buffer, std::unique_ptr<PlyData> &plyData)
|
||||
void write_edges(FileBuffer &buffer, const PlyData &ply_data)
|
||||
{
|
||||
for (const std::pair<int, int> &edge : plyData->edges) {
|
||||
buffer->write_edge(edge.first, edge.second);
|
||||
for (const std::pair<int, int> &edge : ply_data.edges) {
|
||||
buffer.write_edge(edge.first, edge.second);
|
||||
}
|
||||
buffer->write_to_file();
|
||||
buffer.write_to_file();
|
||||
}
|
||||
} // namespace blender::io::ply
|
||||
|
@ -11,10 +11,10 @@
|
||||
|
||||
namespace blender::io::ply {
|
||||
|
||||
void write_vertices(std::unique_ptr<FileBuffer> &buffer, std::unique_ptr<PlyData> &plyData);
|
||||
void write_vertices(FileBuffer &buffer, const PlyData &ply_data);
|
||||
|
||||
void write_faces(std::unique_ptr<FileBuffer> &buffer, std::unique_ptr<PlyData> &plyData);
|
||||
void write_faces(FileBuffer &buffer, const PlyData &ply_data);
|
||||
|
||||
void write_edges(std::unique_ptr<FileBuffer> &buffer, std::unique_ptr<PlyData> &plyData);
|
||||
void write_edges(FileBuffer &buffer, const PlyData &ply_data);
|
||||
|
||||
} // namespace blender::io::ply
|
||||
|
@ -13,54 +13,54 @@
|
||||
|
||||
namespace blender::io::ply {
|
||||
|
||||
void write_header(std::unique_ptr<FileBuffer> &buffer,
|
||||
std::unique_ptr<PlyData> &plyData,
|
||||
void write_header(FileBuffer &buffer,
|
||||
const PlyData &ply_data,
|
||||
const PLYExportParams &export_params)
|
||||
{
|
||||
buffer->write_string("ply");
|
||||
buffer.write_string("ply");
|
||||
|
||||
StringRef format = export_params.ascii_format ? "ascii" : "binary_little_endian";
|
||||
buffer->write_string("format " + format + " 1.0");
|
||||
buffer.write_string("format " + format + " 1.0");
|
||||
|
||||
StringRef version = BKE_blender_version_string();
|
||||
buffer->write_string("comment Created in Blender version " + version);
|
||||
buffer.write_string("comment Created in Blender version " + version);
|
||||
|
||||
buffer->write_header_element("vertex", int32_t(plyData->vertices.size()));
|
||||
buffer->write_header_scalar_property("float", "x");
|
||||
buffer->write_header_scalar_property("float", "y");
|
||||
buffer->write_header_scalar_property("float", "z");
|
||||
buffer.write_header_element("vertex", int32_t(ply_data.vertices.size()));
|
||||
buffer.write_header_scalar_property("float", "x");
|
||||
buffer.write_header_scalar_property("float", "y");
|
||||
buffer.write_header_scalar_property("float", "z");
|
||||
|
||||
if (!plyData->vertex_normals.is_empty()) {
|
||||
buffer->write_header_scalar_property("float", "nx");
|
||||
buffer->write_header_scalar_property("float", "ny");
|
||||
buffer->write_header_scalar_property("float", "nz");
|
||||
if (!ply_data.vertex_normals.is_empty()) {
|
||||
buffer.write_header_scalar_property("float", "nx");
|
||||
buffer.write_header_scalar_property("float", "ny");
|
||||
buffer.write_header_scalar_property("float", "nz");
|
||||
}
|
||||
|
||||
if (!plyData->vertex_colors.is_empty()) {
|
||||
buffer->write_header_scalar_property("uchar", "red");
|
||||
buffer->write_header_scalar_property("uchar", "green");
|
||||
buffer->write_header_scalar_property("uchar", "blue");
|
||||
buffer->write_header_scalar_property("uchar", "alpha");
|
||||
if (!ply_data.vertex_colors.is_empty()) {
|
||||
buffer.write_header_scalar_property("uchar", "red");
|
||||
buffer.write_header_scalar_property("uchar", "green");
|
||||
buffer.write_header_scalar_property("uchar", "blue");
|
||||
buffer.write_header_scalar_property("uchar", "alpha");
|
||||
}
|
||||
|
||||
if (!plyData->UV_coordinates.is_empty()) {
|
||||
buffer->write_header_scalar_property("float", "s");
|
||||
buffer->write_header_scalar_property("float", "t");
|
||||
if (!ply_data.UV_coordinates.is_empty()) {
|
||||
buffer.write_header_scalar_property("float", "s");
|
||||
buffer.write_header_scalar_property("float", "t");
|
||||
}
|
||||
|
||||
if (!plyData->faces.is_empty()) {
|
||||
buffer->write_header_element("face", int32_t(plyData->faces.size()));
|
||||
buffer->write_header_list_property("uchar", "uint", "vertex_indices");
|
||||
if (!ply_data.faces.is_empty()) {
|
||||
buffer.write_header_element("face", int32_t(ply_data.faces.size()));
|
||||
buffer.write_header_list_property("uchar", "uint", "vertex_indices");
|
||||
}
|
||||
|
||||
if (!plyData->edges.is_empty()) {
|
||||
buffer->write_header_element("edge", int32_t(plyData->edges.size()));
|
||||
buffer->write_header_scalar_property("int", "vertex1");
|
||||
buffer->write_header_scalar_property("int", "vertex2");
|
||||
if (!ply_data.edges.is_empty()) {
|
||||
buffer.write_header_element("edge", int32_t(ply_data.edges.size()));
|
||||
buffer.write_header_scalar_property("int", "vertex1");
|
||||
buffer.write_header_scalar_property("int", "vertex2");
|
||||
}
|
||||
|
||||
buffer->write_string("end_header");
|
||||
buffer->write_to_file();
|
||||
buffer.write_string("end_header");
|
||||
buffer.write_to_file();
|
||||
}
|
||||
|
||||
} // namespace blender::io::ply
|
||||
|
@ -11,8 +11,8 @@
|
||||
|
||||
namespace blender::io::ply {
|
||||
|
||||
void write_header(std::unique_ptr<FileBuffer> &buffer,
|
||||
std::unique_ptr<PlyData> &plyData,
|
||||
void write_header(FileBuffer &buffer,
|
||||
const PlyData &ply_data,
|
||||
const PLYExportParams &export_params);
|
||||
|
||||
} // namespace blender::io::ply
|
||||
|
@ -4,6 +4,7 @@
|
||||
* \ingroup ply
|
||||
*/
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_math.h"
|
||||
|
||||
#include "BKE_attribute.hh"
|
||||
@ -40,8 +41,6 @@ Mesh *do_triangulation(const Mesh *mesh, bool force_triangulation)
|
||||
BMeshFromMeshParams bm_convert_params{};
|
||||
bm_convert_params.calc_face_normal = true;
|
||||
bm_convert_params.calc_vert_normal = true;
|
||||
bm_convert_params.add_key_index = false;
|
||||
bm_convert_params.use_shapekey = false;
|
||||
const int triangulation_threshold = force_triangulation ? 4 : 255;
|
||||
|
||||
BMesh *bmesh = BKE_mesh_to_bmesh_ex(mesh, &bm_create_params, &bm_convert_params);
|
||||
@ -115,7 +114,7 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
|
||||
const float2 *uv_map = static_cast<const float2 *>(
|
||||
CustomData_get_layer(&mesh->ldata, CD_PROP_FLOAT2));
|
||||
|
||||
blender::Map<UV_vertex_key, int> vertex_map = generate_vertex_map(mesh, uv_map, export_params);
|
||||
Map<UV_vertex_key, int> vertex_map = generate_vertex_map(mesh, uv_map, export_params);
|
||||
|
||||
set_world_axes_transform(
|
||||
&export_object_eval_, export_params.forward_axis, export_params.up_axis);
|
||||
@ -123,9 +122,9 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
|
||||
/* Load faces into plyData. */
|
||||
int loop_offset = 0;
|
||||
Span<MLoop> loops = mesh->loops();
|
||||
for (auto &&poly : mesh->polys()) {
|
||||
for (const MPoly poly : mesh->polys()) {
|
||||
Span<MLoop> loopSpan = loops.slice(poly.loopstart, poly.totloop);
|
||||
Vector<uint32_t> polyVector;
|
||||
Array<uint32_t> polyVector(loopSpan.size());
|
||||
|
||||
for (int i = 0; i < loopSpan.size(); ++i) {
|
||||
float2 uv;
|
||||
@ -137,7 +136,7 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
|
||||
}
|
||||
UV_vertex_key key = UV_vertex_key(uv, loopSpan[i].v);
|
||||
int ply_vertex_index = vertex_map.lookup(key);
|
||||
polyVector.append(uint32_t(ply_vertex_index + vertex_offset));
|
||||
polyVector[i] = (uint32_t(ply_vertex_index + vertex_offset));
|
||||
}
|
||||
loop_offset += loopSpan.size();
|
||||
|
||||
@ -185,12 +184,12 @@ void load_plydata(PlyData &plyData, Depsgraph *depsgraph, const PLYExportParams
|
||||
const StringRef name = mesh->active_color_attribute;
|
||||
if (!name.is_empty()) {
|
||||
const bke::AttributeAccessor attributes = mesh->attributes();
|
||||
const VArray<ColorGeometry4f> colorAttribute =
|
||||
const VArray<ColorGeometry4f> color_attribute =
|
||||
attributes.lookup_or_default<ColorGeometry4f>(
|
||||
name, ATTR_DOMAIN_POINT, {0.0f, 0.0f, 0.0f, 0.0f});
|
||||
|
||||
for (int i = 0; i < vertex_map.size(); i++) {
|
||||
ColorGeometry4f colorGeometry = colorAttribute[mesh_vertex_index_LUT[i]];
|
||||
ColorGeometry4f colorGeometry = color_attribute[mesh_vertex_index_LUT[i]];
|
||||
float4 vertColor(colorGeometry.r, colorGeometry.g, colorGeometry.b, colorGeometry.a);
|
||||
plyData.vertex_colors.append(vertColor);
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
@ -101,7 +102,7 @@ class FileBuffer : private NonMovable {
|
||||
|
||||
virtual void write_vertex_end() = 0;
|
||||
|
||||
virtual void write_face(char count, Vector<uint32_t> const &vertex_indices) = 0;
|
||||
virtual void write_face(char count, Array<uint32_t> const &vertex_indices) = 0;
|
||||
|
||||
virtual void write_edge(int first, int second) = 0;
|
||||
|
||||
|
@ -8,13 +8,12 @@
|
||||
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "ply_file_buffer.hh"
|
||||
|
||||
@ -53,7 +52,7 @@ class FileBufferAscii : public FileBuffer {
|
||||
write_fstring("\n");
|
||||
}
|
||||
|
||||
void write_face(char count, Vector<uint32_t> const &vertex_indices) override
|
||||
void write_face(char count, Array<uint32_t> const &vertex_indices) override
|
||||
{
|
||||
write_fstring("{}", int(count));
|
||||
|
||||
|
@ -9,12 +9,12 @@
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_fileops.h"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_utility_mixins.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "ply_file_buffer.hh"
|
||||
|
||||
@ -70,19 +70,13 @@ class FileBufferBinary : public FileBuffer {
|
||||
/* In binary, there is no end to a vertex. */
|
||||
}
|
||||
|
||||
void write_face(char size, Vector<uint32_t> const &vertex_indices) override
|
||||
void write_face(char size, Array<uint32_t> const &vertex_indices) override
|
||||
{
|
||||
/* Pre allocate memory so no further allocation has to be done for typical faces. */
|
||||
Vector<char, 128> data;
|
||||
data.append(size);
|
||||
for (auto &&vertexIndex : vertex_indices) {
|
||||
uint32_t x = vertexIndex;
|
||||
auto *vtxbits = static_cast<char *>(static_cast<void *>(&x));
|
||||
data.insert(data.end(), vtxbits, vtxbits + sizeof(uint32_t));
|
||||
}
|
||||
write_bytes(Span<char>({size}));
|
||||
|
||||
Span<char> span(data);
|
||||
write_bytes(span);
|
||||
Span<char> dataSpan(reinterpret_cast<const char *>(vertex_indices.data()),
|
||||
vertex_indices.size() * sizeof(uint32_t));
|
||||
write_bytes(dataSpan);
|
||||
}
|
||||
|
||||
void write_edge(int first, int second) override
|
||||
|
@ -24,46 +24,46 @@ PlyData load_ply_ascii(std::ifstream &file, const PlyHeader *header)
|
||||
PlyData data;
|
||||
/* Check if header contains alpha. */
|
||||
std::pair<std::string, PlyDataTypes> alpha = {"alpha", PlyDataTypes::UCHAR};
|
||||
bool hasAlpha = std::find(header->properties[0].begin(), header->properties[0].end(), alpha) !=
|
||||
bool has_alpha = std::find(header->properties[0].begin(), header->properties[0].end(), alpha) !=
|
||||
header->properties[0].end();
|
||||
|
||||
/* Check if header contains colors. */
|
||||
std::pair<std::string, PlyDataTypes> red = {"red", PlyDataTypes::UCHAR};
|
||||
bool hasColor = std::find(header->properties[0].begin(), header->properties[0].end(), red) !=
|
||||
bool has_color = std::find(header->properties[0].begin(), header->properties[0].end(), red) !=
|
||||
header->properties[0].end();
|
||||
|
||||
/* Check if header contains normals. */
|
||||
std::pair<std::string, PlyDataTypes> normalx = {"nx", PlyDataTypes::FLOAT};
|
||||
bool hasNormals = std::find(header->properties[0].begin(),
|
||||
bool has_normals = std::find(header->properties[0].begin(),
|
||||
header->properties[0].end(),
|
||||
normalx) != header->properties[0].end();
|
||||
|
||||
/* Check if header contains uv data. */
|
||||
std::pair<std::string, PlyDataTypes> uv = {"s", PlyDataTypes::FLOAT};
|
||||
bool hasUv = std::find(header->properties[0].begin(), header->properties[0].end(), uv) !=
|
||||
bool has_UV = std::find(header->properties[0].begin(), header->properties[0].end(), uv) !=
|
||||
header->properties[0].end();
|
||||
|
||||
int3 vertexIndex = get_vertex_index(header);
|
||||
int alphaIndex;
|
||||
int3 colorIndex;
|
||||
int3 normalIndex;
|
||||
int2 uvIndex;
|
||||
int3 vertex_index = get_vertex_index(header);
|
||||
int alpha_index;
|
||||
int3 color_index;
|
||||
int3 normal_index;
|
||||
int2 UV_index;
|
||||
|
||||
if (hasAlpha) {
|
||||
alphaIndex = get_index(header, "alpha", PlyDataTypes::UCHAR);
|
||||
if (has_alpha) {
|
||||
alpha_index = get_index(header, "alpha", PlyDataTypes::UCHAR);
|
||||
}
|
||||
|
||||
if (hasColor) {
|
||||
if (has_color) {
|
||||
/* x=red, y=green, z=blue */
|
||||
colorIndex = get_color_index(header);
|
||||
color_index = get_color_index(header);
|
||||
}
|
||||
|
||||
if (hasNormals) {
|
||||
normalIndex = get_normal_index(header);
|
||||
if (has_normals) {
|
||||
normal_index = get_normal_index(header);
|
||||
}
|
||||
|
||||
if (hasUv) {
|
||||
uvIndex = get_uv_index(header);
|
||||
if (has_UV) {
|
||||
UV_index = get_uv_index(header);
|
||||
}
|
||||
|
||||
for (int i = 0; i < header->vertex_count; i++) {
|
||||
@ -73,20 +73,20 @@ PlyData load_ply_ascii(std::ifstream &file, const PlyHeader *header)
|
||||
|
||||
/* Vertex coords */
|
||||
float3 vertex3;
|
||||
vertex3.x = std::stof(value_vec[vertexIndex.x]);
|
||||
vertex3.y = std::stof(value_vec[vertexIndex.y]);
|
||||
vertex3.z = std::stof(value_vec[vertexIndex.z]);
|
||||
vertex3.x = std::stof(value_vec[vertex_index.x]);
|
||||
vertex3.y = std::stof(value_vec[vertex_index.y]);
|
||||
vertex3.z = std::stof(value_vec[vertex_index.z]);
|
||||
|
||||
data.vertices.append(vertex3);
|
||||
|
||||
/* Vertex colors */
|
||||
if (hasColor) {
|
||||
if (has_color) {
|
||||
float4 colors4;
|
||||
colors4.x = std::stof(value_vec[colorIndex.x]) / 255.0f;
|
||||
colors4.y = std::stof(value_vec[colorIndex.y]) / 255.0f;
|
||||
colors4.z = std::stof(value_vec[colorIndex.z]) / 255.0f;
|
||||
if (hasAlpha) {
|
||||
colors4.w = std::stof(value_vec[alphaIndex]) / 255.0f;
|
||||
colors4.x = std::stof(value_vec[color_index.x]) / 255.0f;
|
||||
colors4.y = std::stof(value_vec[color_index.y]) / 255.0f;
|
||||
colors4.z = std::stof(value_vec[color_index.z]) / 255.0f;
|
||||
if (has_alpha) {
|
||||
colors4.w = std::stof(value_vec[alpha_index]) / 255.0f;
|
||||
}
|
||||
else {
|
||||
colors4.w = 1.0f;
|
||||
@ -96,20 +96,20 @@ PlyData load_ply_ascii(std::ifstream &file, const PlyHeader *header)
|
||||
}
|
||||
|
||||
/* If normals */
|
||||
if (hasNormals) {
|
||||
if (has_normals) {
|
||||
float3 normals3;
|
||||
normals3.x = std::stof(value_vec[normalIndex.x]);
|
||||
normals3.y = std::stof(value_vec[normalIndex.y]);
|
||||
normals3.z = std::stof(value_vec[normalIndex.z]);
|
||||
normals3.x = std::stof(value_vec[normal_index.x]);
|
||||
normals3.y = std::stof(value_vec[normal_index.y]);
|
||||
normals3.z = std::stof(value_vec[normal_index.z]);
|
||||
|
||||
data.vertex_normals.append(normals3);
|
||||
}
|
||||
|
||||
/* If uv */
|
||||
if (hasUv) {
|
||||
if (has_UV) {
|
||||
float2 uvmap;
|
||||
uvmap.x = std::stof(value_vec[uvIndex.x]);
|
||||
uvmap.y = std::stof(value_vec[uvIndex.y]);
|
||||
uvmap.x = std::stof(value_vec[UV_index.x]);
|
||||
uvmap.y = std::stof(value_vec[UV_index.y]);
|
||||
|
||||
data.UV_coordinates.append(uvmap);
|
||||
}
|
||||
@ -118,14 +118,16 @@ PlyData load_ply_ascii(std::ifstream &file, const PlyHeader *header)
|
||||
std::string line;
|
||||
getline(file, line);
|
||||
Vector<std::string> value_vec = explode(line, ' ');
|
||||
Vector<uint> vertex_indices;
|
||||
int count = std::stoi(value_vec[0]);
|
||||
Array<uint> vertex_indices(count);
|
||||
|
||||
for (int j = 1; j <= std::stoi(value_vec[0]); j++) {
|
||||
for (int j = 1; j <= count; j++) {
|
||||
int index = std::stoi(value_vec[j]);
|
||||
/* If the face has a vertex index that is outside the range. */
|
||||
if (std::stoi(value_vec[j]) >= data.vertices.size()) {
|
||||
if (index >= data.vertices.size()) {
|
||||
throw std::runtime_error("Vertex index out of bounds");
|
||||
}
|
||||
vertex_indices.append(std::stoi(value_vec[j]));
|
||||
vertex_indices[j - 1] = index;
|
||||
}
|
||||
data.faces.append(vertex_indices);
|
||||
}
|
||||
@ -144,41 +146,41 @@ PlyData load_ply_ascii(std::ifstream &file, const PlyHeader *header)
|
||||
|
||||
int3 get_vertex_index(const PlyHeader *header)
|
||||
{
|
||||
int3 vertexPos;
|
||||
vertexPos.x = get_index(header, "x", PlyDataTypes::FLOAT);
|
||||
vertexPos.y = get_index(header, "y", PlyDataTypes::FLOAT);
|
||||
vertexPos.z = get_index(header, "z", PlyDataTypes::FLOAT);
|
||||
int3 vertex_index;
|
||||
vertex_index.x = get_index(header, "x", PlyDataTypes::FLOAT);
|
||||
vertex_index.y = get_index(header, "y", PlyDataTypes::FLOAT);
|
||||
vertex_index.z = get_index(header, "z", PlyDataTypes::FLOAT);
|
||||
|
||||
return vertexPos;
|
||||
return vertex_index;
|
||||
}
|
||||
|
||||
int3 get_color_index(const PlyHeader *header)
|
||||
{
|
||||
int3 vertexPos;
|
||||
vertexPos.x = get_index(header, "red", PlyDataTypes::UCHAR);
|
||||
vertexPos.y = get_index(header, "green", PlyDataTypes::UCHAR);
|
||||
vertexPos.z = get_index(header, "blue", PlyDataTypes::UCHAR);
|
||||
int3 color_index;
|
||||
color_index.x = get_index(header, "red", PlyDataTypes::UCHAR);
|
||||
color_index.y = get_index(header, "green", PlyDataTypes::UCHAR);
|
||||
color_index.z = get_index(header, "blue", PlyDataTypes::UCHAR);
|
||||
|
||||
return vertexPos;
|
||||
return color_index;
|
||||
}
|
||||
|
||||
int3 get_normal_index(const PlyHeader *header)
|
||||
{
|
||||
int3 vertexPos;
|
||||
vertexPos.x = get_index(header, "nx", PlyDataTypes::FLOAT);
|
||||
vertexPos.y = get_index(header, "ny", PlyDataTypes::FLOAT);
|
||||
vertexPos.z = get_index(header, "nz", PlyDataTypes::FLOAT);
|
||||
int3 normal_index;
|
||||
normal_index.x = get_index(header, "nx", PlyDataTypes::FLOAT);
|
||||
normal_index.y = get_index(header, "ny", PlyDataTypes::FLOAT);
|
||||
normal_index.z = get_index(header, "nz", PlyDataTypes::FLOAT);
|
||||
|
||||
return vertexPos;
|
||||
return normal_index;
|
||||
}
|
||||
|
||||
int2 get_uv_index(const PlyHeader *header)
|
||||
{
|
||||
int2 uvPos;
|
||||
uvPos.x = get_index(header, "s", PlyDataTypes::FLOAT);
|
||||
uvPos.y = get_index(header, "t", PlyDataTypes::FLOAT);
|
||||
int2 uv_index;
|
||||
uv_index.x = get_index(header, "s", PlyDataTypes::FLOAT);
|
||||
uv_index.y = get_index(header, "t", PlyDataTypes::FLOAT);
|
||||
|
||||
return uvPos;
|
||||
return uv_index;
|
||||
}
|
||||
|
||||
int get_index(const PlyHeader *header, std::string property, PlyDataTypes datatype)
|
||||
@ -188,7 +190,7 @@ int get_index(const PlyHeader *header, std::string property, PlyDataTypes dataty
|
||||
return (int)(it - header->properties[0].begin());
|
||||
}
|
||||
|
||||
Vector<std::string> explode(const StringRef &str, const char &ch)
|
||||
Vector<std::string> explode(const StringRef str, const char &ch)
|
||||
{
|
||||
std::string next;
|
||||
Vector<std::string> result;
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
#include "DNA_mesh_types.h"
|
||||
|
||||
#include "IO_ply.h"
|
||||
@ -35,5 +33,5 @@ int3 get_color_index(const PlyHeader *header);
|
||||
int3 get_normal_index(const PlyHeader *header);
|
||||
int2 get_uv_index(const PlyHeader *header);
|
||||
int get_index(const PlyHeader *header, std::string property, PlyDataTypes datatype);
|
||||
Vector<std::string> explode(const StringRef &str, const char &ch);
|
||||
Vector<std::string> explode(const StringRef str, const char &ch);
|
||||
} // namespace blender::io::ply
|
||||
|
@ -3,6 +3,7 @@
|
||||
/** \file
|
||||
* \ingroup ply
|
||||
*/
|
||||
#include "BLI_array.hh"
|
||||
|
||||
#include "ply_import_binary.hh"
|
||||
|
||||
@ -113,7 +114,7 @@ PlyData load_ply_binary(std::ifstream &file, const PlyHeader *header)
|
||||
for (int j = 0; j < header->elements[i].second; j++) {
|
||||
/* Assume vertex_index_count_type is uchar. */
|
||||
uint8_t count = read<uint8_t>(file, isBigEndian);
|
||||
Vector<uint> vertex_indices;
|
||||
Array<uint> vertex_indices(count);
|
||||
|
||||
/* Loop over the amount of vertex indices in this face. */
|
||||
for (uint8_t k = 0; k < count; k++) {
|
||||
@ -122,7 +123,7 @@ PlyData load_ply_binary(std::ifstream &file, const PlyHeader *header)
|
||||
if (index >= data.vertices.size()) {
|
||||
throw std::runtime_error("Vertex index out of bounds");
|
||||
}
|
||||
vertex_indices.append(index);
|
||||
vertex_indices[k] = index;
|
||||
}
|
||||
data.faces.append(vertex_indices);
|
||||
}
|
||||
|
@ -6,24 +6,22 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BKE_mesh.h"
|
||||
|
||||
#include "ply_data.hh"
|
||||
|
||||
namespace blender::io::ply {
|
||||
|
||||
/**
|
||||
* The function that gets called from the importer.
|
||||
* \param file The PLY file that was opened.
|
||||
* \param header The information in the PLY header.
|
||||
* \param file: The PLY file that was opened.
|
||||
* \param header: The information in the PLY header.
|
||||
* \return The PlyData datastructure that can be used for conversion to a Mesh.
|
||||
*/
|
||||
std::unique_ptr<PlyData> import_ply_binary(std::ifstream &file, const PlyHeader *header);
|
||||
|
||||
/**
|
||||
* Loads the information from the PLY file in binary format to the PlyData datastructure.
|
||||
* \param file The PLY file that was opened.
|
||||
* \param header The information in the PLY header.
|
||||
* \param file: The PLY file that was opened.
|
||||
* \param header: The information in the PLY header.
|
||||
* \return The PlyData datastructure that can be used for conversion to a Mesh.
|
||||
*/
|
||||
PlyData load_ply_binary(std::ifstream &file, const PlyHeader *header);
|
||||
|
@ -24,8 +24,7 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶
|
||||
mesh->totvert = int(data.vertices.size());
|
||||
CustomData_add_layer_named(
|
||||
&mesh->vdata, CD_PROP_FLOAT3, CD_CONSTRUCT, nullptr, mesh->totvert, "position");
|
||||
MutableSpan<float3> verts = mesh->vert_positions_for_write();
|
||||
verts.copy_from(data.vertices);
|
||||
mesh->vert_positions_for_write().copy_from(data.vertices);
|
||||
|
||||
bke::MutableAttributeAccessor attributes = mesh->attributes_for_write();
|
||||
|
||||
@ -83,16 +82,16 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶
|
||||
|
||||
/* Uvmap */
|
||||
if (!data.UV_coordinates.is_empty()) {
|
||||
bke::SpanAttributeWriter<float2> Uv = attributes.lookup_or_add_for_write_only_span<float2>(
|
||||
bke::SpanAttributeWriter<float2> uv_map = attributes.lookup_or_add_for_write_only_span<float2>(
|
||||
"UVMap", ATTR_DOMAIN_CORNER);
|
||||
int counter = 0;
|
||||
for (int i = 0; i < data.faces.size(); i++) {
|
||||
for (int j = 0; j < data.faces[i].size(); j++) {
|
||||
copy_v2_v2(Uv.span[counter], data.UV_coordinates[data.faces[i][j]]);
|
||||
copy_v2_v2(uv_map.span[counter], data.UV_coordinates[data.faces[i][j]]);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
Uv.finish();
|
||||
uv_map.finish();
|
||||
}
|
||||
|
||||
/* Calculate edges from the rest of the mesh. */
|
||||
@ -100,25 +99,8 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams ¶
|
||||
|
||||
/* Note: This is important to do after initializing the loops. */
|
||||
if (!data.vertex_normals.is_empty()) {
|
||||
float(*vertex_normals)[3] = static_cast<float(*)[3]>(
|
||||
MEM_malloc_arrayN(data.vertex_normals.size(), sizeof(float[3]), __func__));
|
||||
|
||||
/* Below code is necessary to access vertex normals within Blender.
|
||||
* Until Blender supports custom vertex normals, this is a workaround. */
|
||||
bke::SpanAttributeWriter<float3> normals;
|
||||
if (params.import_normals_as_attribute) {
|
||||
normals = attributes.lookup_or_add_for_write_span<float3>("Normal", ATTR_DOMAIN_POINT);
|
||||
}
|
||||
|
||||
for (int i = 0; i < data.vertex_normals.size(); i++) {
|
||||
copy_v3_v3(vertex_normals[i], data.vertex_normals[i]);
|
||||
if (normals) {
|
||||
copy_v3_v3(normals.span[i], data.vertex_normals[i]);
|
||||
}
|
||||
}
|
||||
normals.finish();
|
||||
BKE_mesh_set_custom_normals_from_verts(mesh, vertex_normals);
|
||||
MEM_freeN(vertex_normals);
|
||||
BKE_mesh_set_custom_normals_from_verts(
|
||||
mesh, reinterpret_cast<float(*)[3]>(data.vertex_normals.data()));
|
||||
}
|
||||
|
||||
/* Merge all vertices on the same location. */
|
||||
|
@ -6,6 +6,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_math_vector_types.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
@ -20,7 +21,7 @@ struct PlyData {
|
||||
Vector<float4> vertex_colors;
|
||||
Vector<std::pair<int, int>> edges;
|
||||
Vector<float3> edge_colors;
|
||||
Vector<Vector<uint32_t>> faces;
|
||||
Vector<Array<uint32_t>> faces;
|
||||
Vector<float2> UV_coordinates;
|
||||
};
|
||||
|
||||
|
@ -127,7 +127,7 @@ TEST_F(PlyExportTest, WriteHeaderAscii)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer = std::make_unique<FileBufferAscii>(_params.filepath);
|
||||
|
||||
write_header(buffer, plyData, _params);
|
||||
write_header(*buffer.get(), *plyData.get(), _params);
|
||||
|
||||
buffer->close_file();
|
||||
|
||||
@ -165,7 +165,7 @@ TEST_F(PlyExportTest, WriteHeaderBinary)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer = std::make_unique<FileBufferBinary>(_params.filepath);
|
||||
|
||||
write_header(buffer, plyData, _params);
|
||||
write_header(*buffer.get(), *plyData.get(), _params);
|
||||
|
||||
buffer->close_file();
|
||||
|
||||
@ -203,7 +203,7 @@ TEST_F(PlyExportTest, WriteVerticesAscii)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer = std::make_unique<FileBufferAscii>(_params.filepath);
|
||||
|
||||
write_vertices(buffer, plyData);
|
||||
write_vertices(*buffer.get(), *plyData.get());
|
||||
|
||||
buffer->close_file();
|
||||
|
||||
@ -235,7 +235,7 @@ TEST_F(PlyExportTest, WriteVerticesBinary)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer = std::make_unique<FileBufferBinary>(_params.filepath);
|
||||
|
||||
write_vertices(buffer, plyData);
|
||||
write_vertices(*buffer.get(), *plyData.get());
|
||||
|
||||
buffer->close_file();
|
||||
|
||||
@ -277,7 +277,7 @@ TEST_F(PlyExportTest, WriteFacesAscii)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer = std::make_unique<FileBufferAscii>(_params.filepath);
|
||||
|
||||
write_faces(buffer, plyData);
|
||||
write_faces(*buffer.get(), *plyData.get());
|
||||
|
||||
buffer->close_file();
|
||||
|
||||
@ -309,7 +309,7 @@ TEST_F(PlyExportTest, WriteFacesBinary)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer = std::make_unique<FileBufferBinary>(_params.filepath);
|
||||
|
||||
write_faces(buffer, plyData);
|
||||
write_faces(*buffer.get(), *plyData.get());
|
||||
|
||||
buffer->close_file();
|
||||
|
||||
@ -352,7 +352,7 @@ TEST_F(PlyExportTest, WriteVertexNormalsAscii)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer = std::make_unique<FileBufferAscii>(_params.filepath);
|
||||
|
||||
write_vertices(buffer, plyData);
|
||||
write_vertices(*buffer.get(), *plyData.get());
|
||||
|
||||
buffer->close_file();
|
||||
|
||||
@ -384,7 +384,7 @@ TEST_F(PlyExportTest, WriteVertexNormalsBinary)
|
||||
|
||||
std::unique_ptr<FileBuffer> buffer = std::make_unique<FileBufferBinary>(_params.filepath);
|
||||
|
||||
write_vertices(buffer, plyData);
|
||||
write_vertices(*buffer.get(), *plyData.get());
|
||||
|
||||
buffer->close_file();
|
||||
|
||||
|
@ -53,7 +53,6 @@ class PlyImportTest : public BlendfileLoadingBaseTest {
|
||||
params.global_scale = 1.0f;
|
||||
params.forward_axis = IO_AXIS_NEGATIVE_Z;
|
||||
params.up_axis = IO_AXIS_Y;
|
||||
params.import_normals_as_attribute = true;
|
||||
params.merge_verts = false;
|
||||
|
||||
/* Import the test file. */
|
||||
@ -97,14 +96,10 @@ class PlyImportTest : public BlendfileLoadingBaseTest {
|
||||
EXPECT_V3_NEAR(verts.last(), exp.vert_last, 0.0001f);
|
||||
|
||||
/* Fetch normal data from mesh and test if it matches expectation. */
|
||||
/* This uses the normal import workaround for vertex normals. This should be changed when
|
||||
* Blender supports custom vertex normals. */
|
||||
if (BKE_mesh_has_custom_loop_normals(mesh)) {
|
||||
const float3 *vertex_normals = (const float3 *)CustomData_get_layer_named(
|
||||
&mesh->vdata, CD_PROP_FLOAT3, "Normal");
|
||||
ASSERT_TRUE(vertex_normals != nullptr);
|
||||
float3 normal_first = vertex_normals != nullptr ? vertex_normals[0] : float3(0, 0, 0);
|
||||
EXPECT_V3_NEAR(normal_first, exp.normal_first, 0.0001f);
|
||||
const Span<float3> vertex_normals = mesh->vertex_normals();
|
||||
ASSERT_FALSE(vertex_normals.is_empty());
|
||||
EXPECT_V3_NEAR(vertex_normals[0], exp.normal_first, 0.0001f);
|
||||
}
|
||||
|
||||
/* Fetch UV data from mesh and test if it matches expectation. */
|
||||
|
Loading…
Reference in New Issue
Block a user