Cycles: Use Blender headers to access geometry data, avoid copy

Since 34b4487844, attributes are always made mutable when
accessed from the RNA API. This can result in unnecessary copies, which
increases memory usage and reduces performance.

Cycles is the only user of the C++ RNA API, which we'd like to remove
in the future since it doesn't really make sense in the big picture.
Hydra is now a better alternative for external render engines.

To start that change and fix the unnecessary copies, this commit
moves to use Blender headers directly for accessing attribute and
other geometry data. This also removes the few places that still had
overhead from the RNA API after the changes ([0]) in 3.6. In a simple
test with a large grid, I observed a 1.76x performance improvement,
from 1.04 to 0.59 seconds to extract the mesh data to Cycles.

[0]: https://wiki.blender.org/wiki/Reference/Release_Notes/3.6/Cycles#Performance

Pull Request: https://projects.blender.org/blender/blender/pulls/112306
This commit is contained in:
Hans Goudey
2023-09-18 02:50:09 +02:00
committed by Hans Goudey
parent f122193e24
commit 2fac2228d0
10 changed files with 571 additions and 913 deletions

View File

@@ -41,6 +41,7 @@ set(SRC
viewport.cpp viewport.cpp
volume.cpp volume.cpp
attribute_convert.h
CCL_api.h CCL_api.h
device.h device.h
display_driver.h display_driver.h

View File

@@ -0,0 +1,94 @@
/* SPDX-FileCopyrightText: 2023 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#ifndef __BLENDER_ATTRIBUTE_CONVERT_H__
#define __BLENDER_ATTRIBUTE_CONVERT_H__
#include "util/array.h"
#include "util/color.h"
#include "util/param.h"
#include "util/types.h"
#include "BKE_attribute.hh"
#include "BLI_math_color.hh"
#include "BLI_math_quaternion_types.hh"
#include "BLI_math_vector_types.hh"
CCL_NAMESPACE_BEGIN
template<typename BlenderT> struct AttributeConverter {
using CyclesT = void;
};
template<> struct AttributeConverter<float> {
using CyclesT = float;
static constexpr auto type_desc = TypeFloat;
static CyclesT convert(const float &value)
{
return value;
}
};
template<> struct AttributeConverter<int> {
using CyclesT = float;
static constexpr auto type_desc = TypeFloat;
static CyclesT convert(const int &value)
{
return float(value);
}
};
template<> struct AttributeConverter<blender::float3> {
using CyclesT = float3;
static constexpr auto type_desc = TypeVector;
static CyclesT convert(const blender::float3 &value)
{
return make_float3(value[0], value[1], value[2]);
}
};
template<> struct AttributeConverter<blender::ColorGeometry4f> {
using CyclesT = float4;
static constexpr auto type_desc = TypeRGBA;
static CyclesT convert(const blender::ColorGeometry4f &value)
{
return make_float4(value[0], value[1], value[2], value[3]);
}
};
template<> struct AttributeConverter<blender::ColorGeometry4b> {
using CyclesT = float4;
static constexpr auto type_desc = TypeRGBA;
static CyclesT convert(const blender::ColorGeometry4b &value)
{
return color_srgb_to_linear(make_float4(byte_to_float(value[0]),
byte_to_float(value[1]),
byte_to_float(value[2]),
byte_to_float(value[3])));
}
};
template<> struct AttributeConverter<bool> {
using CyclesT = float;
static constexpr auto type_desc = TypeFloat;
static CyclesT convert(const bool &value)
{
return float(value);
}
};
template<> struct AttributeConverter<int8_t> {
using CyclesT = float;
static constexpr auto type_desc = TypeFloat;
static CyclesT convert(const int8_t &value)
{
return float(value);
}
};
template<> struct AttributeConverter<blender::math::Quaternion> {
using CyclesT = float4;
static constexpr auto type_desc = TypeFloat4;
static CyclesT convert(const blender::math::Quaternion &value)
{
return make_float4(value.w, value.x, value.y, value.z);
}
};
CCL_NAMESPACE_END
#endif /* __BLENDER_ATTRIBUTE_CONVERT_H__ */

View File

@@ -4,7 +4,7 @@
#include <optional> #include <optional>
#include "BKE_curves.hh" #include "blender/attribute_convert.h"
#include "blender/sync.h" #include "blender/sync.h"
#include "blender/util.h" #include "blender/util.h"
@@ -20,6 +20,8 @@
#include "util/hash.h" #include "util/hash.h"
#include "util/log.h" #include "util/log.h"
#include "BKE_curves.hh"
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
ParticleCurveData::ParticleCurveData() {} ParticleCurveData::ParticleCurveData() {}
@@ -576,7 +578,7 @@ void BlenderSync::sync_particle_hair(
if (!motion) { if (!motion) {
if (hair->need_attribute(scene, ATTR_STD_GENERATED)) { if (hair->need_attribute(scene, ATTR_STD_GENERATED)) {
float3 loc, size; float3 loc, size;
mesh_texture_space(b_mesh, loc, size); mesh_texture_space(*static_cast<const ::Mesh *>(b_mesh.ptr.data), loc, size);
Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED); Attribute *attr_generated = hair->attributes.add(ATTR_STD_GENERATED);
float3 *generated = attr_generated->data_float3(); float3 *generated = attr_generated->data_float3();
@@ -653,44 +655,6 @@ void BlenderSync::sync_particle_hair(
} }
} }
static const float *find_radius_attribute(BL::Curves b_curves)
{
for (BL::Attribute &b_attribute : b_curves.attributes) {
if (b_attribute.name() != "radius") {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
continue;
}
BL::FloatAttribute b_float_attribute{b_attribute};
if (b_float_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float *>(b_float_attribute.data[0].ptr.data);
}
return nullptr;
}
static const float (*find_position_attribute(BL::Curves b_curves))[3]
{
for (BL::Attribute &b_attribute : b_curves.attributes) {
if (b_attribute.name() != "position") {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
continue;
}
BL::FloatVectorAttribute b_float3_attribute{b_attribute};
if (b_float3_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float(*)[3]>(b_float3_attribute.data[0].ptr.data);
}
/* The position attribute must exist. */
assert(false);
return nullptr;
}
template<typename TypeInCycles, typename GetValueAtIndex> template<typename TypeInCycles, typename GetValueAtIndex>
static void fill_generic_attribute(const int num_curves, static void fill_generic_attribute(const int num_curves,
const int num_points, const int num_points,
@@ -718,16 +682,10 @@ static void fill_generic_attribute(const int num_curves,
} }
} }
static void attr_create_motion(Hair *hair, BL::Attribute &b_attribute, const float motion_scale) static void attr_create_motion(Hair *hair,
const blender::Span<blender::float3> src,
const float motion_scale)
{ {
if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
(b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR))
{
return;
}
BL::FloatVectorAttribute b_vector_attribute(b_attribute);
const float(*src)[3] = static_cast<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);
const int num_curve_keys = hair->get_curve_keys().size(); const int num_curve_keys = hair->get_curve_keys().size();
/* Find or add attribute */ /* Find or add attribute */
@@ -750,177 +708,97 @@ static void attr_create_motion(Hair *hair, BL::Attribute &b_attribute, const flo
} }
} }
static void attr_create_uv(AttributeSet &attributes,
const int num_curves,
const int num_points,
BL::Attribute &b_attribute,
const ustring name)
{
BL::Float2Attribute b_float2_attribute{b_attribute};
const float(*src)[2] = static_cast<const float(*)[2]>(b_float2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(ATTR_STD_UV, name);
float2 *data = attr->data_float2();
fill_generic_attribute(num_curves, num_points, data, ATTR_ELEMENT_CURVE, [&](int i) {
return make_float2(src[i][0], src[i][1]);
});
}
static void attr_create_generic(Scene *scene, static void attr_create_generic(Scene *scene,
Hair *hair, Hair *hair,
BL::Curves &b_curves, const blender::bke::CurvesGeometry &b_curves,
const bool need_motion, const bool need_motion,
const float motion_scale) const float motion_scale)
{ {
const int num_keys = b_curves.points.length(); const blender::bke::AttributeAccessor b_attributes = b_curves.attributes();
const int num_curves = b_curves.curves.length();
AttributeSet &attributes = hair->attributes; AttributeSet &attributes = hair->attributes;
static const ustring u_velocity("velocity"); static const ustring u_velocity("velocity");
const bool need_uv = hair->need_attribute(scene, ATTR_STD_UV); const bool need_uv = hair->need_attribute(scene, ATTR_STD_UV);
bool have_uv = false; bool have_uv = false;
for (BL::Attribute &b_attribute : b_curves.attributes) { b_attributes.for_all([&](const blender::bke::AttributeIDRef &id,
const ustring name{b_attribute.name().c_str()}; const blender::bke::AttributeMetaData meta_data) {
const ustring name{std::string_view(id.name())};
const BL::Attribute::domain_enum b_domain = b_attribute.domain(); const eAttrDomain b_domain = meta_data.domain;
const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type(); const eCustomDataType b_data_type = meta_data.data_type;
if (need_motion && name == u_velocity) { if (need_motion && name == u_velocity) {
attr_create_motion(hair, b_attribute, motion_scale); const blender::VArraySpan b_attr = *b_attributes.lookup<blender::float3>(id,
continue; ATTR_DOMAIN_POINT);
attr_create_motion(hair, b_attr, motion_scale);
return true;
} }
/* Weak, use first float2 attribute as standard UV. */ /* Weak, use first float2 attribute as standard UV. */
if (need_uv && !have_uv && b_data_type == BL::Attribute::data_type_FLOAT2 && if (need_uv && !have_uv && b_data_type == CD_PROP_FLOAT2 && b_domain == ATTR_DOMAIN_CURVE) {
b_domain == BL::Attribute::domain_CURVE) Attribute *attr = attributes.add(ATTR_STD_UV, name);
{
attr_create_uv(attributes, num_curves, num_keys, b_attribute, name); const blender::VArraySpan b_attr = *b_attributes.lookup<blender::float2>(id);
static_assert(sizeof(blender::float2) == sizeof(float2));
const blender::Span src = b_attr.cast<float2>();
std::copy(src.begin(), src.end(), attr->data_float2());
have_uv = true; have_uv = true;
continue; return true;
} }
if (!hair->need_attribute(scene, name)) { if (!hair->need_attribute(scene, name)) {
continue; return true;
} }
if (attributes.find(name)) { if (attributes.find(name)) {
continue; return true;
} }
const blender::bke::GAttributeReader b_attr = b_attributes.lookup(id);
AttributeElement element = ATTR_ELEMENT_NONE; AttributeElement element = ATTR_ELEMENT_NONE;
switch (b_domain) { switch (b_attr.domain) {
case BL::Attribute::domain_POINT: case ATTR_DOMAIN_POINT:
element = ATTR_ELEMENT_CURVE_KEY; element = ATTR_ELEMENT_CURVE_KEY;
break; break;
case BL::Attribute::domain_CURVE: case ATTR_DOMAIN_CURVE:
element = ATTR_ELEMENT_CURVE; element = ATTR_ELEMENT_CURVE;
break; break;
default: default:
break; return true;
} }
if (element == ATTR_ELEMENT_NONE) {
/* Not supported. */ blender::bke::attribute_math::convert_to_static_type(b_attr.varray.type(), [&](auto dummy) {
continue; using BlenderT = decltype(dummy);
} using Converter = typename ccl::AttributeConverter<BlenderT>;
switch (b_data_type) { using CyclesT = typename Converter::CyclesT;
case BL::Attribute::data_type_FLOAT: { if constexpr (!std::is_void_v<CyclesT>) {
BL::FloatAttribute b_float_attribute{b_attribute}; Attribute *attr = attributes.add(name, Converter::type_desc, element);
const float *src = static_cast<const float *>(b_float_attribute.data[0].ptr.data); CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float(); const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) { return src[i]; }); for (const int i : src.index_range()) {
break; data[i] = Converter::convert(src[i]);
}
} }
case BL::Attribute::data_type_BOOLEAN: { });
BL::BoolAttribute b_bool_attribute{b_attribute}; return true;
const bool *src = static_cast<const bool *>(b_bool_attribute.data[0].ptr.data); });
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
num_curves, num_keys, data, element, [&](int i) { return float(src[i]); });
break;
}
case BL::Attribute::data_type_INT: {
BL::IntAttribute b_int_attribute{b_attribute};
const int *src = static_cast<const int *>(b_int_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
num_curves, num_keys, data, element, [&](int i) { return float(src[i]); });
break;
}
case BL::Attribute::data_type_INT32_2D: {
BL::Int2Attribute b_int2_attribute{b_attribute};
const int2 *src = static_cast<const int2 *>(b_int2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float2(float(src[i][0]), float(src[i][1]));
});
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
const float(*src)[3] = static_cast<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float3(src[i][0], src[i][1], src[i][2]);
});
break;
}
case BL::Attribute::data_type_BYTE_COLOR: {
BL::ByteColorAttribute b_color_attribute{b_attribute};
const uchar(*src)[4] = static_cast<const uchar(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float4(color_srgb_to_linear(byte_to_float(src[i][0])),
color_srgb_to_linear(byte_to_float(src[i][1])),
color_srgb_to_linear(byte_to_float(src[i][2])),
color_srgb_to_linear(byte_to_float(src[i][3])));
});
break;
}
case BL::Attribute::data_type_FLOAT_COLOR: {
BL::FloatColorAttribute b_color_attribute{b_attribute};
const float(*src)[4] = static_cast<const float(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float4(src[i][0], src[i][1], src[i][2], src[i][3]);
});
break;
}
case BL::Attribute::data_type_FLOAT2: {
BL::Float2Attribute b_float2_attribute{b_attribute};
const float(*src)[2] = static_cast<const float(*)[2]>(b_float2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
fill_generic_attribute(num_curves, num_keys, data, element, [&](int i) {
return make_float2(src[i][0], src[i][1]);
});
break;
}
default:
/* Not supported. */
break;
}
}
} }
static float4 curve_point_as_float4(const float (*b_attr_position)[3], static float4 curve_point_as_float4(const blender::Span<blender::float3> b_positions,
const float *b_attr_radius, const blender::Span<float> b_radius,
const int index) const int index)
{ {
float4 mP = make_float4( float4 mP = make_float4(
b_attr_position[index][0], b_attr_position[index][1], b_attr_position[index][2], 0.0f); b_positions[index][0], b_positions[index][1], b_positions[index][2], 0.0f);
mP.w = b_attr_radius ? b_attr_radius[index] : 0.005f; mP.w = b_radius.is_empty() ? 0.005f : b_radius[index];
return mP; return mP;
} }
static float4 interpolate_curve_points(const float (*b_attr_position)[3], static float4 interpolate_curve_points(const blender::Span<blender::float3> b_positions,
const float *b_attr_radius, const blender::Span<float> b_radius,
const int first_point_index, const int first_point_index,
const int num_points, const int num_points,
const float step) const float step)
@@ -929,21 +807,21 @@ static float4 interpolate_curve_points(const float (*b_attr_position)[3],
const int point_a = clamp((int)curve_t, 0, num_points - 1); const int point_a = clamp((int)curve_t, 0, num_points - 1);
const int point_b = min(point_a + 1, num_points - 1); const int point_b = min(point_a + 1, num_points - 1);
const float t = curve_t - (float)point_a; const float t = curve_t - (float)point_a;
return mix(curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_a), return mix(curve_point_as_float4(b_positions, b_radius, first_point_index + point_a),
curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_b), curve_point_as_float4(b_positions, b_radius, first_point_index + point_b),
t); t);
} }
static void export_hair_curves(Scene *scene, static void export_hair_curves(Scene *scene,
Hair *hair, Hair *hair,
BL::Curves b_curves, const blender::bke::CurvesGeometry &b_curves,
const bool need_motion, const bool need_motion,
const float motion_scale) const float motion_scale)
{ {
const int num_keys = b_curves.points.length(); const blender::Span<blender::float3> positions = b_curves.positions();
const int num_curves = b_curves.curves.length(); const blender::OffsetIndices points_by_curve = b_curves.points_by_curve();
hair->resize_curves(num_curves, num_keys); hair->resize_curves(points_by_curve.size(), positions.size());
float3 *curve_keys = hair->get_curve_keys().data(); float3 *curve_keys = hair->get_curve_keys().data();
float *curve_radius = hair->get_curve_radius().data(); float *curve_radius = hair->get_curve_radius().data();
@@ -957,11 +835,14 @@ static void export_hair_curves(Scene *scene,
if (hair->need_attribute(scene, ATTR_STD_VERTEX_NORMAL)) { if (hair->need_attribute(scene, ATTR_STD_VERTEX_NORMAL)) {
/* Get geometry normals. */ /* Get geometry normals. */
float3 *attr_normal = hair->attributes.add(ATTR_STD_VERTEX_NORMAL)->data_float3(); float3 *attr_normal = hair->attributes.add(ATTR_STD_VERTEX_NORMAL)->data_float3();
int i = 0; vector<blender::float3> point_normals(positions.size());
for (BL::FloatVectorValueReadOnly &normal : b_curves.normals) { blender::bke::curves_normals_point_domain_calc(
attr_normal[i++] = get_float3(normal.vector()); b_curves, {point_normals.data(), int64_t(point_normals.size())});
for (const int i : positions.index_range()) {
attr_normal[i] = make_float3(point_normals[i][0], point_normals[i][1], point_normals[i][2]);
} }
} }
if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) { if (hair->need_attribute(scene, ATTR_STD_CURVE_INTERCEPT)) {
attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT)->data_float(); attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT)->data_float();
} }
@@ -970,42 +851,40 @@ static void export_hair_curves(Scene *scene,
} }
if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) { if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) {
float *attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM)->data_float(); float *attr_random = hair->attributes.add(ATTR_STD_CURVE_RANDOM)->data_float();
for (int i = 0; i < num_curves; i++) { for (const int i : points_by_curve.index_range()) {
attr_random[i] = hash_uint2_to_float(i, 0); attr_random[i] = hash_uint2_to_float(i, 0);
} }
} }
const int *point_offsets = static_cast<const int *>(b_curves.curve_offset_data[0].ptr.data); const blender::VArraySpan b_radius = *b_curves.attributes().lookup<float>("radius",
const float(*b_attr_position)[3] = find_position_attribute(b_curves); ATTR_DOMAIN_POINT);
const float *b_attr_radius = find_radius_attribute(b_curves);
std::copy(point_offsets, point_offsets + num_curves, curve_first_key); std::copy(points_by_curve.data().data(),
std::fill(curve_shader, curve_shader + num_curves, 0); points_by_curve.data().data() + points_by_curve.size(),
if (b_attr_radius) { curve_first_key);
std::copy(b_attr_radius, b_attr_radius + num_keys, curve_radius); std::fill(curve_shader, curve_shader + points_by_curve.size(), 0);
if (!b_radius.is_empty()) {
std::copy(b_radius.data(), b_radius.data() + positions.size(), curve_radius);
} }
else { else {
std::fill(curve_radius, curve_radius + num_keys, 0.005f); std::fill(curve_radius, curve_radius + positions.size(), 0.005f);
} }
/* Export curves and points. */ /* Export curves and points. */
for (int i = 0; i < num_curves; i++) { for (const int curve : points_by_curve.index_range()) {
const int first_point_index = point_offsets[i]; const blender::IndexRange points = points_by_curve[curve];
const int num_points = point_offsets[i + 1] - first_point_index;
float3 prev_co = zero_float3(); float3 prev_co = zero_float3();
float length = 0.0f; float length = 0.0f;
/* Position and radius. */ /* Position and radius. */
for (int j = 0; j < num_points; j++) { for (const int point : points) {
const int point = first_point_index + j; const float3 co = make_float3(positions[point][0], positions[point][1], positions[point][2]);
const float3 co = make_float3(
b_attr_position[point][0], b_attr_position[point][1], b_attr_position[point][2]);
curve_keys[point] = co; curve_keys[point] = co;
if (attr_length || attr_intercept) { if (attr_length || attr_intercept) {
if (j > 0) { if (point != points.first()) {
length += len(co - prev_co); length += len(co - prev_co);
} }
prev_co = co; prev_co = co;
@@ -1018,22 +897,23 @@ static void export_hair_curves(Scene *scene,
/* Normalized 0..1 attribute along curve. */ /* Normalized 0..1 attribute along curve. */
if (attr_intercept && length > 0.0f) { if (attr_intercept && length > 0.0f) {
for (int j = 1; j < num_points; j++) { for (const int point : points.drop_front(1)) {
const int point = first_point_index + j;
attr_intercept[point] /= length; attr_intercept[point] /= length;
} }
} }
/* Curve length. */ /* Curve length. */
if (attr_length) { if (attr_length) {
attr_length[i] = length; attr_length[curve] = length;
} }
} }
attr_create_generic(scene, hair, b_curves, need_motion, motion_scale); attr_create_generic(scene, hair, b_curves, need_motion, motion_scale);
} }
static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motion_step) static void export_hair_curves_motion(Hair *hair,
const blender::bke::CurvesGeometry &b_curves,
int motion_step)
{ {
/* Find or add attribute. */ /* Find or add attribute. */
Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
@@ -1046,30 +926,29 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
/* Export motion keys. */ /* Export motion keys. */
const int num_keys = hair->get_curve_keys().size(); const int num_keys = hair->get_curve_keys().size();
const int num_curves = b_curves.curves.length();
float4 *mP = attr_mP->data_float4() + motion_step * num_keys; float4 *mP = attr_mP->data_float4() + motion_step * num_keys;
bool have_motion = false; bool have_motion = false;
int num_motion_keys = 0; int num_motion_keys = 0;
int curve_index = 0; int curve_index = 0;
const int *point_offsets = static_cast<const int *>(b_curves.curve_offset_data[0].ptr.data); const blender::Span<blender::float3> b_positions = b_curves.positions();
const float(*b_attr_position)[3] = find_position_attribute(b_curves); const blender::OffsetIndices points_by_curve = b_curves.points_by_curve();
const float *b_attr_radius = find_radius_attribute(b_curves); const blender::VArraySpan b_radius = *b_curves.attributes().lookup<float>("radius",
ATTR_DOMAIN_POINT);
for (int i = 0; i < num_curves; i++) { for (const int i : points_by_curve.index_range()) {
const int first_point_index = point_offsets[i]; const blender::IndexRange points = points_by_curve[i];
const int num_points = point_offsets[i + 1] - first_point_index;
Hair::Curve curve = hair->get_curve(curve_index); Hair::Curve curve = hair->get_curve(curve_index);
curve_index++; curve_index++;
if (num_points == curve.num_keys) { if (points.size() == curve.num_keys) {
/* Number of keys matches. */ /* Number of keys matches. */
for (int i = 0; i < num_points; i++) { for (const int i : points.index_range()) {
int point = first_point_index + i; int point = points[i];
if (point < num_keys) { if (point < num_keys) {
mP[num_motion_keys] = curve_point_as_float4(b_attr_position, b_attr_radius, point); mP[num_motion_keys] = curve_point_as_float4(b_positions, b_radius, point);
num_motion_keys++; num_motion_keys++;
if (!have_motion) { if (!have_motion) {
@@ -1089,7 +968,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
for (int i = 0; i < curve.num_keys; i++) { for (int i = 0; i < curve.num_keys; i++) {
const float step = i * step_size; const float step = i * step_size;
mP[num_motion_keys] = interpolate_curve_points( mP[num_motion_keys] = interpolate_curve_points(
b_attr_position, b_attr_radius, first_point_index, num_points, step); b_positions, b_radius, points.start(), points.size(), step);
num_motion_keys++; num_motion_keys++;
} }
have_motion = true; have_motion = true;
@@ -1113,7 +992,8 @@ void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int
0.0f; 0.0f;
/* Convert Blender hair to Cycles curves. */ /* Convert Blender hair to Cycles curves. */
BL::Curves b_curves(b_ob_info.object_data); const blender::bke::CurvesGeometry &b_curves(
static_cast<const ::Curves *>(b_ob_info.object_data.ptr.data)->geometry.wrap());
if (motion) { if (motion) {
export_hair_curves_motion(hair, b_curves, motion_step); export_hair_curves_motion(hair, b_curves, motion_step);
} }

View File

@@ -4,6 +4,7 @@
#include <optional> #include <optional>
#include "blender/attribute_convert.h"
#include "blender/session.h" #include "blender/session.h"
#include "blender/sync.h" #include "blender/sync.h"
#include "blender/util.h" #include "blender/util.h"
@@ -27,14 +28,16 @@
#include "mikktspace.hh" #include "mikktspace.hh"
#include "DNA_meshdata_types.h" #include "BKE_attribute.hh"
#include "BKE_attribute_math.hh"
#include "BKE_mesh.hh"
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
/* Tangent Space */ /* Tangent Space */
template<bool is_subd> struct MikkMeshWrapper { template<bool is_subd> struct MikkMeshWrapper {
MikkMeshWrapper(const BL::Mesh &b_mesh, MikkMeshWrapper(const ::Mesh &b_mesh,
const char *layer_name, const char *layer_name,
const Mesh *mesh, const Mesh *mesh,
float3 *tangent, float3 *tangent,
@@ -52,7 +55,7 @@ template<bool is_subd> struct MikkMeshWrapper {
if (attr_orco) { if (attr_orco) {
orco = attr_orco->data_float3(); orco = attr_orco->data_float3();
float3 orco_size; float3 orco_size;
mesh_texture_space(*(BL::Mesh *)&b_mesh, orco_loc, orco_size); mesh_texture_space(b_mesh, orco_loc, orco_size);
inv_orco_size = 1.0f / orco_size; inv_orco_size = 1.0f / orco_size;
} }
} }
@@ -179,7 +182,7 @@ template<bool is_subd> struct MikkMeshWrapper {
}; };
static void mikk_compute_tangents( static void mikk_compute_tangents(
const BL::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render) const ::Mesh &b_mesh, const char *layer_name, Mesh *mesh, bool need_sign, bool active_render)
{ {
/* Create tangent attributes. */ /* Create tangent attributes. */
const bool is_subd = mesh->get_num_subd_faces(); const bool is_subd = mesh->get_num_subd_faces();
@@ -233,117 +236,10 @@ static void mikk_compute_tangents(
} }
} }
template<typename TypeInCycles, typename GetValueAtIndex> static void attr_create_motion(Mesh *mesh,
static void fill_generic_attribute(BL::Mesh &b_mesh, const blender::Span<blender::float3> b_attr,
TypeInCycles *data, const float motion_scale)
const BL::Attribute::domain_enum b_domain,
const bool subdivision,
const GetValueAtIndex &get_value_at_index)
{ {
switch (b_domain) {
case BL::Attribute::domain_CORNER: {
if (subdivision) {
const int polys_num = b_mesh.polygons.length();
if (polys_num == 0) {
return;
}
const int *face_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data);
for (int i = 0; i < polys_num; i++) {
const int poly_start = face_offsets[i];
const int poly_size = face_offsets[i + 1] - poly_start;
for (int j = 0; j < poly_size; j++) {
*data = get_value_at_index(poly_start + j);
data++;
}
}
}
else {
const int tris_num = b_mesh.loop_triangles.length();
const MLoopTri *looptris = static_cast<const MLoopTri *>(
b_mesh.loop_triangles[0].ptr.data);
for (int i = 0; i < tris_num; i++) {
const MLoopTri &tri = looptris[i];
data[i * 3 + 0] = get_value_at_index(tri.tri[0]);
data[i * 3 + 1] = get_value_at_index(tri.tri[1]);
data[i * 3 + 2] = get_value_at_index(tri.tri[2]);
}
}
break;
}
case BL::Attribute::domain_EDGE: {
const size_t edges_num = b_mesh.edges.length();
if (edges_num == 0) {
return;
}
if constexpr (std::is_same_v<TypeInCycles, uchar4>) {
/* uchar4 edge attributes do not exist, and averaging in place
* would not work. */
assert(0);
}
else {
const int2 *edges = static_cast<const int2 *>(b_mesh.edges[0].ptr.data);
const size_t verts_num = b_mesh.vertices.length();
vector<int> count(verts_num, 0);
/* Average edge attributes at vertices. */
for (int i = 0; i < edges_num; i++) {
TypeInCycles value = get_value_at_index(i);
const int2 &b_edge = edges[i];
data[b_edge[0]] += value;
data[b_edge[1]] += value;
count[b_edge[0]]++;
count[b_edge[1]]++;
}
for (size_t i = 0; i < verts_num; i++) {
if (count[i] > 1) {
data[i] /= (float)count[i];
}
}
}
break;
}
case BL::Attribute::domain_POINT: {
const int num_verts = b_mesh.vertices.length();
for (int i = 0; i < num_verts; i++) {
data[i] = get_value_at_index(i);
}
break;
}
case BL::Attribute::domain_FACE: {
if (subdivision) {
const int num_polygons = b_mesh.polygons.length();
for (int i = 0; i < num_polygons; i++) {
data[i] = get_value_at_index(i);
}
}
else {
const int tris_num = b_mesh.loop_triangles.length();
const int *looptri_faces = static_cast<const int *>(
b_mesh.loop_triangle_polygons[0].ptr.data);
for (int i = 0; i < tris_num; i++) {
data[i] = get_value_at_index(looptri_faces[i]);
}
}
break;
}
default: {
assert(false);
break;
}
}
}
static void attr_create_motion(Mesh *mesh, BL::Attribute &b_attribute, const float motion_scale)
{
if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
(b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR))
{
return;
}
BL::FloatVectorAttribute b_vector_attribute(b_attribute);
const int numverts = mesh->get_verts().size(); const int numverts = mesh->get_verts().size();
/* Find or add attribute */ /* Find or add attribute */
@@ -361,209 +257,193 @@ static void attr_create_motion(Mesh *mesh, BL::Attribute &b_attribute, const flo
float3 *mP = attr_mP->data_float3() + step * numverts; float3 *mP = attr_mP->data_float3() + step * numverts;
for (int i = 0; i < numverts; i++) { for (int i = 0; i < numverts; i++) {
mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time; mP[i] = P[i] + make_float3(b_attr[i][0], b_attr[i][1], b_attr[i][2]) * relative_time;
} }
} }
} }
static void attr_create_generic(Scene *scene, static void attr_create_generic(Scene *scene,
Mesh *mesh, Mesh *mesh,
BL::Mesh &b_mesh, const ::Mesh &b_mesh,
const bool subdivision, const bool subdivision,
const bool need_motion, const bool need_motion,
const float motion_scale) const float motion_scale)
{ {
blender::Span<MLoopTri> looptris;
blender::Span<int> looptri_faces;
if (!subdivision) {
looptris = b_mesh.looptris();
looptri_faces = b_mesh.looptri_faces();
}
const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes; AttributeSet &attributes = (subdivision) ? mesh->subd_attributes : mesh->attributes;
static const ustring u_velocity("velocity"); static const ustring u_velocity("velocity");
const ustring default_color_name{b_mesh.attributes.default_color_name().c_str()}; const ustring default_color_name{BKE_id_attributes_default_color_name(&b_mesh.id)};
for (BL::Attribute &b_attribute : b_mesh.attributes) { b_attributes.for_all([&](const blender::bke::AttributeIDRef &id,
const ustring name{b_attribute.name().c_str()}; const blender::bke::AttributeMetaData meta_data) {
const ustring name{std::string_view(id.name())};
const bool is_render_color = name == default_color_name; const bool is_render_color = name == default_color_name;
if (need_motion && name == u_velocity) { if (need_motion && name == u_velocity) {
const blender::VArraySpan b_attribute = *b_attributes.lookup<blender::float3>(
id, ATTR_DOMAIN_POINT);
attr_create_motion(mesh, b_attribute, motion_scale); attr_create_motion(mesh, b_attribute, motion_scale);
} }
if (!(mesh->need_attribute(scene, name) || if (!(mesh->need_attribute(scene, name) ||
(is_render_color && mesh->need_attribute(scene, ATTR_STD_VERTEX_COLOR)))) (is_render_color && mesh->need_attribute(scene, ATTR_STD_VERTEX_COLOR))))
{ {
continue; return true;
} }
if (attributes.find(name)) { if (attributes.find(name)) {
continue; return true;
} }
const BL::Attribute::domain_enum b_domain = b_attribute.domain(); eAttrDomain b_domain = meta_data.domain;
const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type(); if (b_domain == ATTR_DOMAIN_EDGE) {
/* Blender's attribute API handles edge to vertex attribute domain interpolation. */
b_domain = ATTR_DOMAIN_POINT;
}
const blender::bke::GAttributeReader b_attr = b_attributes.lookup(id, b_domain);
if (b_attr.varray.is_empty()) {
return true;
}
if (b_attr.domain == ATTR_DOMAIN_CORNER && meta_data.data_type == CD_PROP_BYTE_COLOR) {
Attribute *attr = attributes.add(name, TypeRGBA, ATTR_ELEMENT_CORNER_BYTE);
if (is_render_color) {
attr->std = ATTR_STD_VERTEX_COLOR;
}
uchar4 *data = attr->data_uchar4();
const blender::VArraySpan src = b_attr.varray.typed<blender::ColorGeometry4b>();
if (subdivision) {
for (const int i : src.index_range()) {
data[i] = make_uchar4(src[i][0], src[i][1], src[i][2], src[i][3]);
}
}
else {
for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i];
data[i * 3 + 0] = make_uchar4(
src[tri.tri[0]][0], src[tri.tri[0]][1], src[tri.tri[0]][2], src[tri.tri[0]][3]);
data[i * 3 + 1] = make_uchar4(
src[tri.tri[1]][0], src[tri.tri[1]][1], src[tri.tri[1]][2], src[tri.tri[1]][3]);
data[i * 3 + 2] = make_uchar4(
src[tri.tri[2]][0], src[tri.tri[2]][1], src[tri.tri[2]][2], src[tri.tri[2]][3]);
}
}
return true;
}
AttributeElement element = ATTR_ELEMENT_NONE; AttributeElement element = ATTR_ELEMENT_NONE;
switch (b_domain) { switch (b_domain) {
case BL::Attribute::domain_CORNER: case ATTR_DOMAIN_CORNER:
element = ATTR_ELEMENT_CORNER; element = ATTR_ELEMENT_CORNER;
break; break;
case BL::Attribute::domain_POINT: case ATTR_DOMAIN_POINT:
element = ATTR_ELEMENT_VERTEX; element = ATTR_ELEMENT_VERTEX;
break; break;
case BL::Attribute::domain_EDGE: case ATTR_DOMAIN_FACE:
element = ATTR_ELEMENT_VERTEX;
break;
case BL::Attribute::domain_FACE:
element = ATTR_ELEMENT_FACE; element = ATTR_ELEMENT_FACE;
break; break;
default: default:
break; assert(false);
return true;
} }
if (element == ATTR_ELEMENT_NONE) {
/* Not supported. */
continue;
}
switch (b_data_type) {
case BL::Attribute::data_type_FLOAT: {
BL::FloatAttribute b_float_attribute{b_attribute};
if (b_float_attribute.data.length() == 0) {
continue;
}
const float *src = static_cast<const float *>(b_float_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) { return src[i]; });
break;
}
case BL::Attribute::data_type_BOOLEAN: {
BL::BoolAttribute b_bool_attribute{b_attribute};
if (b_bool_attribute.data.length() == 0) {
continue;
}
const bool *src = static_cast<const bool *>(b_bool_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
b_mesh, data, b_domain, subdivision, [&](int i) { return (float)src[i]; });
break;
}
case BL::Attribute::data_type_INT: {
BL::IntAttribute b_int_attribute{b_attribute};
if (b_int_attribute.data.length() == 0) {
continue;
}
const int *src = static_cast<const int *>(b_int_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
fill_generic_attribute(
b_mesh, data, b_domain, subdivision, [&](int i) { return (float)src[i]; });
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
if (b_vector_attribute.data.length() == 0) {
continue;
}
const float(*src)[3] = static_cast<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return make_float3(src[i][0], src[i][1], src[i][2]);
});
break;
}
case BL::Attribute::data_type_BYTE_COLOR: {
BL::ByteColorAttribute b_color_attribute{b_attribute};
if (b_color_attribute.data.length() == 0) {
continue;
}
const uchar(*src)[4] = static_cast<const uchar(*)[4]>(b_color_attribute.data[0].ptr.data);
if (element == ATTR_ELEMENT_CORNER) { blender::bke::attribute_math::convert_to_static_type(b_attr.varray.type(), [&](auto dummy) {
element = ATTR_ELEMENT_CORNER_BYTE; using BlenderT = decltype(dummy);
} using Converter = typename ccl::AttributeConverter<BlenderT>;
Attribute *attr = attributes.add(name, TypeRGBA, element); using CyclesT = typename Converter::CyclesT;
if constexpr (!std::is_void_v<CyclesT>) {
Attribute *attr = attributes.add(name, Converter::type_desc, element);
if (is_render_color) { if (is_render_color) {
attr->std = ATTR_STD_VERTEX_COLOR; attr->std = ATTR_STD_VERTEX_COLOR;
} }
if (element == ATTR_ELEMENT_CORNER_BYTE) { CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
uchar4 *data = attr->data_uchar4();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
/* Compress/encode vertex color using the sRGB curve. */
return make_uchar4(src[i][0], src[i][1], src[i][2], src[i][3]);
});
}
else {
float4 *data = attr->data_float4();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return make_float4(color_srgb_to_linear(byte_to_float(src[i][0])),
color_srgb_to_linear(byte_to_float(src[i][1])),
color_srgb_to_linear(byte_to_float(src[i][2])),
color_srgb_to_linear(byte_to_float(src[i][3])));
});
}
break;
}
case BL::Attribute::data_type_FLOAT_COLOR: {
BL::FloatColorAttribute b_color_attribute{b_attribute};
if (b_color_attribute.data.length() == 0) {
continue;
}
const float(*src)[4] = static_cast<const float(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element); const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
if (is_render_color) { switch (b_attr.domain) {
attr->std = ATTR_STD_VERTEX_COLOR; case ATTR_DOMAIN_CORNER: {
if (subdivision) {
for (const int i : src.index_range()) {
data[i] = Converter::convert(src[i]);
}
}
else {
for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i];
data[i * 3 + 0] = Converter::convert(src[tri.tri[0]]);
data[i * 3 + 1] = Converter::convert(src[tri.tri[1]]);
data[i * 3 + 2] = Converter::convert(src[tri.tri[2]]);
}
}
break;
}
case ATTR_DOMAIN_POINT: {
for (const int i : src.index_range()) {
data[i] = Converter::convert(src[i]);
}
break;
}
case ATTR_DOMAIN_FACE: {
if (subdivision) {
for (const int i : src.index_range()) {
data[i] = Converter::convert(src[i]);
}
}
else {
for (const int i : looptris.index_range()) {
data[i] = Converter::convert(src[looptri_faces[i]]);
}
}
break;
}
default: {
assert(false);
break;
}
} }
}
});
return true;
});
}
float4 *data = attr->data_float4(); static set<ustring> get_blender_uv_names(const ::Mesh &b_mesh)
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) { {
return make_float4(src[i][0], src[i][1], src[i][2], src[i][3]); set<ustring> uv_names;
}); b_mesh.attributes().for_all([&](const blender::bke::AttributeIDRef &id,
break; const blender::bke::AttributeMetaData meta_data) {
if (meta_data.domain == ATTR_DOMAIN_CORNER && meta_data.data_type == CD_PROP_FLOAT2) {
if (!id.is_anonymous()) {
uv_names.emplace(std::string_view(id.name()));
} }
case BL::Attribute::data_type_FLOAT2: {
BL::Float2Attribute b_float2_attribute{b_attribute};
if (b_float2_attribute.data.length() == 0) {
continue;
}
const float(*src)[2] = static_cast<const float(*)[2]>(b_float2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return make_float2(src[i][0], src[i][1]);
});
break;
}
case BL::Attribute::data_type_INT32_2D: {
BL::Int2Attribute b_int2_attribute{b_attribute};
if (b_int2_attribute.data.length() == 0) {
continue;
}
const int2 *src = static_cast<const int2 *>(b_int2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
fill_generic_attribute(b_mesh, data, b_domain, subdivision, [&](int i) {
return make_float2(float(src[i][0]), float(src[i][1]));
});
break;
}
default:
/* Not supported. */
break;
} }
} return true;
});
return uv_names;
} }
/* Create uv map attributes. */ /* Create uv map attributes. */
static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh) static void attr_create_uv_map(Scene *scene,
Mesh *mesh,
const ::Mesh &b_mesh,
const set<ustring> &blender_uv_names)
{ {
if (!b_mesh.uv_layers.empty()) { const blender::Span<MLoopTri> looptris = b_mesh.looptris();
const int tris_num = b_mesh.loop_triangles.length(); const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
const MLoopTri *looptris = static_cast<const MLoopTri *>(b_mesh.loop_triangles[0].ptr.data); const ustring render_name(CustomData_get_render_layer_name(&b_mesh.loop_data, CD_PROP_FLOAT2));
if (!blender_uv_names.empty()) {
for (BL::MeshUVLoopLayer &l : b_mesh.uv_layers) { for (const ustring &uv_name : blender_uv_names) {
const bool active_render = l.active_render(); const bool active_render = uv_name == render_name;
AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE; AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
ustring uv_name = ustring(l.name().c_str());
AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE; AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
ustring tangent_name = ustring((string(l.name().c_str()) + ".tangent").c_str()); ustring tangent_name = ustring((string(uv_name) + ".tangent").c_str());
/* Denotes whether UV map was requested directly. */ /* Denotes whether UV map was requested directly. */
const bool need_uv = mesh->need_attribute(scene, uv_name) || const bool need_uv = mesh->need_attribute(scene, uv_name) ||
@@ -585,9 +465,10 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER); uv_attr = mesh->attributes.add(uv_name, TypeFloat2, ATTR_ELEMENT_CORNER);
} }
const float(*b_uv_map)[2] = static_cast<const float(*)[2]>(l.uv[0].ptr.data); const blender::VArraySpan b_uv_map = *b_attributes.lookup<blender::float2>(
uv_name.c_str(), ATTR_DOMAIN_CORNER);
float2 *fdata = uv_attr->data_float2(); float2 *fdata = uv_attr->data_float2();
for (int i = 0; i < tris_num; i++) { for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i]; const MLoopTri &tri = looptris[i];
fdata[i * 3 + 0] = make_float2(b_uv_map[tri.tri[0]][0], b_uv_map[tri.tri[0]][1]); fdata[i * 3 + 0] = make_float2(b_uv_map[tri.tri[0]][0], b_uv_map[tri.tri[0]][1]);
fdata[i * 3 + 1] = make_float2(b_uv_map[tri.tri[1]][0], b_uv_map[tri.tri[1]][1]); fdata[i * 3 + 1] = make_float2(b_uv_map[tri.tri[1]][0], b_uv_map[tri.tri[1]][1]);
@@ -598,10 +479,10 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
/* UV tangent */ /* UV tangent */
if (need_tangent) { if (need_tangent) {
AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE; AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
ustring sign_name = ustring((string(l.name().c_str()) + ".tangent_sign").c_str()); ustring sign_name = ustring((string(uv_name) + ".tangent_sign").c_str());
bool need_sign = (mesh->need_attribute(scene, sign_name) || bool need_sign = (mesh->need_attribute(scene, sign_name) ||
mesh->need_attribute(scene, sign_std)); mesh->need_attribute(scene, sign_std));
mikk_compute_tangents(b_mesh, l.name().c_str(), mesh, need_sign, active_render); mikk_compute_tangents(b_mesh, uv_name.c_str(), mesh, need_sign, active_render);
} }
/* Remove temporarily created UV attribute. */ /* Remove temporarily created UV attribute. */
if (!need_uv && uv_attr != NULL) { if (!need_uv && uv_attr != NULL) {
@@ -618,24 +499,25 @@ static void attr_create_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh)
} }
} }
static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivide_uvs) static void attr_create_subd_uv_map(Scene *scene,
Mesh *mesh,
const ::Mesh &b_mesh,
bool subdivide_uvs,
const set<ustring> &blender_uv_names)
{ {
const int polys_num = b_mesh.polygons.length(); const blender::OffsetIndices faces = b_mesh.faces();
if (polys_num == 0) { if (faces.is_empty()) {
return; return;
} }
const int *face_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data);
if (!b_mesh.uv_layers.empty()) { if (!blender_uv_names.empty()) {
BL::Mesh::uv_layers_iterator l; const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
int i = 0; const ustring render_name(CustomData_get_render_layer_name(&b_mesh.loop_data, CD_PROP_FLOAT2));
for (const ustring &uv_name : blender_uv_names) {
for (b_mesh.uv_layers.begin(l); l != b_mesh.uv_layers.end(); ++l, ++i) { const bool active_render = uv_name == render_name;
bool active_render = l->active_render();
AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE; AttributeStandard uv_std = (active_render) ? ATTR_STD_UV : ATTR_STD_NONE;
ustring uv_name = ustring(l->name().c_str());
AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE; AttributeStandard tangent_std = (active_render) ? ATTR_STD_UV_TANGENT : ATTR_STD_NONE;
ustring tangent_name = ustring((string(l->name().c_str()) + ".tangent").c_str()); ustring tangent_name = ustring((string(uv_name) + ".tangent").c_str());
/* Denotes whether UV map was requested directly. */ /* Denotes whether UV map was requested directly. */
const bool need_uv = mesh->need_attribute(scene, uv_name) || const bool need_uv = mesh->need_attribute(scene, uv_name) ||
@@ -659,13 +541,14 @@ static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
uv_attr->flags |= ATTR_SUBDIVIDED; uv_attr->flags |= ATTR_SUBDIVIDED;
} }
const blender::VArraySpan b_uv_map = *b_attributes.lookup<blender::float2>(
uv_name.c_str(), ATTR_DOMAIN_CORNER);
float2 *fdata = uv_attr->data_float2(); float2 *fdata = uv_attr->data_float2();
for (int i = 0; i < polys_num; i++) { for (const int i : faces.index_range()) {
const int poly_start = face_offsets[i]; const blender::IndexRange face = faces[i];
const int poly_size = face_offsets[i + 1] - poly_start; for (const int corner : face) {
for (int j = 0; j < poly_size; j++) { *(fdata++) = make_float2(b_uv_map[corner][0], b_uv_map[corner][1]);
*(fdata++) = get_float2(l->data[poly_start + j].uv());
} }
} }
} }
@@ -673,10 +556,10 @@ static void attr_create_subd_uv_map(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh,
/* UV tangent */ /* UV tangent */
if (need_tangent) { if (need_tangent) {
AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE; AttributeStandard sign_std = (active_render) ? ATTR_STD_UV_TANGENT_SIGN : ATTR_STD_NONE;
ustring sign_name = ustring((string(l->name().c_str()) + ".tangent_sign").c_str()); ustring sign_name = ustring((string(uv_name) + ".tangent_sign").c_str());
bool need_sign = (mesh->need_attribute(scene, sign_name) || bool need_sign = (mesh->need_attribute(scene, sign_name) ||
mesh->need_attribute(scene, sign_std)); mesh->need_attribute(scene, sign_std));
mikk_compute_tangents(b_mesh, l->name().c_str(), mesh, need_sign, active_render); mikk_compute_tangents(b_mesh, uv_name.c_str(), mesh, need_sign, active_render);
} }
/* Remove temporarily created UV attribute. */ /* Remove temporarily created UV attribute. */
if (!need_uv && uv_attr != NULL) { if (!need_uv && uv_attr != NULL) {
@@ -717,16 +600,16 @@ class VertexAverageComparator {
const array<float3> &verts_; const array<float3> &verts_;
}; };
static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, bool subdivision) static void attr_create_pointiness(Mesh *mesh,
const blender::Span<blender::float3> positions,
const blender::Span<blender::float3> b_vert_normals,
const blender::Span<blender::int2> edges,
bool subdivision)
{ {
if (!mesh->need_attribute(scene, ATTR_STD_POINTINESS)) { const int num_verts = positions.size();
if (positions.is_empty()) {
return; return;
} }
const int num_verts = b_mesh.vertices.length();
if (num_verts == 0) {
return;
}
const float(*positions)[3] = static_cast<const float(*)[3]>(b_mesh.vertices[0].ptr.data);
/* STEP 1: Find out duplicated vertices and point duplicates to a single /* STEP 1: Find out duplicated vertices and point duplicates to a single
* original vertex. * original vertex.
@@ -782,8 +665,6 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
*/ */
vector<float3> vert_normal(num_verts, zero_float3()); vector<float3> vert_normal(num_verts, zero_float3());
/* First we accumulate all vertex normals in the original index. */ /* First we accumulate all vertex normals in the original index. */
const float(*b_vert_normals)[3] = static_cast<const float(*)[3]>(
b_mesh.vertex_normals[0].ptr.data);
for (int vert_index = 0; vert_index < num_verts; ++vert_index) { for (int vert_index = 0; vert_index < num_verts; ++vert_index) {
const float *b_vert_normal = b_vert_normals[vert_index]; const float *b_vert_normal = b_vert_normals[vert_index];
const int orig_index = vert_orig_index[vert_index]; const int orig_index = vert_orig_index[vert_index];
@@ -803,11 +684,8 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
EdgeMap visited_edges; EdgeMap visited_edges;
memset(&counter[0], 0, sizeof(int) * counter.size()); memset(&counter[0], 0, sizeof(int) * counter.size());
const int2 *edges = static_cast<int2 *>(b_mesh.edges[0].ptr.data); for (const int i : edges.index_range()) {
const int edges_num = b_mesh.edges.length(); const blender::int2 b_edge = edges[i];
for (int i = 0; i < edges_num; i++) {
const int2 &b_edge = edges[i];
const int v0 = vert_orig_index[b_edge[0]]; const int v0 = vert_orig_index[b_edge[0]];
const int v1 = vert_orig_index[b_edge[1]]; const int v1 = vert_orig_index[b_edge[1]];
if (visited_edges.exists(v0, v1)) { if (visited_edges.exists(v0, v1)) {
@@ -844,8 +722,8 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
memcpy(data, &raw_data[0], sizeof(float) * raw_data.size()); memcpy(data, &raw_data[0], sizeof(float) * raw_data.size());
memset(&counter[0], 0, sizeof(int) * counter.size()); memset(&counter[0], 0, sizeof(int) * counter.size());
visited_edges.clear(); visited_edges.clear();
for (int i = 0; i < edges_num; i++) { for (const int i : edges.index_range()) {
const int2 &b_edge = edges[i]; const blender::int2 b_edge = edges[i];
const int v0 = vert_orig_index[b_edge[0]]; const int v0 = vert_orig_index[b_edge[0]];
const int v1 = vert_orig_index[b_edge[1]]; const int v1 = vert_orig_index[b_edge[1]];
if (visited_edges.exists(v0, v1)) { if (visited_edges.exists(v0, v1)) {
@@ -867,27 +745,6 @@ static void attr_create_pointiness(Scene *scene, Mesh *mesh, BL::Mesh &b_mesh, b
} }
} }
static const int *find_corner_vert_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_CORNER) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_INT) {
continue;
}
if (b_attribute.name() != ".corner_vert") {
continue;
}
BL::IntAttribute b_int_attribute{b_attribute};
if (b_int_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const int *>(b_int_attribute.data[0].ptr.data);
}
return nullptr;
}
/* The Random Per Island attribute is a random float associated with each /* The Random Per Island attribute is a random float associated with each
* connected component (island) of the mesh. The attribute is computed by * connected component (island) of the mesh. The attribute is computed by
* first classifying the vertices into different sets using a Disjoint Set * first classifying the vertices into different sets using a Disjoint Set
@@ -900,25 +757,23 @@ static const int *find_corner_vert_attribute(BL::Mesh b_mesh)
* making the output unsafe to hash. */ * making the output unsafe to hash. */
static void attr_create_random_per_island(Scene *scene, static void attr_create_random_per_island(Scene *scene,
Mesh *mesh, Mesh *mesh,
BL::Mesh &b_mesh, const ::Mesh &b_mesh,
bool subdivision) bool subdivision)
{ {
if (!mesh->need_attribute(scene, ATTR_STD_RANDOM_PER_ISLAND)) { if (!mesh->need_attribute(scene, ATTR_STD_RANDOM_PER_ISLAND)) {
return; return;
} }
int number_of_vertices = b_mesh.vertices.length(); if (b_mesh.totvert == 0) {
if (number_of_vertices == 0) {
return; return;
} }
DisjointSet vertices_sets(number_of_vertices); DisjointSet vertices_sets(b_mesh.totvert);
const int2 *edges = static_cast<int2 *>(b_mesh.edges[0].ptr.data); const blender::Span<blender::int2> edges = b_mesh.edges();
const int edges_num = b_mesh.edges.length(); const blender::Span<int> corner_verts = b_mesh.corner_verts();
const int *corner_verts = find_corner_vert_attribute(b_mesh);
for (int i = 0; i < edges_num; i++) { for (const int i : edges.index_range()) {
vertices_sets.join(edges[i][0], edges[i][1]); vertices_sets.join(edges[i][0], edges[i][1]);
} }
@@ -927,21 +782,19 @@ static void attr_create_random_per_island(Scene *scene,
float *data = attribute->data_float(); float *data = attribute->data_float();
if (!subdivision) { if (!subdivision) {
const int tris_num = b_mesh.loop_triangles.length(); const blender::Span<MLoopTri> looptris = b_mesh.looptris();
if (tris_num != 0) { if (!looptris.is_empty()) {
const MLoopTri *looptris = static_cast<const MLoopTri *>(b_mesh.loop_triangles[0].ptr.data); for (const int i : looptris.index_range()) {
for (int i = 0; i < tris_num; i++) {
const int vert = corner_verts[looptris[i].tri[0]]; const int vert = corner_verts[looptris[i].tri[0]];
data[i] = hash_uint_to_float(vertices_sets.find(vert)); data[i] = hash_uint_to_float(vertices_sets.find(vert));
} }
} }
} }
else { else {
const int polys_num = b_mesh.polygons.length(); const blender::OffsetIndices<int> faces = b_mesh.faces();
if (polys_num != 0) { if (!faces.is_empty()) {
const int *face_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data); for (const int i : faces.index_range()) {
for (int i = 0; i < polys_num; i++) { const int vert = corner_verts[faces[i].start()];
const int vert = corner_verts[face_offsets[i]];
data[i] = hash_uint_to_float(vertices_sets.find(vert)); data[i] = hash_uint_to_float(vertices_sets.find(vert));
} }
} }
@@ -950,118 +803,38 @@ static void attr_create_random_per_island(Scene *scene,
/* Create Mesh */ /* Create Mesh */
static const int *find_material_index_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_FACE) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_INT) {
continue;
}
if (b_attribute.name() != "material_index") {
continue;
}
BL::IntAttribute b_int_attribute{b_attribute};
if (b_int_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const int *>(b_int_attribute.data[0].ptr.data);
}
return nullptr;
}
static const bool *find_sharp_face_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_FACE) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_BOOLEAN) {
continue;
}
if (b_attribute.name() != "sharp_face") {
continue;
}
BL::IntAttribute b_int_attribute{b_attribute};
if (b_int_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const bool *>(b_int_attribute.data[0].ptr.data);
}
return nullptr;
}
static const float *find_edge_crease_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_EDGE) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
continue;
}
if (b_attribute.name() != "crease_edge") {
continue;
}
BL::FloatAttribute b_float_attribute{b_attribute};
if (b_float_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float *>(b_float_attribute.data[0].ptr.data);
}
return nullptr;
}
static const float *find_vert_crease_attribute(BL::Mesh b_mesh)
{
for (BL::Attribute &b_attribute : b_mesh.attributes) {
if (b_attribute.domain() != BL::Attribute::domain_POINT) {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
continue;
}
if (b_attribute.name() != "crease_vert") {
continue;
}
BL::FloatAttribute b_float_attribute{b_attribute};
if (b_float_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float *>(b_float_attribute.data[0].ptr.data);
}
return nullptr;
}
static void create_mesh(Scene *scene, static void create_mesh(Scene *scene,
Mesh *mesh, Mesh *mesh,
BL::Mesh &b_mesh, const ::Mesh &b_mesh,
const array<Node *> &used_shaders, const array<Node *> &used_shaders,
const bool need_motion, const bool need_motion,
const float motion_scale, const float motion_scale,
const bool subdivision = false, const bool subdivision = false,
const bool subdivide_uvs = true) const bool subdivide_uvs = true)
{ {
const int numverts = b_mesh.vertices.length(); const blender::Span<blender::float3> positions = b_mesh.vert_positions();
const int polys_num = b_mesh.polygons.length(); const blender::OffsetIndices faces = b_mesh.faces();
int numfaces = (!subdivision) ? b_mesh.loop_triangles.length() : b_mesh.polygons.length(); const blender::Span<int> corner_verts = b_mesh.corner_verts();
const int numcorners = b_mesh.loops.length(); const blender::bke::AttributeAccessor b_attributes = b_mesh.attributes();
bool use_loop_normals = b_mesh.use_auto_smooth() && int numfaces = (!subdivision) ? b_mesh.looptris().size() : faces.size();
bool use_loop_normals = (b_mesh.flag & ME_AUTOSMOOTH) &&
(mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK); (mesh->get_subdivision_type() != Mesh::SUBDIVISION_CATMULL_CLARK);
/* If no faces, create empty mesh. */ /* If no faces, create empty mesh. */
if (numfaces == 0) { if (faces.is_empty()) {
return; return;
} }
const float(*positions)[3] = static_cast<const float(*)[3]>(b_mesh.vertices[0].ptr.data); const blender::VArraySpan material_indices = *b_attributes.lookup<int>("material_index",
const int *corner_verts = find_corner_vert_attribute(b_mesh); ATTR_DOMAIN_FACE);
const int *material_indices = find_material_index_attribute(b_mesh); const blender::VArraySpan sharp_faces = *b_attributes.lookup<bool>("sharp_face",
const bool *sharp_faces = find_sharp_face_attribute(b_mesh); ATTR_DOMAIN_FACE);
const float(*corner_normals)[3] = nullptr; blender::Span<blender::float3> corner_normals;
if (use_loop_normals) { if (use_loop_normals) {
corner_normals = static_cast<const float(*)[3]>(b_mesh.corner_normals[0].ptr.data); corner_normals = {
static_cast<const blender::float3 *>(CustomData_get_layer(&b_mesh.loop_data, CD_NORMAL)),
corner_verts.size()};
} }
int numngons = 0; int numngons = 0;
@@ -1070,22 +843,20 @@ static void create_mesh(Scene *scene,
numtris = numfaces; numtris = numfaces;
} }
else { else {
const int *face_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data); const blender::OffsetIndices faces = b_mesh.faces();
for (int i = 0; i < polys_num; i++) { for (const int i : faces.index_range()) {
const int poly_start = face_offsets[i]; numngons += (faces[i].size() == 4) ? 0 : 1;
const int poly_size = face_offsets[i + 1] - poly_start;
numngons += (poly_size == 4) ? 0 : 1;
} }
} }
/* allocate memory */ /* allocate memory */
if (subdivision) { if (subdivision) {
mesh->resize_subd_faces(numfaces, numngons, numcorners); mesh->resize_subd_faces(numfaces, numngons, corner_verts.size());
} }
mesh->resize_mesh(numverts, numtris); mesh->resize_mesh(positions.size(), numtris);
float3 *verts = mesh->get_verts().data(); float3 *verts = mesh->get_verts().data();
for (int i = 0; i < numverts; i++) { for (const int i : positions.index_range()) {
verts[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]); verts[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]);
} }
@@ -1093,31 +864,43 @@ static void create_mesh(Scene *scene,
Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL); Attribute *attr_N = attributes.add(ATTR_STD_VERTEX_NORMAL);
float3 *N = attr_N->data_float3(); float3 *N = attr_N->data_float3();
if (subdivision || !(use_loop_normals && corner_normals)) { if (subdivision || !(use_loop_normals && !corner_normals.is_empty())) {
const float(*b_vert_normals)[3] = static_cast<const float(*)[3]>( const blender::Span<blender::float3> vert_normals = b_mesh.vert_normals();
b_mesh.vertex_normals[0].ptr.data); for (const int i : vert_normals.index_range()) {
for (int i = 0; i < numverts; i++) { N[i] = make_float3(vert_normals[i][0], vert_normals[i][1], vert_normals[i][2]);
const float *b_vert_normal = b_vert_normals[i];
N[i] = make_float3(b_vert_normal[0], b_vert_normal[1], b_vert_normal[2]);
} }
} }
const set<ustring> blender_uv_names = get_blender_uv_names(b_mesh);
/* create generated coordinates from undeformed coordinates */ /* create generated coordinates from undeformed coordinates */
const bool need_default_tangent = (subdivision == false) && (b_mesh.uv_layers.empty()) && const bool need_default_tangent = (subdivision == false) && (blender_uv_names.empty()) &&
(mesh->need_attribute(scene, ATTR_STD_UV_TANGENT)); (mesh->need_attribute(scene, ATTR_STD_UV_TANGENT));
if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) { if (mesh->need_attribute(scene, ATTR_STD_GENERATED) || need_default_tangent) {
const float(*orco)[3] = static_cast<const float(*)[3]>(
CustomData_get_layer(&b_mesh.vert_data, CD_ORCO));
Attribute *attr = attributes.add(ATTR_STD_GENERATED); Attribute *attr = attributes.add(ATTR_STD_GENERATED);
attr->flags |= ATTR_SUBDIVIDED; attr->flags |= ATTR_SUBDIVIDED;
float3 loc, size; float3 loc, size;
mesh_texture_space(b_mesh, loc, size); mesh_texture_space(b_mesh, loc, size);
float3 *generated = attr->data_float3(); float texspace_location[3], texspace_size[3];
size_t i = 0; BKE_mesh_texspace_get(const_cast<::Mesh *>(b_mesh.texcomesh ? b_mesh.texcomesh : &b_mesh),
texspace_location,
texspace_size);
BL::Mesh::vertices_iterator v; float3 *generated = attr->data_float3();
for (b_mesh.vertices.begin(v); v != b_mesh.vertices.end(); ++v) {
generated[i++] = get_float3(v->undeformed_co()) * size - loc; for (const int i : positions.index_range()) {
blender::float3 value;
if (orco) {
madd_v3_v3v3v3(value, texspace_location, orco[i], texspace_size);
}
else {
value = positions[i];
}
generated[i] = make_float3(value[0], value[1], value[2]) * size - loc;
} }
} }
@@ -1131,18 +914,17 @@ static void create_mesh(Scene *scene,
bool *smooth = mesh->get_smooth().data(); bool *smooth = mesh->get_smooth().data();
int *shader = mesh->get_shader().data(); int *shader = mesh->get_shader().data();
const MLoopTri *looptris = static_cast<const MLoopTri *>(b_mesh.loop_triangles[0].ptr.data); const blender::Span<MLoopTri> looptris = b_mesh.looptris();
for (int i = 0; i < numtris; i++) { for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i]; const MLoopTri &tri = looptris[i];
triangles[i * 3 + 0] = corner_verts[tri.tri[0]]; triangles[i * 3 + 0] = corner_verts[tri.tri[0]];
triangles[i * 3 + 1] = corner_verts[tri.tri[1]]; triangles[i * 3 + 1] = corner_verts[tri.tri[1]];
triangles[i * 3 + 2] = corner_verts[tri.tri[2]]; triangles[i * 3 + 2] = corner_verts[tri.tri[2]];
} }
if (material_indices) { if (!material_indices.is_empty()) {
const int *looptri_faces = static_cast<const int *>( const blender::Span<int> looptri_faces = b_mesh.looptri_faces();
b_mesh.loop_triangle_polygons[0].ptr.data); for (const int i : looptris.index_range()) {
for (int i = 0; i < numtris; i++) {
shader[i] = clamp_material_index(material_indices[looptri_faces[i]]); shader[i] = clamp_material_index(material_indices[looptri_faces[i]]);
} }
} }
@@ -1150,10 +932,9 @@ static void create_mesh(Scene *scene,
std::fill(shader, shader + numtris, 0); std::fill(shader, shader + numtris, 0);
} }
if (sharp_faces && !(use_loop_normals && corner_normals)) { if (!sharp_faces.is_empty() && !(use_loop_normals && !corner_normals.is_empty())) {
const int *looptri_faces = static_cast<const int *>( const blender::Span<int> looptri_faces = b_mesh.looptri_faces();
b_mesh.loop_triangle_polygons[0].ptr.data); for (const int i : looptris.index_range()) {
for (int i = 0; i < numtris; i++) {
smooth[i] = !sharp_faces[looptri_faces[i]]; smooth[i] = !sharp_faces[looptri_faces[i]];
} }
} }
@@ -1161,8 +942,8 @@ static void create_mesh(Scene *scene,
std::fill(smooth, smooth + numtris, true); std::fill(smooth, smooth + numtris, true);
} }
if (use_loop_normals && corner_normals) { if (use_loop_normals && !corner_normals.is_empty()) {
for (int i = 0; i < numtris; i++) { for (const int i : looptris.index_range()) {
const MLoopTri &tri = looptris[i]; const MLoopTri &tri = looptris[i];
for (int i = 0; i < 3; i++) { for (int i = 0; i < 3; i++) {
const int corner = tri.tri[i]; const int corner = tri.tri[i];
@@ -1185,7 +966,7 @@ static void create_mesh(Scene *scene,
int *subd_ptex_offset = mesh->get_subd_ptex_offset().data(); int *subd_ptex_offset = mesh->get_subd_ptex_offset().data();
int *subd_face_corners = mesh->get_subd_face_corners().data(); int *subd_face_corners = mesh->get_subd_face_corners().data();
if (sharp_faces && !use_loop_normals) { if (!sharp_faces.is_empty() && !use_loop_normals) {
for (int i = 0; i < numfaces; i++) { for (int i = 0; i < numfaces; i++) {
subd_smooth[i] = !sharp_faces[i]; subd_smooth[i] = !sharp_faces[i];
} }
@@ -1194,7 +975,7 @@ static void create_mesh(Scene *scene,
std::fill(subd_smooth, subd_smooth + numfaces, true); std::fill(subd_smooth, subd_smooth + numfaces, true);
} }
if (material_indices) { if (!material_indices.is_empty()) {
for (int i = 0; i < numfaces; i++) { for (int i = 0; i < numfaces; i++) {
subd_shader[i] = clamp_material_index(material_indices[i]); subd_shader[i] = clamp_material_index(material_indices[i]);
} }
@@ -1203,18 +984,17 @@ static void create_mesh(Scene *scene,
std::fill(subd_shader, subd_shader + numfaces, 0); std::fill(subd_shader, subd_shader + numfaces, 0);
} }
std::copy(corner_verts, corner_verts + numcorners, subd_face_corners); std::copy(corner_verts.data(), corner_verts.data() + corner_verts.size(), subd_face_corners);
const int *face_offsets = static_cast<const int *>(b_mesh.polygons[0].ptr.data); const blender::OffsetIndices faces = b_mesh.faces();
int ptex_offset = 0; int ptex_offset = 0;
for (int i = 0; i < numfaces; i++) { for (const int i : faces.index_range()) {
const int poly_start = face_offsets[i]; const blender::IndexRange face = faces[i];
const int poly_size = face_offsets[i + 1] - poly_start;
subd_start_corner[i] = poly_start; subd_start_corner[i] = face.start();
subd_num_corners[i] = poly_size; subd_num_corners[i] = face.size();
subd_ptex_offset[i] = ptex_offset; subd_ptex_offset[i] = ptex_offset;
const int num_ptex = (poly_size == 4) ? 1 : poly_size; const int num_ptex = (face.size() == 4) ? 1 : face.size();
ptex_offset += num_ptex; ptex_offset += num_ptex;
} }
@@ -1229,15 +1009,17 @@ static void create_mesh(Scene *scene,
/* Create all needed attributes. /* Create all needed attributes.
* The calculate functions will check whether they're needed or not. * The calculate functions will check whether they're needed or not.
*/ */
attr_create_pointiness(scene, mesh, b_mesh, subdivision); if (mesh->need_attribute(scene, ATTR_STD_POINTINESS)) {
attr_create_pointiness(mesh, positions, b_mesh.vert_normals(), b_mesh.edges(), subdivision);
}
attr_create_random_per_island(scene, mesh, b_mesh, subdivision); attr_create_random_per_island(scene, mesh, b_mesh, subdivision);
attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale); attr_create_generic(scene, mesh, b_mesh, subdivision, need_motion, motion_scale);
if (subdivision) { if (subdivision) {
attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs); attr_create_subd_uv_map(scene, mesh, b_mesh, subdivide_uvs, blender_uv_names);
} }
else { else {
attr_create_uv_map(scene, mesh, b_mesh); attr_create_uv_map(scene, mesh, b_mesh, blender_uv_names);
} }
/* For volume objects, create a matrix to transform from object space to /* For volume objects, create a matrix to transform from object space to
@@ -1257,7 +1039,7 @@ static void create_mesh(Scene *scene,
static void create_subd_mesh(Scene *scene, static void create_subd_mesh(Scene *scene,
Mesh *mesh, Mesh *mesh,
BObjectInfo &b_ob_info, BObjectInfo &b_ob_info,
BL::Mesh &b_mesh, const ::Mesh &b_mesh,
const array<Node *> &used_shaders, const array<Node *> &used_shaders,
const bool need_motion, const bool need_motion,
const float motion_scale, const float motion_scale,
@@ -1271,14 +1053,11 @@ static void create_subd_mesh(Scene *scene,
create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs); create_mesh(scene, mesh, b_mesh, used_shaders, need_motion, motion_scale, true, subdivide_uvs);
const int verts_num = b_mesh.vertices.length(); const blender::VArraySpan creases = *b_mesh.attributes().lookup<float>("crease_edge",
const int edges_num = b_mesh.edges.length(); ATTR_DOMAIN_EDGE);
if (!creases.is_empty()) {
const float *creases = find_edge_crease_attribute(b_mesh);
if (edges_num != 0 && creases != nullptr) {
size_t num_creases = 0; size_t num_creases = 0;
for (int i = 0; i < edges_num; i++) { for (const int i : creases.index_range()) {
if (creases[i] != 0.0f) { if (creases[i] != 0.0f) {
num_creases++; num_creases++;
} }
@@ -1286,18 +1065,20 @@ static void create_subd_mesh(Scene *scene,
mesh->reserve_subd_creases(num_creases); mesh->reserve_subd_creases(num_creases);
const int2 *edges = static_cast<int2 *>(b_mesh.edges[0].ptr.data); const blender::Span<blender::int2> edges = b_mesh.edges();
for (int i = 0; i < edges_num; i++) { for (const int i : edges.index_range()) {
const float crease = creases[i]; const float crease = creases[i];
if (crease != 0.0f) { if (crease != 0.0f) {
const int2 &b_edge = edges[i]; const blender::int2 &b_edge = edges[i];
mesh->add_edge_crease(b_edge[0], b_edge[1], crease); mesh->add_edge_crease(b_edge[0], b_edge[1], crease);
} }
} }
} }
if (const float *vert_creases = find_vert_crease_attribute(b_mesh)) { const blender::VArraySpan vert_creases = *b_mesh.attributes().lookup<float>("crease_vert",
for (int i = 0; i < verts_num; i++) { ATTR_DOMAIN_POINT);
if (!vert_creases.is_empty()) {
for (const int i : vert_creases.index_range()) {
if (vert_creases[i] != 0.0f) { if (vert_creases[i] != 0.0f) {
mesh->add_vertex_crease(i, vert_creases[i]); mesh->add_vertex_crease(i, vert_creases[i]);
} }
@@ -1350,7 +1131,7 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M
create_subd_mesh(scene, create_subd_mesh(scene,
&new_mesh, &new_mesh,
b_ob_info, b_ob_info,
b_mesh, *static_cast<const ::Mesh *>(b_mesh.ptr.data),
new_mesh.get_used_shaders(), new_mesh.get_used_shaders(),
need_motion, need_motion,
motion_scale, motion_scale,
@@ -1360,7 +1141,7 @@ void BlenderSync::sync_mesh(BL::Depsgraph b_depsgraph, BObjectInfo &b_ob_info, M
else { else {
create_mesh(scene, create_mesh(scene,
&new_mesh, &new_mesh,
b_mesh, *static_cast<const ::Mesh *>(b_mesh.ptr.data),
new_mesh.get_used_shaders(), new_mesh.get_used_shaders(),
need_motion, need_motion,
motion_scale, motion_scale,
@@ -1413,19 +1194,21 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
/* Skip objects without deforming modifiers. this is not totally reliable, /* Skip objects without deforming modifiers. this is not totally reliable,
* would need a more extensive check to see which objects are animated. */ * would need a more extensive check to see which objects are animated. */
BL::Mesh b_mesh(PointerRNA_NULL); BL::Mesh b_mesh_rna(PointerRNA_NULL);
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) { if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
/* get derived mesh */ /* get derived mesh */
b_mesh = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE); b_mesh_rna = object_to_mesh(b_data, b_ob_info, b_depsgraph, false, Mesh::SUBDIVISION_NONE);
} }
const std::string ob_name = b_ob_info.real_object.name(); const std::string ob_name = b_ob_info.real_object.name();
/* TODO(sergey): Perform preliminary check for number of vertices. */ /* TODO(sergey): Perform preliminary check for number of vertices. */
if (b_mesh) { if (b_mesh_rna) {
const int b_verts_num = b_mesh.vertices.length(); const ::Mesh &b_mesh = *static_cast<const ::Mesh *>(b_mesh_rna.ptr.data);
if (b_verts_num == 0) { const int b_verts_num = b_mesh.totvert;
free_object_to_mesh(b_data, b_ob_info, b_mesh); const blender::Span<blender::float3> positions = b_mesh.vert_positions();
if (positions.is_empty()) {
free_object_to_mesh(b_data, b_ob_info, b_mesh_rna);
return; return;
} }
@@ -1448,8 +1231,6 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
float3 *mP = attr_mP->data_float3() + motion_step * numverts; float3 *mP = attr_mP->data_float3() + motion_step * numverts;
float3 *mN = (attr_mN) ? attr_mN->data_float3() + motion_step * numverts : NULL; float3 *mN = (attr_mN) ? attr_mN->data_float3() + motion_step * numverts : NULL;
const float(*positions)[3] = static_cast<const float(*)[3]>(b_mesh.vertices[0].ptr.data);
/* NOTE: We don't copy more that existing amount of vertices to prevent /* NOTE: We don't copy more that existing amount of vertices to prevent
* possible memory corruption. * possible memory corruption.
*/ */
@@ -1457,11 +1238,9 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
mP[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]); mP[i] = make_float3(positions[i][0], positions[i][1], positions[i][2]);
} }
if (mN) { if (mN) {
const float(*b_vert_normals)[3] = static_cast<const float(*)[3]>( const blender::Span<blender::float3> b_vert_normals = b_mesh.vert_normals();
b_mesh.vertex_normals[0].ptr.data);
for (int i = 0; i < std::min<size_t>(b_verts_num, numverts); i++) { for (int i = 0; i < std::min<size_t>(b_verts_num, numverts); i++) {
const float *b_vert_normal = b_vert_normals[i]; mN[i] = make_float3(b_vert_normals[i][0], b_vert_normals[i][1], b_vert_normals[i][2]);
mN[i] = make_float3(b_vert_normal[0], b_vert_normal[1], b_vert_normal[2]);
} }
} }
if (new_attribute) { if (new_attribute) {
@@ -1505,7 +1284,7 @@ void BlenderSync::sync_mesh_motion(BL::Depsgraph b_depsgraph,
} }
} }
free_object_to_mesh(b_data, b_ob_info, b_mesh); free_object_to_mesh(b_data, b_ob_info, b_mesh_rna);
return; return;
} }

View File

@@ -8,6 +8,7 @@
#include "scene/pointcloud.h" #include "scene/pointcloud.h"
#include "scene/scene.h" #include "scene/scene.h"
#include "blender/attribute_convert.h"
#include "blender/sync.h" #include "blender/sync.h"
#include "blender/util.h" #include "blender/util.h"
@@ -15,19 +16,16 @@
#include "util/foreach.h" #include "util/foreach.h"
#include "util/hash.h" #include "util/hash.h"
#include "BKE_attribute.hh"
#include "BKE_attribute_math.hh"
#include "BKE_pointcloud.h"
CCL_NAMESPACE_BEGIN CCL_NAMESPACE_BEGIN
static void attr_create_motion(PointCloud *pointcloud, static void attr_create_motion(PointCloud *pointcloud,
BL::Attribute &b_attribute, const blender::Span<blender::float3> b_attribute,
const float motion_scale) const float motion_scale)
{ {
if (!(b_attribute.domain() == BL::Attribute::domain_POINT) &&
(b_attribute.data_type() == BL::Attribute::data_type_FLOAT_VECTOR))
{
return;
}
BL::FloatVectorAttribute b_vector_attribute(b_attribute);
const int num_points = pointcloud->get_points().size(); const int num_points = pointcloud->get_points().size();
/* Find or add attribute */ /* Find or add attribute */
@@ -46,196 +44,91 @@ static void attr_create_motion(PointCloud *pointcloud,
float4 *mP = attr_mP->data_float4() + step * num_points; float4 *mP = attr_mP->data_float4() + step * num_points;
for (int i = 0; i < num_points; i++) { for (int i = 0; i < num_points; i++) {
float3 Pi = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time; float3 Pi = P[i] + make_float3(b_attribute[i][0], b_attribute[i][1], b_attribute[i][2]) *
relative_time;
mP[i] = make_float4(Pi.x, Pi.y, Pi.z, radius[i]); mP[i] = make_float4(Pi.x, Pi.y, Pi.z, radius[i]);
} }
} }
} }
static void copy_attributes(PointCloud *pointcloud, static void copy_attributes(PointCloud *pointcloud,
BL::PointCloud b_pointcloud, const ::PointCloud &b_pointcloud,
const bool need_motion, const bool need_motion,
const float motion_scale) const float motion_scale)
{ {
const int num_points = b_pointcloud.points.length(); const blender::bke::AttributeAccessor b_attributes = b_pointcloud.attributes();
if (num_points == 0) { if (b_attributes.domain_size(ATTR_DOMAIN_POINT) == 0) {
return; return;
} }
AttributeSet &attributes = pointcloud->attributes; AttributeSet &attributes = pointcloud->attributes;
static const ustring u_velocity("velocity"); static const ustring u_velocity("velocity");
for (BL::Attribute &b_attribute : b_pointcloud.attributes) { b_attributes.for_all([&](const blender::bke::AttributeIDRef &id,
const ustring name{b_attribute.name().c_str()}; const blender::bke::AttributeMetaData /*meta_data*/) {
const ustring name{std::string_view(id.name())};
if (need_motion && name == u_velocity) { if (need_motion && name == u_velocity) {
attr_create_motion(pointcloud, b_attribute, motion_scale); const blender::VArraySpan b_attr = *b_attributes.lookup<blender::float3>(id);
attr_create_motion(pointcloud, b_attr, motion_scale);
} }
if (attributes.find(name)) { if (attributes.find(name)) {
continue; return true;
} }
const AttributeElement element = ATTR_ELEMENT_VERTEX; const blender::bke::GAttributeReader b_attr = b_attributes.lookup(id);
const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type(); blender::bke::attribute_math::convert_to_static_type(b_attr.varray.type(), [&](auto dummy) {
switch (b_data_type) { using BlenderT = decltype(dummy);
case BL::Attribute::data_type_FLOAT: { using Converter = typename ccl::AttributeConverter<BlenderT>;
BL::FloatAttribute b_float_attribute{b_attribute}; using CyclesT = typename Converter::CyclesT;
const float *src = static_cast<const float *>(b_float_attribute.data[0].ptr.data); if constexpr (!std::is_void_v<CyclesT>) {
Attribute *attr = attributes.add(name, TypeFloat, element); Attribute *attr = attributes.add(name, Converter::type_desc, ATTR_ELEMENT_VERTEX);
float *data = attr->data_float(); CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
std::copy(src, src + num_points, data);
break;
}
case BL::Attribute::data_type_BOOLEAN: {
BL::BoolAttribute b_bool_attribute{b_attribute};
const bool *src = static_cast<const bool *>(b_bool_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
for (int i = 0; i < num_points; i++) {
data[i] = float(src[i]);
}
break;
}
case BL::Attribute::data_type_INT: {
BL::IntAttribute b_int_attribute{b_attribute};
const int *src = static_cast<const int *>(b_int_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat, element);
float *data = attr->data_float();
for (int i = 0; i < num_points; i++) {
data[i] = float(src[i]);
}
break;
}
case BL::Attribute::data_type_INT32_2D: {
BL::Int2Attribute b_int2_attribute{b_attribute};
const int2 *src = static_cast<const int2 *>(b_int2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
for (int i = 0; i < num_points; i++) {
data[i] = make_float2(float(src[i][0]), float(src[i][1]));
}
break;
}
case BL::Attribute::data_type_FLOAT_VECTOR: {
BL::FloatVectorAttribute b_vector_attribute{b_attribute};
const float(*src)[3] = static_cast<const float(*)[3]>(b_vector_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeVector, element);
float3 *data = attr->data_float3();
for (int i = 0; i < num_points; i++) {
data[i] = make_float3(src[i][0], src[i][1], src[i][2]);
}
break;
}
case BL::Attribute::data_type_BYTE_COLOR: {
BL::ByteColorAttribute b_color_attribute{b_attribute};
const uchar(*src)[4] = static_cast<const uchar(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
for (int i = 0; i < num_points; i++) {
data[i] = make_float4(color_srgb_to_linear(byte_to_float(src[i][0])),
color_srgb_to_linear(byte_to_float(src[i][1])),
color_srgb_to_linear(byte_to_float(src[i][2])),
color_srgb_to_linear(byte_to_float(src[i][3])));
}
break;
}
case BL::Attribute::data_type_FLOAT_COLOR: {
BL::FloatColorAttribute b_color_attribute{b_attribute};
const float(*src)[4] = static_cast<const float(*)[4]>(b_color_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeRGBA, element);
float4 *data = attr->data_float4();
for (int i = 0; i < num_points; i++) {
data[i] = make_float4(src[i][0], src[i][1], src[i][2], src[i][3]);
}
break;
}
case BL::Attribute::data_type_FLOAT2: {
BL::Float2Attribute b_float2_attribute{b_attribute};
const float(*src)[2] = static_cast<const float(*)[2]>(b_float2_attribute.data[0].ptr.data);
Attribute *attr = attributes.add(name, TypeFloat2, element);
float2 *data = attr->data_float2();
for (int i = 0; i < num_points; i++) {
data[i] = make_float2(src[i][0], src[i][1]);
}
break;
}
default:
/* Not supported. */
break;
}
}
}
static const float *find_radius_attribute(BL::PointCloud b_pointcloud) const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
{ for (const int i : src.index_range()) {
for (BL::Attribute &b_attribute : b_pointcloud.attributes) { data[i] = Converter::convert(src[i]);
if (b_attribute.name() != "radius") { }
continue; }
} });
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT) {
continue;
}
BL::FloatAttribute b_float_attribute{b_attribute};
if (b_float_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float *>(b_float_attribute.data[0].ptr.data);
}
return nullptr;
}
static const float (*find_position_attribute(BL::PointCloud b_pointcloud))[3] return true;
{ });
for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
if (b_attribute.name() != "position") {
continue;
}
if (b_attribute.data_type() != BL::Attribute::data_type_FLOAT_VECTOR) {
continue;
}
BL::FloatVectorAttribute b_float3_attribute{b_attribute};
if (b_float3_attribute.data.length() == 0) {
return nullptr;
}
return static_cast<const float(*)[3]>(b_float3_attribute.data[0].ptr.data);
}
/* The position attribute must exist. */
assert(false);
return nullptr;
} }
static void export_pointcloud(Scene *scene, static void export_pointcloud(Scene *scene,
PointCloud *pointcloud, PointCloud *pointcloud,
BL::PointCloud b_pointcloud, const ::PointCloud &b_pointcloud,
const bool need_motion, const bool need_motion,
const float motion_scale) const float motion_scale)
{ {
const int num_points = b_pointcloud.points.length(); const blender::Span<blender::float3> b_positions = b_pointcloud.positions();
pointcloud->resize(num_points); const blender::VArraySpan b_radius = *b_pointcloud.attributes().lookup<float>("radius",
ATTR_DOMAIN_POINT);
pointcloud->resize(b_positions.size());
const float(*b_attr_position)[3] = find_position_attribute(b_pointcloud);
float3 *points = pointcloud->get_points().data(); float3 *points = pointcloud->get_points().data();
for (int i = 0; i < num_points; i++) { for (const int i : b_positions.index_range()) {
points[i] = make_float3(b_attr_position[i][0], b_attr_position[i][1], b_attr_position[i][2]); points[i] = make_float3(b_positions[i][0], b_positions[i][1], b_positions[i][2]);
} }
const float *b_attr_radius = find_radius_attribute(b_pointcloud);
float *radius = pointcloud->get_radius().data(); float *radius = pointcloud->get_radius().data();
if (b_attr_radius) { if (!b_radius.is_empty()) {
std::copy(b_attr_radius, b_attr_radius + num_points, radius); std::copy(b_radius.data(), b_radius.data() + b_positions.size(), radius);
} }
else { else {
std::fill(radius, radius + num_points, 0.01f); std::fill(radius, radius + b_positions.size(), 0.01f);
} }
int *shader = pointcloud->get_shader().data(); int *shader = pointcloud->get_shader().data();
std::fill(shader, shader + num_points, 0); std::fill(shader, shader + b_positions.size(), 0);
if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) { if (pointcloud->need_attribute(scene, ATTR_STD_POINT_RANDOM)) {
Attribute *attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM); Attribute *attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM);
float *data = attr_random->data_float(); float *data = attr_random->data_float();
for (int i = 0; i < num_points; i++) { for (const int i : b_positions.index_range()) {
data[i] = hash_uint2_to_float(i, 0); data[i] = hash_uint2_to_float(i, 0);
} }
} }
@@ -244,7 +137,7 @@ static void export_pointcloud(Scene *scene,
} }
static void export_pointcloud_motion(PointCloud *pointcloud, static void export_pointcloud_motion(PointCloud *pointcloud,
BL::PointCloud b_pointcloud, const ::PointCloud &b_pointcloud,
int motion_step) int motion_step)
{ {
/* Find or add attribute. */ /* Find or add attribute. */
@@ -264,21 +157,20 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
bool have_motion = false; bool have_motion = false;
const array<float3> &pointcloud_points = pointcloud->get_points(); const array<float3> &pointcloud_points = pointcloud->get_points();
const int b_points_num = b_pointcloud.points.length(); const blender::Span<blender::float3> b_positions = b_pointcloud.positions();
const float(*b_attr_position)[3] = find_position_attribute(b_pointcloud); const blender::VArraySpan b_radius = *b_pointcloud.attributes().lookup<float>("radius",
const float *b_attr_radius = find_radius_attribute(b_pointcloud); ATTR_DOMAIN_POINT);
for (int i = 0; i < std::min(num_points, b_points_num); i++) { for (int i = 0; i < std::min<int>(num_points, b_positions.size()); i++) {
const float3 P = make_float3( const float3 P = make_float3(b_positions[i][0], b_positions[i][1], b_positions[i][2]);
b_attr_position[i][0], b_attr_position[i][1], b_attr_position[i][2]); const float radius = b_radius.is_empty() ? 0.01f : b_radius[i];
const float radius = b_attr_radius ? b_attr_radius[i] : 0.01f;
mP[i] = make_float4(P.x, P.y, P.z, radius); mP[i] = make_float4(P.x, P.y, P.z, radius);
have_motion = have_motion || (P != pointcloud_points[i]); have_motion = have_motion || (P != pointcloud_points[i]);
} }
/* In case of new attribute, we verify if there really was any motion. */ /* In case of new attribute, we verify if there really was any motion. */
if (new_attribute) { if (new_attribute) {
if (b_points_num != num_points || !have_motion) { if (b_positions.size() != num_points || !have_motion) {
pointcloud->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION); pointcloud->attributes.remove(ATTR_STD_MOTION_VERTEX_POSITION);
} }
else if (motion_step > 0) { else if (motion_step > 0) {
@@ -311,7 +203,11 @@ void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info
scene->motion_shutter_time() / scene->motion_shutter_time() /
(b_scene.render().fps() / b_scene.render().fps_base()) : (b_scene.render().fps() / b_scene.render().fps_base()) :
0.0f; 0.0f;
export_pointcloud(scene, &new_pointcloud, b_pointcloud, need_motion, motion_scale); export_pointcloud(scene,
&new_pointcloud,
*static_cast<const ::PointCloud *>(b_pointcloud.ptr.data),
need_motion,
motion_scale);
/* Update original sockets. */ /* Update original sockets. */
for (const SocketType &socket : new_pointcloud.type->inputs) { for (const SocketType &socket : new_pointcloud.type->inputs) {
@@ -347,7 +243,8 @@ void BlenderSync::sync_pointcloud_motion(PointCloud *pointcloud,
if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) { if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
/* PointCloud object. */ /* PointCloud object. */
BL::PointCloud b_pointcloud(b_ob_info.object_data); BL::PointCloud b_pointcloud(b_ob_info.object_data);
export_pointcloud_motion(pointcloud, b_pointcloud, motion_step); export_pointcloud_motion(
pointcloud, *static_cast<const ::PointCloud *>(b_pointcloud.ptr.data), motion_step);
} }
else { else {
/* No deformation on this frame, copy coordinates if other frames did have it. */ /* No deformation on this frame, copy coordinates if other frames did have it. */

View File

@@ -17,6 +17,8 @@
#include "util/types.h" #include "util/types.h"
#include "util/vector.h" #include "util/vector.h"
#include "BKE_mesh.hh"
/* Hacks to hook into Blender API /* Hacks to hook into Blender API
* todo: clean this up ... */ * todo: clean this up ... */
@@ -524,10 +526,13 @@ static inline string get_text_datablock_content(const PointerRNA &ptr)
/* Texture Space */ /* Texture Space */
static inline void mesh_texture_space(BL::Mesh &b_mesh, float3 &loc, float3 &size) static inline void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
{ {
loc = get_float3(b_mesh.texspace_location()); float texspace_location[3], texspace_size[3];
size = get_float3(b_mesh.texspace_size()); BKE_mesh_texspace_get(const_cast<::Mesh *>(&b_mesh), texspace_location, texspace_size);
loc = make_float3(texspace_location[0], texspace_location[1], texspace_location[2]);
size = make_float3(texspace_size[0], texspace_size[1], texspace_size[2]);
if (size.x != 0.0f) if (size.x != 0.0f)
size.x = 0.5f / size.x; size.x = 0.5f / size.x;

View File

@@ -25,8 +25,8 @@ class BlenderSmokeLoader : public ImageLoader {
BlenderSmokeLoader(BL::Object &b_ob, AttributeStandard attribute) BlenderSmokeLoader(BL::Object &b_ob, AttributeStandard attribute)
: b_domain(object_fluid_gas_domain_find(b_ob)), attribute(attribute) : b_domain(object_fluid_gas_domain_find(b_ob)), attribute(attribute)
{ {
BL::Mesh b_mesh(b_ob.data()); mesh_texture_space(
mesh_texture_space(b_mesh, texspace_loc, texspace_size); *static_cast<const ::Mesh *>(b_ob.data().ptr.data), texspace_loc, texspace_size);
} }
bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override bool load_metadata(const ImageDeviceFeatures &, ImageMetaData &metadata) override

View File

@@ -443,6 +443,8 @@ class CurvesEditHints {
bool is_valid() const; bool is_valid() const;
}; };
void curves_normals_point_domain_calc(const CurvesGeometry &curves, MutableSpan<float3> normals);
namespace curves { namespace curves {
/* -------------------------------------------------------------------- */ /* -------------------------------------------------------------------- */

View File

@@ -29,6 +29,7 @@
#include "BKE_anim_data.h" #include "BKE_anim_data.h"
#include "BKE_curves.hh" #include "BKE_curves.hh"
#include "BKE_customdata.h" #include "BKE_customdata.h"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh" #include "BKE_geometry_set.hh"
#include "BKE_global.h" #include "BKE_global.h"
#include "BKE_idtype.h" #include "BKE_idtype.h"
@@ -367,4 +368,13 @@ bool CurvesEditHints::is_valid() const
return true; return true;
} }
void curves_normals_point_domain_calc(const CurvesGeometry &curves, MutableSpan<float3> normals)
{
const bke::CurvesFieldContext context(curves, ATTR_DOMAIN_POINT);
fn::FieldEvaluator evaluator(context, curves.points_num());
fn::Field<float3> field(std::make_shared<bke::NormalFieldInput>());
evaluator.add_with_destination(std::move(field), normals);
evaluator.evaluate();
}
} // namespace blender::bke } // namespace blender::bke

View File

@@ -3,9 +3,6 @@
* SPDX-License-Identifier: GPL-2.0-or-later */ * SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_curves.hh" #include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "BLI_task.hh"
#include "DNA_object_types.h" #include "DNA_object_types.h"
@@ -39,14 +36,7 @@ float (*ED_curves_point_normals_array_create(const Curves *curves_id))[3]
using namespace blender; using namespace blender;
const bke::CurvesGeometry &curves = curves_id->geometry.wrap(); const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
const int size = curves.points_num(); const int size = curves.points_num();
float3 *data = static_cast<float3 *>(MEM_malloc_arrayN(size, sizeof(float3), __func__)); float3 *data = static_cast<float3 *>(MEM_malloc_arrayN(size, sizeof(float3), __func__));
bke::curves_normals_point_domain_calc(curves, {data, size});
const bke::CurvesFieldContext context(curves, ATTR_DOMAIN_POINT);
fn::FieldEvaluator evaluator(context, size);
fn::Field<float3> field(std::make_shared<bke::NormalFieldInput>());
evaluator.add_with_destination(std::move(field), {data, size});
evaluator.evaluate();
return reinterpret_cast<float(*)[3]>(data); return reinterpret_cast<float(*)[3]>(data);
} }