diff --git a/intern/cycles/blender/shader.cpp b/intern/cycles/blender/shader.cpp index d060a8942aa..17634d334c3 100644 --- a/intern/cycles/blender/shader.cpp +++ b/intern/cycles/blender/shader.cpp @@ -1080,6 +1080,12 @@ static ShaderNode *add_node(Scene *scene, nmap->set_attribute(ustring(b_normal_map_node.uv_map())); node = nmap; } + else if (b_node.is_a(&RNA_ShaderNodeRadialTiling)) { + BL::ShaderNodeRadialTiling b_radial_tiling_node(b_node); + RadialTilingNode *radial_tiling = graph->create_node(); + radial_tiling->set_use_normalize(b_radial_tiling_node.normalize()); + node = radial_tiling; + } else if (b_node.is_a(&RNA_ShaderNodeTangent)) { BL::ShaderNodeTangent b_tangent_node(b_node); TangentNode *tangent = graph->create_node(); diff --git a/intern/cycles/kernel/CMakeLists.txt b/intern/cycles/kernel/CMakeLists.txt index 24a9beeae29..2306898f6b8 100644 --- a/intern/cycles/kernel/CMakeLists.txt +++ b/intern/cycles/kernel/CMakeLists.txt @@ -210,6 +210,8 @@ set(SRC_KERNEL_SVM_HEADERS svm/normal.h svm/ramp.h svm/ramp_util.h + svm/radial_tiling.h + svm/radial_tiling_shared.h svm/sepcomb_color.h svm/sepcomb_vector.h svm/sky.h diff --git a/intern/cycles/kernel/osl/shaders/CMakeLists.txt b/intern/cycles/kernel/osl/shaders/CMakeLists.txt index cdc8fe5de26..e29ce17b835 100644 --- a/intern/cycles/kernel/osl/shaders/CMakeLists.txt +++ b/intern/cycles/kernel/osl/shaders/CMakeLists.txt @@ -74,6 +74,7 @@ set(SRC_OSL node_refraction_bsdf.osl node_rgb_curves.osl node_rgb_ramp.osl + node_radial_tiling.osl node_separate_color.osl node_separate_xyz.osl node_set_normal.osl @@ -119,6 +120,7 @@ set(SRC_OSL_HEADERS node_math.h node_noise.h node_ramp_util.h + node_radial_tiling_shared.h node_voronoi.h stdcycles.h ${SRC_OSL_HEADER_DIST} diff --git a/intern/cycles/kernel/osl/shaders/node_math.h b/intern/cycles/kernel/osl/shaders/node_math.h index ac950b54ea0..831b226790e 100644 --- a/intern/cycles/kernel/osl/shaders/node_math.h +++ b/intern/cycles/kernel/osl/shaders/node_math.h @@ -2,6 +2,11 @@ * * SPDX-License-Identifier: Apache-2.0 */ +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + float safe_divide(float a, float b) { return (b != 0.0) ? a / b : 0.0; @@ -24,6 +29,33 @@ float safe_floored_modulo(float a, float b) return (b != 0.0) ? a - floor(a / b) * b : 0.0; } +float sqr(float a) +{ + return a * a; +} + +/* The float and vector3 overloads are already defined in stdosl.h. + * + * float round(float a) + * { + * return floor(a + 0.5); + * } + * + * vector3 round(vector3 a) + * { + * return vector3(floor(a.x + 0.5), floor(a.y + 0.5), floor(a.z + 0.5)); + * } */ + +vector2 round(vector2 a) +{ + return vector2(floor(a.x + 0.5), floor(a.y + 0.5)); +} + +vector4 round(vector4 a) +{ + return vector4(floor(a.x + 0.5), floor(a.y + 0.5), floor(a.z + 0.5), floor(a.w + 0.5)); +} + float fract(float a) { return a - floor(a); diff --git a/intern/cycles/kernel/osl/shaders/node_radial_tiling.osl b/intern/cycles/kernel/osl/shaders/node_radial_tiling.osl new file mode 100644 index 00000000000..295313ccc7d --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_radial_tiling.osl @@ -0,0 +1,54 @@ +/* SPDX-FileCopyrightText: 2024-2025 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +#include "node_math.h" +#include "stdcycles.h" +#include "vector2.h" +#include "vector4.h" + +#define vector3 point + +/* Define macro flags for code adaption. */ +#define ADAPT_TO_OSL + +/* The rounded polygon calculation functions are defined in node_radial_tiling_shared.h. */ +#include "node_radial_tiling_shared.h" + +/* Undefine macro flags used for code adaption. */ +#undef ADAPT_TO_OSL + +shader node_radial_tiling(int use_normalize = 0, + vector3 Vector = P, + float Sides = 5.0, + float Roundness = 0.0, + output vector3 SegmentCoordinates = vector3(0.0, 0.0, 0.0), + output float SegmentID = 0.0, + output float SegmentWidth = 0.0, + output float SegmentRotation = 0.0) +{ + /* isconnected() returns 2 when output socket is connected. */ + int calculate_r_gon_parameter_field = int(isconnected(SegmentCoordinates) != 0); + int calculate_segment_id = int(isconnected(SegmentID) != 0); + int calculate_max_unit_parameter = int(isconnected(SegmentWidth) != 0); + int calculate_x_axis_A_angle_bisector = int(isconnected(SegmentRotation) != 0); + + if (calculate_r_gon_parameter_field || calculate_max_unit_parameter || + calculate_x_axis_A_angle_bisector) + { + vector4 out_variables = calculate_out_variables(calculate_r_gon_parameter_field, + calculate_max_unit_parameter, + use_normalize, + max(Sides, 2.0), + clamp(Roundness, 0.0, 1.0), + vector2(Vector.x, Vector.y)); + + SegmentCoordinates = vector3(out_variables.y, out_variables.x, 0.0); + SegmentWidth = out_variables.z; + SegmentRotation = out_variables.w; + } + + if (calculate_segment_id) { + SegmentID = calculate_out_segment_id(max(Sides, 2.0), vector2(Vector.x, Vector.y)); + } +} diff --git a/intern/cycles/kernel/osl/shaders/node_radial_tiling_shared.h b/intern/cycles/kernel/osl/shaders/node_radial_tiling_shared.h new file mode 100644 index 00000000000..7719bc395fe --- /dev/null +++ b/intern/cycles/kernel/osl/shaders/node_radial_tiling_shared.h @@ -0,0 +1,1179 @@ +/* SPDX-FileCopyrightText: 2024-2025 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +/* The following files are always to be kept as exact copies of each other: + * radial_tiling_shared.hh + * node_radial_tiling_shared.h + * radial_tiling_shared.h + * gpu_shader_material_radial_tiling_shared.glsl */ + +/* The SVM implementation is used as the base shared version because multiple math function + * identifiers are already used as macros in the SVM code, making a code adaption into an SVM + * implementation using macros impossible. */ + +/* Define macros for code adaption. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# define atanf math::atan +# define atan2f math::atan2 +# define ceilf math::ceil +# define cosf math::cos +# define fabsf math::abs +# define floorf math::floor +# define fmaxf math::max +# define fminf math::min +# define fractf math::fract +# define mix math::interpolate +# define sinf math::sin +# define sqrtf math::sqrt +# define sqr math::square +# define tanf math::tan + +# define make_float2 float2 +# define make_float4 float4 +# define M_PI_F M_PI +# define M_2PI_F M_TAU +# define ccl_device +#else +# ifdef ADAPT_TO_OSL +# define atanf atan +# define atan2f atan2 +# define ceilf ceil +# define cosf cos +# define fabsf abs +# define floorf floor +# define fmaxf max +# define fminf min +# define fractf fract +# define mix mix +# define sinf sin +# define sqrtf sqrt +# define sqr sqr +# define tanf tan + +# define bool int +# define float2 vector2 +# define float4 vector4 +# define make_float2 vector2 +# define make_float4 vector4 +# define M_PI_F M_PI +# define M_2PI_F M_2PI +# define ccl_device + +# define false 0 +# define true 1 +# else +# ifdef ADAPT_TO_SVM +/* No code adaption necessary for the SVM implementation as it is the base shared version. */ +# else +/* Adapt code to GLSL by default. */ +# define atanf atan +# define atan2f atan2 +# define ceilf ceil +# define cosf cos +# define fabsf abs +# define floorf floor +# define fmaxf max +# define fminf min +# define fractf fract +# define mix mix +# define sinf sin +# define sqrtf sqrt +# define sqr square +# define tanf tan + +# define make_float2 float2 +# define make_float4 float4 +# define M_PI_F M_PI +# define M_2PI_F M_TAU +# define ccl_device +# endif +# endif +#endif + +/* The geometry nodes has optional specialized functions for certain combinations of input values. + * These specialized functions output the same values as the general functions, but are faster when + * they can be used. To reduce the complexity on the GPU kernel while also keeping all rendering + * implementations the same, they are only enabled in the geometry nodes implementation. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# define ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(X) (X) +#else +# define ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(X) true +#endif + +/* Naming convention for the Radial Tiling node code: + * Let x and y be 2D vectors. + * The length of X is expressed as l_x, which is an abbreviation of length_x. + * The counterclockwise unsinged angle in [0.0, M_TAU] from X to Y is expressed as x_A_y, which + * is an abbreviation of x_Angle_y. The singed angle in [-M_PI, M_PI] from x to y is expressed + * as x_SA_y, which is an abbreviation of x_SingedAngle_y. Counterclockwise angles are positive, + * clockwise angles are negative. A signed angle from x to y of which the output is mirrored along + * a certain vector is expressed as x_MSA_y, which is an abbreviation of x_MirroredSingedAngle_y. + * + * Let z and w be scalars. + * The ratio z/w is expressed as z_R_w, which is an abbreviation of z_Ratio_y. */ + +#ifdef ADAPT_TO_GEOMETRY_NODES +ccl_device float4 +calculate_out_variables_full_roundness_irregular_circular(bool calculate_r_gon_parameter_field, + bool normalize_r_gon_parameter, + float r_gon_sides, + float2 coord, + float l_coord) +{ + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + float l_last_circle_radius = tanf(last_angle_bisector_A_x_axis) / + tanf(float(0.5) * (segment_divider_A_angle_bisector + + last_angle_bisector_A_x_axis)); + float2 last_circle_center = make_float2( + cosf(last_angle_bisector_A_x_axis) - + l_last_circle_radius * cosf(last_angle_bisector_A_x_axis), + l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) - + sinf(last_angle_bisector_A_x_axis)); + float2 outer_last_bevel_start = last_circle_center + + l_last_circle_radius * + make_float2(cosf(segment_divider_A_angle_bisector), + sinf(segment_divider_A_angle_bisector)); + float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y / + outer_last_bevel_start.x); + float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start; + + if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start)) + { + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (calculate_r_gon_parameter_field) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + return make_float4(l_angle_bisector, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular rounded part. */ + + float r_gon_parameter = float(0.0); + if (calculate_r_gon_parameter_field) { + r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= segment_divider_A_angle_bisector; + } + } + return make_float4(l_coord, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + else { + /* Irregular rounded part. */ + + /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector + * to avoid a case distinction. */ + float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x); + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis)) + { + nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis; + nearest_segment_divider_MSA_coord *= -float(1.0); + } + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + float x_axis_A_angle_bisector = float(0.0); + + float l_coord_R_l_last_angle_bisector = + sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x + + sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) + + sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y)); + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_coord / + l_coord_R_l_last_angle_bisector; + + if (nearest_segment_divider_MSA_coord < float(0.0)) { + /* Irregular rounded inner part. */ + + if (calculate_r_gon_parameter_field) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * + (last_angle_bisector_A_x_axis + nearest_segment_divider_MSA_coord); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * + last_angle_bisector_A_x_axis; + } + } + max_unit_parameter = l_angle_bisector_R_l_last_angle_bisector * last_angle_bisector_A_x_axis; + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis; + } + else { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (calculate_r_gon_parameter_field) { + float coord_A_bevel_start = x_axis_A_outer_last_bevel_start - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_outer_last_bevel_start) { + r_gon_parameter += + l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * (float(1.0) - l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start; + } + else { + r_gon_parameter += spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * + cosf(outer_last_bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) + + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / x_axis_A_outer_last_bevel_start); + } + } + max_unit_parameter = segment_divider_A_angle_bisector; + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector; + } + return make_float4( + l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector); + } +} +#endif + +ccl_device float4 calculate_out_variables_irregular_circular(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord, + float l_coord) +{ +#ifdef ADAPT_TO_SVM + /* Silence compiler warnings. */ + (void)calculate_r_gon_parameter_field; + (void)calculate_max_unit_parameter; +#endif + + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + float segment_divider_A_bevel_start = segment_divider_A_angle_bisector - + atanf((float(1.0) - r_gon_roundness) * + tanf(segment_divider_A_angle_bisector)); + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + float inner_last_bevel_start_A_x_axis = last_angle_bisector_A_x_axis - + atanf((float(1.0) - r_gon_roundness) * + tanf(last_angle_bisector_A_x_axis)); + float l_last_circle_radius = r_gon_roundness * tanf(last_angle_bisector_A_x_axis) / + tanf(float(0.5) * (segment_divider_A_angle_bisector + + last_angle_bisector_A_x_axis)); + float2 last_circle_center = make_float2( + (cosf(inner_last_bevel_start_A_x_axis) / + cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis)) - + l_last_circle_radius * cosf(last_angle_bisector_A_x_axis), + l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) - + (sinf(inner_last_bevel_start_A_x_axis) / + cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis))); + float2 outer_last_bevel_start = last_circle_center + + l_last_circle_radius * + make_float2(cosf(segment_divider_A_angle_bisector), + sinf(segment_divider_A_angle_bisector)); + float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y / + outer_last_bevel_start.x); + float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start; + + if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start)) + { + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + + if (((segment_divider_A_coord >= segment_divider_A_bevel_start) && + (segment_divider_A_coord < + segment_divider_A_next_segment_divider - segment_divider_A_bevel_start)) || + (x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_bevel_start) || + (x_axis_A_coord < segment_divider_A_bevel_start)) + { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + else { + /* Regular straight part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + + if (normalize_r_gon_parameter) { + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + else { + /* Regular straight part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular rounded part. */ + + /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise + * angles are negative.*/ + float nearest_segment_divider_SA_coord = segment_divider_A_coord - + float(segment_divider_A_coord > + segment_divider_A_angle_bisector) * + segment_divider_A_next_segment_divider; + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_circle_center = (float(1.0) - r_gon_roundness) / + cosf(segment_divider_A_angle_bisector); + float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center + + sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) * + l_circle_center) + + sqr(r_gon_roundness) - sqr(l_circle_center)); + + l_angle_bisector = l_coord / l_coord_R_l_bevel_start; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = segment_divider_A_bevel_start - + fabsf(nearest_segment_divider_SA_coord); + r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start; + } + else { + r_gon_parameter += spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / segment_divider_A_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + else { + float inner_last_bevel_start_A_last_angle_bisector = last_angle_bisector_A_x_axis - + inner_last_bevel_start_A_x_axis; + + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis + inner_last_bevel_start_A_x_axis) && + (x_axis_A_coord < M_2PI_F - inner_last_bevel_start_A_x_axis)) + { + /* Irregular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord * + cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + inner_last_bevel_start_A_x_axis; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord)); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_l_angle_bisector = + l_angle_bisector_R_l_last_angle_bisector * + (l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + + r_gon_parameter /= normalize_based_on_l_l_angle_bisector; + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) + + l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis); + } + else { + /* Irregular rounded part. */ + + /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector + * to avoid a case distinction. */ + float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x); + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis)) + { + nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis; + nearest_segment_divider_MSA_coord *= -float(1.0); + } + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + float x_axis_A_angle_bisector = float(0.0); + + float l_coord_R_l_last_angle_bisector = + sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x + + sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) + + sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y)); + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord / l_coord_R_l_last_angle_bisector; + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + if (nearest_segment_divider_MSA_coord < float(0.0)) { + /* Irregular rounded inner part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + inner_last_bevel_start_A_x_axis; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = inner_last_bevel_start_A_x_axis - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_coord * + sinf(inner_last_bevel_start_A_last_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += + l_angle_bisector_R_l_last_angle_bisector * + (l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) * + coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start); + } + else { + r_gon_parameter += l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + (float(0.5) * l_coord * + cosf(inner_last_bevel_start_A_last_angle_bisector) - + float(0.5)) + + coord_A_bevel_start); + } + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_l_angle_bisector = + l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis; + float normalize_based_on_l_coord = + l_coord * sinf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * + mix(normalize_based_on_l_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / inner_last_bevel_start_A_x_axis); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) + + l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + } + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis; + } + else { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = x_axis_A_outer_last_bevel_start - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_outer_last_bevel_start) { + r_gon_parameter += l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * + coord_A_bevel_start + + float(0.5) * + (float(1.0) - + l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start; + } + else { + r_gon_parameter += spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * + cosf(outer_last_bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) + + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / x_axis_A_outer_last_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector; + } + return make_float4( + l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector); + } + } +} + +ccl_device float4 calculate_out_variables(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord) +{ +#ifdef ADAPT_TO_SVM + /* Silence compiler warnings. */ + (void)calculate_r_gon_parameter_field; + (void)calculate_max_unit_parameter; +#endif + + float l_coord = sqrtf(sqr(coord.x) + sqr(coord.y)); + float4 out_variables; + + if (fractf(r_gon_sides) == float(0.0)) { + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + if (r_gon_roundness == float(0.0)) { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter && (r_gon_sides != float(2.0))) { + r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = (r_gon_sides != float(2.0)) ? tanf(segment_divider_A_angle_bisector) : + float(0.0); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else if (r_gon_roundness == float(1.0)) { + /* Regular rounded part. */ + + float r_gon_parameter = float(0.0); + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= segment_divider_A_angle_bisector; + } + } + out_variables = make_float4(l_coord, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + float segment_divider_A_bevel_start = segment_divider_A_angle_bisector - + atanf((float(1.0) - r_gon_roundness) * + tanf(segment_divider_A_angle_bisector)); + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + + if ((segment_divider_A_coord >= + segment_divider_A_next_segment_divider - segment_divider_A_bevel_start) || + (segment_divider_A_coord < segment_divider_A_bevel_start)) + { + /* Regular rounded part. */ + + /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise + * angles are negative.*/ + float nearest_segment_divider_SA_coord = segment_divider_A_coord - + float(segment_divider_A_coord > + segment_divider_A_angle_bisector) * + segment_divider_A_next_segment_divider; + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_circle_center = (float(1.0) - r_gon_roundness) / + cosf(segment_divider_A_angle_bisector); + float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center + + sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) * + l_circle_center) + + sqr(r_gon_roundness) - sqr(l_circle_center)); + + l_angle_bisector = l_coord / l_coord_R_l_bevel_start; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = segment_divider_A_bevel_start - + fabsf(nearest_segment_divider_SA_coord); + r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start; + } + else { + r_gon_parameter += spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / segment_divider_A_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + } + else { + if (r_gon_roundness == float(0.0)) { + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + + if (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis) { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(segment_divider_A_angle_bisector); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Irregular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord * + cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord)); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(last_angle_bisector_A_x_axis); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(last_angle_bisector_A_x_axis); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis); + } + } +#ifdef ADAPT_TO_GEOMETRY_NODES + else if (r_gon_roundness == float(1.0)) { + out_variables = calculate_out_variables_full_roundness_irregular_circular( + calculate_r_gon_parameter_field, normalize_r_gon_parameter, r_gon_sides, coord, l_coord); + } +#endif + else { + out_variables = calculate_out_variables_irregular_circular(calculate_r_gon_parameter_field, + calculate_max_unit_parameter, + normalize_r_gon_parameter, + r_gon_sides, + r_gon_roundness, + coord, + l_coord); + } + } + + if ((coord.x == float(0.0)) && (coord.y == float(0.0))) { + /* The r_gon_parameter is defined to 0 when it is not normalized and the input coordinate is + * the zero vector. */ + out_variables.y = float(0.0); + } + + if (normalize_r_gon_parameter) { + /* Normalize r_gon_parameter from a [-1, 1] interval to a [0, 1] interval. */ + out_variables.y = float(0.5) * out_variables.y + float(0.5); + } + else { + out_variables.x -= float(1.0); + } + + return out_variables; +} + +ccl_device float calculate_out_segment_id(float r_gon_sides, float2 coord) +{ + return floorf(r_gon_sides * + ((atan2f(coord.y, coord.x) / M_2PI_F) + float(coord.y < float(0.0)))); +} + +/* Undefine macros used for code adaption. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef make_float2 +# undef make_float4 +# undef ccl_device +#else +# ifdef ADAPT_TO_OSL +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef bool +# undef float2 +# undef float4 +# undef make_float2 +# undef make_float4 +# undef M_PI_F +# undef M_2PI_F +# undef ccl_device + +# undef false +# undef true +# else +# ifdef ADAPT_TO_SVM +/* No code adaption necessary for the SVM implementation as it is the base shared version. */ +# else +/* Adapt code to GLSL by default. */ +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef make_float2 +# undef make_float4 +# undef M_PI_F +# undef M_2PI_F +# undef ccl_device +# endif +# endif +#endif + +#undef ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION diff --git a/intern/cycles/kernel/svm/node_types_template.h b/intern/cycles/kernel/svm/node_types_template.h index 91d9d22361b..749b0ca91d5 100644 --- a/intern/cycles/kernel/svm/node_types_template.h +++ b/intern/cycles/kernel/svm/node_types_template.h @@ -82,6 +82,7 @@ SHADER_NODE_TYPE(NODE_IES) SHADER_NODE_TYPE(NODE_CURVES) SHADER_NODE_TYPE(NODE_TANGENT) SHADER_NODE_TYPE(NODE_NORMAL_MAP) +SHADER_NODE_TYPE(NODE_RADIAL_TILING) SHADER_NODE_TYPE(NODE_INVERT) SHADER_NODE_TYPE(NODE_MIX) SHADER_NODE_TYPE(NODE_SEPARATE_COLOR) @@ -111,6 +112,5 @@ SHADER_NODE_TYPE(NODE_MIX_VECTOR_NON_UNIFORM) /* Padding for struct alignment. */ SHADER_NODE_TYPE(NODE_PAD1) -SHADER_NODE_TYPE(NODE_PAD2) #undef SHADER_NODE_TYPE diff --git a/intern/cycles/kernel/svm/radial_tiling.h b/intern/cycles/kernel/svm/radial_tiling.h new file mode 100644 index 00000000000..e3f36e34a64 --- /dev/null +++ b/intern/cycles/kernel/svm/radial_tiling.h @@ -0,0 +1,81 @@ +/* SPDX-FileCopyrightText: 2024-2025 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +#pragma once + +CCL_NAMESPACE_BEGIN + +/* Define macro flags for code adaption. */ +#define ADAPT_TO_SVM + +/* The rounded polygon calculation functions are defined in radial_tiling_shared.h. */ +#include "radial_tiling_shared.h" + +/* Undefine macro flags used for code adaption. */ +#undef ADAPT_TO_SVM + +struct RoundedPolygonStackOffsets { + uint vector; + uint r_gon_sides; + uint r_gon_roundness; + uint segment_coordinates; + uint segment_id; + uint max_unit_parameter; + uint x_axis_A_angle_bisector; +}; + +template +ccl_device_noinline int svm_node_radial_tiling(ccl_private float *stack, uint4 node, int offset) +{ + RoundedPolygonStackOffsets so; + + uint normalize_r_gon_parameter = node.y; + + svm_unpack_node_uchar4( + node.z, &(so.vector), &(so.r_gon_sides), &(so.r_gon_roundness), &(so.segment_coordinates)); + svm_unpack_node_uchar3( + node.w, &(so.segment_id), &(so.max_unit_parameter), &(so.x_axis_A_angle_bisector)); + + bool calculate_r_gon_parameter_field = stack_valid(so.segment_coordinates); + bool calculate_segment_id = stack_valid(so.segment_id); + bool calculate_max_unit_parameter = stack_valid(so.max_unit_parameter); + bool calculate_x_axis_A_angle_bisector = stack_valid(so.x_axis_A_angle_bisector); + + float3 coord = stack_load_float3(stack, so.vector); + float r_gon_sides = stack_load_float(stack, so.r_gon_sides); + float r_gon_roundness = stack_load_float(stack, so.r_gon_roundness); + + if (calculate_r_gon_parameter_field || calculate_max_unit_parameter || + calculate_x_axis_A_angle_bisector) + { + float4 out_variables = calculate_out_variables(calculate_r_gon_parameter_field, + calculate_max_unit_parameter, + normalize_r_gon_parameter, + fmaxf(r_gon_sides, 2.0f), + clamp(r_gon_roundness, 0.0f, 1.0f), + make_float2(coord.x, coord.y)); + + if (calculate_r_gon_parameter_field) { + stack_store_float3( + stack, so.segment_coordinates, make_float3(out_variables.y, out_variables.x, 0.0f)); + } + if (calculate_max_unit_parameter) { + stack_store_float(stack, so.max_unit_parameter, out_variables.z); + } + if (calculate_x_axis_A_angle_bisector) { + stack_store_float(stack, so.x_axis_A_angle_bisector, out_variables.w); + } + } + + if (calculate_segment_id) { + stack_store_float( + stack, + so.segment_id, + calculate_out_segment_id(fmaxf(r_gon_sides, 2.0f), make_float2(coord.x, coord.y))); + } + + return offset; +} + +CCL_NAMESPACE_END diff --git a/intern/cycles/kernel/svm/radial_tiling_shared.h b/intern/cycles/kernel/svm/radial_tiling_shared.h new file mode 100644 index 00000000000..7719bc395fe --- /dev/null +++ b/intern/cycles/kernel/svm/radial_tiling_shared.h @@ -0,0 +1,1179 @@ +/* SPDX-FileCopyrightText: 2024-2025 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +/* The following files are always to be kept as exact copies of each other: + * radial_tiling_shared.hh + * node_radial_tiling_shared.h + * radial_tiling_shared.h + * gpu_shader_material_radial_tiling_shared.glsl */ + +/* The SVM implementation is used as the base shared version because multiple math function + * identifiers are already used as macros in the SVM code, making a code adaption into an SVM + * implementation using macros impossible. */ + +/* Define macros for code adaption. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# define atanf math::atan +# define atan2f math::atan2 +# define ceilf math::ceil +# define cosf math::cos +# define fabsf math::abs +# define floorf math::floor +# define fmaxf math::max +# define fminf math::min +# define fractf math::fract +# define mix math::interpolate +# define sinf math::sin +# define sqrtf math::sqrt +# define sqr math::square +# define tanf math::tan + +# define make_float2 float2 +# define make_float4 float4 +# define M_PI_F M_PI +# define M_2PI_F M_TAU +# define ccl_device +#else +# ifdef ADAPT_TO_OSL +# define atanf atan +# define atan2f atan2 +# define ceilf ceil +# define cosf cos +# define fabsf abs +# define floorf floor +# define fmaxf max +# define fminf min +# define fractf fract +# define mix mix +# define sinf sin +# define sqrtf sqrt +# define sqr sqr +# define tanf tan + +# define bool int +# define float2 vector2 +# define float4 vector4 +# define make_float2 vector2 +# define make_float4 vector4 +# define M_PI_F M_PI +# define M_2PI_F M_2PI +# define ccl_device + +# define false 0 +# define true 1 +# else +# ifdef ADAPT_TO_SVM +/* No code adaption necessary for the SVM implementation as it is the base shared version. */ +# else +/* Adapt code to GLSL by default. */ +# define atanf atan +# define atan2f atan2 +# define ceilf ceil +# define cosf cos +# define fabsf abs +# define floorf floor +# define fmaxf max +# define fminf min +# define fractf fract +# define mix mix +# define sinf sin +# define sqrtf sqrt +# define sqr square +# define tanf tan + +# define make_float2 float2 +# define make_float4 float4 +# define M_PI_F M_PI +# define M_2PI_F M_TAU +# define ccl_device +# endif +# endif +#endif + +/* The geometry nodes has optional specialized functions for certain combinations of input values. + * These specialized functions output the same values as the general functions, but are faster when + * they can be used. To reduce the complexity on the GPU kernel while also keeping all rendering + * implementations the same, they are only enabled in the geometry nodes implementation. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# define ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(X) (X) +#else +# define ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(X) true +#endif + +/* Naming convention for the Radial Tiling node code: + * Let x and y be 2D vectors. + * The length of X is expressed as l_x, which is an abbreviation of length_x. + * The counterclockwise unsinged angle in [0.0, M_TAU] from X to Y is expressed as x_A_y, which + * is an abbreviation of x_Angle_y. The singed angle in [-M_PI, M_PI] from x to y is expressed + * as x_SA_y, which is an abbreviation of x_SingedAngle_y. Counterclockwise angles are positive, + * clockwise angles are negative. A signed angle from x to y of which the output is mirrored along + * a certain vector is expressed as x_MSA_y, which is an abbreviation of x_MirroredSingedAngle_y. + * + * Let z and w be scalars. + * The ratio z/w is expressed as z_R_w, which is an abbreviation of z_Ratio_y. */ + +#ifdef ADAPT_TO_GEOMETRY_NODES +ccl_device float4 +calculate_out_variables_full_roundness_irregular_circular(bool calculate_r_gon_parameter_field, + bool normalize_r_gon_parameter, + float r_gon_sides, + float2 coord, + float l_coord) +{ + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + float l_last_circle_radius = tanf(last_angle_bisector_A_x_axis) / + tanf(float(0.5) * (segment_divider_A_angle_bisector + + last_angle_bisector_A_x_axis)); + float2 last_circle_center = make_float2( + cosf(last_angle_bisector_A_x_axis) - + l_last_circle_radius * cosf(last_angle_bisector_A_x_axis), + l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) - + sinf(last_angle_bisector_A_x_axis)); + float2 outer_last_bevel_start = last_circle_center + + l_last_circle_radius * + make_float2(cosf(segment_divider_A_angle_bisector), + sinf(segment_divider_A_angle_bisector)); + float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y / + outer_last_bevel_start.x); + float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start; + + if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start)) + { + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (calculate_r_gon_parameter_field) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + return make_float4(l_angle_bisector, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular rounded part. */ + + float r_gon_parameter = float(0.0); + if (calculate_r_gon_parameter_field) { + r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= segment_divider_A_angle_bisector; + } + } + return make_float4(l_coord, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + else { + /* Irregular rounded part. */ + + /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector + * to avoid a case distinction. */ + float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x); + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis)) + { + nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis; + nearest_segment_divider_MSA_coord *= -float(1.0); + } + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + float x_axis_A_angle_bisector = float(0.0); + + float l_coord_R_l_last_angle_bisector = + sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x + + sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) + + sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y)); + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_coord / + l_coord_R_l_last_angle_bisector; + + if (nearest_segment_divider_MSA_coord < float(0.0)) { + /* Irregular rounded inner part. */ + + if (calculate_r_gon_parameter_field) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * + (last_angle_bisector_A_x_axis + nearest_segment_divider_MSA_coord); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * + last_angle_bisector_A_x_axis; + } + } + max_unit_parameter = l_angle_bisector_R_l_last_angle_bisector * last_angle_bisector_A_x_axis; + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis; + } + else { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (calculate_r_gon_parameter_field) { + float coord_A_bevel_start = x_axis_A_outer_last_bevel_start - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_outer_last_bevel_start) { + r_gon_parameter += + l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * (float(1.0) - l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start; + } + else { + r_gon_parameter += spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * + cosf(outer_last_bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) + + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / x_axis_A_outer_last_bevel_start); + } + } + max_unit_parameter = segment_divider_A_angle_bisector; + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector; + } + return make_float4( + l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector); + } +} +#endif + +ccl_device float4 calculate_out_variables_irregular_circular(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord, + float l_coord) +{ +#ifdef ADAPT_TO_SVM + /* Silence compiler warnings. */ + (void)calculate_r_gon_parameter_field; + (void)calculate_max_unit_parameter; +#endif + + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + float segment_divider_A_bevel_start = segment_divider_A_angle_bisector - + atanf((float(1.0) - r_gon_roundness) * + tanf(segment_divider_A_angle_bisector)); + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + float inner_last_bevel_start_A_x_axis = last_angle_bisector_A_x_axis - + atanf((float(1.0) - r_gon_roundness) * + tanf(last_angle_bisector_A_x_axis)); + float l_last_circle_radius = r_gon_roundness * tanf(last_angle_bisector_A_x_axis) / + tanf(float(0.5) * (segment_divider_A_angle_bisector + + last_angle_bisector_A_x_axis)); + float2 last_circle_center = make_float2( + (cosf(inner_last_bevel_start_A_x_axis) / + cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis)) - + l_last_circle_radius * cosf(last_angle_bisector_A_x_axis), + l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) - + (sinf(inner_last_bevel_start_A_x_axis) / + cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis))); + float2 outer_last_bevel_start = last_circle_center + + l_last_circle_radius * + make_float2(cosf(segment_divider_A_angle_bisector), + sinf(segment_divider_A_angle_bisector)); + float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y / + outer_last_bevel_start.x); + float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start; + + if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start)) + { + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + + if (((segment_divider_A_coord >= segment_divider_A_bevel_start) && + (segment_divider_A_coord < + segment_divider_A_next_segment_divider - segment_divider_A_bevel_start)) || + (x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_bevel_start) || + (x_axis_A_coord < segment_divider_A_bevel_start)) + { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + else { + /* Regular straight part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + + if (normalize_r_gon_parameter) { + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + else { + /* Regular straight part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular rounded part. */ + + /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise + * angles are negative.*/ + float nearest_segment_divider_SA_coord = segment_divider_A_coord - + float(segment_divider_A_coord > + segment_divider_A_angle_bisector) * + segment_divider_A_next_segment_divider; + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_circle_center = (float(1.0) - r_gon_roundness) / + cosf(segment_divider_A_angle_bisector); + float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center + + sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) * + l_circle_center) + + sqr(r_gon_roundness) - sqr(l_circle_center)); + + l_angle_bisector = l_coord / l_coord_R_l_bevel_start; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = segment_divider_A_bevel_start - + fabsf(nearest_segment_divider_SA_coord); + r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start; + } + else { + r_gon_parameter += spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / segment_divider_A_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + else { + float inner_last_bevel_start_A_last_angle_bisector = last_angle_bisector_A_x_axis - + inner_last_bevel_start_A_x_axis; + + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis + inner_last_bevel_start_A_x_axis) && + (x_axis_A_coord < M_2PI_F - inner_last_bevel_start_A_x_axis)) + { + /* Irregular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord * + cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + inner_last_bevel_start_A_x_axis; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord)); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_l_angle_bisector = + l_angle_bisector_R_l_last_angle_bisector * + (l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + + r_gon_parameter /= normalize_based_on_l_l_angle_bisector; + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) + + l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis); + } + else { + /* Irregular rounded part. */ + + /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector + * to avoid a case distinction. */ + float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x); + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis)) + { + nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis; + nearest_segment_divider_MSA_coord *= -float(1.0); + } + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + float x_axis_A_angle_bisector = float(0.0); + + float l_coord_R_l_last_angle_bisector = + sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x + + sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) + + sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y)); + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord / l_coord_R_l_last_angle_bisector; + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + if (nearest_segment_divider_MSA_coord < float(0.0)) { + /* Irregular rounded inner part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + inner_last_bevel_start_A_x_axis; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = inner_last_bevel_start_A_x_axis - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_coord * + sinf(inner_last_bevel_start_A_last_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += + l_angle_bisector_R_l_last_angle_bisector * + (l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) * + coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start); + } + else { + r_gon_parameter += l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + (float(0.5) * l_coord * + cosf(inner_last_bevel_start_A_last_angle_bisector) - + float(0.5)) + + coord_A_bevel_start); + } + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_l_angle_bisector = + l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis; + float normalize_based_on_l_coord = + l_coord * sinf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * + mix(normalize_based_on_l_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / inner_last_bevel_start_A_x_axis); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) + + l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + } + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis; + } + else { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = x_axis_A_outer_last_bevel_start - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_outer_last_bevel_start) { + r_gon_parameter += l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * + coord_A_bevel_start + + float(0.5) * + (float(1.0) - + l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start; + } + else { + r_gon_parameter += spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * + cosf(outer_last_bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) + + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / x_axis_A_outer_last_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector; + } + return make_float4( + l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector); + } + } +} + +ccl_device float4 calculate_out_variables(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord) +{ +#ifdef ADAPT_TO_SVM + /* Silence compiler warnings. */ + (void)calculate_r_gon_parameter_field; + (void)calculate_max_unit_parameter; +#endif + + float l_coord = sqrtf(sqr(coord.x) + sqr(coord.y)); + float4 out_variables; + + if (fractf(r_gon_sides) == float(0.0)) { + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + if (r_gon_roundness == float(0.0)) { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter && (r_gon_sides != float(2.0))) { + r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = (r_gon_sides != float(2.0)) ? tanf(segment_divider_A_angle_bisector) : + float(0.0); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else if (r_gon_roundness == float(1.0)) { + /* Regular rounded part. */ + + float r_gon_parameter = float(0.0); + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= segment_divider_A_angle_bisector; + } + } + out_variables = make_float4(l_coord, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + float segment_divider_A_bevel_start = segment_divider_A_angle_bisector - + atanf((float(1.0) - r_gon_roundness) * + tanf(segment_divider_A_angle_bisector)); + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + + if ((segment_divider_A_coord >= + segment_divider_A_next_segment_divider - segment_divider_A_bevel_start) || + (segment_divider_A_coord < segment_divider_A_bevel_start)) + { + /* Regular rounded part. */ + + /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise + * angles are negative.*/ + float nearest_segment_divider_SA_coord = segment_divider_A_coord - + float(segment_divider_A_coord > + segment_divider_A_angle_bisector) * + segment_divider_A_next_segment_divider; + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_circle_center = (float(1.0) - r_gon_roundness) / + cosf(segment_divider_A_angle_bisector); + float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center + + sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) * + l_circle_center) + + sqr(r_gon_roundness) - sqr(l_circle_center)); + + l_angle_bisector = l_coord / l_coord_R_l_bevel_start; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = segment_divider_A_bevel_start - + fabsf(nearest_segment_divider_SA_coord); + r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start; + } + else { + r_gon_parameter += spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / segment_divider_A_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + } + else { + if (r_gon_roundness == float(0.0)) { + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + + if (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis) { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(segment_divider_A_angle_bisector); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Irregular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord * + cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord)); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(last_angle_bisector_A_x_axis); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(last_angle_bisector_A_x_axis); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis); + } + } +#ifdef ADAPT_TO_GEOMETRY_NODES + else if (r_gon_roundness == float(1.0)) { + out_variables = calculate_out_variables_full_roundness_irregular_circular( + calculate_r_gon_parameter_field, normalize_r_gon_parameter, r_gon_sides, coord, l_coord); + } +#endif + else { + out_variables = calculate_out_variables_irregular_circular(calculate_r_gon_parameter_field, + calculate_max_unit_parameter, + normalize_r_gon_parameter, + r_gon_sides, + r_gon_roundness, + coord, + l_coord); + } + } + + if ((coord.x == float(0.0)) && (coord.y == float(0.0))) { + /* The r_gon_parameter is defined to 0 when it is not normalized and the input coordinate is + * the zero vector. */ + out_variables.y = float(0.0); + } + + if (normalize_r_gon_parameter) { + /* Normalize r_gon_parameter from a [-1, 1] interval to a [0, 1] interval. */ + out_variables.y = float(0.5) * out_variables.y + float(0.5); + } + else { + out_variables.x -= float(1.0); + } + + return out_variables; +} + +ccl_device float calculate_out_segment_id(float r_gon_sides, float2 coord) +{ + return floorf(r_gon_sides * + ((atan2f(coord.y, coord.x) / M_2PI_F) + float(coord.y < float(0.0)))); +} + +/* Undefine macros used for code adaption. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef make_float2 +# undef make_float4 +# undef ccl_device +#else +# ifdef ADAPT_TO_OSL +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef bool +# undef float2 +# undef float4 +# undef make_float2 +# undef make_float4 +# undef M_PI_F +# undef M_2PI_F +# undef ccl_device + +# undef false +# undef true +# else +# ifdef ADAPT_TO_SVM +/* No code adaption necessary for the SVM implementation as it is the base shared version. */ +# else +/* Adapt code to GLSL by default. */ +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef make_float2 +# undef make_float4 +# undef M_PI_F +# undef M_2PI_F +# undef ccl_device +# endif +# endif +#endif + +#undef ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION diff --git a/intern/cycles/kernel/svm/svm.h b/intern/cycles/kernel/svm/svm.h index c059fac5c38..b8ec6485e2a 100644 --- a/intern/cycles/kernel/svm/svm.h +++ b/intern/cycles/kernel/svm/svm.h @@ -62,6 +62,7 @@ #include "kernel/svm/mix.h" #include "kernel/svm/noisetex.h" #include "kernel/svm/normal.h" +#include "kernel/svm/radial_tiling.h" #include "kernel/svm/ramp.h" #include "kernel/svm/sepcomb_color.h" #include "kernel/svm/sepcomb_vector.h" @@ -405,6 +406,9 @@ ccl_device void svm_eval_nodes(KernelGlobals kg, SVM_CASE(NODE_NORMAL_MAP) svm_node_normal_map(kg, sd, stack, node); break; + SVM_CASE(NODE_RADIAL_TILING) + offset = svm_node_radial_tiling(stack, node, offset); + break; SVM_CASE(NODE_INVERT) svm_node_invert(stack, node.y, node.z, node.w); break; diff --git a/intern/cycles/scene/shader_nodes.cpp b/intern/cycles/scene/shader_nodes.cpp index 24ddeddccd1..4fa4b2d3750 100644 --- a/intern/cycles/scene/shader_nodes.cpp +++ b/intern/cycles/scene/shader_nodes.cpp @@ -7648,6 +7648,55 @@ void NormalMapNode::compile(OSLCompiler &compiler) compiler.add(this, "node_normal_map"); } +/* Radial Tiling */ + +NODE_DEFINE(RadialTilingNode) +{ + NodeType *type = NodeType::add("radial_tiling", create, NodeType::SHADER); + + SOCKET_BOOLEAN(use_normalize, "Normalize", false); + SOCKET_IN_POINT(vector, "Vector", zero_float3()); + SOCKET_IN_FLOAT(r_gon_sides, "Sides", 5.0f); + SOCKET_IN_FLOAT(r_gon_roundness, "Roundness", 0.0f); + + SOCKET_OUT_POINT(segment_coordinates, "Segment Coordinates"); + SOCKET_OUT_FLOAT(segment_id, "Segment ID"); + SOCKET_OUT_FLOAT(max_unit_parameter, "Segment Width"); + SOCKET_OUT_FLOAT(x_axis_A_angle_bisector, "Segment Rotation"); + + return type; +} + +RadialTilingNode::RadialTilingNode() : ShaderNode(get_node_type()) {} + +void RadialTilingNode::compile(SVMCompiler &compiler) +{ + ShaderInput *vector_in = input("Vector"); + ShaderInput *r_gon_sides_in = input("Sides"); + ShaderInput *r_gon_roundness_in = input("Roundness"); + + ShaderOutput *segment_coordinates_out = output("Segment Coordinates"); + ShaderOutput *segment_id_out = output("Segment ID"); + ShaderOutput *max_unit_parameter_out = output("Segment Width"); + ShaderOutput *x_axis_A_angle_bisector_out = output("Segment Rotation"); + + compiler.add_node(NODE_RADIAL_TILING, + use_normalize, + compiler.encode_uchar4(compiler.stack_assign(vector_in), + compiler.stack_assign(r_gon_sides_in), + compiler.stack_assign(r_gon_roundness_in), + compiler.stack_assign(segment_coordinates_out)), + compiler.encode_uchar4(compiler.stack_assign(segment_id_out), + compiler.stack_assign(max_unit_parameter_out), + compiler.stack_assign(x_axis_A_angle_bisector_out))); +} + +void RadialTilingNode::compile(OSLCompiler &compiler) +{ + compiler.parameter(this, "use_normalize"); + compiler.add(this, "node_radial_tiling"); +} + /* Tangent */ NODE_DEFINE(TangentNode) diff --git a/intern/cycles/scene/shader_nodes.h b/intern/cycles/scene/shader_nodes.h index 9876975d102..38986291fe2 100644 --- a/intern/cycles/scene/shader_nodes.h +++ b/intern/cycles/scene/shader_nodes.h @@ -1680,6 +1680,16 @@ class NormalMapNode : public ShaderNode { NODE_SOCKET_API(float3, color) }; +class RadialTilingNode : public ShaderNode { + public: + SHADER_NODE_CLASS(RadialTilingNode) + + NODE_SOCKET_API(bool, use_normalize) + NODE_SOCKET_API(float3, vector) + NODE_SOCKET_API(float, r_gon_sides) + NODE_SOCKET_API(float, r_gon_roundness) +}; + class TangentNode : public ShaderNode { public: SHADER_NODE_CLASS(TangentNode) diff --git a/scripts/startup/bl_ui/node_add_menu_compositor.py b/scripts/startup/bl_ui/node_add_menu_compositor.py index 55646b1697f..a3e06dda090 100644 --- a/scripts/startup/bl_ui/node_add_menu_compositor.py +++ b/scripts/startup/bl_ui/node_add_menu_compositor.py @@ -321,6 +321,7 @@ class NODE_MT_category_compositor_vector(Menu): ops = props.settings.add() ops.name = "data_type" ops.value = "'VECTOR'" + node_add_menu.add_node_type(layout, "ShaderNodeRadialTiling") node_add_menu.add_node_type(layout, "ShaderNodeVectorCurve") node_add_menu.add_node_type_with_searchable_enum(context, layout, "ShaderNodeVectorMath", "operation") node_add_menu.add_node_type(layout, "ShaderNodeVectorRotate") diff --git a/scripts/startup/bl_ui/node_add_menu_geometry.py b/scripts/startup/bl_ui/node_add_menu_geometry.py index ea017523b07..3f54b65fc9b 100644 --- a/scripts/startup/bl_ui/node_add_menu_geometry.py +++ b/scripts/startup/bl_ui/node_add_menu_geometry.py @@ -818,6 +818,7 @@ class NODE_MT_category_GEO_VECTOR(Menu): def draw(self, context): layout = self.layout + node_add_menu.add_node_type(layout, "ShaderNodeRadialTiling") node_add_menu.add_node_type(layout, "ShaderNodeVectorCurve") node_add_menu.add_node_type_with_searchable_enum(context, layout, "ShaderNodeVectorMath", "operation") node_add_menu.add_node_type(layout, "ShaderNodeVectorRotate") diff --git a/scripts/startup/bl_ui/node_add_menu_shader.py b/scripts/startup/bl_ui/node_add_menu_shader.py index d792a589fbd..92b3096cbe0 100644 --- a/scripts/startup/bl_ui/node_add_menu_shader.py +++ b/scripts/startup/bl_ui/node_add_menu_shader.py @@ -376,6 +376,7 @@ class NODE_MT_category_shader_vector(Menu): node_add_menu.add_node_type(layout, "ShaderNodeMapping") node_add_menu.add_node_type(layout, "ShaderNodeNormal") node_add_menu.add_node_type(layout, "ShaderNodeNormalMap") + node_add_menu.add_node_type(layout, "ShaderNodeRadialTiling") node_add_menu.add_node_type(layout, "ShaderNodeVectorCurve") node_add_menu.add_node_type(layout, "ShaderNodeVectorDisplacement") node_add_menu.add_node_type(layout, "ShaderNodeVectorRotate") diff --git a/source/blender/blenlib/BLI_math_base.hh b/source/blender/blenlib/BLI_math_base.hh index 4e0ef21ed45..5249fa9cb1d 100644 --- a/source/blender/blenlib/BLI_math_base.hh +++ b/source/blender/blenlib/BLI_math_base.hh @@ -86,6 +86,16 @@ template inline T safe_mod(const T &a, const T &b) return (b != 0) ? std::fmod(a, b) : 0; } +template inline T floored_mod(const T &a, const T &b) +{ + return a - std::floor(a / b) * b; +} + +template inline T safe_floored_mod(const T &a, const T &b) +{ + return (b != 0) ? a - std::floor(a / b) * b : 0; +} + template inline void min_max(const T &value, T &min, T &max) { static_assert(std::is_arithmetic_v, diff --git a/source/blender/blenlib/BLI_math_constants.h b/source/blender/blenlib/BLI_math_constants.h index 2e1f00819fc..0abd1d2d448 100644 --- a/source/blender/blenlib/BLI_math_constants.h +++ b/source/blender/blenlib/BLI_math_constants.h @@ -20,6 +20,9 @@ #ifndef M_PI # define M_PI 3.14159265358979323846 /* `pi` */ #endif +#ifndef M_TAU +# define M_TAU 6.28318530717958647692 /* `tau = 2*pi` */ +#endif #ifndef M_PI_2 # define M_PI_2 1.57079632679489661923 /* `pi/2` */ #endif diff --git a/source/blender/blenlib/BLI_math_vector.hh b/source/blender/blenlib/BLI_math_vector.hh index 4acc951513c..1add7335b50 100644 --- a/source/blender/blenlib/BLI_math_vector.hh +++ b/source/blender/blenlib/BLI_math_vector.hh @@ -197,6 +197,29 @@ template return result; } +template +[[nodiscard]] inline VecBase floored_mod(const VecBase &a, + const VecBase &b) +{ + VecBase result; + for (int i = 0; i < Size; i++) { + BLI_assert(b[i] != 0); + result[i] = math::floored_mod(a[i], b[i]); + } + return result; +} + +template +[[nodiscard]] inline VecBase floored_mod(const VecBase &a, const T &b) +{ + BLI_assert(b != 0); + VecBase result; + for (int i = 0; i < Size; i++) { + result[i] = math::floored_mod(a[i], b); + } + return result; +} + /** * Return the value of x raised to the y power. * The result is undefined if x < 0 or if x = 0 and y <= 0. diff --git a/source/blender/blenlib/BLI_radial_tiling.hh b/source/blender/blenlib/BLI_radial_tiling.hh new file mode 100644 index 00000000000..1190fa29549 --- /dev/null +++ b/source/blender/blenlib/BLI_radial_tiling.hh @@ -0,0 +1,24 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +/** \file + * \ingroup bli + */ + +#pragma once + +#include "BLI_math_vector_types.hh" + +namespace blender { + +float4 calculate_out_variables(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord); + +float calculate_out_segment_id(float r_gon_sides, float2 coord); + +} // namespace blender diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt index e35d42a510d..a4e857b3b57 100644 --- a/source/blender/blenlib/CMakeLists.txt +++ b/source/blender/blenlib/CMakeLists.txt @@ -131,6 +131,7 @@ set(SRC intern/polyfill_2d.cc intern/polyfill_2d_beautify.cc intern/quadric.cc + intern/radial_tiling_shared.cc intern/rand.cc intern/rct.cc intern/resource_scope.cc @@ -173,7 +174,7 @@ set(SRC # Header as source (included in C files above). intern/kdtree_impl.h intern/list_sort_impl.h - + intern/radial_tiling_shared.hh BLI_alloca.h BLI_allocator.hh @@ -354,6 +355,7 @@ set(SRC BLI_pool.hh BLI_probing_strategies.hh BLI_quadric.h + BLI_radial_tiling.hh BLI_rand.h BLI_rand.hh BLI_random_access_iterator_mixin.hh diff --git a/source/blender/blenlib/intern/radial_tiling_shared.cc b/source/blender/blenlib/intern/radial_tiling_shared.cc new file mode 100644 index 00000000000..c610c20f442 --- /dev/null +++ b/source/blender/blenlib/intern/radial_tiling_shared.cc @@ -0,0 +1,24 @@ +/* SPDX-FileCopyrightText: 2025 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +/** \file + * \ingroup bli + */ + +#include "BLI_math_base.h" +#include "BLI_math_base.hh" +#include "BLI_math_vector.hh" + +namespace blender { + +/* Define macro flags for code adaption. */ +#define ADAPT_TO_GEOMETRY_NODES + +/* The rounded polygon calculation functions are defined in radial_tiling_shared.hh. */ +#include "radial_tiling_shared.hh" + +/* Undefine macro flags used for code adaption. */ +#undef ADAPT_TO_GEOMETRY_NODES + +} // namespace blender diff --git a/source/blender/blenlib/intern/radial_tiling_shared.hh b/source/blender/blenlib/intern/radial_tiling_shared.hh new file mode 100644 index 00000000000..7719bc395fe --- /dev/null +++ b/source/blender/blenlib/intern/radial_tiling_shared.hh @@ -0,0 +1,1179 @@ +/* SPDX-FileCopyrightText: 2024-2025 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +/* The following files are always to be kept as exact copies of each other: + * radial_tiling_shared.hh + * node_radial_tiling_shared.h + * radial_tiling_shared.h + * gpu_shader_material_radial_tiling_shared.glsl */ + +/* The SVM implementation is used as the base shared version because multiple math function + * identifiers are already used as macros in the SVM code, making a code adaption into an SVM + * implementation using macros impossible. */ + +/* Define macros for code adaption. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# define atanf math::atan +# define atan2f math::atan2 +# define ceilf math::ceil +# define cosf math::cos +# define fabsf math::abs +# define floorf math::floor +# define fmaxf math::max +# define fminf math::min +# define fractf math::fract +# define mix math::interpolate +# define sinf math::sin +# define sqrtf math::sqrt +# define sqr math::square +# define tanf math::tan + +# define make_float2 float2 +# define make_float4 float4 +# define M_PI_F M_PI +# define M_2PI_F M_TAU +# define ccl_device +#else +# ifdef ADAPT_TO_OSL +# define atanf atan +# define atan2f atan2 +# define ceilf ceil +# define cosf cos +# define fabsf abs +# define floorf floor +# define fmaxf max +# define fminf min +# define fractf fract +# define mix mix +# define sinf sin +# define sqrtf sqrt +# define sqr sqr +# define tanf tan + +# define bool int +# define float2 vector2 +# define float4 vector4 +# define make_float2 vector2 +# define make_float4 vector4 +# define M_PI_F M_PI +# define M_2PI_F M_2PI +# define ccl_device + +# define false 0 +# define true 1 +# else +# ifdef ADAPT_TO_SVM +/* No code adaption necessary for the SVM implementation as it is the base shared version. */ +# else +/* Adapt code to GLSL by default. */ +# define atanf atan +# define atan2f atan2 +# define ceilf ceil +# define cosf cos +# define fabsf abs +# define floorf floor +# define fmaxf max +# define fminf min +# define fractf fract +# define mix mix +# define sinf sin +# define sqrtf sqrt +# define sqr square +# define tanf tan + +# define make_float2 float2 +# define make_float4 float4 +# define M_PI_F M_PI +# define M_2PI_F M_TAU +# define ccl_device +# endif +# endif +#endif + +/* The geometry nodes has optional specialized functions for certain combinations of input values. + * These specialized functions output the same values as the general functions, but are faster when + * they can be used. To reduce the complexity on the GPU kernel while also keeping all rendering + * implementations the same, they are only enabled in the geometry nodes implementation. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# define ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(X) (X) +#else +# define ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(X) true +#endif + +/* Naming convention for the Radial Tiling node code: + * Let x and y be 2D vectors. + * The length of X is expressed as l_x, which is an abbreviation of length_x. + * The counterclockwise unsinged angle in [0.0, M_TAU] from X to Y is expressed as x_A_y, which + * is an abbreviation of x_Angle_y. The singed angle in [-M_PI, M_PI] from x to y is expressed + * as x_SA_y, which is an abbreviation of x_SingedAngle_y. Counterclockwise angles are positive, + * clockwise angles are negative. A signed angle from x to y of which the output is mirrored along + * a certain vector is expressed as x_MSA_y, which is an abbreviation of x_MirroredSingedAngle_y. + * + * Let z and w be scalars. + * The ratio z/w is expressed as z_R_w, which is an abbreviation of z_Ratio_y. */ + +#ifdef ADAPT_TO_GEOMETRY_NODES +ccl_device float4 +calculate_out_variables_full_roundness_irregular_circular(bool calculate_r_gon_parameter_field, + bool normalize_r_gon_parameter, + float r_gon_sides, + float2 coord, + float l_coord) +{ + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + float l_last_circle_radius = tanf(last_angle_bisector_A_x_axis) / + tanf(float(0.5) * (segment_divider_A_angle_bisector + + last_angle_bisector_A_x_axis)); + float2 last_circle_center = make_float2( + cosf(last_angle_bisector_A_x_axis) - + l_last_circle_radius * cosf(last_angle_bisector_A_x_axis), + l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) - + sinf(last_angle_bisector_A_x_axis)); + float2 outer_last_bevel_start = last_circle_center + + l_last_circle_radius * + make_float2(cosf(segment_divider_A_angle_bisector), + sinf(segment_divider_A_angle_bisector)); + float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y / + outer_last_bevel_start.x); + float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start; + + if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start)) + { + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (calculate_r_gon_parameter_field) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + return make_float4(l_angle_bisector, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular rounded part. */ + + float r_gon_parameter = float(0.0); + if (calculate_r_gon_parameter_field) { + r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= segment_divider_A_angle_bisector; + } + } + return make_float4(l_coord, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + else { + /* Irregular rounded part. */ + + /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector + * to avoid a case distinction. */ + float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x); + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis)) + { + nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis; + nearest_segment_divider_MSA_coord *= -float(1.0); + } + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + float x_axis_A_angle_bisector = float(0.0); + + float l_coord_R_l_last_angle_bisector = + sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x + + sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) + + sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y)); + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_coord / + l_coord_R_l_last_angle_bisector; + + if (nearest_segment_divider_MSA_coord < float(0.0)) { + /* Irregular rounded inner part. */ + + if (calculate_r_gon_parameter_field) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * + (last_angle_bisector_A_x_axis + nearest_segment_divider_MSA_coord); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * + last_angle_bisector_A_x_axis; + } + } + max_unit_parameter = l_angle_bisector_R_l_last_angle_bisector * last_angle_bisector_A_x_axis; + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis; + } + else { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (calculate_r_gon_parameter_field) { + float coord_A_bevel_start = x_axis_A_outer_last_bevel_start - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_outer_last_bevel_start) { + r_gon_parameter += + l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * (float(1.0) - l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start; + } + else { + r_gon_parameter += spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * + cosf(outer_last_bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) + + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / x_axis_A_outer_last_bevel_start); + } + } + max_unit_parameter = segment_divider_A_angle_bisector; + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector; + } + return make_float4( + l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector); + } +} +#endif + +ccl_device float4 calculate_out_variables_irregular_circular(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord, + float l_coord) +{ +#ifdef ADAPT_TO_SVM + /* Silence compiler warnings. */ + (void)calculate_r_gon_parameter_field; + (void)calculate_max_unit_parameter; +#endif + + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + float segment_divider_A_bevel_start = segment_divider_A_angle_bisector - + atanf((float(1.0) - r_gon_roundness) * + tanf(segment_divider_A_angle_bisector)); + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + float inner_last_bevel_start_A_x_axis = last_angle_bisector_A_x_axis - + atanf((float(1.0) - r_gon_roundness) * + tanf(last_angle_bisector_A_x_axis)); + float l_last_circle_radius = r_gon_roundness * tanf(last_angle_bisector_A_x_axis) / + tanf(float(0.5) * (segment_divider_A_angle_bisector + + last_angle_bisector_A_x_axis)); + float2 last_circle_center = make_float2( + (cosf(inner_last_bevel_start_A_x_axis) / + cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis)) - + l_last_circle_radius * cosf(last_angle_bisector_A_x_axis), + l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) - + (sinf(inner_last_bevel_start_A_x_axis) / + cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis))); + float2 outer_last_bevel_start = last_circle_center + + l_last_circle_radius * + make_float2(cosf(segment_divider_A_angle_bisector), + sinf(segment_divider_A_angle_bisector)); + float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y / + outer_last_bevel_start.x); + float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start; + + if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start)) + { + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + + if (((segment_divider_A_coord >= segment_divider_A_bevel_start) && + (segment_divider_A_coord < + segment_divider_A_next_segment_divider - segment_divider_A_bevel_start)) || + (x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_bevel_start) || + (x_axis_A_coord < segment_divider_A_bevel_start)) + { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + else { + /* Regular straight part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + + if (normalize_r_gon_parameter) { + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + else { + /* Regular straight part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular rounded part. */ + + /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise + * angles are negative.*/ + float nearest_segment_divider_SA_coord = segment_divider_A_coord - + float(segment_divider_A_coord > + segment_divider_A_angle_bisector) * + segment_divider_A_next_segment_divider; + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_circle_center = (float(1.0) - r_gon_roundness) / + cosf(segment_divider_A_angle_bisector); + float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center + + sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) * + l_circle_center) + + sqr(r_gon_roundness) - sqr(l_circle_center)); + + l_angle_bisector = l_coord / l_coord_R_l_bevel_start; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = segment_divider_A_bevel_start - + fabsf(nearest_segment_divider_SA_coord); + r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start; + } + else { + r_gon_parameter += spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / segment_divider_A_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + else { + float inner_last_bevel_start_A_last_angle_bisector = last_angle_bisector_A_x_axis - + inner_last_bevel_start_A_x_axis; + + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis + inner_last_bevel_start_A_x_axis) && + (x_axis_A_coord < M_2PI_F - inner_last_bevel_start_A_x_axis)) + { + /* Irregular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord * + cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + inner_last_bevel_start_A_x_axis; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord)); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_l_angle_bisector = + l_angle_bisector_R_l_last_angle_bisector * + (l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + + r_gon_parameter /= normalize_based_on_l_l_angle_bisector; + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) + + l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis); + } + else { + /* Irregular rounded part. */ + + /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector + * to avoid a case distinction. */ + float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x); + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis)) + { + nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis; + nearest_segment_divider_MSA_coord *= -float(1.0); + } + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + float x_axis_A_angle_bisector = float(0.0); + + float l_coord_R_l_last_angle_bisector = + sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x + + sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) + + sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y)); + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord / l_coord_R_l_last_angle_bisector; + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + if (nearest_segment_divider_MSA_coord < float(0.0)) { + /* Irregular rounded inner part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + inner_last_bevel_start_A_x_axis; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = inner_last_bevel_start_A_x_axis - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_coord * + sinf(inner_last_bevel_start_A_last_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += + l_angle_bisector_R_l_last_angle_bisector * + (l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) * + coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start); + } + else { + r_gon_parameter += l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + (float(0.5) * l_coord * + cosf(inner_last_bevel_start_A_last_angle_bisector) - + float(0.5)) + + coord_A_bevel_start); + } + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_l_angle_bisector = + l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis; + float normalize_based_on_l_coord = + l_coord * sinf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * + mix(normalize_based_on_l_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / inner_last_bevel_start_A_x_axis); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) + + l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + } + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis; + } + else { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = x_axis_A_outer_last_bevel_start - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_outer_last_bevel_start) { + r_gon_parameter += l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * + coord_A_bevel_start + + float(0.5) * + (float(1.0) - + l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start; + } + else { + r_gon_parameter += spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * + cosf(outer_last_bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) + + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / x_axis_A_outer_last_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector; + } + return make_float4( + l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector); + } + } +} + +ccl_device float4 calculate_out_variables(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord) +{ +#ifdef ADAPT_TO_SVM + /* Silence compiler warnings. */ + (void)calculate_r_gon_parameter_field; + (void)calculate_max_unit_parameter; +#endif + + float l_coord = sqrtf(sqr(coord.x) + sqr(coord.y)); + float4 out_variables; + + if (fractf(r_gon_sides) == float(0.0)) { + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + if (r_gon_roundness == float(0.0)) { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter && (r_gon_sides != float(2.0))) { + r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = (r_gon_sides != float(2.0)) ? tanf(segment_divider_A_angle_bisector) : + float(0.0); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else if (r_gon_roundness == float(1.0)) { + /* Regular rounded part. */ + + float r_gon_parameter = float(0.0); + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= segment_divider_A_angle_bisector; + } + } + out_variables = make_float4(l_coord, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + float segment_divider_A_bevel_start = segment_divider_A_angle_bisector - + atanf((float(1.0) - r_gon_roundness) * + tanf(segment_divider_A_angle_bisector)); + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + + if ((segment_divider_A_coord >= + segment_divider_A_next_segment_divider - segment_divider_A_bevel_start) || + (segment_divider_A_coord < segment_divider_A_bevel_start)) + { + /* Regular rounded part. */ + + /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise + * angles are negative.*/ + float nearest_segment_divider_SA_coord = segment_divider_A_coord - + float(segment_divider_A_coord > + segment_divider_A_angle_bisector) * + segment_divider_A_next_segment_divider; + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_circle_center = (float(1.0) - r_gon_roundness) / + cosf(segment_divider_A_angle_bisector); + float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center + + sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) * + l_circle_center) + + sqr(r_gon_roundness) - sqr(l_circle_center)); + + l_angle_bisector = l_coord / l_coord_R_l_bevel_start; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = segment_divider_A_bevel_start - + fabsf(nearest_segment_divider_SA_coord); + r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start; + } + else { + r_gon_parameter += spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / segment_divider_A_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + } + else { + if (r_gon_roundness == float(0.0)) { + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + + if (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis) { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(segment_divider_A_angle_bisector); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Irregular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord * + cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord)); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(last_angle_bisector_A_x_axis); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(last_angle_bisector_A_x_axis); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis); + } + } +#ifdef ADAPT_TO_GEOMETRY_NODES + else if (r_gon_roundness == float(1.0)) { + out_variables = calculate_out_variables_full_roundness_irregular_circular( + calculate_r_gon_parameter_field, normalize_r_gon_parameter, r_gon_sides, coord, l_coord); + } +#endif + else { + out_variables = calculate_out_variables_irregular_circular(calculate_r_gon_parameter_field, + calculate_max_unit_parameter, + normalize_r_gon_parameter, + r_gon_sides, + r_gon_roundness, + coord, + l_coord); + } + } + + if ((coord.x == float(0.0)) && (coord.y == float(0.0))) { + /* The r_gon_parameter is defined to 0 when it is not normalized and the input coordinate is + * the zero vector. */ + out_variables.y = float(0.0); + } + + if (normalize_r_gon_parameter) { + /* Normalize r_gon_parameter from a [-1, 1] interval to a [0, 1] interval. */ + out_variables.y = float(0.5) * out_variables.y + float(0.5); + } + else { + out_variables.x -= float(1.0); + } + + return out_variables; +} + +ccl_device float calculate_out_segment_id(float r_gon_sides, float2 coord) +{ + return floorf(r_gon_sides * + ((atan2f(coord.y, coord.x) / M_2PI_F) + float(coord.y < float(0.0)))); +} + +/* Undefine macros used for code adaption. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef make_float2 +# undef make_float4 +# undef ccl_device +#else +# ifdef ADAPT_TO_OSL +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef bool +# undef float2 +# undef float4 +# undef make_float2 +# undef make_float4 +# undef M_PI_F +# undef M_2PI_F +# undef ccl_device + +# undef false +# undef true +# else +# ifdef ADAPT_TO_SVM +/* No code adaption necessary for the SVM implementation as it is the base shared version. */ +# else +/* Adapt code to GLSL by default. */ +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef make_float2 +# undef make_float4 +# undef M_PI_F +# undef M_2PI_F +# undef ccl_device +# endif +# endif +#endif + +#undef ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION diff --git a/source/blender/gpu/CMakeLists.txt b/source/blender/gpu/CMakeLists.txt index 78e7bf6b3b2..eab86a35543 100644 --- a/source/blender/gpu/CMakeLists.txt +++ b/source/blender/gpu/CMakeLists.txt @@ -612,6 +612,8 @@ set(GLSL_SRC shaders/material/gpu_shader_material_ray_portal.glsl shaders/material/gpu_shader_material_refraction.glsl shaders/material/gpu_shader_material_rgb_to_bw.glsl + shaders/material/gpu_shader_material_radial_tiling.glsl + shaders/material/gpu_shader_material_radial_tiling_shared.glsl shaders/material/gpu_shader_material_separate_color.glsl shaders/material/gpu_shader_material_separate_xyz.glsl shaders/material/gpu_shader_material_set.glsl diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_radial_tiling.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_radial_tiling.glsl new file mode 100644 index 00000000000..562628056b7 --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_radial_tiling.glsl @@ -0,0 +1,48 @@ +/* SPDX-FileCopyrightText: 2024-2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "gpu_shader_math_base_lib.glsl" + +/* Define macro flags for code adaption. */ +/* No macro flags necessary, as code is adapted to GLSL by default. */ + +/* The rounded polygon calculation functions are defined in + * gpu_shader_material_radial_tiling_shared.glsl. */ +#include "gpu_shader_material_radial_tiling_shared.glsl" + +/* Undefine macro flags used for code adaption. */ +/* No macro flags necessary, as code is adapted to GLSL by default. */ + +void node_radial_tiling(float3 coord, + float r_gon_sides, + float r_gon_roundness, + float normalize_r_gon_parameter, + float calculate_r_gon_parameter_field, + float calculate_segment_id, + float calculate_max_unit_parameter, + float calculate_x_axis_A_angle_bisector, + out float3 out_segment_coordinates, + out float out_segment_id, + out float out_max_unit_parameter, + out float out_x_axis_A_angle_bisector) +{ + if (bool(calculate_r_gon_parameter_field) || bool(calculate_max_unit_parameter) || + bool(calculate_x_axis_A_angle_bisector)) + { + float4 out_variables = calculate_out_variables(bool(calculate_r_gon_parameter_field), + bool(calculate_max_unit_parameter), + bool(normalize_r_gon_parameter), + max(r_gon_sides, 2.0), + clamp(r_gon_roundness, 0.0, 1.0), + float2(coord.x, coord.y)); + + out_segment_coordinates = float3(out_variables.y, out_variables.x, 0.0); + out_max_unit_parameter = out_variables.z; + out_x_axis_A_angle_bisector = out_variables.w; + } + + if (bool(calculate_segment_id)) { + out_segment_id = calculate_out_segment_id(max(r_gon_sides, 2.0), float2(coord.x, coord.y)); + } +} diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_radial_tiling_shared.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_radial_tiling_shared.glsl new file mode 100644 index 00000000000..7719bc395fe --- /dev/null +++ b/source/blender/gpu/shaders/material/gpu_shader_material_radial_tiling_shared.glsl @@ -0,0 +1,1179 @@ +/* SPDX-FileCopyrightText: 2024-2025 Blender Authors + * + * SPDX-License-Identifier: Apache-2.0 */ + +/* The following files are always to be kept as exact copies of each other: + * radial_tiling_shared.hh + * node_radial_tiling_shared.h + * radial_tiling_shared.h + * gpu_shader_material_radial_tiling_shared.glsl */ + +/* The SVM implementation is used as the base shared version because multiple math function + * identifiers are already used as macros in the SVM code, making a code adaption into an SVM + * implementation using macros impossible. */ + +/* Define macros for code adaption. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# define atanf math::atan +# define atan2f math::atan2 +# define ceilf math::ceil +# define cosf math::cos +# define fabsf math::abs +# define floorf math::floor +# define fmaxf math::max +# define fminf math::min +# define fractf math::fract +# define mix math::interpolate +# define sinf math::sin +# define sqrtf math::sqrt +# define sqr math::square +# define tanf math::tan + +# define make_float2 float2 +# define make_float4 float4 +# define M_PI_F M_PI +# define M_2PI_F M_TAU +# define ccl_device +#else +# ifdef ADAPT_TO_OSL +# define atanf atan +# define atan2f atan2 +# define ceilf ceil +# define cosf cos +# define fabsf abs +# define floorf floor +# define fmaxf max +# define fminf min +# define fractf fract +# define mix mix +# define sinf sin +# define sqrtf sqrt +# define sqr sqr +# define tanf tan + +# define bool int +# define float2 vector2 +# define float4 vector4 +# define make_float2 vector2 +# define make_float4 vector4 +# define M_PI_F M_PI +# define M_2PI_F M_2PI +# define ccl_device + +# define false 0 +# define true 1 +# else +# ifdef ADAPT_TO_SVM +/* No code adaption necessary for the SVM implementation as it is the base shared version. */ +# else +/* Adapt code to GLSL by default. */ +# define atanf atan +# define atan2f atan2 +# define ceilf ceil +# define cosf cos +# define fabsf abs +# define floorf floor +# define fmaxf max +# define fminf min +# define fractf fract +# define mix mix +# define sinf sin +# define sqrtf sqrt +# define sqr square +# define tanf tan + +# define make_float2 float2 +# define make_float4 float4 +# define M_PI_F M_PI +# define M_2PI_F M_TAU +# define ccl_device +# endif +# endif +#endif + +/* The geometry nodes has optional specialized functions for certain combinations of input values. + * These specialized functions output the same values as the general functions, but are faster when + * they can be used. To reduce the complexity on the GPU kernel while also keeping all rendering + * implementations the same, they are only enabled in the geometry nodes implementation. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# define ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(X) (X) +#else +# define ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(X) true +#endif + +/* Naming convention for the Radial Tiling node code: + * Let x and y be 2D vectors. + * The length of X is expressed as l_x, which is an abbreviation of length_x. + * The counterclockwise unsinged angle in [0.0, M_TAU] from X to Y is expressed as x_A_y, which + * is an abbreviation of x_Angle_y. The singed angle in [-M_PI, M_PI] from x to y is expressed + * as x_SA_y, which is an abbreviation of x_SingedAngle_y. Counterclockwise angles are positive, + * clockwise angles are negative. A signed angle from x to y of which the output is mirrored along + * a certain vector is expressed as x_MSA_y, which is an abbreviation of x_MirroredSingedAngle_y. + * + * Let z and w be scalars. + * The ratio z/w is expressed as z_R_w, which is an abbreviation of z_Ratio_y. */ + +#ifdef ADAPT_TO_GEOMETRY_NODES +ccl_device float4 +calculate_out_variables_full_roundness_irregular_circular(bool calculate_r_gon_parameter_field, + bool normalize_r_gon_parameter, + float r_gon_sides, + float2 coord, + float l_coord) +{ + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + float l_last_circle_radius = tanf(last_angle_bisector_A_x_axis) / + tanf(float(0.5) * (segment_divider_A_angle_bisector + + last_angle_bisector_A_x_axis)); + float2 last_circle_center = make_float2( + cosf(last_angle_bisector_A_x_axis) - + l_last_circle_radius * cosf(last_angle_bisector_A_x_axis), + l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) - + sinf(last_angle_bisector_A_x_axis)); + float2 outer_last_bevel_start = last_circle_center + + l_last_circle_radius * + make_float2(cosf(segment_divider_A_angle_bisector), + sinf(segment_divider_A_angle_bisector)); + float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y / + outer_last_bevel_start.x); + float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start; + + if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start)) + { + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (calculate_r_gon_parameter_field) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + return make_float4(l_angle_bisector, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular rounded part. */ + + float r_gon_parameter = float(0.0); + if (calculate_r_gon_parameter_field) { + r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= segment_divider_A_angle_bisector; + } + } + return make_float4(l_coord, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + else { + /* Irregular rounded part. */ + + /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector + * to avoid a case distinction. */ + float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x); + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis)) + { + nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis; + nearest_segment_divider_MSA_coord *= -float(1.0); + } + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + float x_axis_A_angle_bisector = float(0.0); + + float l_coord_R_l_last_angle_bisector = + sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x + + sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) + + sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y)); + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_coord / + l_coord_R_l_last_angle_bisector; + + if (nearest_segment_divider_MSA_coord < float(0.0)) { + /* Irregular rounded inner part. */ + + if (calculate_r_gon_parameter_field) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * + (last_angle_bisector_A_x_axis + nearest_segment_divider_MSA_coord); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * + last_angle_bisector_A_x_axis; + } + } + max_unit_parameter = l_angle_bisector_R_l_last_angle_bisector * last_angle_bisector_A_x_axis; + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis; + } + else { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (calculate_r_gon_parameter_field) { + float coord_A_bevel_start = x_axis_A_outer_last_bevel_start - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_outer_last_bevel_start) { + r_gon_parameter += + l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * (float(1.0) - l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start; + } + else { + r_gon_parameter += spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * + cosf(outer_last_bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) + + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / x_axis_A_outer_last_bevel_start); + } + } + max_unit_parameter = segment_divider_A_angle_bisector; + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector; + } + return make_float4( + l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector); + } +} +#endif + +ccl_device float4 calculate_out_variables_irregular_circular(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord, + float l_coord) +{ +#ifdef ADAPT_TO_SVM + /* Silence compiler warnings. */ + (void)calculate_r_gon_parameter_field; + (void)calculate_max_unit_parameter; +#endif + + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + float segment_divider_A_bevel_start = segment_divider_A_angle_bisector - + atanf((float(1.0) - r_gon_roundness) * + tanf(segment_divider_A_angle_bisector)); + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + float inner_last_bevel_start_A_x_axis = last_angle_bisector_A_x_axis - + atanf((float(1.0) - r_gon_roundness) * + tanf(last_angle_bisector_A_x_axis)); + float l_last_circle_radius = r_gon_roundness * tanf(last_angle_bisector_A_x_axis) / + tanf(float(0.5) * (segment_divider_A_angle_bisector + + last_angle_bisector_A_x_axis)); + float2 last_circle_center = make_float2( + (cosf(inner_last_bevel_start_A_x_axis) / + cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis)) - + l_last_circle_radius * cosf(last_angle_bisector_A_x_axis), + l_last_circle_radius * sinf(last_angle_bisector_A_x_axis) - + (sinf(inner_last_bevel_start_A_x_axis) / + cosf(last_angle_bisector_A_x_axis - inner_last_bevel_start_A_x_axis))); + float2 outer_last_bevel_start = last_circle_center + + l_last_circle_radius * + make_float2(cosf(segment_divider_A_angle_bisector), + sinf(segment_divider_A_angle_bisector)); + float x_axis_A_outer_last_bevel_start = atanf(outer_last_bevel_start.y / + outer_last_bevel_start.x); + float outer_last_bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start; + + if ((x_axis_A_coord >= x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start)) + { + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + + if (((segment_divider_A_coord >= segment_divider_A_bevel_start) && + (segment_divider_A_coord < + segment_divider_A_next_segment_divider - segment_divider_A_bevel_start)) || + (x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_bevel_start) || + (x_axis_A_coord < segment_divider_A_bevel_start)) + { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + else { + /* Regular straight part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + + if (normalize_r_gon_parameter) { + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - segment_divider_A_angle_bisector) || + (x_axis_A_coord < segment_divider_A_angle_bisector)) + { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + else { + /* Regular straight part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular rounded part. */ + + /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise + * angles are negative.*/ + float nearest_segment_divider_SA_coord = segment_divider_A_coord - + float(segment_divider_A_coord > + segment_divider_A_angle_bisector) * + segment_divider_A_next_segment_divider; + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_circle_center = (float(1.0) - r_gon_roundness) / + cosf(segment_divider_A_angle_bisector); + float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center + + sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) * + l_circle_center) + + sqr(r_gon_roundness) - sqr(l_circle_center)); + + l_angle_bisector = l_coord / l_coord_R_l_bevel_start; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = segment_divider_A_bevel_start - + fabsf(nearest_segment_divider_SA_coord); + r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start; + } + else { + r_gon_parameter += spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / segment_divider_A_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + else { + float inner_last_bevel_start_A_last_angle_bisector = last_angle_bisector_A_x_axis - + inner_last_bevel_start_A_x_axis; + + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis + inner_last_bevel_start_A_x_axis) && + (x_axis_A_coord < M_2PI_F - inner_last_bevel_start_A_x_axis)) + { + /* Irregular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord * + cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + inner_last_bevel_start_A_x_axis; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord)); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_l_angle_bisector = + l_angle_bisector_R_l_last_angle_bisector * + (l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + + r_gon_parameter /= normalize_based_on_l_l_angle_bisector; + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) + + l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + } + return make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis); + } + else { + /* Irregular rounded part. */ + + /* MSA == Mirrored Signed Angle. The values are mirrored around the last angle bisector + * to avoid a case distinction. */ + float nearest_segment_divider_MSA_coord = atan2f(coord.y, coord.x); + if ((x_axis_A_coord >= + M_2PI_F - last_segment_divider_A_x_axis - x_axis_A_outer_last_bevel_start) && + (x_axis_A_coord < M_2PI_F - last_angle_bisector_A_x_axis)) + { + nearest_segment_divider_MSA_coord += last_segment_divider_A_x_axis; + nearest_segment_divider_MSA_coord *= -float(1.0); + } + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + float x_axis_A_angle_bisector = float(0.0); + + float l_coord_R_l_last_angle_bisector = + sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x + + sqrtf(sqr(sinf(nearest_segment_divider_MSA_coord) * last_circle_center.y + + cosf(nearest_segment_divider_MSA_coord) * last_circle_center.x) + + sqr(l_last_circle_radius) - sqr(last_circle_center.x) - sqr(last_circle_center.y)); + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord / l_coord_R_l_last_angle_bisector; + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + if (nearest_segment_divider_MSA_coord < float(0.0)) { + /* Irregular rounded inner part. */ + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + inner_last_bevel_start_A_x_axis; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = inner_last_bevel_start_A_x_axis - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_coord * + sinf(inner_last_bevel_start_A_last_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += + l_angle_bisector_R_l_last_angle_bisector * + (l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) * + coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start); + } + else { + r_gon_parameter += l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + (float(0.5) * l_coord * + cosf(inner_last_bevel_start_A_last_angle_bisector) - + float(0.5)) + + coord_A_bevel_start); + } + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_l_angle_bisector = + l_last_angle_bisector * tanf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_last_angle_bisector + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis; + float normalize_based_on_l_coord = + l_coord * sinf(inner_last_bevel_start_A_last_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(inner_last_bevel_start_A_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * + mix(normalize_based_on_l_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / inner_last_bevel_start_A_x_axis); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(inner_last_bevel_start_A_last_angle_bisector) + + l_angle_bisector_R_l_last_angle_bisector * + (spline_start_A_bevel_start * + ((float(0.5) / l_angle_bisector_R_l_last_angle_bisector) + + float(0.5)) + + r_gon_roundness * inner_last_bevel_start_A_x_axis); + } + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis; + } + else { + /* Irregular rounded outer part. */ + + float effective_roundness = float(1.0) - tanf(segment_divider_A_angle_bisector - + x_axis_A_outer_last_bevel_start) / + tanf(segment_divider_A_angle_bisector); + float spline_start_outer_last_bevel_start = (float(1.0) - effective_roundness) * + x_axis_A_outer_last_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = x_axis_A_outer_last_bevel_start - + fabsf(nearest_segment_divider_MSA_coord); + r_gon_parameter = l_coord * sinf(outer_last_bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_outer_last_bevel_start) { + r_gon_parameter += l_coord * cosf(outer_last_bevel_start_A_angle_bisector) * + coord_A_bevel_start + + float(0.5) * + (float(1.0) - + l_coord * cosf(outer_last_bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_outer_last_bevel_start; + } + else { + r_gon_parameter += spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * + cosf(outer_last_bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_angle_bisector + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(outer_last_bevel_start_A_angle_bisector) + + spline_start_outer_last_bevel_start * + (float(0.5) * l_coord * cosf(outer_last_bevel_start_A_angle_bisector) + + float(0.5)) + + effective_roundness * x_axis_A_outer_last_bevel_start; + + /* For effective_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / x_axis_A_outer_last_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + x_axis_A_angle_bisector = segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector; + } + return make_float4( + l_angle_bisector, r_gon_parameter, max_unit_parameter, x_axis_A_angle_bisector); + } + } +} + +ccl_device float4 calculate_out_variables(bool calculate_r_gon_parameter_field, + bool calculate_max_unit_parameter, + bool normalize_r_gon_parameter, + float r_gon_sides, + float r_gon_roundness, + float2 coord) +{ +#ifdef ADAPT_TO_SVM + /* Silence compiler warnings. */ + (void)calculate_r_gon_parameter_field; + (void)calculate_max_unit_parameter; +#endif + + float l_coord = sqrtf(sqr(coord.x) + sqr(coord.y)); + float4 out_variables; + + if (fractf(r_gon_sides) == float(0.0)) { + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + if (r_gon_roundness == float(0.0)) { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * + tanf(fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter && (r_gon_sides != float(2.0))) { + r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = (r_gon_sides != float(2.0)) ? tanf(segment_divider_A_angle_bisector) : + float(0.0); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else if (r_gon_roundness == float(1.0)) { + /* Regular rounded part. */ + + float r_gon_parameter = float(0.0); + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = fabsf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= segment_divider_A_angle_bisector; + } + } + out_variables = make_float4(l_coord, + r_gon_parameter, + segment_divider_A_angle_bisector, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + float segment_divider_A_bevel_start = segment_divider_A_angle_bisector - + atanf((float(1.0) - r_gon_roundness) * + tanf(segment_divider_A_angle_bisector)); + float bevel_start_A_angle_bisector = segment_divider_A_angle_bisector - + segment_divider_A_bevel_start; + + if ((segment_divider_A_coord >= + segment_divider_A_next_segment_divider - segment_divider_A_bevel_start) || + (segment_divider_A_coord < segment_divider_A_bevel_start)) + { + /* Regular rounded part. */ + + /* SA == Signed Angle in [-M_PI, M_PI]. Counterclockwise angles are positive, clockwise + * angles are negative.*/ + float nearest_segment_divider_SA_coord = segment_divider_A_coord - + float(segment_divider_A_coord > + segment_divider_A_angle_bisector) * + segment_divider_A_next_segment_divider; + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_circle_center = (float(1.0) - r_gon_roundness) / + cosf(segment_divider_A_angle_bisector); + float l_coord_R_l_bevel_start = cosf(nearest_segment_divider_SA_coord) * l_circle_center + + sqrtf(sqr(cosf(nearest_segment_divider_SA_coord) * + l_circle_center) + + sqr(r_gon_roundness) - sqr(l_circle_center)); + + l_angle_bisector = l_coord / l_coord_R_l_bevel_start; + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + float coord_A_bevel_start = segment_divider_A_bevel_start - + fabsf(nearest_segment_divider_SA_coord); + r_gon_parameter = l_coord * sinf(bevel_start_A_angle_bisector); + + if (coord_A_bevel_start < spline_start_A_bevel_start) { + r_gon_parameter += l_coord * cosf(bevel_start_A_angle_bisector) * coord_A_bevel_start + + float(0.5) * + (float(1.0) - l_coord * cosf(bevel_start_A_angle_bisector)) * + sqr(coord_A_bevel_start) / spline_start_A_bevel_start; + } + else { + r_gon_parameter += spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) - + float(0.5)) + + coord_A_bevel_start; + } + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + float normalize_based_on_l_coord = + l_coord * sinf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * + (float(0.5) * l_coord * cosf(bevel_start_A_angle_bisector) + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + /* For r_gon_roundness -> 1.0 the normalize_based_on_l_angle_bisector field and + * normalize_based_on_l_coord field converge against the same scalar field. */ + r_gon_parameter /= mix(normalize_based_on_l_angle_bisector, + normalize_based_on_l_coord, + coord_A_bevel_start / segment_divider_A_bevel_start); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + + float spline_start_A_bevel_start = (float(1.0) - r_gon_roundness) * + segment_divider_A_bevel_start; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + float normalize_based_on_l_angle_bisector = + l_angle_bisector * tanf(bevel_start_A_angle_bisector) + + spline_start_A_bevel_start * (float(0.5) * l_angle_bisector + float(0.5)) + + r_gon_roundness * segment_divider_A_bevel_start; + + r_gon_parameter /= normalize_based_on_l_angle_bisector; + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(bevel_start_A_angle_bisector) + spline_start_A_bevel_start + + r_gon_roundness * segment_divider_A_bevel_start; + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + } + } + else { + if (r_gon_roundness == float(0.0)) { + float x_axis_A_coord = atan2f(coord.y, coord.x) + float(coord.y < float(0.0)) * M_2PI_F; + float segment_divider_A_angle_bisector = M_PI_F / r_gon_sides; + float segment_divider_A_next_segment_divider = float(2.0) * segment_divider_A_angle_bisector; + float segment_id = floorf(x_axis_A_coord / segment_divider_A_next_segment_divider); + float segment_divider_A_coord = x_axis_A_coord - + segment_id * segment_divider_A_next_segment_divider; + + float last_angle_bisector_A_x_axis = M_PI_F - + floorf(r_gon_sides) * segment_divider_A_angle_bisector; + float last_segment_divider_A_x_axis = float(2.0) * last_angle_bisector_A_x_axis; + + if (x_axis_A_coord < M_2PI_F - last_segment_divider_A_x_axis) { + /* Regular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + l_angle_bisector = l_coord * + cosf(segment_divider_A_angle_bisector - segment_divider_A_coord); + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector * tanf(fabsf(segment_divider_A_angle_bisector - + segment_divider_A_coord)); + if (segment_divider_A_coord < segment_divider_A_angle_bisector) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector * tanf(segment_divider_A_angle_bisector); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(segment_divider_A_angle_bisector); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + segment_divider_A_angle_bisector); + } + else { + /* Irregular straight part. */ + + float l_angle_bisector = float(0.0); + float r_gon_parameter = float(0.0); + float max_unit_parameter = float(0.0); + + float l_angle_bisector_R_l_last_angle_bisector = cosf(segment_divider_A_angle_bisector) / + cosf(last_angle_bisector_A_x_axis); + float l_last_angle_bisector = l_coord * + cosf(last_angle_bisector_A_x_axis - segment_divider_A_coord); + + l_angle_bisector = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector; + + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_r_gon_parameter_field)) { + r_gon_parameter = l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(fabsf(last_angle_bisector_A_x_axis - segment_divider_A_coord)); + if (segment_divider_A_coord < last_angle_bisector_A_x_axis) { + r_gon_parameter *= -float(1.0); + } + if (normalize_r_gon_parameter) { + r_gon_parameter /= l_angle_bisector_R_l_last_angle_bisector * l_last_angle_bisector * + tanf(last_angle_bisector_A_x_axis); + } + } + if (ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION(calculate_max_unit_parameter)) { + max_unit_parameter = tanf(last_angle_bisector_A_x_axis); + } + out_variables = make_float4(l_angle_bisector, + r_gon_parameter, + max_unit_parameter, + segment_id * segment_divider_A_next_segment_divider + + last_angle_bisector_A_x_axis); + } + } +#ifdef ADAPT_TO_GEOMETRY_NODES + else if (r_gon_roundness == float(1.0)) { + out_variables = calculate_out_variables_full_roundness_irregular_circular( + calculate_r_gon_parameter_field, normalize_r_gon_parameter, r_gon_sides, coord, l_coord); + } +#endif + else { + out_variables = calculate_out_variables_irregular_circular(calculate_r_gon_parameter_field, + calculate_max_unit_parameter, + normalize_r_gon_parameter, + r_gon_sides, + r_gon_roundness, + coord, + l_coord); + } + } + + if ((coord.x == float(0.0)) && (coord.y == float(0.0))) { + /* The r_gon_parameter is defined to 0 when it is not normalized and the input coordinate is + * the zero vector. */ + out_variables.y = float(0.0); + } + + if (normalize_r_gon_parameter) { + /* Normalize r_gon_parameter from a [-1, 1] interval to a [0, 1] interval. */ + out_variables.y = float(0.5) * out_variables.y + float(0.5); + } + else { + out_variables.x -= float(1.0); + } + + return out_variables; +} + +ccl_device float calculate_out_segment_id(float r_gon_sides, float2 coord) +{ + return floorf(r_gon_sides * + ((atan2f(coord.y, coord.x) / M_2PI_F) + float(coord.y < float(0.0)))); +} + +/* Undefine macros used for code adaption. */ +#ifdef ADAPT_TO_GEOMETRY_NODES +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef make_float2 +# undef make_float4 +# undef ccl_device +#else +# ifdef ADAPT_TO_OSL +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef bool +# undef float2 +# undef float4 +# undef make_float2 +# undef make_float4 +# undef M_PI_F +# undef M_2PI_F +# undef ccl_device + +# undef false +# undef true +# else +# ifdef ADAPT_TO_SVM +/* No code adaption necessary for the SVM implementation as it is the base shared version. */ +# else +/* Adapt code to GLSL by default. */ +# undef atanf +# undef atan2f +# undef ceilf +# undef cosf +# undef fabsf +# undef floorf +# undef fmaxf +# undef fminf +# undef fractf +# undef mix +# undef sinf +# undef sqrtf +# undef sqr +# undef tanf + +# undef make_float2 +# undef make_float4 +# undef M_PI_F +# undef M_2PI_F +# undef ccl_device +# endif +# endif +#endif + +#undef ONLY_CHECK_IN_GEOMETRY_NODES_IMPLEMENTATION diff --git a/source/blender/makesdna/DNA_node_types.h b/source/blender/makesdna/DNA_node_types.h index 1a89069812f..0fea0af3e96 100644 --- a/source/blender/makesdna/DNA_node_types.h +++ b/source/blender/makesdna/DNA_node_types.h @@ -1683,6 +1683,11 @@ typedef struct NodeShaderNormalMap { char uv_map[/*MAX_CUSTOMDATA_LAYER_NAME_NO_PREFIX*/ 64]; } NodeShaderNormalMap; +typedef struct NodeRadialTiling { + uint8_t normalize; + char _pad[7]; +} NodeRadialTiling; + typedef struct NodeShaderUVMap { char uv_map[/*MAX_CUSTOMDATA_LAYER_NAME_NO_PREFIX*/ 64]; } NodeShaderUVMap; diff --git a/source/blender/makesrna/intern/rna_nodetree.cc b/source/blender/makesrna/intern/rna_nodetree.cc index a7f7aa0f010..b750f2eaa3d 100644 --- a/source/blender/makesrna/intern/rna_nodetree.cc +++ b/source/blender/makesrna/intern/rna_nodetree.cc @@ -5941,6 +5941,24 @@ static void def_sh_normal_map(BlenderRNA * /*brna*/, StructRNA *srna) RNA_def_struct_sdna_from(srna, "bNode", nullptr); } +static void def_sh_radial_tiling(BlenderRNA * /*brna*/, StructRNA *srna) +{ + PropertyRNA *prop; + + RNA_def_struct_sdna_from(srna, "NodeRadialTiling", "storage"); + + prop = RNA_def_property(srna, "normalize", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "normalize", 0); + RNA_def_property_ui_text( + prop, + "Normalize", + "Normalize the X coordinate of the Segment Coordinates output to a [0, 1] interval and " + "offset the Y coordinate into a [0, infinity) interval. When checked, the textures are " + "stretched to fit into each angular segment. When not checked, the parts of the textures " + "that don't fit into each angular segment are cropped"); + RNA_def_property_update(prop, NC_NODE | NA_EDITED, "rna_Node_update"); +} + static void def_sh_displacement(BlenderRNA * /*brna*/, StructRNA *srna) { static const EnumPropertyItem prop_space_items[] = { @@ -9589,6 +9607,7 @@ static void rna_def_nodes(BlenderRNA *brna) define("ShaderNode", "ShaderNodeOutputWorld", def_sh_output); define("ShaderNode", "ShaderNodeParticleInfo"); define("ShaderNode", "ShaderNodePointInfo"); + define("ShaderNode", "ShaderNodeRadialTiling", def_sh_radial_tiling); define("ShaderNode", "ShaderNodeRGB"); define("ShaderNode", "ShaderNodeRGBCurve", def_rgb_curve); define("ShaderNode", "ShaderNodeRGBToBW"); diff --git a/source/blender/nodes/shader/CMakeLists.txt b/source/blender/nodes/shader/CMakeLists.txt index 1b7df35c31f..885f90bc5bb 100644 --- a/source/blender/nodes/shader/CMakeLists.txt +++ b/source/blender/nodes/shader/CMakeLists.txt @@ -73,6 +73,7 @@ set(SRC nodes/node_shader_output_world.cc nodes/node_shader_particle_info.cc nodes/node_shader_point_info.cc + nodes/node_shader_radial_tiling.cc nodes/node_shader_rgb.cc nodes/node_shader_rgb_to_bw.cc nodes/node_shader_script.cc diff --git a/source/blender/nodes/shader/node_shader_register.cc b/source/blender/nodes/shader/node_shader_register.cc index 8f8b757c1df..27fc7316692 100644 --- a/source/blender/nodes/shader/node_shader_register.cc +++ b/source/blender/nodes/shader/node_shader_register.cc @@ -69,6 +69,7 @@ void register_shader_nodes() register_node_type_sh_output_world(); register_node_type_sh_particle_info(); register_node_type_sh_point_info(); + register_node_type_sh_radial_tiling(); register_node_type_sh_rgb(); register_node_type_sh_rgbtobw(); register_node_type_sh_script(); diff --git a/source/blender/nodes/shader/node_shader_register.hh b/source/blender/nodes/shader/node_shader_register.hh index 9f004e7866b..8b085cd3e7f 100644 --- a/source/blender/nodes/shader/node_shader_register.hh +++ b/source/blender/nodes/shader/node_shader_register.hh @@ -68,6 +68,7 @@ void register_node_type_sh_output_material(); void register_node_type_sh_output_world(); void register_node_type_sh_particle_info(); void register_node_type_sh_point_info(); +void register_node_type_sh_radial_tiling(); void register_node_type_sh_rgb(); void register_node_type_sh_rgbtobw(); void register_node_type_sh_script(); diff --git a/source/blender/nodes/shader/nodes/node_shader_radial_tiling.cc b/source/blender/nodes/shader/nodes/node_shader_radial_tiling.cc new file mode 100644 index 00000000000..a6dcc544e1b --- /dev/null +++ b/source/blender/nodes/shader/nodes/node_shader_radial_tiling.cc @@ -0,0 +1,225 @@ +/* SPDX-FileCopyrightText: 2024-2025 Blender Authors + * + * SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "node_shader_util.hh" +#include "node_util.hh" + +#include "NOD_multi_function.hh" + +#include "RNA_access.hh" + +#include "UI_interface_layout.hh" +#include "UI_resources.hh" + +#include "BLI_radial_tiling.hh" + +namespace blender::nodes::node_shader_radial_tiling_cc { + +NODE_STORAGE_FUNCS(NodeRadialTiling) + +static void sh_node_radial_tiling_declare(NodeDeclarationBuilder &b) +{ + b.is_function_node(); + + b.add_output("Segment Coordinates") + .no_muted_links() + .description("Segment coordinates for texture mapping within each angular segment"); + b.add_output("Segment ID") + .no_muted_links() + .description( + "Unique ID for every angular segment starting at 0 and increasing counterclockwise by " + "1"); + b.add_output("Segment Width") + .no_muted_links() + .description( + "Relatve width of each angular segment. May be used to scale textures to fit into each " + "segment"); + b.add_output("Segment Rotation") + .no_muted_links() + .description( + "Counterclockwise rotation of each segment coordinates system. May be used to align the " + "rotation of the textures of each segment"); + + b.add_input("Vector") + .dimensions(2) + .default_value(float3{0.0f, 0.0f, 0.0f}) + .description("Input texture coordinates"); + b.add_input("Sides").min(2.0f).max(1000.0f).default_value(5.0f).description( + "Number of angular segments for tiling. A non-integer value results in an irregular " + "segment"); + b.add_input("Roundness") + .min(0.0f) + .max(1.0f) + .default_value(0.0f) + .subtype(PROP_FACTOR) + .description("Roundness of the segment coordinates systems"); +} + +static void node_shader_buts_radial_tiling(uiLayout *layout, bContext * /*C*/, PointerRNA *ptr) +{ + layout->prop(ptr, "normalize", UI_ITEM_R_SPLIT_EMPTY_NAME, std::nullopt, ICON_NONE); +} + +static void node_shader_init_radial_tiling(bNodeTree * /*ntree*/, bNode *node) +{ + NodeRadialTiling *storage = MEM_callocN(__func__); + storage->normalize = false; + + node->storage = storage; +} + +static const char *gpu_shader_get_name() +{ + return "node_radial_tiling"; +} + +static int node_shader_gpu_radial_tiling(GPUMaterial *mat, + bNode *node, + bNodeExecData * /*execdata*/, + GPUNodeStack *in, + GPUNodeStack *out) +{ + const NodeRadialTiling &storage = node_storage(*node); + float normalize_r_gon_parameter = storage.normalize; + float calculate_r_gon_parameter_field = out[0].hasoutput; + float calculate_segment_id = out[1].hasoutput; + float calculate_max_unit_parameter = out[2].hasoutput; + float calculate_x_axis_A_angle_bisector = out[3].hasoutput; + + const char *name = gpu_shader_get_name(); + + return GPU_stack_link(mat, + node, + name, + in, + out, + GPU_constant(&normalize_r_gon_parameter), + GPU_constant(&calculate_r_gon_parameter_field), + GPU_constant(&calculate_segment_id), + GPU_constant(&calculate_max_unit_parameter), + GPU_constant(&calculate_x_axis_A_angle_bisector)); +} + +class RoundedPolygonFunction : public mf::MultiFunction { + private: + bool normalize_r_gon_parameter_; + + mf::Signature signature_; + + public: + RoundedPolygonFunction(bool normalize_r_gon_parameter) + : normalize_r_gon_parameter_(normalize_r_gon_parameter) + { + signature_ = create_signature(); + this->set_signature(&signature_); + } + + static mf::Signature create_signature() + { + mf::Signature signature; + mf::SignatureBuilder builder{"radial_tiling", signature}; + + builder.single_input("Vector"); + + builder.single_input("Sides"); + builder.single_input("Roundness"); + + builder.single_output("Segment Coordinates", mf::ParamFlag::SupportsUnusedOutput); + builder.single_output("Segment ID", mf::ParamFlag::SupportsUnusedOutput); + builder.single_output("Segment Width", mf::ParamFlag::SupportsUnusedOutput); + builder.single_output("Segment Rotation", mf::ParamFlag::SupportsUnusedOutput); + + return signature; + } + + void call(const IndexMask &mask, mf::Params params, mf::Context /*context*/) const override + { + int param = 0; + + const VArray &coord = params.readonly_single_input(param++, "Vector"); + + const VArray &r_gon_sides = params.readonly_single_input(param++, "Sides"); + const VArray &r_gon_roundness = params.readonly_single_input(param++, + "Roundness"); + + MutableSpan r_segment_coordinates = + params.uninitialized_single_output_if_required(param++, "Segment Coordinates"); + MutableSpan r_segment_id = params.uninitialized_single_output_if_required( + param++, "Segment ID"); + MutableSpan r_max_unit_parameter = + params.uninitialized_single_output_if_required(param++, "Segment Width"); + MutableSpan r_x_axis_A_angle_bisector = + params.uninitialized_single_output_if_required(param++, "Segment Rotation"); + + const bool calculate_r_gon_parameter_field = !r_segment_coordinates.is_empty(); + const bool calculate_segment_id = !r_segment_id.is_empty(); + const bool calculate_max_unit_parameter = !r_max_unit_parameter.is_empty(); + const bool calculate_x_axis_A_angle_bisector = !r_x_axis_A_angle_bisector.is_empty(); + + mask.foreach_index([&](const int64_t i) { + if (calculate_r_gon_parameter_field || calculate_max_unit_parameter || + calculate_x_axis_A_angle_bisector) + { + float4 out_variables = calculate_out_variables(calculate_r_gon_parameter_field, + calculate_max_unit_parameter, + normalize_r_gon_parameter_, + math::max(r_gon_sides[i], 2.0f), + math::clamp(r_gon_roundness[i], 0.0f, 1.0f), + float2(coord[i].x, coord[i].y)); + + if (calculate_r_gon_parameter_field) { + r_segment_coordinates[i] = float3(out_variables.y, out_variables.x, 0.0f); + } + if (calculate_max_unit_parameter) { + r_max_unit_parameter[i] = out_variables.z; + } + if (calculate_x_axis_A_angle_bisector) { + r_x_axis_A_angle_bisector[i] = out_variables.w; + } + } + + if (calculate_segment_id) { + r_segment_id[i] = calculate_out_segment_id(math::max(r_gon_sides[i], 2.0f), + float2(coord[i].x, coord[i].y)); + } + }); + } + + ExecutionHints get_execution_hints() const override + { + ExecutionHints hints; + hints.allocates_array = false; + hints.min_grain_size = 50; + return hints; + } +}; + +static void sh_node_radial_tiling_build_multi_function(NodeMultiFunctionBuilder &builder) +{ + const NodeRadialTiling &storage = node_storage(builder.node()); + builder.construct_and_set_matching_fn(storage.normalize); +} + +} // namespace blender::nodes::node_shader_radial_tiling_cc + +void register_node_type_sh_radial_tiling() +{ + namespace file_ns = blender::nodes::node_shader_radial_tiling_cc; + + static blender::bke::bNodeType ntype; + + common_node_type_base(&ntype, "ShaderNodeRadialTiling"); + ntype.ui_name = "Radial Tiling"; + ntype.ui_description = "Transform Coordinate System for Radial Tiling"; + ntype.nclass = NODE_CLASS_OP_VECTOR; + ntype.declare = file_ns::sh_node_radial_tiling_declare; + ntype.draw_buttons = file_ns::node_shader_buts_radial_tiling; + ntype.initfunc = file_ns::node_shader_init_radial_tiling; + blender::bke::node_type_storage( + ntype, "NodeRadialTiling", node_free_standard_storage, node_copy_standard_storage); + ntype.gpu_fn = file_ns::node_shader_gpu_radial_tiling; + ntype.build_multi_function = file_ns::sh_node_radial_tiling_build_multi_function; + + blender::bke::node_register_type(ntype); +} diff --git a/tests/files/modeling/geometry_nodes/vector/radial_tiling.blend b/tests/files/modeling/geometry_nodes/vector/radial_tiling.blend new file mode 100644 index 00000000000..8c67972fbcf --- /dev/null +++ b/tests/files/modeling/geometry_nodes/vector/radial_tiling.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6d5311892a719ccab79a965a27ac209c1733cc27ba7836a569d8f7b251a13e86 +size 505800 diff --git a/tests/files/render/render_layer/cycles_renders/radial_tiling_render.png b/tests/files/render/render_layer/cycles_renders/radial_tiling_render.png new file mode 100644 index 00000000000..84cd490a82d --- /dev/null +++ b/tests/files/render/render_layer/cycles_renders/radial_tiling_render.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ede820bc9aa9b2d588725532baa64af072e0d0d7a6bff44e816044bb634df60c +size 228218 diff --git a/tests/files/render/render_layer/eevee_renders/radial_tiling_render.png b/tests/files/render/render_layer/eevee_renders/radial_tiling_render.png new file mode 100644 index 00000000000..9bd3b5019f5 --- /dev/null +++ b/tests/files/render/render_layer/eevee_renders/radial_tiling_render.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:99cb8c4217231f1d75ed39751187cc01ea1ab3a9409152fe1be6859cda56a75c +size 223182 diff --git a/tests/files/render/render_layer/radial_tiling_render.blend b/tests/files/render/render_layer/radial_tiling_render.blend new file mode 100644 index 00000000000..d4ea7694ada --- /dev/null +++ b/tests/files/render/render_layer/radial_tiling_render.blend @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a202fb458506292494e30bccb8e39c74f72f2dfc555119394aafbaa2f0bddecd +size 209429 diff --git a/tests/files/render/render_layer/storm_hydra_renders/radial_tiling_render.png b/tests/files/render/render_layer/storm_hydra_renders/radial_tiling_render.png new file mode 100644 index 00000000000..ad6eeb9b9b5 --- /dev/null +++ b/tests/files/render/render_layer/storm_hydra_renders/radial_tiling_render.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:dbbccc56dd89348c60d12d316350bc7f70097e9f066652a667100805b21d1ccd +size 121390 diff --git a/tests/files/render/render_layer/storm_usd_renders/radial_tiling_render.png b/tests/files/render/render_layer/storm_usd_renders/radial_tiling_render.png new file mode 100644 index 00000000000..5d0656f9a46 --- /dev/null +++ b/tests/files/render/render_layer/storm_usd_renders/radial_tiling_render.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4613881680182ac0b1a46e548b27f191891e5c593ecf8a6a41a667483a21ceca +size 81577 diff --git a/tests/files/render/render_layer/workbench_renders/radial_tiling_render.png b/tests/files/render/render_layer/workbench_renders/radial_tiling_render.png new file mode 100644 index 00000000000..3c2c3c1130d --- /dev/null +++ b/tests/files/render/render_layer/workbench_renders/radial_tiling_render.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5a6d1c550884f5b389d12e6afcd084d0168c4edc90dca1fdde3676d893a5dd1e +size 238223