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