UI: Operator Props Dialog Changes #117528

Merged
Harley Acheson merged 9 commits from Harley/blender:OpPropertyDialog into main 2024-01-26 20:52:39 +01:00
19 changed files with 391 additions and 299 deletions
Showing only changes of commit 8a1b01b357 - Show all commits

View File

@ -177,9 +177,9 @@ Batch *VKBackend::batch_alloc()
return new VKBatch();
}
DrawList *VKBackend::drawlist_alloc(int /*list_length*/)
DrawList *VKBackend::drawlist_alloc(int list_length)
{
return new VKDrawList();
return new VKDrawList(list_length);
}
Fence *VKBackend::fence_alloc()

View File

@ -31,4 +31,9 @@ class VKBatch : public Batch {
void draw_setup();
};
BLI_INLINE VKBatch *unwrap(GPUBatch *batch)
{
return static_cast<VKBatch *>(batch);
}
} // namespace blender::gpu

View File

@ -8,15 +8,81 @@
#include "GPU_batch.h"
#include "vk_batch.hh"
#include "vk_common.hh"
#include "vk_drawlist.hh"
#include "vk_index_buffer.hh"
#include "vk_vertex_buffer.hh"
namespace blender::gpu {
void VKDrawList::append(GPUBatch *batch, int instance_first, int instance_count)
VKDrawList::VKDrawList(int list_length)
: command_buffer_(
list_length * sizeof(VkDrawIndexedIndirectCommand), GPU_USAGE_STREAM, __func__),
length_(list_length)
{
GPU_batch_draw_advanced(batch, 0, 0, instance_first, instance_count);
command_buffer_.ensure_allocated();
}
void VKDrawList::submit() {}
void VKDrawList::append(GPUBatch *gpu_batch, int instance_first, int instance_count)
{
/* Check for different batch. When batch is different the previous commands should be flushed to
* the gpu. */
VKBatch *batch = unwrap(gpu_batch);
if (batch_ != batch) {
submit();
batch_ = batch;
}
/* Record the new command */
const VKIndexBuffer *index_buffer = batch_->index_buffer_get();
const bool is_indexed = index_buffer != nullptr;
if (is_indexed) {
VkDrawIndexedIndirectCommand &command = get_command<VkDrawIndexedIndirectCommand>();
command.firstIndex = index_buffer->index_base_get();
command.vertexOffset = index_buffer->index_start_get();
command.indexCount = index_buffer->index_len_get();
command.firstInstance = instance_first;
command.instanceCount = instance_count;
}
else {
const VKVertexBuffer *vertex_buffer = batch_->vertex_buffer_get(0);
if (vertex_buffer == nullptr) {
batch_ = nullptr;
return;
}
VkDrawIndirectCommand &command = get_command<VkDrawIndirectCommand>();
command.vertexCount = vertex_buffer->vertex_len;
command.instanceCount = instance_count;
command.firstVertex = 0;
command.firstInstance = instance_first;
}
command_index_++;
/* Submit commands when command buffer is full. */
if (command_index_ == length_) {
submit();
}
}
void VKDrawList::submit()
{
if (batch_ == nullptr || command_index_ == 0) {
command_index_ = 0;
batch_ = nullptr;
return;
}
const VKIndexBuffer *index_buffer = batch_->index_buffer_get();
const bool is_indexed = index_buffer != nullptr;
command_buffer_.buffer_get().flush();
batch_->multi_draw_indirect(wrap(wrap(&command_buffer_)),
command_index_,
0,
is_indexed ? sizeof(VkDrawIndexedIndirectCommand) :
sizeof(VkDrawIndirectCommand));
command_index_ = 0;
batch_ = nullptr;
}
} // namespace blender::gpu

View File

@ -10,12 +10,68 @@
#include "gpu_drawlist_private.hh"
#include "vk_storage_buffer.hh"
namespace blender::gpu {
class VKBatch;
class VKDrawList : public DrawList {
private:
/**
* Batch from who the commands are being recorded.
*/
VKBatch *batch_ = nullptr;
/**
* Storage buffer containing the commands.
*
* The storage buffer is host visible and new commands are directly added to the buffer. Reducing
* the need to copy the commands from an intermediate buffer to the GPU. The commands are only
* written once and used once.
*
* The data can be used to record VkDrawIndirectCommands or VkDrawIndirectIndexedCommands.
*/
VKStorageBuffer command_buffer_;
/**
* Maximum number of commands that can be recorded per batch. Commands will be flushed when this
* number of commands are added.
*/
const int length_;
/**
* Current number of recorded commands.
*/
int command_index_ = 0;
public:
VKDrawList(int list_length);
/**
* Append a new command for the given batch to the draw list.
*
* Will flush when batch is different than the previous one or when the command_buffer_ is full.
*/
void append(GPUBatch *batch, int instance_first, int instance_count) override;
/**
* Submit buffered commands to the GPU.
*
* NOTE: after calling this method the command_index_ and the batch_ are reset.
*/
void submit() override;
private:
/**
* Retrieve command to write to. The returned memory is part of the mapped memory of the
* commands_buffer_.
*/
template<typename CommandType> CommandType &get_command() const
{
return MutableSpan<CommandType>(
static_cast<CommandType *>(command_buffer_.buffer_get().mapped_memory_get()),
length_)[command_index_];
}
};
} // namespace blender::gpu

View File

@ -38,12 +38,14 @@ void VKStorageBuffer::ensure_allocated()
void VKStorageBuffer::allocate()
{
const bool is_host_visible = false;
buffer_.create(size_in_bytes_,
usage_,
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_SRC_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
is_host_visible);
const bool is_host_visible = ELEM(usage_, GPU_USAGE_STREAM);
VkBufferUsageFlags buffer_usage_flags = ELEM(usage_, GPU_USAGE_STREAM) ?
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT :
VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT |
VK_BUFFER_USAGE_STORAGE_BUFFER_BIT |
VK_BUFFER_USAGE_TRANSFER_SRC_BIT |
VK_BUFFER_USAGE_TRANSFER_DST_BIT;
buffer_.create(size_in_bytes_, usage_, buffer_usage_flags, is_host_visible);
debug::object_label(buffer_.vk_handle(), name_);
}

View File

@ -49,6 +49,11 @@ class VKStorageBuffer : public StorageBuf, public VKBindableResource {
void ensure_allocated();
const VKBuffer &buffer_get() const
{
return buffer_;
}
private:
void allocate();
};
@ -57,5 +62,9 @@ BLI_INLINE VKStorageBuffer *unwrap(StorageBuf *storage_buffer)
{
return static_cast<VKStorageBuffer *>(storage_buffer);
}
BLI_INLINE StorageBuf *wrap(VKStorageBuffer *storage_buffer)
{
return static_cast<StorageBuf *>(storage_buffer);
}
} // namespace blender::gpu

View File

