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