18#include "util/color.h"
32static float shaperadius(
float shape,
float root,
float tip,
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() == b_mod.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 int shader =
clamp(b_part.material() - 1, 0, hair->get_used_shaders().size() - 1);
76 int display_step = background ? b_part.render_step() : b_part.display_step();
77 int totparts = b_psys.particles.length();
78 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;
89 int ren_step = (1 << display_step) + 1;
90 if (b_part.kink() == BL::ParticleSettings::kink_SPIRAL)
91 ren_step += b_part.kink_extra_steps();
97 float radius = b_part.radius_scale() * 0.5f;
105 if (!(b_part.child_type() == 0) && totchild != 0)
108 int num_add = (totparts + totchild - pa_no);
115 for (; pa_no < totparts + totchild; pa_no++) {
119 float curve_length = 0.0f;
122 for (
int step_no = 0; step_no < ren_step; step_no++) {
123 float3 co_world = prev_co_world;
124 b_psys.co_hair(*b_ob, pa_no, step_no, &co_world.
x);
127 const float step_length =
len(co_object - prev_co_object);
128 curve_length += step_length;
132 prev_co_object = co_object;
133 prev_co_world = co_world;
156 if (!(hair && b_mesh && b_ob && CData)) {
162 for (BL::Modifier &b_mod : b_ob->modifiers) {
163 if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
164 (background ? b_mod.show_render() : b_mod.show_viewport()))
166 BL::ParticleSystemModifier psmd((
const PointerRNA)b_mod.ptr);
167 BL::ParticleSystem b_psys((
const PointerRNA)psmd.particle_system().ptr);
168 BL::ParticleSettings b_part((
const PointerRNA)b_psys.settings().ptr);
170 if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
171 (b_part.type() == BL::ParticleSettings::type_HAIR))
173 int totparts = b_psys.particles.length();
174 int totchild = background ? b_psys.child_particles.length() :
175 (
int)((
float)b_psys.child_particles.length() *
176 (
float)b_part.display_percentage() / 100.0f);
177 int totcurves = totchild;
179 if (b_part.child_type() == 0 || totchild == 0)
180 totcurves += totparts;
186 if (!(b_part.child_type() == 0) && totchild != 0)
189 int num_add = (totparts + totchild - pa_no);
192 BL::ParticleSystem::particles_iterator b_pa;
193 b_psys.particles.begin(b_pa);
194 for (; pa_no < totparts + totchild; pa_no++) {
196 BL::Mesh::uv_layers_iterator
l;
197 b_mesh->uv_layers.begin(
l);
200 if (!b_mesh->uv_layers.empty())
201 b_psys.uv_on_emitter(psmd, *b_pa, pa_no, uv_num, &uv.
x);
204 if (pa_no < totparts && b_pa != b_psys.particles.end())
221 if (!(hair && b_mesh && b_ob && CData)) {
227 for (BL::Modifier &b_mod : b_ob->modifiers) {
228 if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
229 (background ? b_mod.show_render() : b_mod.show_viewport()))
231 BL::ParticleSystemModifier psmd((
const PointerRNA)b_mod.ptr);
232 BL::ParticleSystem b_psys((
const PointerRNA)psmd.particle_system().ptr);
233 BL::ParticleSettings b_part((
const PointerRNA)b_psys.settings().ptr);
235 if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
236 (b_part.type() == BL::ParticleSettings::type_HAIR))
238 int totparts = b_psys.particles.length();
239 int totchild = background ? b_psys.child_particles.length() :
240 (
int)((
float)b_psys.child_particles.length() *
241 (
float)b_part.display_percentage() / 100.0f);
242 int totcurves = totchild;
244 if (b_part.child_type() == 0 || totchild == 0)
245 totcurves += totparts;
251 if (!(b_part.child_type() == 0) && totchild != 0)
254 int num_add = (totparts + totchild - pa_no);
257 BL::ParticleSystem::particles_iterator b_pa;
258 b_psys.particles.begin(b_pa);
259 for (; pa_no < totparts + totchild; pa_no++) {
261 BL::Mesh::vertex_colors_iterator
l;
262 b_mesh->vertex_colors.begin(
l);
265 if (!b_mesh->vertex_colors.empty())
266 b_psys.mcol_on_emitter(psmd, *b_pa, pa_no, vcol_num, &vcol.x);
269 if (pa_no < totparts && b_pa != b_psys.particles.end())
284 if (hair->num_curves()) {
317 hair->reserve_curves(hair->num_curves() + num_curves, hair->get_curve_keys().size() + num_keys);
328 size_t num_curve_keys = 0;
337 const float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
345 hair->add_curve_key(ickey_loc, radius);
346 if (attr_intercept) {
347 attr_intercept->
add(time);
359 if (attr_length !=
NULL) {
363 if (attr_random !=
NULL) {
367 hair->add_curve(num_keys, CData->
psys_shader[sys]);
368 num_keys += num_curve_keys;
374 if ((hair->get_curve_keys().size() != num_keys) || (hair->num_curves() != num_curves)) {
375 VLOG_WARNING <<
"Hair memory allocation failed, clearing data.";
385 float time = (curve_length > 0.0f) ? curve_time / curve_length : 0.0f;
403 assert(step >= 0.0f);
404 assert(step <= 1.0f);
408 const float remainder = curve_key_f - curvekey;
409 if (remainder == 0.0f) {
412 int curvekey2 = curvekey + 1;
415 curvekey = curvekey2 - 1;
419 return mix(mP, mP2, remainder);
428 const int num_keys = hair->get_curve_keys().size();
430 if (num_motion_keys != num_keys || !have_motion) {
432 if (num_motion_keys != num_keys) {
433 VLOG_WORK <<
"Hair topology changed, removing motion attribute.";
437 else if (motion_step > 0) {
440 for (
int step = 0; step < motion_step; step++) {
441 float4 *mP = attr_mP->
data_float4() + step * num_keys;
443 for (
int key = 0; key < num_keys; key++) {
445 mP[key].w = hair->get_curve_radius()[key];
455 bool new_attribute =
false;
460 new_attribute =
true;
464 size_t numkeys = hair->get_curve_keys().size();
465 float4 *mP = attr_mP->
data_float4() + motion_step * numkeys;
466 bool have_motion =
false;
476 int curve_key_end = (num_curves + 1 < (
int)hair->get_curve_first_key().size() ?
477 hair->get_curve_first_key()[num_curves + 1] :
478 (
int)hair->get_curve_keys().size());
479 const int num_center_curve_keys = curve_key_end - hair->get_curve_first_key()[num_curves];
480 const int is_num_keys_different = CData->
curve_keynum[
curve] - num_center_curve_keys;
482 if (!is_num_keys_different) {
487 if (i < hair->get_curve_keys().size()) {
494 curve_key.w = hair->get_curve_radius()[i];
495 if (
len_squared(mP[i] - curve_key) > 1e-5f * 1e-5f) {
506 const float step_size = num_center_curve_keys > 1 ? 1.0f / (num_center_curve_keys - 1) :
508 for (
int step_index = 0; step_index < num_center_curve_keys; ++step_index) {
509 const float step = step_index * step_size;
527bool BlenderSync::object_has_particle_hair(BL::Object b_ob)
530 for (BL::Modifier &b_mod : b_ob.modifiers) {
531 if ((b_mod.type() == b_mod.type_PARTICLE_SYSTEM) &&
532 (preview ? b_mod.show_viewport() : b_mod.show_render()))
534 BL::ParticleSystemModifier psmd((
const PointerRNA)b_mod.ptr);
535 BL::ParticleSystem b_psys((
const PointerRNA)psmd.particle_system().ptr);
536 BL::ParticleSettings b_part((
const PointerRNA)b_psys.settings().ptr);
538 if ((b_part.render_type() == BL::ParticleSettings::render_type_PATH) &&
539 (b_part.type() == BL::ParticleSettings::type_HAIR))
550void BlenderSync::sync_particle_hair(
551 Hair *hair, BL::Mesh &b_mesh,
BObjectInfo &b_ob_info,
bool motion,
int motion_step)
559 if (b_ob.mode() == b_ob.mode_PARTICLE_EDIT || b_ob.mode() == b_ob.mode_EDIT) {
587 for (
size_t i = 0; i < hair->num_curves(); i++) {
588 float3 co = hair->get_curve_keys()[hair->get_curve(i).first_key];
589 generated[i] = co * size - loc;
596 BL::Mesh::vertex_colors_iterator
l;
599 for (b_mesh.vertex_colors.begin(
l);
l != b_mesh.vertex_colors.end(); ++
l, vcol_num++) {
600 if (!hair->need_attribute(scene, ustring(
l->name().c_str()))) {
615 for (
size_t curve = 0; curve < CData.
curve_vcol.
size(); curve++) {
624 BL::Mesh::uv_layers_iterator
l;
627 for (b_mesh.uv_layers.begin(
l);
l != b_mesh.uv_layers.end(); ++
l, uv_num++) {
628 bool active_render =
l->active_render();
630 ustring name = ustring(
l->name().c_str());
633 if (hair->need_attribute(scene, name) || hair->need_attribute(scene, std)) {
639 attr_uv = hair->attributes.
add(std, name);
650 for (
size_t curve = 0; curve < CData.
curve_uv.
size(); curve++) {
659template<
typename TypeInCycles,
typename GetValueAtIndex>
661 const int num_points,
664 const GetValueAtIndex &get_value_at_index)
668 for (
int i = 0; i < num_points; i++) {
669 data[i] = get_value_at_index(i);
674 for (
int i = 0; i < num_curves; i++) {
675 data[i] = get_value_at_index(i);
688 const float motion_scale)
690 const int num_curve_keys = hair->get_curve_keys().size();
693 hair->set_motion_steps(3);
696 float3 *
P = &hair->get_curve_keys()[0];
704 float motion_times[2] = {-1.0f, 1.0f};
705 for (
int step = 0; step < 2; step++) {
706 const float relative_time = motion_times[step] * 0.5f * motion_scale;
709 for (
int i = 0; i < num_curve_keys; i++) {
710 mP[i] =
P[i] +
make_float3(src[i][0], src[i][1], src[i][2]) * relative_time;
718 const bool need_motion,
719 const float motion_scale)
724 static const ustring u_velocity(
"velocity");
725 const bool need_uv = hair->need_attribute(scene,
ATTR_STD_UV);
726 bool have_uv =
false;
729 const ustring name{std::string_view(iter.
name)};
734 if (need_motion && name == u_velocity) {
751 std::copy(src.begin(), src.end(), attr->
data_float2());
756 if (!hair->need_attribute(scene, name)) {
759 if (attributes.find(name)) {
778 using BlenderT = decltype(dummy);
779 using Converter = typename ccl::AttributeConverter<BlenderT>;
780 using CyclesT = typename Converter::CyclesT;
781 if constexpr (!std::is_void_v<CyclesT>) {
782 Attribute *attr = attributes.add(name, Converter::type_desc, element);
783 CyclesT *data = reinterpret_cast<CyclesT *>(attr->data());
785 const blender::VArraySpan src = b_attr.varray.typed<BlenderT>();
786 for (const int i : src.index_range()) {
787 data[i] = Converter::convert(src[i]);
799 b_positions[index][0], b_positions[index][1], b_positions[index][2], 0.0f);
800 mP.w = b_radius.
is_empty() ? 0.005f : b_radius[index];
806 const int first_point_index,
807 const int num_points,
810 const float curve_t = step * (num_points - 1);
811 const int point_a =
clamp((
int)curve_t, 0, num_points - 1);
812 const int point_b =
min(point_a + 1, num_points - 1);
813 const float t = curve_t - (
float)point_a;
822 const bool need_motion,
823 const float motion_scale)
828 hair->resize_curves(points_by_curve.
size(), positions.size());
830 float3 *curve_keys = hair->get_curve_keys().data();
831 float *curve_radius = hair->get_curve_radius().data();
832 int *curve_first_key = hair->get_curve_first_key().data();
833 int *curve_shader = hair->get_curve_shader().data();
836 float *attr_intercept =
NULL;
837 float *attr_length =
NULL;
844 b_curves, {point_normals.data(),
int64_t(point_normals.size())});
845 for (
const int i : positions.index_range()) {
846 attr_normal[i] =
make_float3(point_normals[i][0], point_normals[i][1], point_normals[i][2]);
858 for (
const int i : points_by_curve.
index_range()) {
866 std::copy(points_by_curve.
data().data(),
867 points_by_curve.
data().data() + points_by_curve.
size(),
869 std::fill(curve_shader, curve_shader + points_by_curve.
size(), 0);
871 std::copy(b_radius.
data(), b_radius.
data() + positions.size(), curve_radius);
874 std::fill(curve_radius, curve_radius + positions.size(), 0.005f);
878 for (
const int curve : points_by_curve.
index_range()) {
885 for (
const int point : points) {
886 const float3 co =
make_float3(positions[point][0], positions[point][1], positions[point][2]);
888 curve_keys[
point] = co;
890 if (attr_length || attr_intercept) {
891 if (point != points.first()) {
892 length +=
len(co - prev_co);
896 if (attr_intercept) {
903 if (attr_intercept && length > 0.0f) {
904 for (
const int point : points.drop_front(1)) {
924 bool new_attribute =
false;
928 new_attribute =
true;
932 const size_t num_keys = hair->num_keys();
933 const size_t num_curves = hair->num_curves();
934 float4 *mP = attr_mP->
data_float4() + motion_step * num_keys;
935 bool have_motion =
false;
936 int num_motion_keys = 0;
944 for (
const int i : points_by_curve.
index_range()) {
946 if (curve_index >= num_curves) {
953 if (points.size() == curve.num_keys) {
955 for (
const int i : points.index_range()) {
956 int point = points[i];
958 if (point < num_keys) {
966 curve_key.w = hair->get_curve_radius()[i];
967 have_motion = !(mP[i] == curve_key);
975 const float step_size = curve.num_keys > 1 ? 1.0f / (curve.num_keys - 1) : 0.0f;
976 for (
int i = 0; i < curve.num_keys; i++) {
977 const float step = i * step_size;
979 b_positions, b_radius, points.start(), points.
size(), step);
993void BlenderSync::sync_hair(
Hair *hair,
BObjectInfo &b_ob_info,
bool motion,
int motion_step)
997 const float motion_scale = (need_motion) ?
998 scene->motion_shutter_time() /
999 (b_scene.render().fps() / b_scene.render().fps_base()) :
1013void BlenderSync::sync_hair(BL::Depsgraph b_depsgraph,
BObjectInfo &b_ob_info,
Hair *hair)
1020 new_hair.set_used_shaders(used_shaders);
1022 if (view_layer.use_hair) {
1025 sync_hair(&new_hair, b_ob_info,
false);
1034 sync_particle_hair(&new_hair, b_mesh, b_ob_info,
false);
1042 for (
const SocketType &socket : new_hair.type->inputs) {
1044 if (socket.name ==
"use_motion_blur" || socket.name ==
"motion_steps" ||
1045 socket.name ==
"used_shaders")
1049 hair->set_value(socket, new_hair, socket);
1052 hair->attributes.update(std::move(new_hair.
attributes));
1058 const bool rebuild = (hair->curve_keys_is_modified() || hair->curve_radius_is_modified());
1060 hair->tag_update(scene, rebuild);
1063void BlenderSync::sync_hair_motion(BL::Depsgraph b_depsgraph,
1069 if (hair->num_keys() == 0) {
1074 if (ccl::BKE_object_is_deform_modified(b_ob_info, b_scene, preview)) {
1077 sync_hair(hair, b_ob_info,
true, motion_step);
1085 sync_particle_hair(hair, b_mesh, b_ob_info,
true, motion_step);
1093 hair->copy_center_to_motion_step(motion_step);
Low-level operations for curves.
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a point
static bool ObtainCacheParticleData(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background)
static float4 CurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, int curvekey)
static void export_hair_motion_validate_attribute(Hair *hair, int motion_step, int num_motion_keys, bool have_motion)
static bool ObtainCacheParticleUV(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int uv_num)
static bool ObtainCacheParticleVcol(Hair *hair, BL::Mesh *b_mesh, BL::Object *b_ob, ParticleCurveData *CData, bool background, int vcol_num)
static void ExportCurveSegments(Scene *scene, Hair *hair, ParticleCurveData *CData)
static float shaperadius(float shape, float root, float tip, float time)
static void export_hair_curves_motion(Hair *hair, const blender::bke::CurvesGeometry &b_curves, int motion_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 void ExportCurveSegmentsMotion(Hair *hair, ParticleCurveData *CData, int motion_step)
static void attr_create_motion_from_velocity(Hair *hair, const blender::Span< blender::float3 > src, const float motion_scale)
static float4 LerpCurveSegmentMotionCV(ParticleCurveData *CData, int sys, int curve, float step)
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 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)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE btScalar length() const
Return the length of the vector.
list< Attribute > attributes
bool need_attribute(Scene *scene, AttributeStandard std)
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(size_t newcapacity)
void push_back_slow(const T &t)
const CPPType & type() const
Span< NewT > constexpr cast() const
constexpr const T * data() const
constexpr int64_t size() const
constexpr bool is_empty() const
void foreach_attribute(const FunctionRef< void(const AttributeIter &)> fn) const
GAttributeReader lookup(const StringRef attribute_id) const
eCustomDataType data_type
GAttributeReader get() const
OffsetIndices< int > points_by_curve() const
Span< float3 > positions() const
AttributeAccessor attributes() const
IndexRange index_range() const
static void mesh_texture_space(const ::Mesh &b_mesh, float3 &loc, float3 &size)
static void free_object_to_mesh(BL::BlendData &, BObjectInfo &b_ob_info, BL::Mesh &mesh)
static BL::Mesh object_to_mesh(BL::BlendData &, BObjectInfo &b_ob_info, BL::Depsgraph &, bool, Mesh::SubdivisionType subdivision_type)
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
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
ccl_device_inline float hash_uint2_to_float(uint kx, 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, 4 > float4
VecBase< float, 2 > float2
static constexpr TypeDesc TypeRGBA(TypeDesc::FLOAT, TypeDesc::VEC4, TypeDesc::COLOR)
CCL_NAMESPACE_BEGIN static OIIO_NAMESPACE_USING constexpr TypeDesc TypeFloat2(TypeDesc::FLOAT, TypeDesc::VEC2)
bool is_real_object_data() const
ccl_device float4 color_srgb_to_linear_v4(float4 c)
ccl_device_inline float4 float3_to_float4(const float3 a)
ccl_device_inline int clamp(int a, int mn, int mx)