Implemented feedback from Hans #1

Merged
Nathan Rozendaal merged 1 commits from Hans_feedback into D16792 2023-02-16 15:11:21 +01:00
20 changed files with 184 additions and 223 deletions

View File

@ -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", "");

View File

@ -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);

View File

@ -49,7 +49,6 @@ struct PLYImportParams {
eIOAxis up_axis;
bool use_scene_unit;
float global_scale;
bool import_normals_as_attribute;
bool merge_verts;
};

View File

@ -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();

View 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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);
}

View File

@ -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;

View File

@ -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));

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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);
}

View File

@ -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);

View File

@ -24,8 +24,7 @@ Mesh *convert_ply_to_mesh(PlyData &data, Mesh *mesh, const PLYImportParams &para
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 &para
/* 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 &para
/* 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. */

View File

@ -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;
};

View File

@ -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();

View 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. */