From 4a719ab7072313252e978ca544c1b8c997864753 Mon Sep 17 00:00:00 2001 From: Shekn Date: Thu, 20 Jul 2023 16:28:00 +0500 Subject: [PATCH 1/8] Improve GLTF pbrMetallicRoughness shader suppot Fix #16. Use only R-channel of the occlusion color. --- .../cyc_materials/cyc_gltf_shaders.cpp | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/render_cycles/cyc_scene/cyc_materials/cyc_gltf_shaders.cpp b/src/render_cycles/cyc_scene/cyc_materials/cyc_gltf_shaders.cpp index d4161c6..fef2cb4 100644 --- a/src/render_cycles/cyc_scene/cyc_materials/cyc_gltf_shaders.cpp +++ b/src/render_cycles/cyc_scene/cyc_materials/cyc_gltf_shaders.cpp @@ -61,11 +61,24 @@ ccl::ShaderNode* sync_gltf_shader(ccl::Scene* scene, ccl::ShaderGraph* shader_gr XSI::MATH::CColor4f xsi_emissive_color = get_color_parameter_value(xsi_gltf_params, "emissiveFactor", eval_time); // base color is mix of the actual base color texture and occlusion + ccl::SeparateColorNode* occlusion_separator = shader_graph->create_node(); + shader_graph->add(occlusion_separator); + XSI::ShaderParameter xsi_occlusion_texture = xsi_gltf_params.GetItem("occlusionTexture"); + sync_float3_parameter(scene, shader_graph, occlusion_separator, xsi_occlusion_texture, nodes_map, aovs, "Color", eval_time); + occlusion_separator->set_color(ccl::make_float3(1.0f, 1.0f, 1.0f)); + // extract only R channel from occlusion color + // conver it to the color + ccl::CombineColorNode* occlusion_combiner = shader_graph->create_node(); + shader_graph->add(occlusion_combiner); + // connect r-output of the separator to all cahnnels of the combiner + shader_graph->connect(occlusion_separator->output("Red"), occlusion_combiner->input("Red")); + shader_graph->connect(occlusion_separator->output("Red"), occlusion_combiner->input("Green")); + shader_graph->connect(occlusion_separator->output("Red"), occlusion_combiner->input("Blue")); + + // use occlusion combiner output (Color port) as input to the color multiplicator ccl::MixNode* occlusion_mix = shader_graph->create_node(); shader_graph->add(occlusion_mix); - XSI::ShaderParameter xsi_occlusion_texture = xsi_gltf_params.GetItem("occlusionTexture"); - sync_float3_parameter(scene, shader_graph, occlusion_mix, xsi_occlusion_texture, nodes_map, aovs, "Color2", eval_time); - occlusion_mix->set_color2(ccl::make_float3(1.0f, 1.0f, 1.0f)); + shader_graph->connect(occlusion_combiner->output("Color"), occlusion_mix->input("Color2")); occlusion_mix->set_mix_type(ccl::NodeMix::NODE_MIX_MUL); occlusion_mix->set_fac(xsi_occlusion_strength); From 99439c6b27bbf6c6c35edc6bc3fcd669f9971a77 Mon Sep 17 00:00:00 2001 From: Shekn Date: Thu, 20 Jul 2023 17:50:10 +0500 Subject: [PATCH 2/8] Setup proper names of the Cycles geometry objects Fix #11. Not only polygon mesh objects, but also for pointclouds, strands, hairs and vdb-primitives. --- .../cyc_scene/cyc_geometry/cyc_hair.cpp | 3 ++ .../cyc_scene/cyc_geometry/cyc_points.cpp | 3 ++ .../cyc_scene/cyc_geometry/cyc_polymesh.cpp | 1 + .../cyc_scene/cyc_geometry/cyc_strands.cpp | 3 ++ .../cyc_scene/cyc_geometry/cyc_vdb_volume.cpp | 2 ++ .../cyc_scene/cyc_geometry/cyc_volume.cpp | 3 ++ src/utilities/strings.cpp | 29 +++++++++++++++++++ src/utilities/strings.h | 12 +++++++- 8 files changed, 55 insertions(+), 1 deletion(-) diff --git a/src/render_cycles/cyc_scene/cyc_geometry/cyc_hair.cpp b/src/render_cycles/cyc_scene/cyc_geometry/cyc_hair.cpp index 12d76a7..5919162 100644 --- a/src/render_cycles/cyc_scene/cyc_geometry/cyc_hair.cpp +++ b/src/render_cycles/cyc_scene/cyc_geometry/cyc_hair.cpp @@ -15,6 +15,7 @@ #include "../../../utilities/xsi_properties.h" #include "../../../utilities/math.h" #include "../../../utilities/logs.h" +#include "../../../utilities/strings.h" #include "../cyc_scene.h" #include "cyc_geometry.h" @@ -416,6 +417,8 @@ void sync_hair_motion_deform(ccl::Hair* hair, UpdateContext* update_context, con void sync_hair_geom_process(ccl::Scene* scene, ccl::Hair* hair_geom, UpdateContext* update_context, const XSI::HairPrimitive &xsi_hair, XSI::X3DObject &xsi_object, bool motion_deform) { + hair_geom->name = combine_geometry_name(xsi_object, xsi_hair).GetAsciiString(); + ccl::vector original_positions; // save here positions for motion invalid attributes LONG num_keys = 0; bool use_motion_blur = update_context->get_need_motion() && motion_deform; diff --git a/src/render_cycles/cyc_scene/cyc_geometry/cyc_points.cpp b/src/render_cycles/cyc_scene/cyc_geometry/cyc_points.cpp index aed47fa..b350f34 100644 --- a/src/render_cycles/cyc_scene/cyc_geometry/cyc_points.cpp +++ b/src/render_cycles/cyc_scene/cyc_geometry/cyc_points.cpp @@ -20,6 +20,7 @@ #include "cyc_geometry.h" #include "../cyc_scene.h" #include "../../../utilities/math.h" +#include "../../../utilities/strings.h" bool is_pointcloud_points(XSI::X3DObject &xsi_object, const XSI::CTime &eval_time) { @@ -224,6 +225,8 @@ void sync_points_deform(ccl::PointCloud* points_geom, UpdateContext* update_cont void sync_points_geom_process(ccl::Scene* scene, ccl::PointCloud* points_geom, UpdateContext* update_context, const XSI::Primitive& xsi_primitive, XSI::X3DObject& xsi_object, bool motion_deform) { + points_geom->name = combine_geometry_name(xsi_object, xsi_primitive).GetAsciiString(); + ccl::vector original_positions; bool use_motion_blur = update_context->get_need_motion() && motion_deform; diff --git a/src/render_cycles/cyc_scene/cyc_geometry/cyc_polymesh.cpp b/src/render_cycles/cyc_scene/cyc_geometry/cyc_polymesh.cpp index 0ac172f..495855b 100644 --- a/src/render_cycles/cyc_scene/cyc_geometry/cyc_polymesh.cpp +++ b/src/render_cycles/cyc_scene/cyc_geometry/cyc_polymesh.cpp @@ -558,6 +558,7 @@ void sync_polymesh_process(ccl::Scene* scene, ccl::Mesh* mesh_geom, UpdateContex { // geometry is new, create it XSI::PolygonMesh xsi_polymesh = xsi_primitive.GetGeometry(eval_time, XSI::siConstructionModeSecondaryShape); + mesh_geom->name = combine_geometry_name(xsi_object, xsi_polymesh).GetAsciiString(); // get geometry property XSI::Property geo_property; diff --git a/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp b/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp index a932e61..f8bbba7 100644 --- a/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp +++ b/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp @@ -18,6 +18,7 @@ #include "../cyc_scene.h" #include "../../../utilities/math.h" #include "../../../utilities/logs.h" +#include "../../../utilities/strings.h" #include "../../../utilities/xsi_properties.h" bool is_pointcloud_strands(const XSI::X3DObject& xsi_object) @@ -306,6 +307,8 @@ void sync_strands_property(XSI::X3DObject& xsi_object, float& io_tip_prop, const // and also define motion deform, if we need it void sync_strands_geom_process(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext* update_context, const XSI::Primitive& xsi_primitive, XSI::X3DObject& xsi_object, bool motion_deform) { + strands_geom->name = combine_geometry_name(xsi_object, xsi_primitive).GetAsciiString(); + ccl::vector original_positions; LONG num_curves = 0; bool use_motion_blur = update_context->get_need_motion() && motion_deform; diff --git a/src/render_cycles/cyc_scene/cyc_geometry/cyc_vdb_volume.cpp b/src/render_cycles/cyc_scene/cyc_geometry/cyc_vdb_volume.cpp index 819f855..a33c13f 100644 --- a/src/render_cycles/cyc_scene/cyc_geometry/cyc_vdb_volume.cpp +++ b/src/render_cycles/cyc_scene/cyc_geometry/cyc_vdb_volume.cpp @@ -47,6 +47,8 @@ bool is_vector_type(openvdb::GridBase::ConstPtr grid) void sync_vdb_volume_geom_process(ccl::Scene* scene, ccl::Volume* volume_geom, UpdateContext* update_context, XSI::X3DObject& xsi_object, const VDBData& vdb_data, const XSI::CString &file_path) { + volume_geom->name = combine_geometry_name(xsi_object, "vdb").GetAsciiString(); + XSI::CTime eval_time = update_context->get_time(); sync_volume_parameters(volume_geom, xsi_object, eval_time); diff --git a/src/render_cycles/cyc_scene/cyc_geometry/cyc_volume.cpp b/src/render_cycles/cyc_scene/cyc_geometry/cyc_volume.cpp index 322c8a6..819dc81 100644 --- a/src/render_cycles/cyc_scene/cyc_geometry/cyc_volume.cpp +++ b/src/render_cycles/cyc_scene/cyc_geometry/cyc_volume.cpp @@ -26,6 +26,7 @@ #include "../../../utilities/xsi_properties.h" #include "../../../utilities/logs.h" #include "../../../utilities/arrays.h" +#include "../../../utilities/strings.h" #include "../../../render_base/type_enums.h" bool is_pointcloud_volume(const XSI::X3DObject &xsi_object, const XSI::CTime &eval_time) @@ -187,6 +188,8 @@ void sync_volume_attribute(ccl::Scene* scene, ccl::Volume* volume_geom, bool is_ void sync_volume_geom_process(ccl::Scene* scene, ccl::Volume* volume_geom, UpdateContext* update_context, const XSI::Primitive &xsi_primitive, XSI::X3DObject &xsi_object) { + volume_geom->name = combine_geometry_name(xsi_object, xsi_primitive).GetAsciiString(); + XSI::CTime eval_time = update_context->get_time(); sync_volume_parameters(volume_geom, xsi_object, eval_time); diff --git a/src/utilities/strings.cpp b/src/utilities/strings.cpp index 2ebf8ec..10986d3 100644 --- a/src/utilities/strings.cpp +++ b/src/utilities/strings.cpp @@ -2,6 +2,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -426,4 +430,29 @@ XSI::CString vdbprimitive_inputs_to_path(const XSI::CParameterRefArray& params, } return full_path; +} + +XSI::CString combine_names(const XSI::CString &prefix, const XSI::CString &postfix) +{ + return prefix + "." + postfix; +} + +XSI::CString combine_geometry_name(const XSI::X3DObject &xsi_object, const XSI::PolygonMesh &xsi_polymesh) +{ + return combine_names(xsi_object.GetName(), xsi_polymesh.GetName()); +} + +XSI::CString combine_geometry_name(const XSI::X3DObject& xsi_object, const XSI::HairPrimitive& xsi_hair) +{ + return combine_names(xsi_object.GetName(), xsi_hair.GetName()); +} + +XSI::CString combine_geometry_name(const XSI::X3DObject& xsi_object, const XSI::Primitive& xsi_primitive) +{ + return combine_names(xsi_object.GetName(), xsi_primitive.GetName()); +} + +XSI::CString combine_geometry_name(const XSI::X3DObject& xsi_object, const XSI::CString &name) +{ + return combine_names(xsi_object.GetName(), name); } \ No newline at end of file diff --git a/src/utilities/strings.h b/src/utilities/strings.h index 3a613da..500c91d 100644 --- a/src/utilities/strings.h +++ b/src/utilities/strings.h @@ -2,6 +2,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -34,4 +38,10 @@ std::string build_source_image_path(const XSI::CString& path, const XSI::CString std::string replace_all_substrings(const std::string& input_string, const std::string& what_part, const std::string& replace_part); // return true if input string ends with a given fragment bool is_ends_with(const OIIO::ustring& input_string, const XSI::CString& end_fragment); -XSI::CString vdbprimitive_inputs_to_path(const XSI::CParameterRefArray& params, const XSI::CTime& eval_time); \ No newline at end of file +XSI::CString vdbprimitive_inputs_to_path(const XSI::CParameterRefArray& params, const XSI::CTime& eval_time); + +// these functions used for define Cycles geometry name from different types of XSI objects (for example for mesh->name) +XSI::CString combine_geometry_name(const XSI::X3DObject& xsi_object, const XSI::PolygonMesh& xsi_polymesh); +XSI::CString combine_geometry_name(const XSI::X3DObject& xsi_object, const XSI::HairPrimitive& xsi_hair); +XSI::CString combine_geometry_name(const XSI::X3DObject& xsi_object, const XSI::Primitive& xsi_primitive); +XSI::CString combine_geometry_name(const XSI::X3DObject& xsi_object, const XSI::CString& name); \ No newline at end of file From b189eec8c5916c6a920bc9f578d59cb6aa4a5bbc Mon Sep 17 00:00:00 2001 From: Shekn Date: Fri, 21 Jul 2023 18:59:28 +0500 Subject: [PATCH 3/8] Improve and bugfix of the strand rendering Fix #17. Also introduce the support of the strand size attribute. If it exists, then the system ignore tip property. For start point it use point size, for other strand knots (from strand positions) it use sizes of the array from StrandSize attribute. --- .../cyc_scene/cyc_geometry/cyc_strands.cpp | 272 ++++++++++++++---- src/utilities/logs.cpp | 33 +++ src/utilities/logs.h | 3 + 3 files changed, 251 insertions(+), 57 deletions(-) diff --git a/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp b/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp index f8bbba7..b4aae38 100644 --- a/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp +++ b/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp @@ -40,34 +40,79 @@ bool is_pointcloud_strands(const XSI::X3DObject& xsi_object) } } -void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext* update_context, const XSI::Primitive& xsi_primitive, bool use_motion_blur, float tip_prop, ccl::vector& out_original_positions, LONG& out_num_curves) +void sync_strands_geom(ccl::Scene* scene, + ccl::Hair* strands_geom, + UpdateContext* update_context, + const XSI::Primitive& xsi_primitive, + bool use_motion_blur, + float tip_prop, + // next three arrays comes with zero size + ccl::vector& out_original_positions, // total positions and sizes of current frame strands, one plain array, the split template into individual curves stores in the geometry object + ccl::vector &out_strand_points, // store here point indices with non-empty strands (the length of strand positions is non-zero), all other points should be ignored + ccl::vector &out_strand_lengths // store here strand sizes (the length of strand position attribute), consider only non-zero strands +) { XSI::CTime eval_time = update_context->get_time(); XSI::Geometry xsi_geometry = xsi_primitive.GetGeometry(eval_time); // get strands data from ICE XSI::ICEAttribute point_position_attr = xsi_geometry.GetICEAttributeFromName("PointPosition"); - XSI::ICEAttribute strand_position_atr = xsi_geometry.GetICEAttributeFromName("StrandPosition"); - XSI::ICEAttribute size_atr = xsi_geometry.GetICEAttributeFromName("Size"); + XSI::ICEAttribute strand_position_attr = xsi_geometry.GetICEAttributeFromName("StrandPosition"); + XSI::ICEAttribute size_attr = xsi_geometry.GetICEAttributeFromName("Size"); + // TODO: use, if it is possible, strand size attribute + XSI::ICEAttribute strand_size_attr = xsi_geometry.GetICEAttributeFromName("StrandSize"); // this is the radius of the strand, NOT the number of points + // strand_size_attr.IsDefined() can be false if the attribute is not defined in the ICE tree + // strand_size_attr.GetElementCount() is equal to the number of points + // context is siICENodeContextComponent0D (one element per point) + // data type is siICENodeDataFloat + // structure is siICENodeStructureArray (array of values), even if defined by only one value, it contains array with this one value, the length of the array may not be equal to the count of strand points + // fill the data XSI::CICEAttributeDataArrayVector3f point_position_data; point_position_attr.GetDataArray(point_position_data); XSI::CICEAttributeDataArray2DVector3f strand_position_data; - strand_position_atr.GetDataArray2D(strand_position_data); + strand_position_attr.GetDataArray2D(strand_position_data); XSI::CICEAttributeDataArrayFloat size_data; - size_atr.GetDataArray(size_data); + // TODO: more accurate control of the point size + // in trivial case (when we generate grid from two strands (1x2 or 2x1)) the data contains only one element, instead of 2 + // use this in prepare stage + size_attr.GetDataArray(size_data); + ULONG size_data_length = size_data.GetCount(); + + XSI::CICEAttributeDataArray2DFloat strand_size_data; + XSI::CICEAttributeDataArrayFloat one_strand_size_data; + bool use_strand_size = strand_size_attr.IsDefined(); + if (use_strand_size) + { + strand_size_attr.GetDataArray2D(strand_size_data); + } XSI::CICEAttributeDataArrayVector3f one_strand_data; - strand_position_data.GetSubArray(0, one_strand_data); - ULONG curves_count = point_position_data.GetCount(); - ULONG keys_count = one_strand_data.GetCount(); + // at first we should reserve the curves in the geometry + // so, iterate throw points and calculate indices of non-trivail strands + ULONG total_keys = 0; + ULONG total_curves = 0; + ULONG points_count = point_position_data.GetCount(); + for (size_t i = 0; i < points_count; i++) + { + // get the current strand length data + strand_position_data.GetSubArray(i, one_strand_data); + ULONG strand_length = one_strand_data.GetCount(); + // TODO: consider non-zero size or even the size is exist + if (strand_length > 0) + { + out_strand_points.push_back(i); + out_strand_lengths.push_back(strand_length); - out_num_curves = curves_count; + total_keys += strand_length + 1; // because each strand does not contains start point (point position) + total_curves += 1; + } + } - strands_geom->reserve_curves(curves_count, curves_count * (keys_count + 1)); + strands_geom->reserve_curves(total_curves, total_keys); ccl::Attribute* attr_intercept = NULL; ccl::Attribute* attr_random = NULL; ccl::Attribute* attr_length = NULL; @@ -87,45 +132,82 @@ void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext if (use_motion_blur) { - out_original_positions.resize(curves_count * (keys_count + 1)); + out_original_positions.resize(total_keys); } - for (size_t curve_index = 0; curve_index < curves_count; curve_index++) + ULONG strand_sizes_length = 0; + ULONG first_key = 0; + for (size_t curve_index = 0; curve_index < total_curves; curve_index++) { - strands_geom->add_curve_key(vector3_to_float3(point_position_data[curve_index]), size_data[curve_index]); + // get actual point index for this curve + size_t point_index = out_strand_points[curve_index]; // we should get data for this point and strand + + // set start point of the strand - point position + XSI::MATH::CVector3f point_position = point_position_data[point_index]; + // for initial strand point use point size + // if points size aray is empty, use zero value + // if the point index outside of the array, use the last value of the array + float point_size = size_data_length > 0 ? size_data[point_index < size_data_length ? point_index : size_data_length - 1] : 0.0; + strands_geom->add_curve_key(vector3_to_float3(point_position), point_size); + + // if we need motion blur, fill original positions array if (use_motion_blur) { - out_original_positions[original_index] = ccl::make_float4(point_position_data[curve_index].GetX(), point_position_data[curve_index].GetY(), point_position_data[curve_index].GetZ(), size_data[curve_index]); - original_index++; + out_original_positions[original_index] = ccl::make_float4(point_position.GetX(), point_position.GetY(), point_position.GetZ(), point_size); } + + // start strand, so the intercept attribute is 0.0 if (attr_intercept) { attr_intercept->add(0.0); } - strand_position_data.GetSubArray(curve_index, one_strand_data); - float total_time = one_strand_data.GetCount() + 1; - float strand_length = 0.0f; - for (ULONG k_index = 0; k_index < one_strand_data.GetCount(); k_index++) + // next we should fill positions of the other strand nodes + // get strand positions array + strand_position_data.GetSubArray(point_index, one_strand_data); + // one strand data contains non-zero values + // also extract strand sizes, if it exists + if (use_strand_size) { + strand_size_data.GetSubArray(point_index, one_strand_size_data); + // and save the array length + // we will use it later to check is the array is too short or not + strand_sizes_length = one_strand_size_data.GetCount(); + } + + ULONG strand_knots_length = one_strand_data.GetCount(); + float total_time = strand_knots_length + 1; // the total number of knots in the strand, with the star one + float strand_sparse_length = 0.0f; + for (ULONG k_index = 0; k_index < strand_knots_length; k_index++) + { + // use point size attribute and interpolate value by using tip_prop (by default = 0.0) float time = static_cast(k_index + 1) / total_time; - float radius = (1 - time) * size_data[curve_index] + time * size_data[curve_index] * tip_prop; - if (k_index + 1 == one_strand_data.GetCount() && tip_prop < 0.0001f) + float radius = (1 - time) * point_size + time * point_size * tip_prop; + if (k_index + 1 == strand_knots_length && tip_prop < 0.0001f) { radius = 0.0; } - strands_geom->add_curve_key(vector3_to_float3(one_strand_data[k_index]), radius); + + if (use_strand_size && strand_sizes_length > 0) + { + // if we have the valid strand size attribute, override radius from point size + radius = one_strand_size_data[k_index < strand_sizes_length ? k_index : strand_sizes_length - 1]; + } + + XSI::MATH::CVector3f knot_position = one_strand_data[k_index]; + strands_geom->add_curve_key(vector3_to_float3(knot_position), radius); if (k_index > 0) { - float dx = one_strand_data[k_index].GetX() - one_strand_data[k_index - 1].GetX(); - float dy = one_strand_data[k_index].GetY() - one_strand_data[k_index - 1].GetY(); - float dz = one_strand_data[k_index].GetZ() - one_strand_data[k_index - 1].GetZ(); - strand_length += sqrtf(dx * dx + dy * dy + dz * dz); + XSI::MATH::CVector3f prev_knot_position = one_strand_data[k_index - 1]; + float dx = knot_position.GetX() - prev_knot_position.GetX(); + float dy = knot_position.GetY() - prev_knot_position.GetY(); + float dz = knot_position.GetZ() - prev_knot_position.GetZ(); + strand_sparse_length += sqrtf(dx * dx + dy * dy + dz * dz); } if (use_motion_blur) { - out_original_positions[original_index] = ccl::make_float4(one_strand_data[k_index].GetX(), one_strand_data[k_index].GetY(), one_strand_data[k_index].GetZ(), radius); + out_original_positions[original_index] = ccl::make_float4(knot_position.GetX(), knot_position.GetY(), knot_position.GetZ(), radius); original_index++; } @@ -140,9 +222,10 @@ void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext } if (attr_length != NULL) { - attr_length->add(strand_length); + attr_length->add(strand_sparse_length); } - strands_geom->add_curve(curve_index * (one_strand_data.GetCount() + 1), 0); + strands_geom->add_curve(first_key, 0); + first_key += strand_knots_length + 1; } ccl::Attribute* attr_generated = strands_geom->attributes.add(ccl::ATTR_STD_GENERATED); @@ -170,6 +253,8 @@ void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext if (attr_context == XSI::siICENodeContextComponent0D && attr_structure == XSI::siICENodeStructureSingle) { + // supports only one element per point + // like color and something similar XSI::siICENodeDataType attr_data_type = xsi_attribute.GetDataType(); if (attr_data_type == XSI::siICENodeDataVector3) @@ -180,9 +265,9 @@ void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext ccl::Attribute* cycles_attribute = strands_geom->attributes.add(attr_name, ccl::TypeVector, ccl::ATTR_ELEMENT_CURVE); ccl::float3* cyc_attr_data = cycles_attribute->data_float3(); - for (size_t v_index = 0; v_index < curves_count; v_index++) + for (size_t v_index = 0; v_index < total_curves; v_index++) { - *cyc_attr_data = vector3_to_float3(attr_data[v_index]); + *cyc_attr_data = vector3_to_float3(attr_data[out_strand_points[v_index]]); cyc_attr_data++; } } @@ -194,9 +279,9 @@ void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext ccl::Attribute* cycles_attribute = strands_geom->attributes.add(attr_name, ccl::TypeColor, ccl::ATTR_ELEMENT_CURVE); ccl::float4* cyc_attr_data = cycles_attribute->data_float4(); - for (size_t v_index = 0; v_index < curves_count; v_index++) + for (size_t v_index = 0; v_index < total_curves; v_index++) { - *cyc_attr_data = color4_to_float4(attr_data[v_index]); + *cyc_attr_data = color4_to_float4(attr_data[out_strand_points[v_index]]); cyc_attr_data++; } } @@ -208,9 +293,9 @@ void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext ccl::Attribute* cycles_attribute = strands_geom->attributes.add(attr_name, ccl::TypeFloat, ccl::ATTR_ELEMENT_CURVE); float* cyc_attr_data = cycles_attribute->data_float(); - for (size_t v_index = 0; v_index < curves_count; v_index++) + for (size_t v_index = 0; v_index < total_curves; v_index++) { - *cyc_attr_data = attr_data[v_index]; + *cyc_attr_data = attr_data[out_strand_points[v_index]]; cyc_attr_data++; } } @@ -219,7 +304,13 @@ void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext } } -void sync_strands_deform(ccl::Hair* hair, UpdateContext* update_context, const XSI::X3DObject &xsi_object, LONG num_curves, float tip_prop, const ccl::vector& original_positions) +void sync_strands_deform(ccl::Hair* hair, + UpdateContext* update_context, + const XSI::X3DObject &xsi_object, + float tip_prop, + const ccl::vector& original_positions, + const ccl::vector &strand_points, + const ccl::vector& strand_length) { size_t motion_steps = update_context->get_motion_steps(); hair->set_motion_steps(motion_steps); @@ -229,6 +320,12 @@ void sync_strands_deform(ccl::Hair* hair, UpdateContext* update_context, const X ccl::Attribute* attr_m_positions = hair->attributes.add(ccl::ATTR_STD_MOTION_VERTEX_POSITION, ccl::ustring("std_motion_strand_position")); ccl::float4* motion_positions = attr_m_positions->data_float4(); MotionSettingsPosition motion_position = update_context->get_motion_position(); + + // prepare data buffers + XSI::CICEAttributeDataArrayVector3f time_pos_data; + XSI::CICEAttributeDataArray2DVector3f time_strand_data; + XSI::CICEAttributeDataArrayFloat time_size_data; + XSI::CICEAttributeDataArray2DFloat time_strand_size_data; for (size_t mi = 0; mi < motion_steps - 1; mi++) { size_t time_motion_step = mi; @@ -250,35 +347,94 @@ void sync_strands_deform(ccl::Hair* hair, UpdateContext* update_context, const X XSI::ICEAttribute time_pos = time_xsi_geometry.GetICEAttributeFromName("PointPosition"); XSI::ICEAttribute time_strand = time_xsi_geometry.GetICEAttributeFromName("StrandPosition"); XSI::ICEAttribute time_size = time_xsi_geometry.GetICEAttributeFromName("Size"); + XSI::ICEAttribute time_strand_size = time_xsi_geometry.GetICEAttributeFromName("StrandSize"); + bool use_strand_size = time_strand_size.IsDefined(); if (time_pos.GetElementCount() > 0 && time_strand.GetElementCount() > 0 && time_size.GetElementCount() > 0) {// attributes exists, get the data - XSI::CICEAttributeDataArrayVector3f time_pos_data; - XSI::CICEAttributeDataArray2DVector3f time_strand_data; - XSI::CICEAttributeDataArrayFloat time_size_data; time_pos.GetDataArray(time_pos_data); time_strand.GetDataArray2D(time_strand_data); time_size.GetDataArray(time_size_data); + + ULONG time_points_count = time_pos_data.GetCount(); + ULONG time_sizes_count = time_size_data.GetCount(); + ULONG time_strands_count = time_strand_data.GetCount(); + ULONG time_strand_size_count = 0; + if (use_strand_size) + { + time_strand_size.GetDataArray2D(time_strand_size_data); + time_strand_size_count = time_strand_size_data.GetCount(); + } + // iterate throw strands - for (size_t c_index = 0; c_index < num_curves; c_index++) + size_t total_curves = strand_points.size(); + size_t original_positions_iterator = 0; + // we should iterate throw curves in the original frame + for (size_t curve_index = 0; curve_index < total_curves; curve_index++) { - XSI::MATH::CVector3f p = time_pos_data[c_index]; - float s = time_size_data[c_index]; - motion_positions[attribute_index++] = ccl::make_float4(p.GetX(), p.GetY(), p.GetZ(), s); - // next keys for strand positions - XSI::CICEAttributeDataArrayVector3f strand; - time_strand_data.GetSubArray(c_index, strand); - float strand_prop_length = strand.GetCount() + 1; - for (ULONG k_index = 0; k_index < strand.GetCount(); k_index++) + size_t point_index = strand_points[curve_index]; + size_t strand_knots_count = strand_length[curve_index]; + // check that in this time the point exists + bool is_fail = true; + if (point_index < time_points_count && point_index < time_sizes_count && point_index < time_strands_count) + { + XSI::CICEAttributeDataArrayVector3f strand; + time_strand_data.GetSubArray(point_index, strand); + XSI::CICEAttributeDataArrayFloat strand_sizes; + ULONG strand_sizes_length = 0; + if (use_strand_size && point_index < time_strand_size_count) + { + time_strand_size_data.GetSubArray(point_index, strand_sizes); + strand_sizes_length = strand_sizes.GetCount(); + } + size_t time_strand_knots_count = strand.GetCount(); // the number of knots in the current strand at current time + float strand_prop_length = time_strand_knots_count + 1; + + if (time_strand_knots_count == strand_knots_count) + { + // the strand length at the time equal to the strand length at original frame + is_fail = false; + + XSI::MATH::CVector3f p = time_pos_data[point_index]; + float s = time_size_data[point_index]; + motion_positions[attribute_index++] = ccl::make_float4(p.GetX(), p.GetY(), p.GetZ(), s); + // next keys for strand positions + + for (ULONG k_index = 0; k_index < strand_knots_count; k_index++) + { + // calculate the radius from point size + // this is copy of the similar lines in sync_strands_geom function + float prop = static_cast(k_index + 1) / strand_prop_length; + s = (1 - prop) * s + prop * s * tip_prop; + if (k_index == strand.GetCount() - 1 && tip_prop < 0.0001f) + { + s = 0.0; + } + if (use_strand_size && strand_sizes_length > 0) + { + s = strand_sizes[k_index < strand_sizes_length ? k_index : strand_sizes_length - 1]; + } + p = strand[k_index]; + motion_positions[attribute_index++] = ccl::make_float4(p.GetX(), p.GetY(), p.GetZ(), s); + } + } + else + { + // the strand length is different with original one + // in this case simply copy original positions + is_fail = true; + } + } + if (is_fail) { - float prop = static_cast(k_index + 1) / strand_prop_length; - s = (1 - prop) * time_size_data[c_index] + prop * time_size_data[c_index] * tip_prop; - if (k_index == strand.GetCount() - 1 && tip_prop < 0.0001f) + // at present time the pointcloud does not contains data for a given point + // or the strand length is different with original one + // in this case we should copy strand positions from original positions (only for this strand) + for (size_t k = 0; k < strand_knots_count + 1; k++) { - s = 0.0; + motion_positions[attribute_index++] = original_positions[original_positions_iterator + k]; } - p = strand[k_index]; - motion_positions[attribute_index++] = ccl::make_float4(p.GetX(), p.GetY(), p.GetZ(), s); } + original_positions_iterator += strand_knots_count + 1; } } else @@ -310,17 +466,19 @@ void sync_strands_geom_process(ccl::Scene* scene, ccl::Hair* strands_geom, Updat strands_geom->name = combine_geometry_name(xsi_object, xsi_primitive).GetAsciiString(); ccl::vector original_positions; - LONG num_curves = 0; + ccl::vector strand_points; + ccl::vector strand_lengths; bool use_motion_blur = update_context->get_need_motion() && motion_deform; float tip_prop = 0.0f; sync_strands_property(xsi_object, tip_prop, update_context->get_time()); - sync_strands_geom(scene, strands_geom, update_context, xsi_primitive, use_motion_blur, tip_prop, original_positions, num_curves); + sync_strands_geom(scene, strands_geom, update_context, xsi_primitive, use_motion_blur, tip_prop, original_positions, strand_points, strand_lengths); + // TODO: set proper blur for strands if (use_motion_blur) { - sync_strands_deform(strands_geom, update_context, xsi_object, num_curves, tip_prop, original_positions); + sync_strands_deform(strands_geom, update_context, xsi_object, tip_prop, original_positions, strand_points, strand_lengths); } else { diff --git a/src/utilities/logs.cpp b/src/utilities/logs.cpp index 42d4109..045283e 100644 --- a/src/utilities/logs.cpp +++ b/src/utilities/logs.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -67,6 +68,38 @@ XSI::CString to_string(const XSI::CDoubleArray& array) return to_return; } +XSI::CString to_string(const XSI::CICEAttributeDataArrayVector3f& array) +{ + if (array.GetCount() == 0) + { + return "[]"; + } + + XSI::CString to_return = XSI::CString(array.GetCount()) + "[" + XSI::CString(array[0]); + for (ULONG i = 1; i < array.GetCount(); i++) + { + to_return += ", " + XSI::CString(array[i]); + } + to_return += "]"; + return to_return; +} + +XSI::CString to_string(const XSI::CICEAttributeDataArrayFloat& array) +{ + if (array.GetCount() == 0) + { + return "[]"; + } + + XSI::CString to_return = XSI::CString(array.GetCount()) + "[" + XSI::CString(array[0]); + for (ULONG i = 1; i < array.GetCount(); i++) + { + to_return += ", " + XSI::CString(array[i]); + } + to_return += "]"; + return to_return; +} + XSI::CString to_string(const std::vector& array) { if (array.size() == 0) diff --git a/src/utilities/logs.h b/src/utilities/logs.h index 414d52e..31fa239 100644 --- a/src/utilities/logs.h +++ b/src/utilities/logs.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include @@ -19,6 +20,8 @@ void log_message(const XSI::CString &message, XSI::siSeverityType level = XSI::s XSI::CString to_string(const XSI::CFloatArray& array); XSI::CString to_string(const XSI::CLongArray& array); XSI::CString to_string(const XSI::CDoubleArray& array); +XSI::CString to_string(const XSI::CICEAttributeDataArrayVector3f& array); +XSI::CString to_string(const XSI::CICEAttributeDataArrayFloat& array); XSI::CString to_string(const std::vector& array); XSI::CString to_string(const std::vector &array); XSI::CString to_string(const std::vector& array); From c810bd74dcc9f1f1025b39fc48b022e32949891c Mon Sep 17 00:00:00 2001 From: Shekn Date: Sun, 23 Jul 2023 16:06:48 +0500 Subject: [PATCH 4/8] Once more improvement ofa strand size rendering Remove tip_prop property for pointcloud. By default each strand is rendered with the size of initial point. If we would like to decresase the size during the strand, then StrandSize attribute should be used. It's enough to create 2-valued array for each strand, and then these two values will be define the profile of the strand. Additional compound Set Strand Profile is added. It allows to contol the strand profile by using f-curve. --- Application/Plugins/CyclesPropertiesPlugin.py | 6 - Data/Compounds/Set Strand Profile.xsicompound | 127 ++++++++++++++ .../cyc_scene/cyc_geometry/cyc_strands.cpp | 166 +++++++++--------- src/utilities/logs.cpp | 13 ++ src/utilities/logs.h | 3 +- 5 files changed, 228 insertions(+), 87 deletions(-) create mode 100644 Data/Compounds/Set Strand Profile.xsicompound diff --git a/Application/Plugins/CyclesPropertiesPlugin.py b/Application/Plugins/CyclesPropertiesPlugin.py index 657cee8..6f846ca 100644 --- a/Application/Plugins/CyclesPropertiesPlugin.py +++ b/Application/Plugins/CyclesPropertiesPlugin.py @@ -285,7 +285,6 @@ def CyclesVolume_Define(in_ctxt): def CyclesPointcloud_Define(in_ctxt): prop = in_ctxt.Source - prop.AddParameter3("tip_prop", c.siFloat, 0.0, 0.0, 1.0) prop.AddParameter3("primitive_pc", c.siBool, False) prop.AddParameter3("use_pc_color", c.siBool, True) setup_common_properties(prop) @@ -621,10 +620,8 @@ def cycles_volume_property_build_ui(): def pointcloud_ui_update(prop): primitive_pc = prop.Parameters("primitive_pc").Value if primitive_pc: - prop.Parameters("tip_prop").ReadOnly = True prop.Parameters("use_pc_color").ReadOnly = True else: - prop.Parameters("tip_prop").ReadOnly = False prop.Parameters("use_pc_color").ReadOnly = False @@ -637,9 +634,6 @@ def cycles_pointcloud_property_build_ui(): layout.AddGroup("Particles") layout.AddItem("primitive_pc", "Native Cycles Pointcloud") layout.EndGroup() - layout.AddGroup("Strands") - layout.AddItem("tip_prop", "Tip Proportion") - layout.EndGroup() layout.AddGroup("Pointcloud") layout.AddItem("use_pc_color", "Override Pointcloud Color") layout.EndGroup() diff --git a/Data/Compounds/Set Strand Profile.xsicompound b/Data/Compounds/Set Strand Profile.xsicompound new file mode 100644 index 0000000..8b38c31 --- /dev/null +++ b/Data/Compounds/Set Strand Profile.xsicompound @@ -0,0 +1,127 @@ + + + + + + + + + + + + 406 + 339 + Normal + + + + + + + + + + + -210 + 341 + Normal + + + + + + + 76 + 487 + Normal + + + + + + + -497 + 373 + Normal + + + + 2 20 1 0 -1.79769E+308 1.79769E+308 2 0 +0 0.000000 1.000000 0.333333 0.000000 -0.333333 0.000000 4 2 +0 1.000000 0.000000 0.333333 0.000000 -0.333333 0.000000 4 2 + + + + + 73 + 371 + Normal + + + + + + + + + -512 + 301 + Normal + + + + + + + + + -346 + 300 + Normal + + + + + + + + + 215 + 365 + Normal + + + + + + + + + -755 + 296 + Normal + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp b/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp index b4aae38..16dd681 100644 --- a/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp +++ b/src/render_cycles/cyc_scene/cyc_geometry/cyc_strands.cpp @@ -40,12 +40,53 @@ bool is_pointcloud_strands(const XSI::X3DObject& xsi_object) } } +float calculate_strand_radius(const ULONG point_index, // the index of the point in the pointcloud + const XSI::CICEAttributeDataArrayFloat &point_size, // array of point radiuses + const ULONG point_size_length, // the size of the array with point radiuses + const ULONG strand_index, // index of the strand knot in the current point, for initial point it equals to 0, for last knot it equals to strand_positions_count + const ULONG strand_length, // the length of the strand (the number of knots with the start one), so, for strand *---*---*, where the first * is point, strand_length = 3 (and strand_positions_count = 2) + const XSI::CICEAttributeDataArrayFloat &strand_size, // array of size values for a given strand + const ULONG strand_size_length // the number of elements of the size array for strand (it can be different from strand_length) +) +{ + // if strand_size_length = 0, then use point radius + // laso return point radius in the case when the strand has zero knots (strand_length = konts count + 1) + if (strand_size_length == 0 || strand_length <= 1) + { + // return either 0.0 (if the array with sizes is empty) + // or last value of the array (if point index greater the the length) + // or actual value in the array + return point_size_length > 0 ? point_size[point_index < point_size_length ? point_index : point_size_length - 1] : 0.0; + } + + // if there is only one value in strand sizes, then return it + if (strand_size_length == 1) + { + return strand_size[0]; + } + + float p = (float)strand_index / (float)(strand_length - 1); // p from 0.0 (for initial point) to 1.0 (for end tip of the strand) + float l = 1.0f / (float)(strand_size_length - 1); // the length of one segment in the sizes array (for *---*---*---* l = 1/3) + int interval_index = (int)(p / l); // index of the interval, where the knot is, so, we should return the lerp of end points of this interval + + // check is the interval index is correct + if (interval_index <= 0) { return strand_size[0]; } + if (interval_index + 1 >= strand_size_length) { return strand_size[strand_size_length - 1]; } + + float delta = p - (float)interval_index * l; // delta between interval start and the point (*-delta-|-----*) + float c = delta / l; // lerp coefficient + // clamp lerp coefficient + if (c <= 0.0f) { c = 0.0f; } + else if (c >= 1.0f) { c = 1.0f; } + + return (1.0f - c) * strand_size[interval_index] + c * strand_size[interval_index + 1]; +} + void sync_strands_geom(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext* update_context, const XSI::Primitive& xsi_primitive, bool use_motion_blur, - float tip_prop, // next three arrays comes with zero size ccl::vector& out_original_positions, // total positions and sizes of current frame strands, one plain array, the split template into individual curves stores in the geometry object ccl::vector &out_strand_points, // store here point indices with non-empty strands (the length of strand positions is non-zero), all other points should be ignored @@ -59,7 +100,6 @@ void sync_strands_geom(ccl::Scene* scene, XSI::ICEAttribute point_position_attr = xsi_geometry.GetICEAttributeFromName("PointPosition"); XSI::ICEAttribute strand_position_attr = xsi_geometry.GetICEAttributeFromName("StrandPosition"); XSI::ICEAttribute size_attr = xsi_geometry.GetICEAttributeFromName("Size"); - // TODO: use, if it is possible, strand size attribute XSI::ICEAttribute strand_size_attr = xsi_geometry.GetICEAttributeFromName("StrandSize"); // this is the radius of the strand, NOT the number of points // strand_size_attr.IsDefined() can be false if the attribute is not defined in the ICE tree // strand_size_attr.GetElementCount() is equal to the number of points @@ -75,7 +115,6 @@ void sync_strands_geom(ccl::Scene* scene, strand_position_attr.GetDataArray2D(strand_position_data); XSI::CICEAttributeDataArrayFloat size_data; - // TODO: more accurate control of the point size // in trivial case (when we generate grid from two strands (1x2 or 2x1)) the data contains only one element, instead of 2 // use this in prepare stage size_attr.GetDataArray(size_data); @@ -101,7 +140,6 @@ void sync_strands_geom(ccl::Scene* scene, // get the current strand length data strand_position_data.GetSubArray(i, one_strand_data); ULONG strand_length = one_strand_data.GetCount(); - // TODO: consider non-zero size or even the size is exist if (strand_length > 0) { out_strand_points.push_back(i); @@ -142,18 +180,36 @@ void sync_strands_geom(ccl::Scene* scene, // get actual point index for this curve size_t point_index = out_strand_points[curve_index]; // we should get data for this point and strand + // get strand positions array + strand_position_data.GetSubArray(point_index, one_strand_data); + ULONG strand_knots_length = one_strand_data.GetCount(); + // one strand data contains non-zero values + // also extract strand sizes, if it exists + if (use_strand_size) + { + strand_size_data.GetSubArray(point_index, one_strand_size_data); + // and save the array length + // we will use it later to check is the array is too short or not + strand_sizes_length = one_strand_size_data.GetCount(); + } + else + { + strand_sizes_length = 0; + } + // set start point of the strand - point position XSI::MATH::CVector3f point_position = point_position_data[point_index]; // for initial strand point use point size // if points size aray is empty, use zero value // if the point index outside of the array, use the last value of the array - float point_size = size_data_length > 0 ? size_data[point_index < size_data_length ? point_index : size_data_length - 1] : 0.0; - strands_geom->add_curve_key(vector3_to_float3(point_position), point_size); + float point_radius = calculate_strand_radius(point_index, size_data, size_data_length, 0, strand_knots_length + 1, one_strand_size_data, strand_sizes_length); + strands_geom->add_curve_key(vector3_to_float3(point_position), point_radius); // if we need motion blur, fill original positions array if (use_motion_blur) { - out_original_positions[original_index] = ccl::make_float4(point_position.GetX(), point_position.GetY(), point_position.GetZ(), point_size); + out_original_positions[original_index] = ccl::make_float4(point_position.GetX(), point_position.GetY(), point_position.GetZ(), point_radius); + original_index++; } // start strand, so the intercept attribute is 0.0 @@ -162,37 +218,11 @@ void sync_strands_geom(ccl::Scene* scene, attr_intercept->add(0.0); } - // next we should fill positions of the other strand nodes - // get strand positions array - strand_position_data.GetSubArray(point_index, one_strand_data); - // one strand data contains non-zero values - // also extract strand sizes, if it exists - if (use_strand_size) - { - strand_size_data.GetSubArray(point_index, one_strand_size_data); - // and save the array length - // we will use it later to check is the array is too short or not - strand_sizes_length = one_strand_size_data.GetCount(); - } - - ULONG strand_knots_length = one_strand_data.GetCount(); - float total_time = strand_knots_length + 1; // the total number of knots in the strand, with the star one float strand_sparse_length = 0.0f; + float total_time = strand_knots_length + 1; for (ULONG k_index = 0; k_index < strand_knots_length; k_index++) { - // use point size attribute and interpolate value by using tip_prop (by default = 0.0) - float time = static_cast(k_index + 1) / total_time; - float radius = (1 - time) * point_size + time * point_size * tip_prop; - if (k_index + 1 == strand_knots_length && tip_prop < 0.0001f) - { - radius = 0.0; - } - - if (use_strand_size && strand_sizes_length > 0) - { - // if we have the valid strand size attribute, override radius from point size - radius = one_strand_size_data[k_index < strand_sizes_length ? k_index : strand_sizes_length - 1]; - } + float radius = calculate_strand_radius(point_index, size_data, size_data_length, k_index + 1, strand_knots_length + 1, one_strand_size_data, strand_sizes_length); XSI::MATH::CVector3f knot_position = one_strand_data[k_index]; strands_geom->add_curve_key(vector3_to_float3(knot_position), radius); @@ -213,6 +243,8 @@ void sync_strands_geom(ccl::Scene* scene, if (attr_intercept) { + float time = static_cast(k_index + 1) / total_time; + attr_intercept->add(time); } } @@ -307,7 +339,6 @@ void sync_strands_geom(ccl::Scene* scene, void sync_strands_deform(ccl::Hair* hair, UpdateContext* update_context, const XSI::X3DObject &xsi_object, - float tip_prop, const ccl::vector& original_positions, const ccl::vector &strand_points, const ccl::vector& strand_length) @@ -321,11 +352,6 @@ void sync_strands_deform(ccl::Hair* hair, ccl::float4* motion_positions = attr_m_positions->data_float4(); MotionSettingsPosition motion_position = update_context->get_motion_position(); - // prepare data buffers - XSI::CICEAttributeDataArrayVector3f time_pos_data; - XSI::CICEAttributeDataArray2DVector3f time_strand_data; - XSI::CICEAttributeDataArrayFloat time_size_data; - XSI::CICEAttributeDataArray2DFloat time_strand_size_data; for (size_t mi = 0; mi < motion_steps - 1; mi++) { size_t time_motion_step = mi; @@ -351,6 +377,13 @@ void sync_strands_deform(ccl::Hair* hair, bool use_strand_size = time_strand_size.IsDefined(); if (time_pos.GetElementCount() > 0 && time_strand.GetElementCount() > 0 && time_size.GetElementCount() > 0) {// attributes exists, get the data + // prepare data buffers + // make it every time step, because there are some problems if we done it once at very beginning + XSI::CICEAttributeDataArrayVector3f time_pos_data; + XSI::CICEAttributeDataArray2DVector3f time_strand_data; + XSI::CICEAttributeDataArrayFloat time_size_data; + XSI::CICEAttributeDataArray2DFloat time_strand_size_data; + time_pos.GetDataArray(time_pos_data); time_strand.GetDataArray2D(time_strand_data); time_size.GetDataArray(time_size_data); @@ -377,8 +410,10 @@ void sync_strands_deform(ccl::Hair* hair, bool is_fail = true; if (point_index < time_points_count && point_index < time_sizes_count && point_index < time_strands_count) { - XSI::CICEAttributeDataArrayVector3f strand; - time_strand_data.GetSubArray(point_index, strand); + // create buffer for every strand independently + // in onether case the render is crashed + XSI::CICEAttributeDataArrayVector3f time_one_strand_positions; + time_strand_data.GetSubArray(point_index, time_one_strand_positions); XSI::CICEAttributeDataArrayFloat strand_sizes; ULONG strand_sizes_length = 0; if (use_strand_size && point_index < time_strand_size_count) @@ -386,34 +421,21 @@ void sync_strands_deform(ccl::Hair* hair, time_strand_size_data.GetSubArray(point_index, strand_sizes); strand_sizes_length = strand_sizes.GetCount(); } - size_t time_strand_knots_count = strand.GetCount(); // the number of knots in the current strand at current time + size_t time_strand_knots_count = time_one_strand_positions.GetCount(); // the number of knots in the current strand at current time float strand_prop_length = time_strand_knots_count + 1; - if (time_strand_knots_count == strand_knots_count) { // the strand length at the time equal to the strand length at original frame is_fail = false; XSI::MATH::CVector3f p = time_pos_data[point_index]; - float s = time_size_data[point_index]; - motion_positions[attribute_index++] = ccl::make_float4(p.GetX(), p.GetY(), p.GetZ(), s); + float point_radius = calculate_strand_radius(point_index, time_size_data, time_sizes_count, 0, time_strand_knots_count + 1, strand_sizes, strand_sizes_length); + motion_positions[attribute_index++] = ccl::make_float4(p.GetX(), p.GetY(), p.GetZ(), point_radius); // next keys for strand positions - - for (ULONG k_index = 0; k_index < strand_knots_count; k_index++) + for (ULONG k_index = 0; k_index < time_strand_knots_count; k_index++) { - // calculate the radius from point size - // this is copy of the similar lines in sync_strands_geom function - float prop = static_cast(k_index + 1) / strand_prop_length; - s = (1 - prop) * s + prop * s * tip_prop; - if (k_index == strand.GetCount() - 1 && tip_prop < 0.0001f) - { - s = 0.0; - } - if (use_strand_size && strand_sizes_length > 0) - { - s = strand_sizes[k_index < strand_sizes_length ? k_index : strand_sizes_length - 1]; - } - p = strand[k_index]; + float s = calculate_strand_radius(point_index, time_size_data, time_sizes_count, k_index + 1, time_strand_knots_count + 1, strand_sizes, strand_sizes_length); + p = time_one_strand_positions[k_index]; motion_positions[attribute_index++] = ccl::make_float4(p.GetX(), p.GetY(), p.GetZ(), s); } } @@ -447,18 +469,6 @@ void sync_strands_deform(ccl::Hair* hair, } } -void sync_strands_property(XSI::X3DObject& xsi_object, float& io_tip_prop, const XSI::CTime &eval_time) -{ - XSI::Property xsi_property; - bool use_property = get_xsi_object_property(xsi_object, "CyclesPointcloud", xsi_property); - if (use_property) - { - XSI::CParameterRefArray xsi_params = xsi_property.GetParameters(); - - io_tip_prop = xsi_params.GetValue("tip_prop", eval_time); - } -} - // in this function we actually create geometry // and also define motion deform, if we need it void sync_strands_geom_process(ccl::Scene* scene, ccl::Hair* strands_geom, UpdateContext* update_context, const XSI::Primitive& xsi_primitive, XSI::X3DObject& xsi_object, bool motion_deform) @@ -470,15 +480,11 @@ void sync_strands_geom_process(ccl::Scene* scene, ccl::Hair* strands_geom, Updat ccl::vector strand_lengths; bool use_motion_blur = update_context->get_need_motion() && motion_deform; - float tip_prop = 0.0f; - sync_strands_property(xsi_object, tip_prop, update_context->get_time()); - - sync_strands_geom(scene, strands_geom, update_context, xsi_primitive, use_motion_blur, tip_prop, original_positions, strand_points, strand_lengths); + sync_strands_geom(scene, strands_geom, update_context, xsi_primitive, use_motion_blur, original_positions, strand_points, strand_lengths); - // TODO: set proper blur for strands if (use_motion_blur) { - sync_strands_deform(strands_geom, update_context, xsi_object, tip_prop, original_positions, strand_points, strand_lengths); + sync_strands_deform(strands_geom, update_context, xsi_object, original_positions, strand_points, strand_lengths); } else { diff --git a/src/utilities/logs.cpp b/src/utilities/logs.cpp index 045283e..6041c11 100644 --- a/src/utilities/logs.cpp +++ b/src/utilities/logs.cpp @@ -345,5 +345,18 @@ XSI::CString to_string(const ccl::array& array) to_return += "]"; + return to_return; +} + +XSI::CString to_string(const ccl::vector& array) +{ + XSI::CString to_return = "["; + for (ULONG i = 0; i < array.size(); i++) + { + to_return += XSI::CString(array[i]) + ((i == array.size() - 1) ? "" : ", "); + } + + to_return += "]"; + return to_return; } \ No newline at end of file diff --git a/src/utilities/logs.h b/src/utilities/logs.h index 31fa239..db7ad8f 100644 --- a/src/utilities/logs.h +++ b/src/utilities/logs.h @@ -40,4 +40,5 @@ XSI::CString to_string(const ccl::array &array); XSI::CString to_string(const ccl::vector& array); XSI::CString to_string(const ccl::vector& array); XSI::CString to_string_flot4(const ccl::float4 &value); // to_string name exists in ccl namespace -XSI::CString to_string(const ccl::array& array); \ No newline at end of file +XSI::CString to_string(const ccl::array& array); +XSI::CString to_string(const ccl::vector& array); \ No newline at end of file From ed61f5a2140baf3282e166f19a8f55aa46a67a99 Mon Sep 17 00:00:00 2001 From: Shekn Date: Fri, 4 Aug 2023 22:03:22 +0500 Subject: [PATCH 5/8] Fix wrong baking object name Instead of getting geometry, get proper object index from the Cycles objects array. --- src/render_cycles/cyc_session/cyc_baking.cpp | 6 +++++- src/render_cycles/render_engine_cyc.cpp | 1 - 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/render_cycles/cyc_session/cyc_baking.cpp b/src/render_cycles/cyc_session/cyc_baking.cpp index 888231b..057fd0f 100644 --- a/src/render_cycles/cyc_session/cyc_baking.cpp +++ b/src/render_cycles/cyc_session/cyc_baking.cpp @@ -642,7 +642,11 @@ void sync_baking(ccl::Scene* scene, UpdateContext* update_context, BakingContext } else { - object = scene->objects[update_context->get_geometry_index(baking_object_id)]; + const std::vector obj_cyc_ids = update_context->get_object_cycles_indexes(baking_object_id); + // this array may contains several objects + // one object for each instance + // get the first one + object = scene->objects[obj_cyc_ids[0]]; } ccl::Mesh* mesh = (ccl::Mesh*)object->get_geometry(); diff --git a/src/render_cycles/render_engine_cyc.cpp b/src/render_cycles/render_engine_cyc.cpp index 3daddd2..21b3167 100644 --- a/src/render_cycles/render_engine_cyc.cpp +++ b/src/render_cycles/render_engine_cyc.cpp @@ -803,7 +803,6 @@ XSI::CStatus RenderEngineCyc::create_scene() { sync_baking(session->scene, update_context, baking_context, baking_object, baking_uv, image_full_size_width, image_full_size_height); } - } is_update_camera = true; From 0aeeec35a0a7376db590af66565f31d03fad2032 Mon Sep 17 00:00:00 2001 From: Shekn Date: Sun, 6 Aug 2023 12:30:59 +0500 Subject: [PATCH 6/8] Additional checks for baking object --- src/render_cycles/cyc_session/cyc_baking.cpp | 56 ++++++++++++-------- src/render_cycles/render_engine_cyc.cpp | 6 ++- 2 files changed, 38 insertions(+), 24 deletions(-) diff --git a/src/render_cycles/cyc_session/cyc_baking.cpp b/src/render_cycles/cyc_session/cyc_baking.cpp index 057fd0f..a8ff268 100644 --- a/src/render_cycles/cyc_session/cyc_baking.cpp +++ b/src/render_cycles/cyc_session/cyc_baking.cpp @@ -630,30 +630,40 @@ void sync_baking(ccl::Scene* scene, UpdateContext* update_context, BakingContext ULONG baking_object_id = bake_object.GetObjectID(); ccl::Object* object = NULL; - if (!update_context->is_object_exists(baking_object_id)) - {// object is not exported - // do it now - object = scene->create_node(); - ccl::Mesh* mesh_geom = sync_polymesh_object(scene, object, update_context, bake_object); - object->set_geometry(mesh_geom); - - update_context->add_object_index(baking_object_id, scene->objects.size() - 1); - sync_transform(object, update_context, bake_object.GetKinematics().GetGlobal()); - } - else + // again, chek that bake object is polymesh + if (bake_object.GetType() == XSI::siPolyMeshType) { - const std::vector obj_cyc_ids = update_context->get_object_cycles_indexes(baking_object_id); - // this array may contains several objects - // one object for each instance - // get the first one - object = scene->objects[obj_cyc_ids[0]]; + if (!update_context->is_object_exists(baking_object_id)) + {// object is not exported + // do it now + object = scene->create_node(); + ccl::Mesh* mesh_geom = sync_polymesh_object(scene, object, update_context, bake_object); + object->set_geometry(mesh_geom); + + update_context->add_object_index(baking_object_id, scene->objects.size() - 1); + sync_transform(object, update_context, bake_object.GetKinematics().GetGlobal()); + } + else + { + const std::vector obj_cyc_ids = update_context->get_object_cycles_indexes(baking_object_id); + // this array may contains several objects + // one object for each instance + // get the first one + if (obj_cyc_ids.size() > 0) + { + object = scene->objects[obj_cyc_ids[0]]; + } + } } - ccl::Mesh* mesh = (ccl::Mesh*)object->get_geometry(); - baking_context->setup(bake_width, bake_height); - size_t uv_index = get_uv_attribute_index(mesh, ccl::ustring(baking_uv_name.GetAsciiString())); - - populate_bake_data(mesh, uv_index, baking_context); - scene->bake_manager->set(scene, object->name.c_str()); - scene->bake_manager->set_use_camera(baking_context->get_use_camera()); + if (object) + { + ccl::Mesh* mesh = (ccl::Mesh*)object->get_geometry(); + baking_context->setup(bake_width, bake_height); + size_t uv_index = get_uv_attribute_index(mesh, ccl::ustring(baking_uv_name.GetAsciiString())); + + populate_bake_data(mesh, uv_index, baking_context); + scene->bake_manager->set(scene, object->name.c_str()); + scene->bake_manager->set_use_camera(baking_context->get_use_camera()); + } } \ No newline at end of file diff --git a/src/render_cycles/render_engine_cyc.cpp b/src/render_cycles/render_engine_cyc.cpp index 21b3167..0653a01 100644 --- a/src/render_cycles/render_engine_cyc.cpp +++ b/src/render_cycles/render_engine_cyc.cpp @@ -271,7 +271,8 @@ void RenderEngineCyc::progress_cancel_callback() void RenderEngineCyc::pre_bake() { // here we should only set output paths and formats - if (baking_object.IsValid() && baking_uv.Length() > 0) + const XSI::CString baking_object_type = baking_object.GetType(); + if (baking_object_type == XSI::siPolyMeshType && baking_object.IsValid() && baking_uv.Length() > 0) { baking_context->make_valid(); baking_context->set_use_camera(false); @@ -359,6 +360,9 @@ void RenderEngineCyc::pre_bake() // bake object is invalid // so, nothing to bake baking_context->make_invalid(); + log_message("Baking is fail, object is invalid" + + baking_object_type != XSI::siPolyMeshType ? ", type must be polymesh" : ( + baking_uv.Length() == 0 ? ", no uv coordinates" : ""), XSI::siWarningMsg); } } From 4f3b34b0e22a347531c0bc8044e4ae77961dfc43 Mon Sep 17 00:00:00 2001 From: Shekn Date: Sun, 6 Aug 2023 13:18:56 +0500 Subject: [PATCH 7/8] Fix empty aov passes It store at the shader node actual aov name, but in pass it creaete and try to get with prefix. That's why the aov was empty. Now store name in the sahder node also with prefix. --- src/render_cycles/cyc_scene/cyc_materials/cyc_shaders.cpp | 5 +++-- .../cyc_scene/cyc_materials/cyc_shaders_common.cpp | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/render_cycles/cyc_scene/cyc_materials/cyc_shaders.cpp b/src/render_cycles/cyc_scene/cyc_materials/cyc_shaders.cpp index 741d962..f0f54c0 100644 --- a/src/render_cycles/cyc_scene/cyc_materials/cyc_shaders.cpp +++ b/src/render_cycles/cyc_scene/cyc_materials/cyc_shaders.cpp @@ -22,6 +22,7 @@ #include "../../../utilities/xsi_shaders.h" #include "../../../utilities/xsi_properties.h" #include "../../../utilities/files_io.h" +#include "../../cyc_session/cyc_pass_utils.h" #include "cyc_materials.h" #include "names_converter.h" @@ -977,7 +978,7 @@ ccl::ShaderNode* sync_cycles_shader(ccl::Scene* scene, common_routine(scene, node, shader_graph, nodes_map, xsi_shader, xsi_parameters, eval_time, aovs); XSI::CString channel_name = get_string_parameter_value(xsi_parameters, "aov_name", eval_time); - node->set_name(OIIO::ustring(channel_name.GetAsciiString())); + node->set_name(OIIO::ustring(add_prefix_to_aov_name(channel_name, true).GetAsciiString())); aovs[0].Add(channel_name); return node; @@ -988,7 +989,7 @@ ccl::ShaderNode* sync_cycles_shader(ccl::Scene* scene, common_routine(scene, node, shader_graph, nodes_map, xsi_shader, xsi_parameters, eval_time, aovs); XSI::CString channel_name = get_string_parameter_value(xsi_parameters, "aov_name", eval_time); - node->set_name(OIIO::ustring(channel_name.GetAsciiString())); + node->set_name(OIIO::ustring(add_prefix_to_aov_name(channel_name, false).GetAsciiString())); aovs[1].Add(channel_name); return node; diff --git a/src/render_cycles/cyc_scene/cyc_materials/cyc_shaders_common.cpp b/src/render_cycles/cyc_scene/cyc_materials/cyc_shaders_common.cpp index c08019e..d1cf534 100644 --- a/src/render_cycles/cyc_scene/cyc_materials/cyc_shaders_common.cpp +++ b/src/render_cycles/cyc_scene/cyc_materials/cyc_shaders_common.cpp @@ -92,7 +92,7 @@ void make_aovs_reconnections(ccl::ShaderGraph* shader_graph, ccl::ShaderNode* ao else { // nothing connected to aov node - // but user assume that value from the node affects to the sahder + // but user assume that value from the node affects to the shader // so, create constant node (with value from aov) and connect it as to aov and next node if (is_color) { From d2a0675efd04eae9ffec4ba1768ce56acd6fbaec Mon Sep 17 00:00:00 2001 From: Shekn Date: Sun, 6 Aug 2023 13:45:40 +0500 Subject: [PATCH 8/8] Implement #7, supports gpu rendering for shaderballs Add parameter use_gpu to the config.ini file. By defaul it set to 0. It means that cpu device should be used for rendering shaderball previes. If the parameter is set to 1, then it tries to use gpu. But for now osl rendering does not support by gpu. So, is osl is activated (used_osl = 1), then it disables the gpu and alwasy use cpu. --- Application/Plugins/config.ini | 3 +- src/input/config_ini.h | 1 + src/input/input.cpp | 4 ++ src/render_cycles/cyc_session/cyc_session.cpp | 47 +++++++++++++++++-- 4 files changed, 50 insertions(+), 5 deletions(-) diff --git a/Application/Plugins/config.ini b/Application/Plugins/config.ini index b94706e..426d060 100644 --- a/Application/Plugins/config.ini +++ b/Application/Plugins/config.ini @@ -6,10 +6,11 @@ glossy_bounces = 2 transmission_bounces = 2 transparent_bounces = 2 volume_bounces = 2 -use_ocl = 1 +use_ocl = 1; 0 - use svm, 1 - use ocl clamp_direct = 1.0 clamp_indirect = 1.0 displacement_method = 2; 0 - bump, 1 - only displacement, 2 - both +use_gpu = 0; 0 - cpu, 1 - one gpu device (optix if it exists) [Render] devices = 16; render devices count [SeriesRendering] diff --git a/src/input/config_ini.h b/src/input/config_ini.h index cd6627a..2003f3f 100644 --- a/src/input/config_ini.h +++ b/src/input/config_ini.h @@ -14,6 +14,7 @@ struct ConfigShaderball float clamp_direct; float clamp_indirect; ULONG displacement_method; + bool use_gpu; }; struct ConfigRender diff --git a/src/input/input.cpp b/src/input/input.cpp index f48e8ee..c2b3f6a 100644 --- a/src/input/input.cpp +++ b/src/input/input.cpp @@ -152,6 +152,10 @@ void read_config_ini() const char* displacement_method_str = ini.GetValue("Shaderball", "displacement_method", "2"); shaderball.displacement_method = std::max(0, std::min(2, std::stoi(displacement_method_str, nullptr))); + const char* use_gpu_str = ini.GetValue("Shaderball", "use_gpu", "0"); // by default gpu is off, ise only cpu for material previes + const float use_gpu_float = strtof(use_gpu_str, nullptr); + shaderball.use_gpu = use_gpu_float >= 0.5; + ConfigRender render; const char* devices_str = ini.GetValue("Render", "devices", "16"); render.devices = std::stoi(devices_str, nullptr); diff --git a/src/render_cycles/cyc_session/cyc_session.cpp b/src/render_cycles/cyc_session/cyc_session.cpp index 0e74c5e..e53fead 100644 --- a/src/render_cycles/cyc_session/cyc_session.cpp +++ b/src/render_cycles/cyc_session/cyc_session.cpp @@ -29,24 +29,63 @@ ccl::SessionParams get_session_params(RenderType render_type, const XSI::CParame { // for shaderball rendering use simple parameters session_params.threads = 0; - // use only cpu device - ccl::vector cpu_devices = ccl::Device::available_devices(ccl::DEVICE_MASK_CPU); - // we assume that cpu always exists - session_params.device = cpu_devices[0]; session_params.experimental = true; session_params.pixel_size = 1; session_params.use_auto_tile = false; bool use_ocl = true; int samples = 32; + bool use_gpu = false; InputConfig input_config = get_input_config(); if (input_config.is_init) { ConfigShaderball config_shaderball = input_config.shaderball; use_ocl = config_shaderball.use_ocl; + use_gpu = config_shaderball.use_gpu; + + if (use_ocl && use_gpu) + { + // for now use ocl rendering only at cpu device + // so, disable gpu + // svm/ocl is more important than cpu/gpu + use_gpu = false; + } samples = config_shaderball.samples; } + if (use_gpu) + { + ccl::vector hip_devices = ccl::Device::available_devices(ccl::DEVICE_MASK_HIP); + ccl::vector cuda_devices = ccl::Device::available_devices(ccl::DEVICE_MASK_CUDA); + ccl::vector optix_devices = ccl::Device::available_devices(ccl::DEVICE_MASK_OPTIX); + if (optix_devices.size() > 0) + { + session_params.device = optix_devices[0]; + } + else if (cuda_devices.size() > 0) + { + session_params.device = cuda_devices[0]; + } + else if (hip_devices.size() > 0) + { + session_params.device = hip_devices[0]; + } + else + { + // use cpu + use_gpu = false; + } + } + + if (!use_gpu) + { + // assign cpu device either when it enabled in settings, or there are not gpus + ccl::vector cpu_devices = ccl::Device::available_devices(ccl::DEVICE_MASK_CPU); + // we assume that cpu always exists + // use the first cpu device + session_params.device = cpu_devices[0]; + } + // set shading system by using shaderball config session_params.shadingsystem = use_ocl ? ccl::SHADINGSYSTEM_OSL : ccl::SHADINGSYSTEM_SVM; session_params.use_profiling = false;