From f8d579d153b908753f2c11f3fbc1d5a37e62072c Mon Sep 17 00:00:00 2001 From: Tenkai Raiko Date: Mon, 22 Sep 2025 16:02:37 +0200 Subject: [PATCH] Nodes: Add Radial Tiling Node On its own, the main functionality of the Radial Tiling node is the ability to divide a 2D Cartesian coordinate system into as many radial segments as specified by the "Segments" input. Each segment has its own affinely transformed coordinate system, provided through the "Segment Coordinates" output, which can be used to tile textures in a radially symmetric manner. Additionally, a unique index is provided for every segment through the "Segment ID" output, the width of each segment at Y-coordinate of the "Segment Coordinates" output without normalization = 0 is provided through the "Segment Width" output and the rotation value of the affine transformation of the coordinate system of each segment is provided through the "Segment Rotation" output. The roundness of the coordinate lines of the "Segment Coordinates" output can be controlled through the "Roundness" inputs. This can be used to make the coordinate systems of the segments a mix of Cartesian and polar coordinates. Lastly, the lines of points of the "Segment Coordinates" output with constant Y-coordinates have the shape of polygon with rounded corners, which can be used to procedurally create rounded polygons. Pull Request: https://projects.blender.org/blender/blender/pulls/127711 --- intern/cycles/blender/shader.cpp | 6 + intern/cycles/kernel/CMakeLists.txt | 2 + .../cycles/kernel/osl/shaders/CMakeLists.txt | 2 + intern/cycles/kernel/osl/shaders/node_math.h | 32 + .../kernel/osl/shaders/node_radial_tiling.osl | 54 + .../osl/shaders/node_radial_tiling_shared.h | 1179 +++++++++++++++++ .../cycles/kernel/svm/node_types_template.h | 2 +- intern/cycles/kernel/svm/radial_tiling.h | 81 ++ .../cycles/kernel/svm/radial_tiling_shared.h | 1179 +++++++++++++++++ intern/cycles/kernel/svm/svm.h | 4 + intern/cycles/scene/shader_nodes.cpp | 49 + intern/cycles/scene/shader_nodes.h | 10 + .../startup/bl_ui/node_add_menu_compositor.py | 1 + .../startup/bl_ui/node_add_menu_geometry.py | 1 + scripts/startup/bl_ui/node_add_menu_shader.py | 1 + source/blender/blenlib/BLI_math_base.hh | 10 + source/blender/blenlib/BLI_math_constants.h | 3 + source/blender/blenlib/BLI_math_vector.hh | 23 + source/blender/blenlib/BLI_radial_tiling.hh | 24 + source/blender/blenlib/CMakeLists.txt | 4 +- .../blenlib/intern/radial_tiling_shared.cc | 24 + .../blenlib/intern/radial_tiling_shared.hh | 1179 +++++++++++++++++ source/blender/gpu/CMakeLists.txt | 2 + .../gpu_shader_material_radial_tiling.glsl | 48 + ..._shader_material_radial_tiling_shared.glsl | 1179 +++++++++++++++++ source/blender/makesdna/DNA_node_types.h | 5 + .../blender/makesrna/intern/rna_nodetree.cc | 19 + source/blender/nodes/shader/CMakeLists.txt | 1 + .../nodes/shader/node_shader_register.cc | 1 + .../nodes/shader/node_shader_register.hh | 1 + .../shader/nodes/node_shader_radial_tiling.cc | 225 ++++ .../geometry_nodes/vector/radial_tiling.blend | 3 + .../cycles_renders/radial_tiling_render.png | 3 + .../eevee_renders/radial_tiling_render.png | 3 + .../render_layer/radial_tiling_render.blend | 3 + .../radial_tiling_render.png | 3 + .../radial_tiling_render.png | 3 + .../radial_tiling_render.png | 3 + 38 files changed, 5370 insertions(+), 2 deletions(-) create mode 100644 intern/cycles/kernel/osl/shaders/node_radial_tiling.osl create mode 100644 intern/cycles/kernel/osl/shaders/node_radial_tiling_shared.h create mode 100644 intern/cycles/kernel/svm/radial_tiling.h create mode 100644 intern/cycles/kernel/svm/radial_tiling_shared.h create mode 100644 source/blender/blenlib/BLI_radial_tiling.hh create mode 100644 source/blender/blenlib/intern/radial_tiling_shared.cc create mode 100644 source/blender/blenlib/intern/radial_tiling_shared.hh create mode 100644 source/blender/gpu/shaders/material/gpu_shader_material_radial_tiling.glsl create mode 100644 source/blender/gpu/shaders/material/gpu_shader_material_radial_tiling_shared.glsl create mode 100644 source/blender/nodes/shader/nodes/node_shader_radial_tiling.cc create mode 100644 tests/files/modeling/geometry_nodes/vector/radial_tiling.blend create mode 100644 tests/files/render/render_layer/cycles_renders/radial_tiling_render.png create mode 100644 tests/files/render/render_layer/eevee_renders/radial_tiling_render.png create mode 100644 tests/files/render/render_layer/radial_tiling_render.blend create mode 100644 tests/files/render/render_layer/storm_hydra_renders/radial_tiling_render.png create mode 100644 tests/files/render/render_layer/storm_usd_renders/radial_tiling_render.png create mode 100644 tests/files/render/render_layer/workbench_renders/radial_tiling_render.png 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