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/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/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/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_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..16dd681 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) @@ -39,34 +40,117 @@ 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) +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, + // 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"); + 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); + // 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(); + 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; @@ -86,50 +170,81 @@ 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 + + // 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_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_data[curve_index].GetX(), point_position_data[curve_index].GetY(), point_position_data[curve_index].GetZ(), size_data[curve_index]); + 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 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++) + 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++) { - 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) - { - radius = 0.0; - } - strands_geom->add_curve_key(vector3_to_float3(one_strand_data[k_index]), radius); + 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); 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++; } if (attr_intercept) { + float time = static_cast(k_index + 1) / total_time; + attr_intercept->add(time); } } @@ -139,9 +254,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); @@ -169,6 +285,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) @@ -179,9 +297,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++; } } @@ -193,9 +311,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++; } } @@ -207,9 +325,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++; } } @@ -218,7 +336,12 @@ 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, + 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); @@ -228,6 +351,7 @@ 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(); + for (size_t mi = 0; mi < motion_steps - 1; mi++) { size_t time_motion_step = mi; @@ -249,35 +373,90 @@ 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 + // 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); + + 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) { - 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) + // 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) { - s = 0.0; + time_strand_size_data.GetSubArray(point_index, strand_sizes); + strand_sizes_length = strand_sizes.GetCount(); + } + 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 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 < time_strand_knots_count; 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); + } + } + else + { + // the strand length is different with original one + // in this case simply copy original positions + is_fail = true; } - p = strand[k_index]; - motion_positions[attribute_index++] = ccl::make_float4(p.GetX(), p.GetY(), p.GetZ(), s); } + if (is_fail) + { + // 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++) + { + motion_positions[attribute_index++] = original_positions[original_positions_iterator + k]; + } + } + original_positions_iterator += strand_knots_count + 1; } } else @@ -290,34 +469,22 @@ void sync_strands_deform(ccl::Hair* hair, UpdateContext* update_context, const X } } -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) { + 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, original_positions, strand_points, strand_lengths); 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, original_positions, strand_points, strand_lengths); } else { 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/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); 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) { diff --git a/src/render_cycles/cyc_session/cyc_baking.cpp b/src/render_cycles/cyc_session/cyc_baking.cpp index 888231b..a8ff268 100644 --- a/src/render_cycles/cyc_session/cyc_baking.cpp +++ b/src/render_cycles/cyc_session/cyc_baking.cpp @@ -630,26 +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) { - object = scene->objects[update_context->get_geometry_index(baking_object_id)]; + 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/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; diff --git a/src/render_cycles/render_engine_cyc.cpp b/src/render_cycles/render_engine_cyc.cpp index 3daddd2..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); } } @@ -803,7 +807,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; diff --git a/src/utilities/logs.cpp b/src/utilities/logs.cpp index 42d4109..6041c11 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) @@ -312,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 414d52e..db7ad8f 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); @@ -37,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 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