@ -62,10 +62,10 @@ void OBJWriter::write_vert_uv_normal_indices(FormatHandler &fh,
const int uv_offset = offsets.uv_vertex_offset + 1;
const int normal_offset = offsets.normal_offset + 1;
const int n = vert_indices.size();
fh.write_obj_poly_begin();
fh.write_obj_face_begin();
if (!flip) {
for (int j = 0; j < n; ++j) {
fh.write_obj_poly_v_uv_normal(vert_indices[j] + vertex_offset,
fh.write_obj_face_v_uv_normal(vert_indices[j] + vertex_offset,
uv_indices[j] + uv_offset,
normal_indices[j] + normal_offset);
}
@ -76,12 +76,12 @@ void OBJWriter::write_vert_uv_normal_indices(FormatHandler &fh,
* then go backwards. Same logic in other write_*_indices functions below. */
for (int k = 0; k < n; ++k) {
int j = k == 0 ? 0 : n - k;
fh.write_obj_poly_v_uv_normal(vert_indices[j] + vertex_offset,
fh.write_obj_face_v_uv_normal(vert_indices[j] + vertex_offset,
uv_indices[j] + uv_offset,
normal_indices[j] + normal_offset);
}
}
fh.write_obj_poly_end();
fh.write_obj_face_end();
}
void OBJWriter::write_vert_normal_indices(FormatHandler &fh,
@ -95,21 +95,21 @@ void OBJWriter::write_vert_normal_indices(FormatHandler &fh,
const int vertex_offset = offsets.vertex_offset + 1;
const int normal_offset = offsets.normal_offset + 1;
const int n = vert_indices.size();
fh.write_obj_poly_begin();
fh.write_obj_face_begin();
if (!flip) {
for (int j = 0; j < n; ++j) {
fh.write_obj_poly_v_normal(vert_indices[j] + vertex_offset,
fh.write_obj_face_v_normal(vert_indices[j] + vertex_offset,
normal_indices[j] + normal_offset);
}
}
else {
for (int k = 0; k < n; ++k) {
int j = k == 0 ? 0 : n - k;
fh.write_obj_poly_v_normal(vert_indices[j] + vertex_offset,
fh.write_obj_face_v_normal(vert_indices[j] + vertex_offset,
normal_indices[j] + normal_offset);
}
}
fh.write_obj_poly_end();
fh.write_obj_face_end();
}
void OBJWriter::write_vert_uv_indices(FormatHandler &fh,
@ -123,19 +123,19 @@ void OBJWriter::write_vert_uv_indices(FormatHandler &fh,
const int vertex_offset = offsets.vertex_offset + 1;
const int uv_offset = offsets.uv_vertex_offset + 1;
const int n = vert_indices.size();
fh.write_obj_poly_begin();
fh.write_obj_face_begin();
if (!flip) {
for (int j = 0; j < n; ++j) {
fh.write_obj_poly_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset);
fh.write_obj_face_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset);
}
}
else {
for (int k = 0; k < n; ++k) {
int j = k == 0 ? 0 : n - k;
fh.write_obj_poly_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset);
fh.write_obj_face_v_uv(vert_indices[j] + vertex_offset, uv_indices[j] + uv_offset);
}
}
fh.write_obj_poly_end();
fh.write_obj_face_end();
}
void OBJWriter::write_vert_indices(FormatHandler &fh,
@ -147,19 +147,19 @@ void OBJWriter::write_vert_indices(FormatHandler &fh,
{
const int vertex_offset = offsets.vertex_offset + 1;
const int n = vert_indices.size();
fh.write_obj_poly_begin();
fh.write_obj_face_begin();
if (!flip) {
for (int j = 0; j < n; ++j) {
fh.write_obj_poly_v(vert_indices[j] + vertex_offset);
fh.write_obj_face_v(vert_indices[j] + vertex_offset);
}
}
else {
for (int k = 0; k < n; ++k) {
int j = k == 0 ? 0 : n - k;
fh.write_obj_poly_v(vert_indices[j] + vertex_offset);
fh.write_obj_face_v(vert_indices[j] + vertex_offset);
}
}
fh.write_obj_poly_end();
fh.write_obj_face_end();
}
void OBJWriter::write_header() const
@ -295,7 +295,7 @@ void OBJWriter::write_uv_coords(FormatHandler &fh, OBJMesh &r_obj_mesh_data) con
});
}
void OBJWriter::write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data)
void OBJWriter::write_normals(FormatHandler &fh, OBJMesh &obj_mesh_data)
{
/* Poly normals should be calculated earlier via store_normal_coords_and_indices. */
const Span<float3> normal_coords = obj_mesh_data.get_normal_coords();
@ -305,7 +305,7 @@ void OBJWriter::write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data)
});
}
OBJWriter::func_vert_uv_normal_indices OBJWriter::get_poly_element_writer(
OBJWriter::func_vert_uv_normal_indices OBJWriter::get_face_element_writer(
const int total_uv_vertices) const
{
if (export_params_.export_normals) {
@ -330,18 +330,18 @@ static int get_smooth_group(const OBJMesh &mesh, const OBJExportParams &params,
return NEGATIVE_INIT;
}
int group = SMOOTH_GROUP_DISABLED;
if (mesh.is_ith_poly_smooth(face_idx)) {
if (mesh.is_ith_face_smooth(face_idx)) {
group = !params.export_smooth_groups ? SMOOTH_GROUP_DEFAULT : mesh.ith_smooth_group(face_idx);
}
return group;
}
void OBJWriter::write_poly_elements(FormatHandler &fh,
void OBJWriter::write_face_elements(FormatHandler &fh,
const IndexOffsets &offsets,
const OBJMesh &obj_mesh_data,
FunctionRef<const char *(int)> matname_fn)
{
const func_vert_uv_normal_indices poly_element_writer = get_poly_element_writer(
const func_vert_uv_normal_indices face_element_writer = get_face_element_writer(
obj_mesh_data.tot_uv_vertices());
const int tot_faces = obj_mesh_data.tot_faces();
@ -358,9 +358,9 @@ void OBJWriter::write_poly_elements(FormatHandler &fh,
int prev_i = obj_mesh_data.remap_face_index(idx - 1);
int i = obj_mesh_data.remap_face_index(idx);
Span<int> poly_vertex_indices = obj_mesh_data.calc_poly_vertex_indices(i);
Span<int> poly_uv_indices = obj_mesh_data.calc_poly_uv_indices(i);
Vector<int> poly_normal_indices = obj_mesh_data.calc_poly_normal_indices(i);
const Span<int> face_vertex_indices = obj_mesh_data.calc_face_vert_indices(i);
const Span<int> face_uv_indices = obj_mesh_data.get_face_uv_indices(i);
const Span<int> face_normal_indices = obj_mesh_data.get_face_normal_indices(i);
/* Write smoothing group if different from previous. */
{
@ -376,12 +376,12 @@ void OBJWriter::write_poly_elements(FormatHandler &fh,
Vector<float> &local_weights = group_weights.local();
local_weights.resize(tot_deform_groups);
const int16_t prev_group = idx == 0 ? NEGATIVE_INIT :
obj_mesh_data.get_poly_deform_group_index(
obj_mesh_data.get_face_deform_group_index(
prev_i, local_weights);
const int16_t group = obj_mesh_data.get_poly_deform_group_index(i, local_weights);
const int16_t group = obj_mesh_data.get_face_deform_group_index(i, local_weights);
if (group != prev_group) {
buf.write_obj_group(group == NOT_FOUND ? DEFORM_GROUP_DISABLED :
obj_mesh_data.get_poly_deform_group_name(group));
obj_mesh_data.get_face_deform_group_name(group));
}
}
@ -409,11 +409,11 @@ void OBJWriter::write_poly_elements(FormatHandler &fh,
}
/* Write face elements. */
(this->*poly_element_writer)(buf,
(this->*face_element_writer)(buf,
offsets,
poly_vertex_indices,
poly_uv_indices,
poly_normal_indices,
face_vertex_indices,
face_uv_indices,
face_normal_indices,
obj_mesh_data.is_mirrored_transform());
});
}
@ -465,7 +465,7 @@ void OBJWriter::write_nurbs_curve(FormatHandler &fh, const OBJCurve &obj_nurbs_d
for (int i = 0; i < total_control_points; i++) {
/* "+1" to keep indices one-based, even if they're negative: i.e., -1 refers to the
* last vertex coordinate, -2 second last. */
fh.write_obj_poly_v(-((i % total_vertices) + 1));
fh.write_obj_face_v(-((i % total_vertices) + 1));
}
fh.write_obj_curve_end();

View File

@ -81,22 +81,22 @@ class OBJWriter : NonMovable, NonCopyable {
bool write_colors) const;
/**
* Write UV vertex coordinates for all vertices as `vt u v`.
* \note UV indices are stored here, but written with polygons later.
* \note UV indices are stored here, but written with faces later.
*/
void write_uv_coords(FormatHandler &fh, OBJMesh &obj_mesh_data) const;
/**
* Write loop normals for smooth-shaded polygons, and polygon normals otherwise, as "vn x y z".
* \note Normal indices ares stored here, but written with polygons later.
* Write corner normals for smooth-shaded faces, and face normals otherwise, as "vn x y z".
* \note Normal indices ares stored here, but written with faces later.
*/
void write_poly_normals(FormatHandler &fh, OBJMesh &obj_mesh_data);
void write_normals(FormatHandler &fh, OBJMesh &obj_mesh_data);
/**
* Write polygon elements with at least vertex indices, and conditionally with UV vertex
* indices and polygon normal indices. Also write groups: smooth, vertex, material.
* Write face elements with at least vertex indices, and conditionally with UV vertex
* indices and face normal indices. Also write groups: smooth, vertex, material.
* The matname_fn turns a 0-indexed material slot number in an Object into the
* name used in the .obj file.
* \note UV indices were stored while writing UV vertices.
*/
void write_poly_elements(FormatHandler &fh,
void write_face_elements(FormatHandler &fh,
const IndexOffsets &offsets,
const OBJMesh &obj_mesh_data,
FunctionRef<const char *(int)> matname_fn);
@ -119,12 +119,12 @@ class OBJWriter : NonMovable, NonCopyable {
Span<int> normal_indices,
bool flip) const;
/**
* \return Writer function with appropriate polygon-element syntax.
* \return Writer function with appropriate face-element syntax.
*/
func_vert_uv_normal_indices get_poly_element_writer(int total_uv_vertices) const;
func_vert_uv_normal_indices get_face_element_writer(int total_uv_vertices) const;
/**
* Write one line of polygon indices as "f v1/vt1/vn1 v2/vt2/vn2 ...".
* Write one line of face indices as "f v1/vt1/vn1 v2/vt2/vn2 ...".
*/
void write_vert_uv_normal_indices(FormatHandler &fh,
const IndexOffsets &offsets,
@ -133,7 +133,7 @@ class OBJWriter : NonMovable, NonCopyable {
Span<int> normal_indices,
bool flip) const;
/**
* Write one line of polygon indices as "f v1//vn1 v2//vn2 ...".
* Write one line of face indices as "f v1//vn1 v2//vn2 ...".
*/
void write_vert_normal_indices(FormatHandler &fh,
const IndexOffsets &offsets,
@ -142,7 +142,7 @@ class OBJWriter : NonMovable, NonCopyable {
Span<int> normal_indices,
bool flip) const;
/**
* Write one line of polygon indices as "f v1/vt1 v2/vt2 ...".
* Write one line of face indices as "f v1/vt1 v2/vt2 ...".
*/
void write_vert_uv_indices(FormatHandler &fh,
const IndexOffsets &offsets,
@ -151,7 +151,7 @@ class OBJWriter : NonMovable, NonCopyable {
Span<int> /*normal_indices*/,
bool flip) const;
/**
* Write one line of polygon indices as "f v1 v2 ...".
* Write one line of face indices as "f v1 v2 ...".
*/
void write_vert_indices(FormatHandler &fh,
const IndexOffsets &offsets,

View File

@ -85,27 +85,27 @@ class FormatHandler : NonCopyable, NonMovable {
{
write_impl("vn {:.4f} {:.4f} {:.4f}\n", x, y, z);
}
void write_obj_poly_begin()
void write_obj_face_begin()
{
write_impl("f");
}
void write_obj_poly_end()
void write_obj_face_end()
{
write_obj_newline();
}
void write_obj_poly_v_uv_normal(int v, int uv, int n)
void write_obj_face_v_uv_normal(int v, int uv, int n)
{
write_impl(" {}/{}/{}", v, uv, n);
}
void write_obj_poly_v_normal(int v, int n)
void write_obj_face_v_normal(int v, int n)
{
write_impl(" {}//{}", v, n);
}
void write_obj_poly_v_uv(int v, int uv)
void write_obj_face_v_uv(int v, int uv)
{
write_impl(" {}/{}", v, uv);
}
void write_obj_poly_v(int v)
void write_obj_face_v(int v)
{
write_impl(" {}", v);
}

View File

@ -15,12 +15,14 @@
#include "BKE_mesh_mapping.hh"
#include "BKE_object.hh"
#include "BLI_array_utils.hh"
#include "BLI_listbase.h"
#include "BLI_map.hh"
#include "BLI_math_matrix.h"
#include "BLI_math_matrix.hh"
#include "BLI_math_rotation.h"
#include "BLI_sort.hh"
#include "BLI_vector_set.hh"
#include "DEG_depsgraph_query.hh"
@ -48,7 +50,6 @@ OBJMesh::OBJMesh(Depsgraph *depsgraph, const OBJExportParams &export_params, Obj
}
if (export_mesh_) {
mesh_positions_ = export_mesh_->vert_positions();
mesh_edges_ = export_mesh_->edges();
mesh_faces_ = export_mesh_->faces();
mesh_corner_verts_ = export_mesh_->corner_verts();
@ -89,7 +90,6 @@ void OBJMesh::set_mesh(Mesh *mesh)
}
owned_export_mesh_ = mesh;
export_mesh_ = owned_export_mesh_;
mesh_positions_ = mesh->vert_positions();
mesh_edges_ = mesh->edges();
mesh_faces_ = mesh->faces();
mesh_corner_verts_ = mesh->corner_verts();
@ -104,14 +104,14 @@ void OBJMesh::clear()
owned_export_mesh_ = nullptr;
}
export_mesh_ = nullptr;
loop_to_uv_index_ = {};
corner_to_uv_index_ = {};
uv_coords_.clear_and_shrink();
loop_to_normal_index_ = {};
normal_coords_.clear_and_shrink();
poly_order_ = {};
if (poly_smooth_groups_) {
MEM_freeN(poly_smooth_groups_);
poly_smooth_groups_ = nullptr;
corner_to_normal_index_ = {};
normal_coords_ = {};
face_order_ = {};
if (face_smooth_groups_) {
MEM_freeN(face_smooth_groups_);
face_smooth_groups_ = nullptr;
}
}
@ -195,17 +195,12 @@ int16_t OBJMesh::tot_materials() const
return this->materials.size();
}
int OBJMesh::tot_normal_indices() const
{
return tot_normal_indices_;
}
int OBJMesh::ith_smooth_group(const int face_index) const
{
/* Calculate smooth groups first: #OBJMesh::calc_smooth_groups. */
BLI_assert(tot_smooth_groups_ != -NEGATIVE_INIT);
BLI_assert(poly_smooth_groups_);
return poly_smooth_groups_[face_index];
BLI_assert(face_smooth_groups_);
return face_smooth_groups_[face_index];
}
void OBJMesh::calc_smooth_groups(const bool use_bitflags)
@ -213,7 +208,7 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
const bke::AttributeAccessor attributes = export_mesh_->attributes();
const VArraySpan sharp_edges = *attributes.lookup<bool>("sharp_edge", bke::AttrDomain::Edge);
const VArraySpan sharp_faces = *attributes.lookup<bool>("sharp_face", bke::AttrDomain::Face);
poly_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.size(),
face_smooth_groups_ = BKE_mesh_calc_smoothgroups(mesh_edges_.size(),
mesh_faces_,
export_mesh_->corner_edges(),
sharp_edges,
@ -222,7 +217,7 @@ void OBJMesh::calc_smooth_groups(const bool use_bitflags)
use_bitflags);
}
void OBJMesh::calc_poly_order()
void OBJMesh::calc_face_order()
{
const bke::AttributeAccessor attributes = export_mesh_->attributes();
const VArray<int> material_indices = *attributes.lookup_or_default<int>(
@ -232,13 +227,10 @@ void OBJMesh::calc_poly_order()
}
const VArraySpan<int> material_indices_span(material_indices);
poly_order_.reinitialize(material_indices_span.size());
for (const int i : material_indices_span.index_range()) {
poly_order_[i] = i;
}
/* Sort polygons by their material index. */
blender::parallel_sort(poly_order_.begin(), poly_order_.end(), [&](int a, int b) {
/* Sort faces by their material index. */
face_order_.reinitialize(material_indices_span.size());
array_utils::fill_index_range(face_order_.as_mutable_span());
blender::parallel_sort(face_order_.begin(), face_order_.end(), [&](int a, int b) {
int mat_a = material_indices_span[a];
int mat_b = material_indices_span[b];
if (mat_a != mat_b) {
@ -248,26 +240,21 @@ void OBJMesh::calc_poly_order()
});
}
bool OBJMesh::is_ith_poly_smooth(const int face_index) const
bool OBJMesh::is_ith_face_smooth(const int face_index) const
{
return !sharp_faces_[face_index];
}
const char *OBJMesh::get_object_name() const
StringRef OBJMesh::get_object_name() const
{
return object_name_.c_str();
return object_name_;
}
const char *OBJMesh::get_object_mesh_name() const
StringRef OBJMesh::get_object_mesh_name() const
{
return export_mesh_->id.name + 2;
}
Span<int> OBJMesh::calc_poly_vertex_indices(const int face_index) const
{
return mesh_corner_verts_.slice(mesh_faces_[face_index]);
}
void OBJMesh::store_uv_coords_and_indices()
{
const StringRef active_uv_name = CustomData_get_active_layer_name(&export_mesh_->corner_data,
@ -289,7 +276,7 @@ void OBJMesh::store_uv_coords_and_indices()
uv_to_index.reserve(export_mesh_->verts_num);
uv_coords_.reserve(export_mesh_->verts_num);
loop_to_uv_index_.reinitialize(uv_map.size());
corner_to_uv_index_.reinitialize(uv_map.size());
for (int index = 0; index < int(uv_map.size()); index++) {
float2 uv = uv_map[index];
@ -299,26 +286,10 @@ void OBJMesh::store_uv_coords_and_indices()
uv_to_index.add(uv, uv_index);
uv_coords_.append(uv);
}
loop_to_uv_index_[index] = uv_index;
corner_to_uv_index_[index] = uv_index;
}
}
Span<int> OBJMesh::calc_poly_uv_indices(const int face_index) const
{
if (uv_coords_.is_empty()) {
return {};
}
BLI_assert(face_index < export_mesh_->faces_num);
return loop_to_uv_index_.as_span().slice(mesh_faces_[face_index]);
}
float3 OBJMesh::calc_poly_normal(const int face_index) const
{
const Span<int> face_verts = mesh_corner_verts_.slice(mesh_faces_[face_index]);
const float3 normal = bke::mesh::face_normal_calc(mesh_positions_, face_verts);
return math::normalize(world_and_axes_normal_transform_ * normal);
}
/** Round \a f to \a round_digits decimal digits. */
static float round_float_to_n_digits(const float f, int round_digits)
{
@ -343,68 +314,59 @@ void OBJMesh::store_normal_coords_and_indices()
* Since normals are normalized, there will be no perceptible loss
* of precision when rounding to 4 digits. */
constexpr int round_digits = 4;
int cur_normal_index = 0;
Map<float3, int> normal_to_index;
VectorSet<float3> unique_normals;
/* We don't know how many unique normals there will be, but this is a guess. */
normal_to_index.reserve(export_mesh_->faces_num);
loop_to_normal_index_.reinitialize(export_mesh_->corners_num);
loop_to_normal_index_.fill(-1);
unique_normals.reserve(export_mesh_->faces_num);
corner_to_normal_index_.reinitialize(export_mesh_->corners_num);
Span<float3> corner_normals;
if (ELEM(export_mesh_->normals_domain(),
bke::MeshNormalDomain::Point,
bke::MeshNormalDomain::Corner))
{
corner_normals = export_mesh_->corner_normals();
}
/* Normals need inverse transpose of the regular matrix to handle non-uniform scale. */
const float3x3 transform = world_and_axes_normal_transform_;
auto add_normal = [&](const float3 &normal) {
const float3 transformed = math::normalize(transform * normal);
const float3 rounded = round_float3_to_n_digits(transformed, round_digits);
return unique_normals.index_of_or_add(rounded);
};
for (int face_index = 0; face_index < export_mesh_->faces_num; ++face_index) {
const IndexRange face = mesh_faces_[face_index];
bool need_per_loop_normals = !corner_normals.is_empty() || !(sharp_faces_[face_index]);
if (need_per_loop_normals) {
for (const int corner : face) {
BLI_assert(corner < export_mesh_->corners_num);
const float3 normal = math::normalize(world_and_axes_normal_transform_ *
corner_normals[corner]);
const float3 rounded = round_float3_to_n_digits(normal, round_digits);
int loop_norm_index = normal_to_index.lookup_default(rounded, -1);
if (loop_norm_index == -1) {
loop_norm_index = cur_normal_index++;
normal_to_index.add(rounded, loop_norm_index);
normal_coords_.append(rounded);
switch (export_mesh_->normals_domain()) {
case bke::MeshNormalDomain::Face: {
const Span<float3> face_normals = export_mesh_->face_normals();
for (const int face : mesh_faces_.index_range()) {
const int index = add_normal(face_normals[face]);
corner_to_normal_index_.as_mutable_span().slice(mesh_faces_[face]).fill(index);
}
break;
}
case bke::MeshNormalDomain::Point: {
const Span<float3> vert_normals = export_mesh_->vert_normals();
Array<int> vert_normal_indices(vert_normals.size());
const bke::LooseVertCache &verts_no_face = export_mesh_->verts_no_face();
if (verts_no_face.count == 0) {
for (const int vert : vert_normals.index_range()) {
vert_normal_indices[vert] = add_normal(vert_normals[vert]);
}
loop_to_normal_index_[corner] = loop_norm_index;
}
else {
for (const int vert : vert_normals.index_range()) {
if (!verts_no_face.is_loose_bits[vert]) {
vert_normal_indices[vert] = add_normal(vert_normals[vert]);
}
}
}
array_utils::gather(vert_normal_indices.as_span(),
mesh_corner_verts_,
corner_to_normal_index_.as_mutable_span());
break;
}
else {
float3 poly_normal = calc_poly_normal(face_index);
float3 rounded_poly_normal = round_float3_to_n_digits(poly_normal, round_digits);
int poly_norm_index = normal_to_index.lookup_default(rounded_poly_normal, -1);
if (poly_norm_index == -1) {
poly_norm_index = cur_normal_index++;
normal_to_index.add(rounded_poly_normal, poly_norm_index);
normal_coords_.append(rounded_poly_normal);
}
for (const int corner : face) {
BLI_assert(corner < export_mesh_->corners_num);
loop_to_normal_index_[corner] = poly_norm_index;
case bke::MeshNormalDomain::Corner: {
const Span<float3> corner_normals = export_mesh_->corner_normals();
for (const int corner : corner_normals.index_range()) {
corner_to_normal_index_[corner] = add_normal(corner_normals[corner]);
}
break;
}
}
tot_normal_indices_ = cur_normal_index;
}
Vector<int> OBJMesh::calc_poly_normal_indices(const int face_index) const
{
if (loop_to_normal_index_.is_empty()) {
return {};
}
const IndexRange face = mesh_faces_[face_index];
Vector<int> r_poly_normal_indices(face.size());
for (const int i : IndexRange(face.size())) {
r_poly_normal_indices[i] = loop_to_normal_index_[face[i]];
}
return r_poly_normal_indices;
normal_coords_ = unique_normals.as_span();
}
int OBJMesh::tot_deform_groups() const
@ -412,7 +374,7 @@ int OBJMesh::tot_deform_groups() const
return BLI_listbase_count(&export_mesh_->vertex_group_names);
}
int16_t OBJMesh::get_poly_deform_group_index(const int face_index,
int16_t OBJMesh::get_face_deform_group_index(const int face_index,
MutableSpan<float> group_weights) const
{
BLI_assert(face_index < export_mesh_->faces_num);
@ -444,7 +406,7 @@ int16_t OBJMesh::get_poly_deform_group_index(const int face_index,
return max_idx;
}
const char *OBJMesh::get_poly_deform_group_name(const int16_t def_group_index) const
const char *OBJMesh::get_face_deform_group_name(const int16_t def_group_index) const
{
const bDeformGroup &vertex_group = *(static_cast<bDeformGroup *>(
BLI_findlink(&export_mesh_->vertex_group_names, def_group_index)));

View File

@ -35,7 +35,6 @@ class OBJMesh : NonCopyable {
const Mesh *export_mesh_;
/** A mesh owned here, if created or modified for the export. May be null. */
Mesh *owned_export_mesh_ = nullptr;
Span<float3> mesh_positions_;
Span<int2> mesh_edges_;
OffsetIndices<int> mesh_faces_;
Span<int> mesh_corner_verts_;
@ -49,28 +48,15 @@ class OBJMesh : NonCopyable {
float3x3 world_and_axes_normal_transform_;
bool mirrored_transform_;
/**
* Per-loop UV index.
*/
Array<int> loop_to_uv_index_;
/*
* UV vertices.
*/
/** Per-corner UV index. */
Array<int> corner_to_uv_index_;
/** UV vertices. */
Vector<float2> uv_coords_;
/**
* Per-loop normal index.
*/
Array<int> loop_to_normal_index_;
/*
* Normal coords.
*/
Vector<float3> normal_coords_;
/*
* Total number of normal indices (maximum entry, plus 1, in
* the loop_to_norm_index_ vector).
*/
int tot_normal_indices_ = 0;
/** Index into #normal_coords_ for every face corner. */
Array<int> corner_to_normal_index_;
/** De-duplicated normals, indexed by #corner_to_normal_index_. */
Array<float3> normal_coords_;
/**
* Total smooth groups in an object.
*/
@ -78,11 +64,11 @@ class OBJMesh : NonCopyable {
/**
* Polygon aligned array of their smooth groups.
*/
int *poly_smooth_groups_ = nullptr;
int *face_smooth_groups_ = nullptr;
/**
* Order in which the polygons should be written into the file (sorted by material index).
* Order in which the faces should be written into the file (sorted by material index).
*/
Array<int> poly_order_;
Array<int> face_order_;
public:
Array<const Material *> materials;
@ -100,7 +86,6 @@ class OBJMesh : NonCopyable {
int tot_vertices() const;
int tot_faces() const;
int tot_uv_vertices() const;
int tot_normal_indices() const;
int tot_edges() const;
int tot_deform_groups() const;
bool is_mirrored_transform() const
@ -115,23 +100,23 @@ class OBJMesh : NonCopyable {
/**
* Calculate smooth groups of a smooth-shaded object.
* \return A polygon aligned array of smooth group numbers.
* \return A face aligned array of smooth group numbers.
*/
void calc_smooth_groups(bool use_bitflags);
/**
* \return Smooth group of the polygon at the given index.
* \return Smooth group of the face at the given index.
*/
int ith_smooth_group(int face_index) const;
bool is_ith_poly_smooth(int face_index) const;
bool is_ith_face_smooth(int face_index) const;
/**
* Get object name as it appears in the outliner.
*/
const char *get_object_name() const;
StringRef get_object_name() const;
/**
* Get Object's Mesh's name.
*/
const char *get_object_mesh_name() const;
StringRef get_object_mesh_name() const;
const float4x4 &get_world_axes_transform() const
{
@ -139,72 +124,86 @@ class OBJMesh : NonCopyable {
}
/**
* Calculate vertex indices of all vertices of the polygon at the given index.
* Calculate vertex indices of all vertices of the face at the given index.
*/
Span<int> calc_poly_vertex_indices(int face_index) const;
Span<int> calc_face_vert_indices(const int face_index) const
{
return mesh_corner_verts_.slice(mesh_faces_[face_index]);
}
/**
* Calculate UV vertex coordinates of an Object.
* Stores the coordinates and UV vertex indices in the member variables.
*/
void store_uv_coords_and_indices();
/* Get UV coordinates computed by store_uv_coords_and_indices. */
const Vector<float2> &get_uv_coords() const
const Span<float2> get_uv_coords() const
{
return uv_coords_;
}
Span<int> calc_poly_uv_indices(int face_index) const;
/**
* Calculate polygon normal of a polygon at given index.
*
* Should be used for flat-shaded polygons.
*/
float3 calc_poly_normal(int face_index) const;
Span<int> get_face_uv_indices(const int face_index) const
{
if (uv_coords_.is_empty()) {
return {};
}
BLI_assert(face_index < mesh_faces_.size());
return corner_to_uv_index_.as_span().slice(mesh_faces_[face_index]);
}
/**
* Find the unique normals of the mesh and stores them in a member variable.
* Also stores the indices into that vector with for each loop.
* Also stores the indices into that vector with for each corner.
*/
void store_normal_coords_and_indices();
/* Get normals calculate by store_normal_coords_and_indices. */
const Vector<float3> &get_normal_coords() const
Span<float3> get_normal_coords() const
{
return normal_coords_;
}
/**
* Calculate a polygon's polygon/loop normal indices.
* \param face_index: Index of the polygon to calculate indices for.
* \return Vector of normal indices, aligned with vertices of polygon.
* Calculate a face's face/corner normal indices.
* \param face_index: Index of the face to calculate indices for.
* \return Span of normal indices, aligned with vertices of face.
*/
Vector<int> calc_poly_normal_indices(int face_index) const;
Span<int> get_face_normal_indices(const int face_index) const
{
if (corner_to_normal_index_.is_empty()) {
return {};
}
const IndexRange face = mesh_faces_[face_index];
return corner_to_normal_index_.as_span().slice(face);
}
/**
* Find the most representative vertex group of a polygon.
* Find the most representative vertex group of a face.
*
* This adds up vertex group weights, and the group with the largest
* weight sum across the polygon is the one returned.
* weight sum across the face is the one returned.
*
* group_weights is temporary storage to avoid reallocations, it must
* be the size of amount of vertex groups in the object.
*/
int16_t get_poly_deform_group_index(int face_index, MutableSpan<float> group_weights) const;
int16_t get_face_deform_group_index(int face_index, MutableSpan<float> group_weights) const;
/**
* Find the name of the vertex deform group at the given index.
* The index indices into the #Object.defbase.
*/
const char *get_poly_deform_group_name(int16_t def_group_index) const;
const char *get_face_deform_group_name(int16_t def_group_index) const;
/**
* Calculate the order in which the polygons should be written into the file (sorted by material
* Calculate the order in which the faces should be written into the file (sorted by material
* index).
*/
void calc_poly_order();
void calc_face_order();
/**
* Remap polygon index according to polygon writing order.
* When materials are not being written, the polygon order array
* Remap face index according to face writing order.
* When materials are not being written, the face order array
* might be empty, in which case remap is a no-op.
*/
int remap_face_index(int i) const
{
return i < 0 || i >= poly_order_.size() ? i : poly_order_[i];
return i < 0 || i >= face_order_.size() ? i : face_order_[i];
}
const Mesh *get_mesh() const

View File

@ -185,7 +185,7 @@ static void write_mesh_objects(const Span<std::unique_ptr<OBJMesh>> exportable_a
index_offsets.append(offsets);
offsets.vertex_offset += obj.tot_vertices();
offsets.uv_vertex_offset += obj.tot_uv_vertices();
offsets.normal_offset += obj.tot_normal_indices();
offsets.normal_offset += obj.get_normal_coords().size();
}
/* Parallel over meshes: main result writing. */
@ -202,10 +202,10 @@ static void write_mesh_objects(const Span<std::unique_ptr<OBJMesh>> exportable_a
obj.calc_smooth_groups(export_params.smooth_groups_bitflags);
}
if (export_params.export_materials) {
obj.calc_poly_order();
obj.calc_face_order();
}
if (export_params.export_normals) {
obj_writer.write_poly_normals(fh, obj);
obj_writer.write_normals(fh, obj);
}
if (export_params.export_uv) {
obj_writer.write_uv_coords(fh, obj);
@ -219,7 +219,7 @@ static void write_mesh_objects(const Span<std::unique_ptr<OBJMesh>> exportable_a
}
return mtl_writer->mtlmaterial_name((*obj_mtlindices)[s]);
};
obj_writer.write_poly_elements(fh, index_offsets[i], obj, matname_fn);
obj_writer.write_face_elements(fh, index_offsets[i], obj, matname_fn);
}
obj_writer.write_edges_indices(fh, index_offsets[i], obj);

View File

@ -24,7 +24,7 @@
namespace blender::io::obj {
Vector<Vector<int>> fixup_invalid_polygon(Span<float3> vert_positions, Span<int> face_verts)
Vector<Vector<int>> fixup_invalid_face(Span<float3> vert_positions, Span<int> face_verts)
{
using namespace blender::meshintersect;
if (face_verts.size() < 3) {
@ -68,11 +68,9 @@ Vector<Vector<int>> fixup_invalid_polygon(Span<float3> vert_positions, Span<int>
int idx = f[i];
BLI_assert(idx >= 0 && idx < res.vert_orig.size());
if (res.vert_orig[idx].is_empty()) {
/* If we have a whole new vertex in the tessellated result,
* we won't quite know what to do with it (how to create normal/UV
* for it, for example). Such vertices are often due to
* self-intersecting polygons. Just skip them from the output
* face. */
/* If we have a whole new vertex in the tessellated result, we won't quite know what to do
* with it (how to create normal/UV for it, for example). Such vertices are often due to
* self-intersecting faces. Just skip them from the output face. */
}
else {
/* Vertex corresponds to one or more of the input vertices, use it. */

View File

@ -19,18 +19,17 @@ struct OBJImportParams;
namespace blender::io::obj {
/**
* Given an invalid polygon (with holes or duplicated vertex indices),
* turn it into possibly multiple polygons that are valid.
* Given an invalid face (with holes or duplicated vertex indices),
* turn it into possibly multiple faces that are valid.
*
* \param vertex_coords: Polygon's vertex coordinate list.
* \param face_vertex_indices: A polygon's indices that index into the given vertex coordinate
* \param vert_coords: Polygon's vertex coordinate list.
* \param face_vert_indices: A face's indices that index into the given vertex coordinate
* list.
*
* \return List of polygons with each element containing indices of one polygon. The indices
* are into face_vertex_indices array.
* \return List of faces with each element containing indices of one face. The indices
* are into face_vert_indices array.
*/
Vector<Vector<int>> fixup_invalid_polygon(Span<float3> vertex_coords,
Span<int> face_vertex_indices);
Vector<Vector<int>> fixup_invalid_face(Span<float3> vert_coords, Span<int> face_vert_indices);
/**
* Apply axes transform to the Object, and clamp object dimensions to the specified value.

View File

@ -229,7 +229,7 @@ static void geom_add_polygon(Geometry *geom,
const int group_index,
const bool shaded_smooth)
{
PolyElem curr_face;
FaceElem curr_face;
curr_face.shaded_smooth = shaded_smooth;
curr_face.material_index = material_index;
if (group_index >= 0) {
@ -243,7 +243,7 @@ static void geom_add_polygon(Geometry *geom,
bool face_valid = true;
p = drop_whitespace(p, end);
while (p < end && face_valid) {
PolyCorner corner;
FaceCorner corner;
bool got_uv = false, got_normal = false;
/* Parse vertex index. */
p = parse_int(p, end, INT32_MAX, corner.vert_index, false);
@ -313,7 +313,7 @@ static void geom_add_polygon(Geometry *geom,
if (face_valid) {
geom->face_elements_.append(curr_face);
geom->total_loops_ += curr_face.corner_count_;
geom->total_corner_ += curr_face.corner_count_;
}
else {
/* Remove just-added corners for the invalid face. */

View File

@ -48,17 +48,16 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
}
fixup_invalid_faces();
/* Total explicitly imported edges, not the ones belonging the polygons to be created. */
const int64_t tot_edges{mesh_geometry_.edges_.size()};
const int64_t tot_face_elems{mesh_geometry_.face_elements_.size()};
const int64_t tot_loops{mesh_geometry_.total_loops_};
Mesh *mesh = BKE_mesh_new_nomain(tot_verts_object, tot_edges, tot_face_elems, tot_loops);
/* Includes explicitly imported edges, not the ones belonging the faces to be created. */
Mesh *mesh = BKE_mesh_new_nomain(tot_verts_object,
mesh_geometry_.edges_.size(),
mesh_geometry_.face_elements_.size(),
mesh_geometry_.total_corner_);
Object *obj = BKE_object_add_only_object(bmain, OB_MESH, ob_name.c_str());
obj->data = BKE_object_obdata_add_from_type(bmain, OB_MESH, ob_name.c_str());
create_vertices(mesh);
create_faces_loops(mesh, import_params.import_vertex_groups && !import_params.use_split_groups);
create_faces(mesh, import_params.import_vertex_groups && !import_params.use_split_groups);
create_edges(mesh);
create_uv_verts(mesh);
create_normals(mesh);
@ -85,11 +84,11 @@ Object *MeshFromGeometry::create_mesh(Main *bmain,
void MeshFromGeometry::fixup_invalid_faces()
{
for (int64_t face_idx = 0; face_idx < mesh_geometry_.face_elements_.size(); ++face_idx) {
const PolyElem &curr_face = mesh_geometry_.face_elements_[face_idx];
const FaceElem &curr_face = mesh_geometry_.face_elements_[face_idx];
if (curr_face.corner_count_ < 3) {
/* Skip and remove faces that have fewer than 3 corners. */
mesh_geometry_.total_loops_ -= curr_face.corner_count_;
mesh_geometry_.total_corner_ -= curr_face.corner_count_;
mesh_geometry_.face_elements_.remove_and_reorder(face_idx);
--face_idx;
continue;
@ -122,7 +121,7 @@ void MeshFromGeometry::fixup_invalid_faces()
face_normals.reserve(curr_face.corner_count_);
for (int i = 0; i < curr_face.corner_count_; ++i) {
int corner_idx = curr_face.start_index_ + i;
const PolyCorner &corner = mesh_geometry_.face_corners_[corner_idx];
const FaceCorner &corner = mesh_geometry_.face_corners_[corner_idx];
face_verts.append(corner.vert_index);
face_normals.append(corner.vertex_normal_index);
face_uvs.append(corner.uv_vert_index);
@ -132,18 +131,18 @@ void MeshFromGeometry::fixup_invalid_faces()
bool face_shaded_smooth = curr_face.shaded_smooth;
/* Remove the invalid face. */
mesh_geometry_.total_loops_ -= curr_face.corner_count_;
mesh_geometry_.total_corner_ -= curr_face.corner_count_;
mesh_geometry_.face_elements_.remove_and_reorder(face_idx);
--face_idx;
Vector<Vector<int>> new_faces = fixup_invalid_polygon(global_vertices_.vertices, face_verts);
Vector<Vector<int>> new_faces = fixup_invalid_face(global_vertices_.vertices, face_verts);
/* Create the newly formed faces. */
for (Span<int> face : new_faces) {
if (face.size() < 3) {
continue;
}
PolyElem new_face{};
FaceElem new_face{};
new_face.vertex_group_index = face_vertex_group;
new_face.material_index = face_material;
new_face.shaded_smooth = face_shaded_smooth;
@ -154,7 +153,7 @@ void MeshFromGeometry::fixup_invalid_faces()
mesh_geometry_.face_corners_.append({face_verts[idx], face_uvs[idx], face_normals[idx]});
}
mesh_geometry_.face_elements_.append(new_face);
mesh_geometry_.total_loops_ += face.size();
mesh_geometry_.total_corner_ += face.size();
}
}
}
@ -180,7 +179,7 @@ void MeshFromGeometry::create_vertices(Mesh *mesh)
}
}
void MeshFromGeometry::create_faces_loops(Mesh *mesh, bool use_vertex_groups)
void MeshFromGeometry::create_faces(Mesh *mesh, bool use_vertex_groups)
{
MutableSpan<MDeformVert> dverts;
const int64_t total_verts = mesh_geometry_.get_vertex_count();
@ -196,18 +195,17 @@ void MeshFromGeometry::create_faces_loops(Mesh *mesh, bool use_vertex_groups)
bke::SpanAttributeWriter<bool> sharp_faces = attributes.lookup_or_add_for_write_span<bool>(
"sharp_face", bke::AttrDomain::Face);
const int64_t tot_face_elems{mesh->faces_num};
int tot_loop_idx = 0;
int corner_index = 0;
for (int face_idx = 0; face_idx < tot_face_elems; ++face_idx) {
const PolyElem &curr_face = mesh_geometry_.face_elements_[face_idx];
for (int face_idx = 0; face_idx < mesh->faces_num; ++face_idx) {
const FaceElem &curr_face = mesh_geometry_.face_elements_[face_idx];
if (curr_face.corner_count_ < 3) {
/* Don't add single vertex face, or edges. */
std::cerr << "Face with less than 3 vertices found, skipping." << std::endl;
continue;
}
face_offsets[face_idx] = tot_loop_idx;
face_offsets[face_idx] = corner_index;
sharp_faces.span[face_idx] = !curr_face.shaded_smooth;
material_indices.span[face_idx] = curr_face.material_index;
/* Importing obj files without any materials would result in negative indices, which is not
@ -217,8 +215,8 @@ void MeshFromGeometry::create_faces_loops(Mesh *mesh, bool use_vertex_groups)
}
for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
const PolyCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
corner_verts[tot_loop_idx] = mesh_geometry_.global_to_local_vertices_.lookup_default(
const FaceCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
corner_verts[corner_index] = mesh_geometry_.global_to_local_vertices_.lookup_default(
curr_corner.vert_index, 0);
/* Setup vertex group data, if needed. */
@ -226,13 +224,13 @@ void MeshFromGeometry::create_faces_loops(Mesh *mesh, bool use_vertex_groups)
const int group_index = curr_face.vertex_group_index;
/* NOTE: face might not belong to any group. */
if (group_index >= 0 || true) {
MDeformWeight *dw = BKE_defvert_ensure_index(&dverts[corner_verts[tot_loop_idx]],
MDeformWeight *dw = BKE_defvert_ensure_index(&dverts[corner_verts[corner_index]],
group_index);
dw->weight = 1.0f;
}
}
tot_loop_idx++;
corner_index++;
}
}
@ -267,7 +265,7 @@ void MeshFromGeometry::create_edges(Mesh *mesh)
}
/* Set argument `update` to true so that existing, explicitly imported edges can be merged
* with the new ones created from polygons. */
* with the new ones created from faces. */
bke::mesh_calc_edges(*mesh, true, false);
}
@ -281,22 +279,22 @@ void MeshFromGeometry::create_uv_verts(Mesh *mesh)
bke::SpanAttributeWriter<float2> uv_map = attributes.lookup_or_add_for_write_only_span<float2>(
"UVMap", bke::AttrDomain::Corner);
int tot_loop_idx = 0;
int corner_index = 0;
bool added_uv = false;
for (const PolyElem &curr_face : mesh_geometry_.face_elements_) {
for (const FaceElem &curr_face : mesh_geometry_.face_elements_) {
for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
const PolyCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
const FaceCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
if (curr_corner.uv_vert_index >= 0 &&
curr_corner.uv_vert_index < global_vertices_.uv_vertices.size())
{
uv_map.span[tot_loop_idx] = global_vertices_.uv_vertices[curr_corner.uv_vert_index];
uv_map.span[corner_index] = global_vertices_.uv_vertices[curr_corner.uv_vert_index];
added_uv = true;
}
else {
uv_map.span[tot_loop_idx] = {0.0f, 0.0f};
uv_map.span[corner_index] = {0.0f, 0.0f};
}
tot_loop_idx++;
corner_index++;
}
}
@ -368,27 +366,25 @@ void MeshFromGeometry::create_normals(Mesh *mesh)
return;
}
/* Custom normals can only be stored on face corners. */
if (mesh_geometry_.total_loops_ == 0) {
if (mesh_geometry_.total_corner_ == 0) {
return;
}
float(*corner_normals)[3] = static_cast<float(*)[3]>(
MEM_malloc_arrayN(mesh_geometry_.total_loops_, sizeof(float[3]), __func__));
int tot_loop_idx = 0;
for (const PolyElem &curr_face : mesh_geometry_.face_elements_) {
Array<float3> corner_normals(mesh_geometry_.total_corner_);
int corner_index = 0;
for (const FaceElem &curr_face : mesh_geometry_.face_elements_) {
for (int idx = 0; idx < curr_face.corner_count_; ++idx) {
const PolyCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
const FaceCorner &curr_corner = mesh_geometry_.face_corners_[curr_face.start_index_ + idx];
int n_index = curr_corner.vertex_normal_index;
float3 normal(0, 0, 0);
if (n_index >= 0 && n_index < global_vertices_.vert_normals.size()) {
normal = global_vertices_.vert_normals[n_index];
}
copy_v3_v3(corner_normals[tot_loop_idx], normal);
tot_loop_idx++;
corner_normals[corner_index] = normal;
corner_index++;
}
}
BKE_mesh_set_custom_normals(mesh, corner_normals);
MEM_freeN(corner_normals);
BKE_mesh_set_custom_normals(mesh, reinterpret_cast<float(*)[3]>(corner_normals.data()));
}
void MeshFromGeometry::create_colors(Mesh *mesh)

View File

@ -42,14 +42,14 @@ class MeshFromGeometry : NonMovable, NonCopyable {
/**
* OBJ files coming from the wild might have faces that are invalid in Blender
* (mostly with duplicate vertex indices, used by some software to indicate
* polygons with holes). This method tries to fix them up.
* faces with holes). This method tries to fix them up.
*/
void fixup_invalid_faces();
void create_vertices(Mesh *mesh);
/**
* Create polygons for the Mesh, set smooth shading flags, Materials.
* Create faces for the Mesh, set smooth shading flags, Materials.
*/
void create_faces_loops(Mesh *mesh, bool use_vertex_groups);
void create_faces(Mesh *mesh, bool use_vertex_groups);
/**
* Add explicitly imported OBJ edges to the mesh.
*/

View File

@ -44,7 +44,7 @@ struct GlobalVertices {
/**
* A face's corner in an OBJ file. In Blender, it translates to a corner vertex.
*/
struct PolyCorner {
struct FaceCorner {
/* These indices range from zero to total vertices in the OBJ file. */
int vert_index;
/* -1 is to indicate absence of UV vertices. Only < 0 condition should be checked since
@ -53,7 +53,7 @@ struct PolyCorner {
int vertex_normal_index = -1;
};
struct PolyElem {
struct FaceElem {
int vertex_group_index = -1;
int material_index = -1;
bool shaded_smooth = false;
@ -101,13 +101,13 @@ struct Geometry {
/* Loose edges in the file. */
Vector<int2> edges_;
Vector<PolyCorner> face_corners_;
Vector<PolyElem> face_elements_;
Vector<FaceCorner> face_corners_;
Vector<FaceElem> face_elements_;
bool has_invalid_faces_ = false;
bool has_vertex_groups_ = false;
NurbsElement nurbs_element_;
int total_loops_ = 0;
int total_corner_ = 0;
int get_vertex_count() const
{

View File

@ -40,8 +40,8 @@ namespace blender::io::obj {
struct Expectation {
std::string name;
short type; /* OB_MESH, ... */
int totvert, mesh_totedge_or_curve_endp, mesh_faces_num_or_curve_order,
mesh_totloop_or_curve_cyclic;
int totvert, mesh_edges_num_or_curve_endp, mesh_faces_num_or_curve_order,
mesh_corner_num_or_curve_cyclic;
float3 vert_first, vert_last;
float3 normal_first;
float2 uv_first;
@ -131,9 +131,9 @@ class OBJImportTest : public BlendfileLoadingBaseTest {
if (object->type == OB_MESH) {
Mesh *mesh = BKE_object_get_evaluated_mesh(object);
EXPECT_EQ(mesh->verts_num, exp.totvert);
EXPECT_EQ(mesh->edges_num, exp.mesh_totedge_or_curve_endp);
EXPECT_EQ(mesh->edges_num, exp.mesh_edges_num_or_curve_endp);
EXPECT_EQ(mesh->faces_num, exp.mesh_faces_num_or_curve_order);
EXPECT_EQ(mesh->corners_num, exp.mesh_totloop_or_curve_cyclic);
EXPECT_EQ(mesh->corners_num, exp.mesh_corner_num_or_curve_cyclic);
const Span<float3> positions = mesh->vert_positions();
EXPECT_V3_NEAR(positions.first(), exp.vert_first, 0.0001f);
EXPECT_V3_NEAR(positions.last(), exp.vert_last, 0.0001f);
@ -167,10 +167,10 @@ class OBJImportTest : public BlendfileLoadingBaseTest {
const Nurb *nurb = static_cast<const Nurb *>(BLI_findlink(&curve->nurb, 0));
int endpoint = (nurb->flagu & CU_NURB_ENDPOINT) ? 1 : 0;
EXPECT_EQ(nurb->orderu, exp.mesh_faces_num_or_curve_order);
EXPECT_EQ(endpoint, exp.mesh_totedge_or_curve_endp);
EXPECT_EQ(endpoint, exp.mesh_edges_num_or_curve_endp);
/* Cyclic flag is not set by the importer yet. */
// int cyclic = (nurb->flagu & CU_NURB_CYCLIC) ? 1 : 0;
// EXPECT_EQ(cyclic, exp.mesh_totloop_or_curve_cyclic);
// EXPECT_EQ(cyclic, exp.mesh_corner_num_or_curve_cyclic);
}
if (!exp.first_mat.empty()) {
Material *mat = BKE_object_material_get(object, 1);