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

Merged
Hans Goudey merged 7 commits from HooglyBoogly/blender:cycles-blender-geometry-no-copy into main 2023-09-18 02:50:16 +02:00
10 changed files with 571 additions and 913 deletions

View File

@ -41,6 +41,7 @@ set(SRC
viewport.cpp
volume.cpp
attribute_convert.h
CCL_api.h
device.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__
Review

In the new code we use #pragma once.
Perhaps we should just go ahead and convert the header guards to uniform case, similar to what we did in Blender.

In the new code we use `#pragma once`. Perhaps we should just go ahead and convert the header guards to uniform case, similar to what we did in Blender.
#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 "BKE_curves.hh"
#include "blender/attribute_convert.h"
#include "blender/sync.h"
#include "blender/util.h"
@ -20,6 +20,8 @@
#include "util/hash.h"
#include "util/log.h"
#include "BKE_curves.hh"
CCL_NAMESPACE_BEGIN
ParticleCurveData::ParticleCurveData() {}
@ -560,7 +562,7 @@ void BlenderSync::sync_particle_hair(
if (!motion) {
if (hair->need_attribute(scene, ATTR_STD_GENERATED)) {
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);
float3 *generated = attr_generated->data_float3();
@ -634,44 +636,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>
static void fill_generic_attribute(const int num_curves,
const int num_points,
@ -699,16 +663,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();
/* Find or add attribute */
@ -731,177 +689,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,
Hair *hair,
BL::Curves &b_curves,
const blender::bke::CurvesGeometry &b_curves,
const bool need_motion,
const float motion_scale)
{
const int num_keys = b_curves.points.length();
const int num_curves = b_curves.curves.length();
const blender::bke::AttributeAccessor b_attributes = b_curves.attributes();
AttributeSet &attributes = hair->attributes;
static const ustring u_velocity("velocity");
const bool need_uv = hair->need_attribute(scene, ATTR_STD_UV);
bool have_uv = false;
for (BL::Attribute &b_attribute : b_curves.attributes) {
const ustring name{b_attribute.name().c_str()};
b_attributes.for_all([&](const blender::bke::AttributeIDRef &id,
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 BL::Attribute::data_type_enum b_data_type = b_attribute.data_type();
const eAttrDomain b_domain = meta_data.domain;
const eCustomDataType b_data_type = meta_data.data_type;
if (need_motion && name == u_velocity) {
attr_create_motion(hair, b_attribute, motion_scale);
continue;
const blender::VArraySpan b_attr = *b_attributes.lookup<blender::float3>(id,
ATTR_DOMAIN_POINT);
attr_create_motion(hair, b_attr, motion_scale);
return true;
}
/* Weak, use first float2 attribute as standard UV. */
if (need_uv && !have_uv && b_data_type == BL::Attribute::data_type_FLOAT2 &&
b_domain == BL::Attribute::domain_CURVE)
{
attr_create_uv(attributes, num_curves, num_keys, b_attribute, name);
if (need_uv && !have_uv && b_data_type == CD_PROP_FLOAT2 && b_domain == ATTR_DOMAIN_CURVE) {
Attribute *attr = attributes.add(ATTR_STD_UV, 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;
continue;
return true;
}
if (!hair->need_attribute(scene, name)) {
continue;
return true;
}
if (attributes.find(name)) {
continue;
return true;
}
const blender::bke::GAttributeReader b_attr = b_attributes.lookup(id);
AttributeElement element = ATTR_ELEMENT_NONE;
switch (b_domain) {
case BL::Attribute::domain_POINT:
switch (b_attr.domain) {
case ATTR_DOMAIN_POINT:
element = ATTR_ELEMENT_CURVE_KEY;
break;
case BL::Attribute::domain_CURVE:
case ATTR_DOMAIN_CURVE:
element = ATTR_ELEMENT_CURVE;
break;
default:
break;
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};
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(num_curves, num_keys, data, element, [&](int i) { return src[i]; });
break;
blender::bke::attribute_math::convert_to_static_type(b_attr.varray.type(), [&](auto dummy) {
using BlenderT = decltype(dummy);
using Converter = typename ccl::AttributeConverter<BlenderT>;
using CyclesT = typename Converter::CyclesT;
if constexpr (!std::is_void_v<CyclesT>) {
Attribute *attr = attributes.add(name, Converter::type_desc, element);
CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
for (const int i : src.index_range()) {
data[i] = Converter::convert(src[i]);
}
}
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();
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;
}
}
});
return true;
});
}
static float4 curve_point_as_float4(const float (*b_attr_position)[3],
const float *b_attr_radius,
static float4 curve_point_as_float4(const blender::Span<blender::float3> b_positions,
const blender::Span<float> b_radius,
const int index)
{
float4 mP = make_float4(
b_attr_position[index][0], b_attr_position[index][1], b_attr_position[index][2], 0.0f);
mP.w = b_attr_radius ? b_attr_radius[index] : 0.005f;
b_positions[index][0], b_positions[index][1], b_positions[index][2], 0.0f);
mP.w = b_radius.is_empty() ? 0.005f : b_radius[index];
return mP;
}
static float4 interpolate_curve_points(const float (*b_attr_position)[3],
const float *b_attr_radius,
static float4 interpolate_curve_points(const blender::Span<blender::float3> b_positions,
const blender::Span<float> b_radius,
const int first_point_index,
const int num_points,
const float step)
@ -910,21 +788,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_b = min(point_a + 1, num_points - 1);
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),
curve_point_as_float4(b_attr_position, b_attr_radius, first_point_index + point_b),
return mix(curve_point_as_float4(b_positions, b_radius, first_point_index + point_a),
curve_point_as_float4(b_positions, b_radius, first_point_index + point_b),
t);
}
static void export_hair_curves(Scene *scene,
Hair *hair,
BL::Curves b_curves,
const blender::bke::CurvesGeometry &b_curves,
const bool need_motion,
const float motion_scale)
{
const int num_keys = b_curves.points.length();
const int num_curves = b_curves.curves.length();
const blender::Span<blender::float3> positions = b_curves.positions();
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();
float *curve_radius = hair->get_curve_radius().data();
@ -938,11 +816,14 @@ static void export_hair_curves(Scene *scene,
if (hair->need_attribute(scene, ATTR_STD_VERTEX_NORMAL)) {
/* Get geometry normals. */
float3 *attr_normal = hair->attributes.add(ATTR_STD_VERTEX_NORMAL)->data_float3();
int i = 0;
for (BL::FloatVectorValueReadOnly &normal : b_curves.normals) {
attr_normal[i++] = get_float3(normal.vector());
vector<blender::float3> point_normals(positions.size());
blender::bke::curves_normals_point_domain_calc(
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)) {
attr_intercept = hair->attributes.add(ATTR_STD_CURVE_INTERCEPT)->data_float();
}
@ -951,42 +832,40 @@ static void export_hair_curves(Scene *scene,
}
if (hair->need_attribute(scene, ATTR_STD_CURVE_RANDOM)) {
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);
}
}
const int *point_offsets = static_cast<const int *>(b_curves.curve_offset_data[0].ptr.data);
const float(*b_attr_position)[3] = find_position_attribute(b_curves);
const float *b_attr_radius = find_radius_attribute(b_curves);
const blender::VArraySpan b_radius = *b_curves.attributes().lookup<float>("radius",
ATTR_DOMAIN_POINT);
std::copy(point_offsets, point_offsets + num_curves, curve_first_key);
std::fill(curve_shader, curve_shader + num_curves, 0);
if (b_attr_radius) {
std::copy(b_attr_radius, b_attr_radius + num_keys, curve_radius);
std::copy(points_by_curve.data().data(),
points_by_curve.data().data() + points_by_curve.size(),
curve_first_key);
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 {
std::fill(curve_radius, curve_radius + num_keys, 0.005f);
std::fill(curve_radius, curve_radius + positions.size(), 0.005f);
}
/* Export curves and points. */
for (int i = 0; i < num_curves; i++) {
const int first_point_index = point_offsets[i];
const int num_points = point_offsets[i + 1] - first_point_index;
for (const int curve : points_by_curve.index_range()) {
const blender::IndexRange points = points_by_curve[curve];
float3 prev_co = zero_float3();
float length = 0.0f;
/* Position and radius. */
for (int j = 0; j < num_points; j++) {
const int point = first_point_index + j;
const float3 co = make_float3(
b_attr_position[point][0], b_attr_position[point][1], b_attr_position[point][2]);
for (const int point : points) {
const float3 co = make_float3(positions[point][0], positions[point][1], positions[point][2]);
curve_keys[point] = co;
if (attr_length || attr_intercept) {
if (j > 0) {
if (point != points.first()) {
length += len(co - prev_co);
}
prev_co = co;
@ -999,22 +878,23 @@ static void export_hair_curves(Scene *scene,
/* Normalized 0..1 attribute along curve. */
if (attr_intercept && length > 0.0f) {
for (int j = 1; j < num_points; j++) {
const int point = first_point_index + j;
for (const int point : points.drop_front(1)) {
attr_intercept[point] /= length;
}
}
/* Curve length. */
if (attr_length) {
attr_length[i] = length;
attr_length[curve] = length;
}
}
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. */
Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION);
@ -1027,30 +907,29 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
/* Export motion keys. */
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;
bool have_motion = false;
int num_motion_keys = 0;
int curve_index = 0;
const int *point_offsets = static_cast<const int *>(b_curves.curve_offset_data[0].ptr.data);
const float(*b_attr_position)[3] = find_position_attribute(b_curves);
const float *b_attr_radius = find_radius_attribute(b_curves);
const blender::Span<blender::float3> b_positions = b_curves.positions();
const blender::OffsetIndices points_by_curve = b_curves.points_by_curve();
const blender::VArraySpan b_radius = *b_curves.attributes().lookup<float>("radius",
ATTR_DOMAIN_POINT);
for (int i = 0; i < num_curves; i++) {
const int first_point_index = point_offsets[i];
const int num_points = point_offsets[i + 1] - first_point_index;
for (const int i : points_by_curve.index_range()) {
const blender::IndexRange points = points_by_curve[i];
Hair::Curve curve = hair->get_curve(curve_index);
curve_index++;
if (num_points == curve.num_keys) {
if (points.size() == curve.num_keys) {
/* Number of keys matches. */
for (int i = 0; i < num_points; i++) {
int point = first_point_index + i;
for (const int i : points.index_range()) {
int point = points[i];
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++;
if (!have_motion) {
@ -1070,7 +949,7 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio
for (int i = 0; i < curve.num_keys; i++) {
const float step = i * step_size;
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++;
}
have_motion = true;
@ -1094,7 +973,8 @@ void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int
0.0f;
/* 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) {
export_hair_curves_motion(hair, b_curves, motion_step);
}

File diff suppressed because it is too large Load Diff

View File

@ -8,6 +8,7 @@
#include "scene/pointcloud.h"
#include "scene/scene.h"
#include "blender/attribute_convert.h"
#include "blender/sync.h"
#include "blender/util.h"
@ -15,19 +16,16 @@
#include "util/foreach.h"
#include "util/hash.h"
#include "BKE_attribute.hh"
#include "BKE_attribute_math.hh"
#include "BKE_pointcloud.h"
CCL_NAMESPACE_BEGIN
static void attr_create_motion(PointCloud *pointcloud,
BL::Attribute &b_attribute,
const blender::Span<blender::float3> 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 num_points = pointcloud->get_points().size();
/* Find or add attribute */
@ -46,196 +44,91 @@ static void attr_create_motion(PointCloud *pointcloud,
float4 *mP = attr_mP->data_float4() + step * num_points;
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]);
}
}
}
static void copy_attributes(PointCloud *pointcloud,
BL::PointCloud b_pointcloud,
const ::PointCloud &b_pointcloud,
const bool need_motion,
const float motion_scale)
{
const int num_points = b_pointcloud.points.length();
if (num_points == 0) {
const blender::bke::AttributeAccessor b_attributes = b_pointcloud.attributes();
if (b_attributes.domain_size(ATTR_DOMAIN_POINT) == 0) {
return;
}
AttributeSet &attributes = pointcloud->attributes;
static const ustring u_velocity("velocity");
for (BL::Attribute &b_attribute : b_pointcloud.attributes) {
const ustring name{b_attribute.name().c_str()};
b_attributes.for_all([&](const blender::bke::AttributeIDRef &id,
const blender::bke::AttributeMetaData /*meta_data*/) {
const ustring name{std::string_view(id.name())};
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)) {
continue;
return true;
}
const AttributeElement element = ATTR_ELEMENT_VERTEX;
const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type();
switch (b_data_type) {
case BL::Attribute::data_type_FLOAT: {
BL::FloatAttribute b_float_attribute{b_attribute};
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();
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;
}
}
}
const blender::bke::GAttributeReader b_attr = b_attributes.lookup(id);
blender::bke::attribute_math::convert_to_static_type(b_attr.varray.type(), [&](auto dummy) {
using BlenderT = decltype(dummy);
using Converter = typename ccl::AttributeConverter<BlenderT>;
using CyclesT = typename Converter::CyclesT;
if constexpr (!std::is_void_v<CyclesT>) {
Attribute *attr = attributes.add(name, Converter::type_desc, ATTR_ELEMENT_VERTEX);
CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
static const float *find_radius_attribute(BL::PointCloud b_pointcloud)
{
for (BL::Attribute &b_attribute : b_pointcloud.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;
}
const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
for (const int i : src.index_range()) {
data[i] = Converter::convert(src[i]);
}
}
});
static const float (*find_position_attribute(BL::PointCloud b_pointcloud))[3]
{
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;
return true;
});
}
static void export_pointcloud(Scene *scene,
PointCloud *pointcloud,
BL::PointCloud b_pointcloud,
const ::PointCloud &b_pointcloud,
const bool need_motion,
const float motion_scale)
{
const int num_points = b_pointcloud.points.length();
pointcloud->resize(num_points);
const blender::Span<blender::float3> b_positions = b_pointcloud.positions();
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();
for (int i = 0; i < num_points; i++) {
points[i] = make_float3(b_attr_position[i][0], b_attr_position[i][1], b_attr_position[i][2]);
for (const int i : b_positions.index_range()) {
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();
if (b_attr_radius) {
std::copy(b_attr_radius, b_attr_radius + num_points, radius);
if (!b_radius.is_empty()) {
std::copy(b_radius.data(), b_radius.data() + b_positions.size(), radius);
}
else {
std::fill(radius, radius + num_points, 0.01f);
std::fill(radius, radius + b_positions.size(), 0.01f);
}
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)) {
Attribute *attr_random = pointcloud->attributes.add(ATTR_STD_POINT_RANDOM);
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);
}
}
@ -244,7 +137,7 @@ static void export_pointcloud(Scene *scene,
}
static void export_pointcloud_motion(PointCloud *pointcloud,
BL::PointCloud b_pointcloud,
const ::PointCloud &b_pointcloud,
int motion_step)
{
/* Find or add attribute. */
@ -264,21 +157,20 @@ static void export_pointcloud_motion(PointCloud *pointcloud,
bool have_motion = false;
const array<float3> &pointcloud_points = pointcloud->get_points();
const int b_points_num = b_pointcloud.points.length();
const float(*b_attr_position)[3] = find_position_attribute(b_pointcloud);
const float *b_attr_radius = find_radius_attribute(b_pointcloud);
const blender::Span<blender::float3> b_positions = b_pointcloud.positions();
const blender::VArraySpan b_radius = *b_pointcloud.attributes().lookup<float>("radius",
ATTR_DOMAIN_POINT);
for (int i = 0; i < std::min(num_points, b_points_num); i++) {
const float3 P = make_float3(
b_attr_position[i][0], b_attr_position[i][1], b_attr_position[i][2]);
const float radius = b_attr_radius ? b_attr_radius[i] : 0.01f;
for (int i = 0; i < std::min<int>(num_points, b_positions.size()); i++) {
const float3 P = make_float3(b_positions[i][0], b_positions[i][1], b_positions[i][2]);
const float radius = b_radius.is_empty() ? 0.01f : b_radius[i];
mP[i] = make_float4(P.x, P.y, P.z, radius);
have_motion = have_motion || (P != pointcloud_points[i]);
}
/* In case of new attribute, we verify if there really was any motion. */
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);
}
else if (motion_step > 0) {
@ -311,7 +203,11 @@ void BlenderSync::sync_pointcloud(PointCloud *pointcloud, BObjectInfo &b_ob_info
scene->motion_shutter_time() /
(b_scene.render().fps() / b_scene.render().fps_base()) :
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. */
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)) {
/* PointCloud object. */
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 {
/* 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/vector.h"
#include "BKE_mesh.hh"
/* Hacks to hook into Blender API
* todo: clean this up ... */
@ -524,10 +526,13 @@ static inline string get_text_datablock_content(const PointerRNA &ptr)
/* 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());
size = get_float3(b_mesh.texspace_size());
float texspace_location[3], texspace_size[3];
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)
size.x = 0.5f / size.x;

View File

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

View File

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

View File

@ -29,6 +29,7 @@
#include "BKE_anim_data.h"
#include "BKE_curves.hh"
#include "BKE_customdata.h"
#include "BKE_geometry_fields.hh"
#include "BKE_geometry_set.hh"
#include "BKE_global.h"
#include "BKE_idtype.h"
@ -367,4 +368,13 @@ bool CurvesEditHints::is_valid() const
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

View File

@ -3,9 +3,6 @@
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BKE_curves.hh"
#include "BKE_geometry_fields.hh"
#include "BLI_task.hh"
#include "DNA_object_types.h"
@ -39,14 +36,7 @@ float (*ED_curves_point_normals_array_create(const Curves *curves_id))[3]
using namespace blender;
const bke::CurvesGeometry &curves = curves_id->geometry.wrap();
const int size = curves.points_num();
float3 *data = static_cast<float3 *>(MEM_malloc_arrayN(size, sizeof(float3), __func__));
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();
bke::curves_normals_point_domain_calc(curves, {data, size});
return reinterpret_cast<float(*)[3]>(data);
}