Blender V5.0
primitive.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/* Primitive Utilities
6 *
7 * Generic functions to look up mesh, curve and volume primitive attributes for
8 * shading and render passes. */
9
10#pragma once
11
12#include "kernel/globals.h"
13
15
17#include "kernel/geom/curve.h"
18#include "kernel/geom/object.h"
19#include "kernel/geom/point.h"
21#include "kernel/geom/volume.h"
22
24
25/* Surface Attributes
26 *
27 * Read geometry attributes for surface shading. This is distinct from volume
28 * attributes for performance, mainly for GPU performance to avoid bringing in
29 * heavy volume interpolation code. */
30
31template<typename T>
33 const ccl_private ShaderData *sd,
34 const AttributeDescriptor desc,
35 const bool dx = false,
36 const bool dy = false)
37{
39 return dual<T>(attribute_data_fetch<T>(kg, desc.offset));
40 }
41
42 if (sd->type & PRIMITIVE_TRIANGLE) {
43 return triangle_attribute<T>(kg, sd, desc, dx, dy);
44 }
45#ifdef __HAIR__
46 if (sd->type & PRIMITIVE_CURVE) {
47 return curve_attribute<T>(kg, sd, desc, dx, dy);
48 }
49#endif
50#ifdef __POINTCLOUD__
51 else if (sd->type & PRIMITIVE_POINT) {
52 return point_attribute<T>(kg, sd, desc, dx, dy);
53 }
54#endif
55 else {
56 return make_zero<dual<T>>();
57 }
58}
59
60#ifdef __VOLUME__
61/* Volume Attributes
62 *
63 * Read geometry attributes for volume shading. This is distinct from surface
64 * attributes for performance, mainly for GPU performance to avoid bringing in
65 * heavy volume interpolation code. */
66
67ccl_device_forceinline bool primitive_is_volume_attribute(const ccl_private ShaderData *sd)
68{
69 return sd->type == PRIMITIVE_VOLUME;
70}
71
72template<typename T>
73ccl_device_inline T primitive_volume_attribute(KernelGlobals kg,
74 ccl_private ShaderData *sd,
75 const AttributeDescriptor desc,
76 const bool stochastic)
77{
78 if (primitive_is_volume_attribute(sd)) {
79 return volume_attribute_value<T>(volume_attribute_float4(kg, sd, desc, stochastic));
80 }
81 return make_zero<T>();
82}
83#endif
84
85/* Default UV coordinate */
86
88{
90
91 if (desc.offset == ATTR_STD_NOT_FOUND) {
92 return make_float3(0.0f, 0.0f, 0.0f);
93 }
94
95 const float2 uv = primitive_surface_attribute<float2>(kg, sd, desc).val;
96 return make_float3(uv.x, uv.y, 1.0f);
97}
98
99/* PTEX coordinates. */
100
102 ccl_private ShaderData *sd,
104 ccl_private int *face_id)
105{
106 /* storing ptex data as attributes is not memory efficient but simple for tests */
107 const AttributeDescriptor desc_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID);
108 const AttributeDescriptor desc_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV);
109
110 if (desc_face_id.offset == ATTR_STD_NOT_FOUND || desc_uv.offset == ATTR_STD_NOT_FOUND) {
111 return false;
112 }
113
114 const float3 uv3 = primitive_surface_attribute<float3>(kg, sd, desc_uv).val;
115 const float face_id_f = primitive_surface_attribute<float>(kg, sd, desc_face_id).val;
116
117 *uv = make_float2(uv3.x, uv3.y);
118 *face_id = (int)face_id_f;
119
120 return true;
121}
122
123/* Surface tangent */
124
126{
127#if defined(__HAIR__) || defined(__POINTCLOUD__)
128 if (sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT)) {
129# ifdef __DPDU__
130 return normalize(sd->dPdu);
131 }
132# else
133 return make_float3(0.0f, 0.0f, 0.0f);
134# endif
135#endif
136
137 /* try to create spherical tangent from generated coordinates */
139
140 if (desc.offset != ATTR_STD_NOT_FOUND) {
142 data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
144 return cross(sd->N, normalize(cross(data, sd->N)));
145 }
146 /* otherwise use surface derivatives */
147#ifdef __DPDU__
148 return normalize(sd->dPdu);
149#else
150 return make_float3(0.0f, 0.0f, 0.0f);
151#endif
152}
153
154/* Motion vector for motion pass */
155
157 const ccl_private ShaderData *sd)
158{
159 /* center position */
160 float3 center;
161
162#if defined(__HAIR__) || defined(__POINTCLOUD__)
163 const bool is_curve_or_point = sd->type & (PRIMITIVE_CURVE | PRIMITIVE_POINT);
164 if (is_curve_or_point) {
165 center = make_float3(0.0f, 0.0f, 0.0f);
166
167 if (sd->type & PRIMITIVE_CURVE) {
168# if defined(__HAIR__)
169 center = curve_motion_center_location(kg, sd);
170# endif
171 }
172 else if (sd->type & PRIMITIVE_POINT) {
173# if defined(__POINTCLOUD__)
174 center = point_motion_center_location(kg, sd);
175# endif
176 }
177
178 if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
179 object_position_transform(kg, sd, &center);
180 }
181 }
182 else
183#endif
184 {
185 center = sd->P;
186 }
187
188 float3 motion_pre = center;
189 float3 motion_post = center;
190
191 /* deformation motion */
193
194 if (desc.offset != ATTR_STD_NOT_FOUND) {
195 /* get motion info */
196 const int numverts = kernel_data_fetch(objects, sd->object).numverts;
197
198#if defined(__HAIR__) || defined(__POINTCLOUD__)
199 if (is_curve_or_point) {
200 motion_pre = make_float3(primitive_surface_attribute<float4>(kg, sd, desc).val);
201 desc.offset += numverts;
202 motion_post = make_float3(primitive_surface_attribute<float4>(kg, sd, desc).val);
203
204 /* Curve */
205 if ((sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
206 object_position_transform(kg, sd, &motion_pre);
207 object_position_transform(kg, sd, &motion_post);
208 }
209 }
210 else
211#endif
212 if (sd->type & PRIMITIVE_TRIANGLE)
213 {
214 /* Triangle */
215 motion_pre = triangle_attribute<float3>(kg, sd, desc).val;
216 desc.offset += numverts;
217 motion_post = triangle_attribute<float3>(kg, sd, desc).val;
218 }
219 }
220
221 /* object motion. note that depending on the mesh having motion vectors, this
222 * transformation was set match the world/object space of motion_pre/post */
223 Transform tfm;
224
226 motion_pre = transform_point(&tfm, motion_pre);
227
229 motion_post = transform_point(&tfm, motion_post);
230
231 float3 motion_center;
232
233 /* camera motion, for perspective/orthographic motion.pre/post will be a
234 * world-to-raster matrix, for panorama it's world-to-camera, for custom
235 * we fall back to the world position until we have inverse mapping for it */
236 if (kernel_data.cam.type == CAMERA_CUSTOM) {
237 /* TODO: Custom cameras don't have inverse mappings yet, so we fall back to
238 * camera-space vectors here for now. */
239 tfm = kernel_data.cam.worldtocamera;
240 motion_center = normalize(transform_point(&tfm, center));
241
242 tfm = kernel_data.cam.motion_pass_pre;
243 motion_pre = normalize(transform_point(&tfm, motion_pre));
244
245 tfm = kernel_data.cam.motion_pass_post;
246 motion_post = normalize(transform_point(&tfm, motion_post));
247 }
248 else if (kernel_data.cam.type != CAMERA_PANORAMA) {
249 /* Perspective and orthographics camera use the world-to-raster matrix. */
250 ProjectionTransform projection = kernel_data.cam.worldtoraster;
251 motion_center = transform_perspective(&projection, center);
252
253 projection = kernel_data.cam.perspective_pre;
254 motion_pre = transform_perspective(&projection, motion_pre);
255
256 projection = kernel_data.cam.perspective_post;
257 motion_post = transform_perspective(&projection, motion_post);
258 }
259 else {
260 /* Panorama cameras have their own inverse mappings. */
261 tfm = kernel_data.cam.worldtocamera;
262 motion_center = normalize(transform_point(&tfm, center));
263 motion_center = make_float3(direction_to_panorama(&kernel_data.cam, motion_center));
264 motion_center.x *= kernel_data.cam.width;
265 motion_center.y *= kernel_data.cam.height;
266
267 tfm = kernel_data.cam.motion_pass_pre;
268 motion_pre = normalize(transform_point(&tfm, motion_pre));
269 motion_pre = make_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
270 motion_pre.x *= kernel_data.cam.width;
271 motion_pre.y *= kernel_data.cam.height;
272
273 tfm = kernel_data.cam.motion_pass_post;
274 motion_post = normalize(transform_point(&tfm, motion_post));
275 motion_post = make_float3(direction_to_panorama(&kernel_data.cam, motion_post));
276 motion_post.x *= kernel_data.cam.width;
277 motion_post.y *= kernel_data.cam.height;
278 }
279
280 motion_pre = motion_pre - motion_center;
281 motion_post = motion_center - motion_post;
282
283 return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
284}
285
BMesh const char void * data
ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, const float3 dir)
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_perspective(const ccl_private ProjectionTransform *t, const float3 a)
#define kernel_data
#define ccl_device_forceinline
#define kernel_data_fetch(name, index)
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
ccl_device dual< T > triangle_attribute(KernelGlobals kg, const ccl_private ShaderData *sd, const AttributeDescriptor desc, const bool dx=false, const bool dy=false)
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
ccl_device_inline T attribute_data_fetch(KernelGlobals kg, int offset)
ccl_device_inline void object_normal_transform(KernelGlobals kg, const ccl_private ShaderData *sd, ccl_private float3 *N)
ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals kg, const int object, enum ObjectVectorTransform type)
ccl_device_inline void object_position_transform(KernelGlobals kg, const ccl_private ShaderData *sd, ccl_private T *P)
@ OBJECT_PASS_MOTION_PRE
@ OBJECT_PASS_MOTION_POST
@ PRIMITIVE_VOLUME
@ PRIMITIVE_CURVE
@ PRIMITIVE_TRIANGLE
@ PRIMITIVE_POINT
@ ATTR_STD_UV
@ ATTR_STD_NOT_FOUND
@ ATTR_STD_PTEX_FACE_ID
@ ATTR_STD_MOTION_VERTEX_POSITION
@ ATTR_STD_PTEX_UV
@ ATTR_STD_GENERATED
@ SD_OBJECT_TRANSFORM_APPLIED
@ SD_OBJECT_HAS_VERTEX_MOTION
@ ATTR_ELEMENT_OBJECT
@ ATTR_ELEMENT_MESH
@ CAMERA_PANORAMA
@ CAMERA_CUSTOM
ccl_device_inline T make_zero()
Definition math_dual.h:17
#define T
ccl_device_forceinline float3 primitive_uv(KernelGlobals kg, const ccl_private ShaderData *sd)
Definition primitive.h:87
ccl_device_forceinline float4 primitive_motion_vector(KernelGlobals kg, const ccl_private ShaderData *sd)
Definition primitive.h:156
CCL_NAMESPACE_BEGIN ccl_device_forceinline dual< T > primitive_surface_attribute(KernelGlobals kg, const ccl_private ShaderData *sd, const AttributeDescriptor desc, const bool dx=false, const bool dy=false)
Definition primitive.h:32
ccl_device float3 primitive_tangent(KernelGlobals kg, ccl_private ShaderData *sd)
Definition primitive.h:125
ccl_device bool primitive_ptex(KernelGlobals kg, ccl_private ShaderData *sd, ccl_private float2 *uv, ccl_private int *face_id)
Definition primitive.h:101
#define ccl_device
#define make_float2
#define make_float4
static bool find_attribute(const std::string &attributes, const char *search_attribute)
AttributeElement element
float x
float y
float y
Definition sky_math.h:136
float x
Definition sky_math.h:136
ccl_device_inline float3 transform_point(const ccl_private Transform *t, const float3 a)
Definition transform.h:56