Blender V5.0
curve.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
7#include "kernel/globals.h"
8
11#include "kernel/geom/object.h"
12
14
15/* Curve Primitive
16 *
17 * Curve primitive for rendering hair and fur. These can be render as flat
18 * ribbons or curves with actual thickness. The curve can also be rendered as
19 * line segments rather than curves for better performance.
20 */
21
22#ifdef __HAIR__
23
24/* Partial derivative of f w.r.t. x, namely ∂f/∂x
25 * f is a function of u (along the curve)
26 * f(u) = f0 * (1 - u) + f1 * u,
27 * The partial derivative in x is
28 * ∂f/∂x = ∂f/∂u * ∂u/∂x
29 * = (f1 - f0) * du.dx. */
30template<typename T>
31ccl_device_inline T curve_attribute_dfdx(const ccl_private differential &du,
32 const ccl_private T &f0,
33 const ccl_private T &f1)
34{
35 return du.dx * (f1 - f0);
36}
37
38/* Partial derivative of f w.r.t. in x, namely ∂f/∂y, similarly computed as ∂f/∂x above. */
39template<typename T>
40ccl_device_inline T curve_attribute_dfdy(const ccl_private differential &du,
41 const ccl_private T &f0,
42 const ccl_private T &f1)
43{
44 return du.dy * (f1 - f0);
45}
46
47/* Read attributes on various curve elements, and compute the partial derivatives if requested. */
48
49template<typename T>
50ccl_device dual<T> curve_attribute(KernelGlobals kg,
51 const ccl_private ShaderData *sd,
52 const AttributeDescriptor desc,
53 const bool dx = false,
54 const bool dy = false)
55{
58 const KernelCurve curve = kernel_data_fetch(curves, sd->prim);
59 const int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
60 const int k1 = k0 + 1;
61
62 const T f0 = attribute_data_fetch<T>(kg, desc.offset + k0);
63 const T f1 = attribute_data_fetch<T>(kg, desc.offset + k1);
64
65# ifdef __RAY_DIFFERENTIALS__
66 if (dx) {
67 result.dx = curve_attribute_dfdx(sd->du, f0, f1);
68 }
69 if (dy) {
70 result.dy = curve_attribute_dfdy(sd->du, f0, f1);
71 }
72# endif
73
74 result.val = mix(f0, f1, sd->u);
75 return result;
76 }
77
78 /* idea: we can't derive any useful differentials here, but for tiled
79 * mipmap image caching it would be useful to avoid reading the highest
80 * detail level always. maybe a derivative based on the hair density
81 * could be computed somehow? */
82
83 if (desc.element == ATTR_ELEMENT_CURVE) {
84 return dual<T>(attribute_data_fetch<T>(kg, desc.offset + sd->prim));
85 }
86 return make_zero<dual<T>>();
87}
88
89/* Curve thickness */
90
91ccl_device float curve_thickness(KernelGlobals kg, const ccl_private ShaderData *sd)
92{
93 if (!(sd->type & PRIMITIVE_CURVE)) {
94 return 0.0f;
95 }
96
97 const KernelCurve curve = kernel_data_fetch(curves, sd->prim);
98 const int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
99 const int k1 = k0 + 1;
100
101 float4 P_curve[2];
102
103# ifdef __OBJECT_MOTION__
104 if (sd->type & PRIMITIVE_MOTION) {
105 motion_curve_keys_linear(kg, sd->object, sd->time, k0, k1, P_curve);
106 }
107 else
108# endif
109 {
110 P_curve[0] = kernel_data_fetch(curve_keys, k0);
111 P_curve[1] = kernel_data_fetch(curve_keys, k1);
112 }
113
114 float r = 2.0f * ((P_curve[1].w - P_curve[0].w) * sd->u + P_curve[0].w);
115
116 if (sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED) {
117 return r;
118 }
119
120 const float normalized_r = r * (1.0f / M_SQRT3_F);
121 float3 dir = make_float3(normalized_r, normalized_r, normalized_r);
122 object_dir_transform(kg, sd, &dir);
123 return len(dir);
124}
125
126/* Curve random */
127
128ccl_device float curve_random(KernelGlobals kg, const ccl_private ShaderData *sd)
129{
130 if (sd->type & PRIMITIVE_CURVE) {
132 return (desc.offset != ATTR_STD_NOT_FOUND) ? curve_attribute<float>(kg, sd, desc).val : 0.0f;
133 }
134 return 0.0f;
135}
136
137/* Curve location for motion pass, linear interpolation between keys and
138 * ignoring radius because we do the same for the motion keys */
139
140ccl_device float3 curve_motion_center_location(KernelGlobals kg, const ccl_private ShaderData *sd)
141{
142 const KernelCurve curve = kernel_data_fetch(curves, sd->prim);
143 const int k0 = curve.first_key + PRIMITIVE_UNPACK_SEGMENT(sd->type);
144 const int k1 = k0 + 1;
145
146 float4 P_curve[2];
147
148 P_curve[0] = kernel_data_fetch(curve_keys, k0);
149 P_curve[1] = kernel_data_fetch(curve_keys, k1);
150
151 return make_float3(P_curve[1]) * sd->u + make_float3(P_curve[0]) * (1.0f - sd->u);
152}
153
154/* Curve tangent normal */
155
156ccl_device float3 curve_tangent_normal(const ccl_private ShaderData *sd)
157{
158 float3 tgN = make_float3(0.0f, 0.0f, 0.0f);
159
160 if (sd->type & PRIMITIVE_CURVE) {
161
162 tgN = -(-sd->wi - sd->dPdu * (dot(sd->dPdu, -sd->wi) / len_squared(sd->dPdu)));
163 tgN = normalize(tgN);
164
165 /* need to find suitable scaled gd for corrected normal */
166# if 0
167 tgN = normalize(tgN - gd * sd->dPdu);
168# endif
169 }
170
171 return tgN;
172}
173
174/* Curve bounds utility function */
175
177 ccl_private float *upper,
178 ccl_private float *extremta,
179 ccl_private float *extrema,
180 ccl_private float *extremtb,
181 ccl_private float *extremb,
182 float p0,
183 float p1,
184 float p2,
185 float p3)
186{
187 float halfdiscroot = (p2 * p2 - 3 * p3 * p1);
188 float ta = -1.0f;
189 float tb = -1.0f;
190
191 *extremta = -1.0f;
192 *extremtb = -1.0f;
193 *upper = p0;
194 *lower = (p0 + p1) + (p2 + p3);
195 *extrema = *upper;
196 *extremb = *lower;
197
198 if (*lower >= *upper) {
199 *upper = *lower;
200 *lower = p0;
201 }
202
203 if (halfdiscroot >= 0) {
204 const float inv3p3 = (1.0f / 3.0f) / p3;
205 halfdiscroot = sqrtf(halfdiscroot);
206 ta = (-p2 - halfdiscroot) * inv3p3;
207 tb = (-p2 + halfdiscroot) * inv3p3;
208 }
209
210 float t2;
211 float t3;
212
213 if (ta > 0.0f && ta < 1.0f) {
214 t2 = ta * ta;
215 t3 = t2 * ta;
216 *extremta = ta;
217 *extrema = p3 * t3 + p2 * t2 + p1 * ta + p0;
218
219 *upper = fmaxf(*extrema, *upper);
220 *lower = fminf(*extrema, *lower);
221 }
222
223 if (tb > 0.0f && tb < 1.0f) {
224 t2 = tb * tb;
225 t3 = t2 * tb;
226 *extremtb = tb;
227 *extremb = p3 * t3 + p2 * t2 + p1 * tb + p0;
228
229 *upper = fmaxf(*extremb, *upper);
230 *lower = fminf(*extremb, *lower);
231 }
232}
233
234#endif /* __HAIR__ */
235
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define kernel_data_fetch(name, index)
#define PRIMITIVE_UNPACK_SEGMENT(type)
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define M_SQRT3_F
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
VecBase< float, D > normalize(VecOp< float, D >) RET
ccl_device_inline T attribute_data_fetch(KernelGlobals kg, int offset)
ccl_device_inline void object_dir_transform(KernelGlobals kg, const ccl_private ShaderData *sd, ccl_private float3 *D)
@ PRIMITIVE_MOTION
@ PRIMITIVE_CURVE
@ ATTR_STD_NOT_FOUND
@ ATTR_STD_CURVE_RANDOM
@ SD_OBJECT_TRANSFORM_APPLIED
@ ATTR_ELEMENT_CURVE_KEY
@ ATTR_ELEMENT_CURVE_KEY_MOTION
@ ATTR_ELEMENT_CURVE
ccl_device_inline T make_zero()
Definition math_dual.h:17
ccl_device_inline float len_squared(const float2 a)
#define T
#define mix
#define sqrtf
#define ccl_device
#define fmaxf
#define fminf
CCL_NAMESPACE_BEGIN void curvebounds(float *lower, float *upper, float3 *p, const int dim)
static bool find_attribute(const std::string &attributes, const char *search_attribute)
AttributeElement element
float w
Definition sky_math.h:225
uint len