From fcec55796ee63cfaed366608b94ff85103344e8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?K=C3=A9vin=20Dietrich?= Date: Fri, 11 Feb 2022 08:33:46 +0100 Subject: [PATCH] Cycles: support rendering attributes for Curves objects This adds support for exporting attributes from a Blender Curves object to Cycles. The implementation follows that of the Mesh object. This also creates motion blur data if the "velocity" attribute is present on the Curves. Ref T94193 Reviewed By: brecht Maniphest Tasks: T94193 Differential Revision: https://developer.blender.org/D14088 --- intern/cycles/blender/curves.cpp | 180 ++++++++++++++++++++++++++++++- 1 file changed, 178 insertions(+), 2 deletions(-) diff --git a/intern/cycles/blender/curves.cpp b/intern/cycles/blender/curves.cpp index 102ddf5ee32..dcb02c1ce47 100644 --- a/intern/cycles/blender/curves.cpp +++ b/intern/cycles/blender/curves.cpp @@ -645,6 +645,169 @@ static std::optional find_curves_radius_attribute(BL::Curves return std::nullopt; } +template +static void fill_generic_attribute(BL::Curves &b_curves, + TypeInCycles *data, + const AttributeElement element, + const GetValueAtIndex &get_value_at_index) +{ + switch (element) { + case ATTR_ELEMENT_CURVE_KEY: { + const int num_points = b_curves.points.length(); + for (int i = 0; i < num_points; i++) { + data[i] = get_value_at_index(i); + } + break; + } + case ATTR_ELEMENT_CURVE: { + const int num_verts = b_curves.curves.length(); + for (int i = 0; i < num_verts; i++) { + data[i] = get_value_at_index(i); + } + break; + } + default: { + assert(false); + break; + } + } +} + +static void attr_create_motion(Hair *hair, 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 num_curve_keys = hair->get_curve_keys().size(); + + /* Find or add attribute */ + float3 *P = &hair->get_curve_keys()[0]; + Attribute *attr_mP = hair->attributes.find(ATTR_STD_MOTION_VERTEX_POSITION); + + if (!attr_mP) { + attr_mP = hair->attributes.add(ATTR_STD_MOTION_VERTEX_POSITION); + } + + /* Only export previous and next frame, we don't have any in between data. */ + float motion_times[2] = {-1.0f, 1.0f}; + for (int step = 0; step < 2; step++) { + const float relative_time = motion_times[step] * 0.5f * motion_scale; + float3 *mP = attr_mP->data_float3() + step * num_curve_keys; + + for (int i = 0; i < num_curve_keys; i++) { + mP[i] = P[i] + get_float3(b_vector_attribute.data[i].vector()) * relative_time; + } + } +} + +static void attr_create_generic(Scene *scene, + Hair *hair, + BL::Curves &b_curves, + const bool need_motion, + const float motion_scale) +{ + AttributeSet &attributes = hair->attributes; + static const ustring u_velocity("velocity"); + + for (BL::Attribute &b_attribute : b_curves.attributes) { + const ustring name{b_attribute.name().c_str()}; + + if (need_motion && name == u_velocity) { + attr_create_motion(hair, b_attribute, motion_scale); + } + + if (!hair->need_attribute(scene, name)) { + continue; + } + if (attributes.find(name)) { + continue; + } + + const BL::Attribute::domain_enum b_domain = b_attribute.domain(); + const BL::Attribute::data_type_enum b_data_type = b_attribute.data_type(); + + AttributeElement element = ATTR_ELEMENT_NONE; + switch (b_domain) { + case BL::Attribute::domain_POINT: + element = ATTR_ELEMENT_CURVE_KEY; + break; + case BL::Attribute::domain_CURVE: + element = ATTR_ELEMENT_CURVE; + break; + default: + break; + } + 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}; + Attribute *attr = attributes.add(name, TypeFloat, element); + float *data = attr->data_float(); + fill_generic_attribute( + b_curves, data, element, [&](int i) { return b_float_attribute.data[i].value(); }); + break; + } + case BL::Attribute::data_type_BOOLEAN: { + BL::BoolAttribute b_bool_attribute{b_attribute}; + Attribute *attr = attributes.add(name, TypeFloat, element); + float *data = attr->data_float(); + fill_generic_attribute(b_curves, data, element, [&](int i) { + return (float)b_bool_attribute.data[i].value(); + }); + break; + } + case BL::Attribute::data_type_INT: { + BL::IntAttribute b_int_attribute{b_attribute}; + Attribute *attr = attributes.add(name, TypeFloat, element); + float *data = attr->data_float(); + fill_generic_attribute(b_curves, data, element, [&](int i) { + return (float)b_int_attribute.data[i].value(); + }); + break; + } + case BL::Attribute::data_type_FLOAT_VECTOR: { + BL::FloatVectorAttribute b_vector_attribute{b_attribute}; + Attribute *attr = attributes.add(name, TypeVector, element); + float3 *data = attr->data_float3(); + fill_generic_attribute(b_curves, data, element, [&](int i) { + BL::Array v = b_vector_attribute.data[i].vector(); + return make_float3(v[0], v[1], v[2]); + }); + break; + } + case BL::Attribute::data_type_FLOAT_COLOR: { + BL::FloatColorAttribute b_color_attribute{b_attribute}; + Attribute *attr = attributes.add(name, TypeRGBA, element); + float4 *data = attr->data_float4(); + fill_generic_attribute(b_curves, data, element, [&](int i) { + BL::Array v = b_color_attribute.data[i].color(); + return make_float4(v[0], v[1], v[2], v[3]); + }); + break; + } + case BL::Attribute::data_type_FLOAT2: { + BL::Float2Attribute b_float2_attribute{b_attribute}; + Attribute *attr = attributes.add(name, TypeFloat2, element); + float2 *data = attr->data_float2(); + fill_generic_attribute(b_curves, data, element, [&](int i) { + BL::Array v = b_float2_attribute.data[i].vector(); + return make_float2(v[0], v[1]); + }); + break; + } + default: + /* Not supported. */ + break; + } + } +} + static float4 hair_point_as_float4(BL::Curves b_curves, std::optional b_attr_radius, const int index) @@ -669,7 +832,11 @@ static float4 interpolate_hair_points(BL::Curves b_curves, t); } -static void export_hair_curves(Scene *scene, Hair *hair, BL::Curves b_curves) +static void export_hair_curves(Scene *scene, + Hair *hair, + BL::Curves b_curves, + const bool need_motion, + const float motion_scale) { /* TODO: optimize so we can straight memcpy arrays from Blender? */ @@ -746,6 +913,8 @@ static void export_hair_curves(Scene *scene, Hair *hair, BL::Curves b_curves) const int shader_index = 0; hair->add_curve(first_point_index, shader_index); } + + 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) @@ -818,13 +987,20 @@ static void export_hair_curves_motion(Hair *hair, BL::Curves b_curves, int motio /* Hair object. */ void BlenderSync::sync_hair(Hair *hair, BObjectInfo &b_ob_info, bool motion, int motion_step) { + /* Motion blur attribute is relative to seconds, we need it relative to frames. */ + const bool need_motion = object_need_motion_attribute(b_ob_info, scene); + const float motion_scale = (need_motion) ? + scene->motion_shutter_time() / + (b_scene.render().fps() / b_scene.render().fps_base()) : + 0.0f; + /* Convert Blender hair to Cycles curves. */ BL::Curves b_curves(b_ob_info.object_data); if (motion) { export_hair_curves_motion(hair, b_curves, motion_step); } else { - export_hair_curves(scene, hair, b_curves); + export_hair_curves(scene, hair, b_curves, need_motion, motion_scale); } } #else