32static float shaperadius(
const float shape,
const float root,
const float tip,
const float time)
36 float radius = 1.0f - time;
40 radius =
powf(radius, 1.0f + shape);
43 radius =
powf(radius, 1.0f / (1.0f - shape));
46 return (radius * (root - tip)) + tip;
57 if (!(hair && b_mesh && b_ob && CData)) {
64 for (BL::Modifier &b_mod : b_ob->modifiers) {
65 if ((b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) &&
66 (background ? b_mod.show_render() : b_mod.show_viewport()))
68 BL::ParticleSystemModifier psmd((
const PointerRNA)b_mod.ptr);
69 BL::ParticleSystem b_psys((
const PointerRNA)psmd.particle_system().ptr);
70 BL::ParticleSettings b_part((
const PointerRNA)b_psys.settings().ptr);
72 if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
73 (b_part.type() == BL::ParticleSettings::type_HAIR))
75 const int shader =
clamp(b_part.material() - 1, 0, hair->get_used_shaders().size() - 1);
76 const int display_step = background ? b_part.render_step() : b_part.display_step();
77 const int totparts = b_psys.particles.length();
78 const int totchild = background ? b_psys.child_particles.length() :
79 (int)((
float)b_psys.child_particles.length() *
80 (
float)b_part.display_percentage() / 100.0f);
81 int totcurves = totchild;
83 if (b_part.child_type() == 0 || totchild == 0) {
84 totcurves += totparts;
91 int ren_step = (1 << display_step) + 1;
92 if (b_part.kink() == BL::ParticleSettings::kink_SPIRAL) {
93 ren_step += b_part.kink_extra_steps();
100 const float radius = b_part.radius_scale() * 0.5f;
108 if (!(b_part.child_type() == 0) && totchild != 0) {
112 const int num_add = (totparts + totchild - pa_no);
119 for (; pa_no < totparts + totchild; pa_no++) {
123 float curve_length = 0.0f;
126 for (
int step_no = 0; step_no < ren_step; step_no++) {
127 float3 co_world = prev_co_world;
128 b_psys.co_hair(*b_ob, pa_no, step_no, &co_world.
x);
131 const float step_length =
len(co_object - prev_co_object);
132 curve_length += step_length;
136 prev_co_object = co_object;
137 prev_co_world = co_world;
160 if (!(hair && b_mesh && b_ob && CData)) {
166 for (BL::Modifier &b_mod : b_ob->modifiers) {
167 if ((b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) &&
168 (background ? b_mod.show_render() : b_mod.show_viewport()))
170 BL::ParticleSystemModifier psmd((
const PointerRNA)b_mod.ptr);
171 BL::ParticleSystem b_psys((
const PointerRNA)psmd.particle_system().ptr);
172 BL::ParticleSettings b_part((
const PointerRNA)b_psys.settings().ptr);
174 if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
175 (b_part.type() == BL::ParticleSettings::type_HAIR))
177 const int totparts = b_psys.particles.length();
178 const int totchild = background ? b_psys.child_particles.length() :
179 (int)((
float)b_psys.child_particles.length() *
180 (
float)b_part.display_percentage() / 100.0f);
181 int totcurves = totchild;
183 if (b_part.child_type() == 0 || totchild == 0) {
184 totcurves += totparts;
187 if (totcurves == 0) {
192 if (!(b_part.child_type() == 0) && totchild != 0) {
196 const int num_add = (totparts + totchild - pa_no);
199 BL::ParticleSystem::particles_iterator b_pa;
200 b_psys.particles.begin(b_pa);
201 for (; pa_no < totparts + totchild; pa_no++) {
203 BL::Mesh::uv_layers_iterator
l;
204 b_mesh->uv_layers.begin(
l);
207 if (!b_mesh->uv_layers.empty()) {
208 b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.
x);
212 if (pa_no < totparts && b_pa != b_psys.particles.end()) {
230 if (!(hair && b_mesh && b_ob && CData)) {
236 for (BL::Modifier &b_mod : b_ob->modifiers) {
237 if ((b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) &&
238 (background ? b_mod.show_render() : b_mod.show_viewport()))
240 BL::ParticleSystemModifier psmd((
const PointerRNA)b_mod.ptr);
241 BL::ParticleSystem b_psys((
const PointerRNA)psmd.particle_system().ptr);
242 BL::ParticleSettings b_part((
const PointerRNA)b_psys.settings().ptr);
244 if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
245 (b_part.type() == BL::ParticleSettings::type_HAIR))
247 const int totparts = b_psys.particles.length();
248 const int totchild = background ? b_psys.child_particles.length() :
249 (int)((
float)b_psys.child_particles.length() *
250 (
float)b_part.display_percentage() / 100.0f);
251 int totcurves = totchild;
253 if (b_part.child_type() == 0 || totchild == 0) {
254 totcurves += totparts;
257 if (totcurves == 0) {
262 if (!(b_part.child_type() == 0) && totchild != 0) {
266 const int num_add = (totparts + totchild - pa_no);
269 BL::ParticleSystem::particles_iterator b_pa;
270 b_psys.particles.begin(b_pa);
271 for (; pa_no < totparts + totchild; pa_no++) {
273 BL::Mesh::vertex_colors_iterator
l;
274 b_mesh->vertex_colors.begin(
l);
277 if (!b_mesh->vertex_colors.empty()) {
278 b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.
x);
282 if (pa_no < totparts && b_pa != b_psys.particles.end()) {
323 curve < CData->psys_firstcurve[sys] + CData->
psys_curvenum[sys];
339 curve < CData->psys_firstcurve[sys] + CData->
psys_curvenum[sys];
342 size_t num_curve_keys = 0;
345 curvekey < CData->curve_firstkey[curve] + CData->
curve_keynum[curve];
351 const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
360 if (attr_intercept) {
361 attr_intercept->
add(time);
373 if (attr_length !=
nullptr) {
377 if (attr_random !=
nullptr) {
382 num_keys += num_curve_keys;
388 if ((hair->get_curve_keys().size() != num_keys) || (hair->
num_curves() != num_curves)) {
389 LOG_ERROR <<
"Hair memory allocation failed, clearing data.";
402 const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
427 int curvekey = (int)
floorf(curve_key_f);
428 const float remainder = curve_key_f - curvekey;
429 if (remainder == 0.0f) {
432 int curvekey2 = curvekey + 1;
435 curvekey = curvekey2 - 1;
439 return mix(mP, mP2, remainder);
443 const int motion_step,
444 const int num_motion_keys,
448 const int num_keys = hair->get_curve_keys().size();
450 if (num_motion_keys != num_keys || !have_motion) {
452 if (num_motion_keys != num_keys) {
453 LOG_DEBUG <<
"Hair topology changed, removing motion attribute.";
457 else if (motion_step > 0) {
463 for (
int key = 0; key < num_keys; key++) {
464 mP[key] =
make_float4(hair->get_curve_keys()[key]);
465 mP[key].
w = hair->get_curve_radius()[key];
475 bool new_attribute =
false;
480 new_attribute =
true;
484 const size_t numkeys = hair->get_curve_keys().size();
486 bool have_motion =
false;
492 curve < CData->psys_firstcurve[sys] + CData->
psys_curvenum[sys];
496 const int curve_key_end = (num_curves + 1 < (int)hair->get_curve_first_key().
size() ?
497 hair->get_curve_first_key()[num_curves + 1] :
498 (
int)hair->get_curve_keys().size());
499 const int num_center_curve_keys = curve_key_end - hair->get_curve_first_key()[num_curves];
500 const int is_num_keys_different = CData->
curve_keynum[curve] - num_center_curve_keys;
502 if (!is_num_keys_different) {
504 curvekey < CData->curve_firstkey[curve] + CData->
curve_keynum[curve];
514 curve_key.
w = hair->get_curve_radius()[
i];
526 const float step_size = num_center_curve_keys > 1 ? 1.0f / (num_center_curve_keys - 1) :
528 for (
int step_index = 0; step_index < num_center_curve_keys; ++step_index) {
529 const float step = step_index * step_size;
547bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
550 for (BL::Modifier &b_mod : b_ob.modifiers) {
551 if ((b_mod.type() == BL::Modifier::type_PARTICLE_SYSTEM) &&
552 (preview ? b_mod.show_viewport() : b_mod.show_render()))
554 BL::ParticleSystemModifier psmd((
const PointerRNA)b_mod.ptr);
555 BL::ParticleSystem b_psys((
const PointerRNA)psmd.particle_system().ptr);
556 BL::ParticleSettings b_part((
const PointerRNA)b_psys.settings().ptr);
558 if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
559 (b_part.type() == BL::ParticleSettings::type_HAIR))
570void BlenderSync::sync_particle_hair(
571 Hair *hair, BL::Mesh &b_mesh,
BObjectInfo &b_ob_info,
bool motion,
const int motion_step)
579 if (b_ob.mode() == BL::Object::mode_PARTICLE_EDIT || b_ob.mode() == BL::Object::mode_EDIT) {
585 ParticleCurveData CData;
610 generated[
i] = co *
size - loc;
617 BL::Mesh::vertex_colors_iterator
l;
620 for (b_mesh.vertex_colors.begin(
l);
l != b_mesh.vertex_colors.end(); ++
l, vcol_num++) {
636 for (
size_t curve = 0; curve < CData.
curve_vcol.
size(); curve++) {
645 BL::Mesh::uv_layers_iterator
l;
648 for (b_mesh.uv_layers.begin(
l);
l != b_mesh.uv_layers.end(); ++
l, uv_num++) {
649 const bool active_render =
l->active_render();
651 const ustring
name = ustring(
l->name().c_str());
671 for (
size_t curve = 0; curve < CData.
curve_uv.
size(); curve++) {
682template<
typename TypeInCycles,
typename GetValueAtIndex>
684 const int num_points,
687 const GetValueAtIndex &get_value_at_index)
691 for (
int i = 0;
i < num_points;
i++) {
692 data[
i] = get_value_at_index(
i);
697 for (
int i = 0;
i < num_curves;
i++) {
698 data[
i] = get_value_at_index(
i);
711 const float motion_scale)
713 const int num_curve_keys = hair->get_curve_keys().size();
716 hair->set_motion_steps(3);
719 float3 *
P = hair->get_curve_keys().data();
727 const float motion_times[2] = {-1.0f, 1.0f};
729 const float relative_time = motion_times[
step] * 0.5f * motion_scale;
732 for (
int i = 0;
i < num_curve_keys;
i++) {
741 const bool need_motion,
742 const float motion_scale)
747 static const ustring u_velocity(
"velocity");
749 bool have_uv =
false;
752 const ustring
name{std::string_view(iter.
name)};
757 if (need_motion &&
name == u_velocity) {
774 std::copy(src.begin(), src.end(), attr->
data_float2());
801 using BlenderT = decltype(dummy);
802 using Converter = typename ccl::AttributeConverter<BlenderT>;
803 using CyclesT = typename Converter::CyclesT;
804 if constexpr (!std::is_void_v<CyclesT>) {
805 Attribute *attr = attributes.add(name, Converter::type_desc, element);
806 CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
808 const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
809 for (const int i : src.index_range()) {
810 data[i] = Converter::convert(src[i]);
822 b_positions[index][0], b_positions[index][1], b_positions[index][2], 0.0f);
823 mP.
w = b_radius.
is_empty() ? 0.005f : b_radius[index];
829 const int first_point_index,
830 const int num_points,
833 const float curve_t =
step * (num_points - 1);
834 const int point_a =
clamp((
int)curve_t, 0, num_points - 1);
835 const int point_b =
min(point_a + 1, num_points - 1);
836 const float t = curve_t - (
float)point_a;
845 const bool need_motion,
846 const float motion_scale)
853 float3 *curve_keys = hair->get_curve_keys().data();
854 float *curve_radius = hair->get_curve_radius().data();
855 int *curve_first_key = hair->get_curve_first_key().data();
856 int *curve_shader = hair->get_curve_shader().data();
859 float *attr_intercept =
nullptr;
860 float *attr_length =
nullptr;
867 b_curves, {point_normals.data(),
int64_t(point_normals.size())});
869 attr_normal[
i] =
make_float3(point_normals[
i][0], point_normals[
i][1], point_normals[
i][2]);
889 std::copy(points_by_curve.
data().data(),
890 points_by_curve.
data().data() + points_by_curve.
size(),
892 std::fill(curve_shader, curve_shader + points_by_curve.
size(), 0);
894 std::copy(b_radius.
data(), b_radius.
data() + positions.
size(), curve_radius);
897 std::fill(curve_radius, curve_radius + positions.
size(), 0.005f);
901 for (
const int curve : points_by_curve.
index_range()) {
908 for (
const int point : points) {
909 const float3 co =
make_float3(positions[point][0], positions[point][1], positions[point][2]);
911 curve_keys[point] = co;
913 if (attr_length || attr_intercept) {
914 if (point != points.
first()) {
919 if (attr_intercept) {
920 attr_intercept[point] =
length;
926 if (attr_intercept &&
length > 0.0f) {
927 for (
const int point : points.
drop_front(1)) {
928 attr_intercept[point] /=
length;
934 attr_length[curve] =
length;
943 const int motion_step)
947 bool new_attribute =
false;
951 new_attribute =
true;
955 const size_t num_keys = hair->
num_keys();
958 bool have_motion =
false;
959 int num_motion_keys = 0;
969 if (curve_index >= num_curves) {
979 const int point = points[
i];
981 if (point < num_keys) {
989 curve_key.
w = hair->get_curve_radius()[
i];
990 have_motion = !(mP[
i] == curve_key);
998 const float step_size = curve.
num_keys > 1 ? 1.0f / (curve.
num_keys - 1) : 0.0f;
1000 const float step =
i * step_size;
1002 b_positions, b_radius, points.
start(), points.
size(),
step);
1010 if (new_attribute) {
1016void BlenderSync::sync_hair(
Hair *hair,
BObjectInfo &b_ob_info,
bool motion,
const int motion_step)
1020 const float motion_scale = (need_motion) ?
1021 scene->motion_shutter_time() /
1022 (b_scene.render().fps() / b_scene.render().fps_base()) :
1026 const blender::bke::CurvesGeometry &b_curves(
1035 const blender::VArray<int8_t> b_types = b_curves.curve_types();
1049 array<Node *> used_shaders = hair->get_used_shaders();
1052 new_hair.set_used_shaders(used_shaders);
1054 if (view_layer.use_hair) {
1057 sync_hair(&new_hair, b_ob_info,
false);
1064 sync_particle_hair(&new_hair, b_mesh, b_ob_info,
false);
1072 for (
const SocketType &socket : new_hair.
type->
inputs) {
1074 if (socket.
name ==
"use_motion_blur" || socket.
name ==
"used_shaders") {
1077 hair->
set_value(socket, new_hair, socket);
1088 const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
1093void BlenderSync::sync_hair_motion(
BObjectInfo &b_ob_info,
Hair *hair,
const int motion_step)
1101 if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
1104 sync_hair(hair, b_ob_info,
true, motion_step);
1111 sync_particle_hair(hair, b_mesh, b_ob_info,
true, motion_step);
Low-level operations for curves.
static bool ObtainCacheParticleData(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
static void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, const int motion_step)
static bool ObtainCacheParticleUV(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, const int uv_num)
static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CData)
static void export_hair_curves_motion(Hair *hair, const blender::bke::CurvesGeometry &b_curves, const int motion_step)
static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, const int sys, const int curve, const float step)
static void export_hair_curves(Scene *scene, Hair *hair, const blender::bke::CurvesGeometry &b_curves, const bool need_motion, const float motion_scale)
static float4 curve_point_as_float4(const blender::Span< blender::float3 > b_positions, const blender::Span< float > b_radius, const int index)
static float shaperadius(const float shape, const float root, const float tip, const float time)
static float4 CurveSegmentMotionCV(ParticleCurveData *CData, const int sys, const int curve, const int curvekey)
static void attr_create_motion_from_velocity(Hair *hair, const blender::Span< blender::float3 > src, const float motion_scale)
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)
static void export_hair_motion_validate_attribute(Hair *hair, const int motion_step, const int num_motion_keys, bool have_motion)
static void fill_generic_attribute(const int num_curves, const int num_points, TypeInCycles *data, const AttributeElement element, const GetValueAtIndex &get_value_at_index)
static void attr_create_generic(Scene *scene, Hair *hair, const blender::bke::CurvesGeometry &b_curves, const bool need_motion, const float motion_scale)
static bool ObtainCacheParticleVcol(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, const int vcol_num)
BMesh const char void * data
ATTR_WARN_UNUSED_RESULT const void * element
ATTR_WARN_UNUSED_RESULT const BMLoop * l
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
void update(AttributeSet &&new_attributes)
Attribute * find(ustring name) const
Attribute * add(ustring name, const TypeDesc type, AttributeElement element)
void remove(ustring name)
void tag_update(Scene *scene, bool rebuild)
bool need_attribute(Scene *scene, AttributeStandard std)
void add_curve_key(const float3 co, const float radius)
Curve get_curve(const size_t i) const
void add_curve(const int first_key, const int shader)
size_t num_curves() const
void copy_center_to_motion_step(const int motion_step)
void resize_curves(const int numcurves, const int numkeys)
CurveShapeType curve_shape
void clear(bool preserve_shaders=false) override
void reserve_curves(const int numcurves, const int numkeys)
array< int > curve_firstkey
array< bool > psys_closetip
array< float > psys_tipradius
array< float > curve_length
array< float4 > curve_vcol
array< float > curvekey_time
array< float > psys_rootradius
array< int > psys_firstcurve
array< int > psys_curvenum
array< float > psys_shape
array< int > curve_keynum
array< float3 > curvekey_co
void reserve(const size_t newcapacity)
void push_back_slow(const T &t)
const CPPType & type() const
constexpr int64_t first() const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange index_range() const
constexpr IndexRange drop_front(int64_t n) const
Span< NewT > constexpr cast() const
constexpr const T * data() const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
GAttributeReader get() const
OffsetIndices< int > points_by_curve() const
Span< float3 > positions() const
AttributeAccessor attributes() const
IndexRange index_range() const
ccl_device float4 color_srgb_to_linear_v4(const float4 c)
static BL::Mesh object_to_mesh(BObjectInfo &b_ob_info)
static void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
static void free_object_to_mesh(BObjectInfo &b_ob_info, BL::Mesh &mesh)
static bool object_need_motion_attribute(BObjectInfo &b_ob_info, Scene *scene)
static Transform get_transform(const BL::Array< float, 16 > &array)
#define CCL_NAMESPACE_END
#define assert(assertion)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
constexpr T clamp(T, U, U) RET
float length(VecOp< float, D >) RET
VecBase< float, 2 > float2
VecBase< float, 4 > float4
VecBase< float, 3 > float3
ccl_device_inline float hash_uint2_to_float(const uint kx, const uint ky)
@ ATTR_STD_CURVE_INTERCEPT
@ ATTR_STD_MOTION_VERTEX_POSITION
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
ccl_device_inline float len_squared(const float2 a)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void curves_normals_point_domain_calc(const CurvesGeometry &curves, MutableSpan< float3 > normals)
VecBase< float, 2 > float2
VecBase< float, 3 > float3
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR)
bool is_real_object_data() const
vector< SocketType, std::allocator< SocketType > > inputs
void set_value(const SocketType &socket, const Node &other, const SocketType &other_socket)