1 /*
2 * Copyright 2011-2013 Blender Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /* Primitive Utilities
18 *
19 * Generic functions to look up mesh, curve and volume primitive attributes for
20 * shading and render passes. */
21
22 CCL_NAMESPACE_BEGIN
23
24 /* Generic primitive attribute reading functions */
primitive_attribute_float(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc,float * dx,float * dy)25 ccl_device_inline float primitive_attribute_float(
26 KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
27 {
28 if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
29 if (subd_triangle_patch(kg, sd) == ~0)
30 return triangle_attribute_float(kg, sd, desc, dx, dy);
31 else
32 return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
33 }
34 #ifdef __HAIR__
35 else if (sd->type & PRIMITIVE_ALL_CURVE) {
36 return curve_attribute_float(kg, sd, desc, dx, dy);
37 }
38 #endif
39 #ifdef __VOLUME__
40 else if (sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
41 if (dx)
42 *dx = 0.0f;
43 if (dy)
44 *dy = 0.0f;
45 return volume_attribute_float(kg, sd, desc);
46 }
47 #endif
48 else {
49 if (dx)
50 *dx = 0.0f;
51 if (dy)
52 *dy = 0.0f;
53 return 0.0f;
54 }
55 }
56
primitive_surface_attribute_float(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc,float * dx,float * dy)57 ccl_device_inline float primitive_surface_attribute_float(
58 KernelGlobals *kg, const ShaderData *sd, const AttributeDescriptor desc, float *dx, float *dy)
59 {
60 if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
61 if (subd_triangle_patch(kg, sd) == ~0)
62 return triangle_attribute_float(kg, sd, desc, dx, dy);
63 else
64 return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
65 }
66 #ifdef __HAIR__
67 else if (sd->type & PRIMITIVE_ALL_CURVE) {
68 return curve_attribute_float(kg, sd, desc, dx, dy);
69 }
70 #endif
71 else {
72 if (dx)
73 *dx = 0.0f;
74 if (dy)
75 *dy = 0.0f;
76 return 0.0f;
77 }
78 }
79
80 #ifdef __VOLUME__
primitive_volume_attribute_float(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc)81 ccl_device_inline float primitive_volume_attribute_float(KernelGlobals *kg,
82 const ShaderData *sd,
83 const AttributeDescriptor desc)
84 {
85 if (sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
86 return volume_attribute_float(kg, sd, desc);
87 }
88 else {
89 return 0.0f;
90 }
91 }
92 #endif
93
primitive_attribute_float2(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc,float2 * dx,float2 * dy)94 ccl_device_inline float2 primitive_attribute_float2(KernelGlobals *kg,
95 const ShaderData *sd,
96 const AttributeDescriptor desc,
97 float2 *dx,
98 float2 *dy)
99 {
100 if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
101 if (subd_triangle_patch(kg, sd) == ~0)
102 return triangle_attribute_float2(kg, sd, desc, dx, dy);
103 else
104 return subd_triangle_attribute_float2(kg, sd, desc, dx, dy);
105 }
106 #ifdef __HAIR__
107 else if (sd->type & PRIMITIVE_ALL_CURVE) {
108 return curve_attribute_float2(kg, sd, desc, dx, dy);
109 }
110 #endif
111 #ifdef __VOLUME__
112 else if (sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
113 kernel_assert(0);
114 if (dx)
115 *dx = make_float2(0.0f, 0.0f);
116 if (dy)
117 *dy = make_float2(0.0f, 0.0f);
118 return make_float2(0.0f, 0.0f);
119 }
120 #endif
121 else {
122 if (dx)
123 *dx = make_float2(0.0f, 0.0f);
124 if (dy)
125 *dy = make_float2(0.0f, 0.0f);
126 return make_float2(0.0f, 0.0f);
127 }
128 }
129
primitive_attribute_float3(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc,float3 * dx,float3 * dy)130 ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
131 const ShaderData *sd,
132 const AttributeDescriptor desc,
133 float3 *dx,
134 float3 *dy)
135 {
136 if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
137 if (subd_triangle_patch(kg, sd) == ~0)
138 return triangle_attribute_float3(kg, sd, desc, dx, dy);
139 else
140 return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
141 }
142 #ifdef __HAIR__
143 else if (sd->type & PRIMITIVE_ALL_CURVE) {
144 return curve_attribute_float3(kg, sd, desc, dx, dy);
145 }
146 #endif
147 #ifdef __VOLUME__
148 else if (sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
149 if (dx)
150 *dx = make_float3(0.0f, 0.0f, 0.0f);
151 if (dy)
152 *dy = make_float3(0.0f, 0.0f, 0.0f);
153 return volume_attribute_float3(kg, sd, desc);
154 }
155 #endif
156 else {
157 if (dx)
158 *dx = make_float3(0.0f, 0.0f, 0.0f);
159 if (dy)
160 *dy = make_float3(0.0f, 0.0f, 0.0f);
161 return make_float3(0.0f, 0.0f, 0.0f);
162 }
163 }
164
primitive_attribute_float4(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc,float4 * dx,float4 * dy)165 ccl_device_inline float4 primitive_attribute_float4(KernelGlobals *kg,
166 const ShaderData *sd,
167 const AttributeDescriptor desc,
168 float4 *dx,
169 float4 *dy)
170 {
171 if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
172 if (subd_triangle_patch(kg, sd) == ~0)
173 return triangle_attribute_float4(kg, sd, desc, dx, dy);
174 else
175 return subd_triangle_attribute_float4(kg, sd, desc, dx, dy);
176 }
177 #ifdef __HAIR__
178 else if (sd->type & PRIMITIVE_ALL_CURVE) {
179 return curve_attribute_float4(kg, sd, desc, dx, dy);
180 }
181 #endif
182 else {
183 if (dx)
184 *dx = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
185 if (dy)
186 *dy = make_float4(0.0f, 0.0f, 0.0f, 0.0f);
187 return make_float4(0.0f, 0.0f, 0.0f, 0.0f);
188 }
189 }
190
primitive_surface_attribute_float2(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc,float2 * dx,float2 * dy)191 ccl_device_inline float2 primitive_surface_attribute_float2(KernelGlobals *kg,
192 const ShaderData *sd,
193 const AttributeDescriptor desc,
194 float2 *dx,
195 float2 *dy)
196 {
197 if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
198 if (subd_triangle_patch(kg, sd) == ~0)
199 return triangle_attribute_float2(kg, sd, desc, dx, dy);
200 else
201 return subd_triangle_attribute_float2(kg, sd, desc, dx, dy);
202 }
203 #ifdef __HAIR__
204 else if (sd->type & PRIMITIVE_ALL_CURVE) {
205 return curve_attribute_float2(kg, sd, desc, dx, dy);
206 }
207 #endif
208 else {
209 if (dx)
210 *dx = make_float2(0.0f, 0.0f);
211 if (dy)
212 *dy = make_float2(0.0f, 0.0f);
213 return make_float2(0.0f, 0.0f);
214 }
215 }
216
primitive_surface_attribute_float3(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc,float3 * dx,float3 * dy)217 ccl_device_inline float3 primitive_surface_attribute_float3(KernelGlobals *kg,
218 const ShaderData *sd,
219 const AttributeDescriptor desc,
220 float3 *dx,
221 float3 *dy)
222 {
223 if (sd->type & PRIMITIVE_ALL_TRIANGLE) {
224 if (subd_triangle_patch(kg, sd) == ~0)
225 return triangle_attribute_float3(kg, sd, desc, dx, dy);
226 else
227 return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
228 }
229 #ifdef __HAIR__
230 else if (sd->type & PRIMITIVE_ALL_CURVE) {
231 return curve_attribute_float3(kg, sd, desc, dx, dy);
232 }
233 #endif
234 else {
235 if (dx)
236 *dx = make_float3(0.0f, 0.0f, 0.0f);
237 if (dy)
238 *dy = make_float3(0.0f, 0.0f, 0.0f);
239 return make_float3(0.0f, 0.0f, 0.0f);
240 }
241 }
242
243 #ifdef __VOLUME__
primitive_volume_attribute_float3(KernelGlobals * kg,const ShaderData * sd,const AttributeDescriptor desc)244 ccl_device_inline float3 primitive_volume_attribute_float3(KernelGlobals *kg,
245 const ShaderData *sd,
246 const AttributeDescriptor desc)
247 {
248 if (sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
249 return volume_attribute_float3(kg, sd, desc);
250 }
251 else {
252 return make_float3(0.0f, 0.0f, 0.0f);
253 }
254 }
255 #endif
256
257 /* Default UV coordinate */
258
primitive_uv(KernelGlobals * kg,ShaderData * sd)259 ccl_device_inline float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
260 {
261 const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_UV);
262
263 if (desc.offset == ATTR_STD_NOT_FOUND)
264 return make_float3(0.0f, 0.0f, 0.0f);
265
266 float2 uv = primitive_surface_attribute_float2(kg, sd, desc, NULL, NULL);
267 return make_float3(uv.x, uv.y, 1.0f);
268 }
269
270 /* Ptex coordinates */
271
primitive_ptex(KernelGlobals * kg,ShaderData * sd,float2 * uv,int * face_id)272 ccl_device bool primitive_ptex(KernelGlobals *kg, ShaderData *sd, float2 *uv, int *face_id)
273 {
274 /* storing ptex data as attributes is not memory efficient but simple for tests */
275 const AttributeDescriptor desc_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID);
276 const AttributeDescriptor desc_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV);
277
278 if (desc_face_id.offset == ATTR_STD_NOT_FOUND || desc_uv.offset == ATTR_STD_NOT_FOUND)
279 return false;
280
281 float3 uv3 = primitive_surface_attribute_float3(kg, sd, desc_uv, NULL, NULL);
282 float face_id_f = primitive_surface_attribute_float(kg, sd, desc_face_id, NULL, NULL);
283
284 *uv = make_float2(uv3.x, uv3.y);
285 *face_id = (int)face_id_f;
286
287 return true;
288 }
289
290 /* Surface tangent */
291
primitive_tangent(KernelGlobals * kg,ShaderData * sd)292 ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
293 {
294 #ifdef __HAIR__
295 if (sd->type & PRIMITIVE_ALL_CURVE)
296 # ifdef __DPDU__
297 return normalize(sd->dPdu);
298 # else
299 return make_float3(0.0f, 0.0f, 0.0f);
300 # endif
301 #endif
302
303 /* try to create spherical tangent from generated coordinates */
304 const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED);
305
306 if (desc.offset != ATTR_STD_NOT_FOUND) {
307 float3 data = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
308 data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
309 object_normal_transform(kg, sd, &data);
310 return cross(sd->N, normalize(cross(data, sd->N)));
311 }
312 else {
313 /* otherwise use surface derivatives */
314 #ifdef __DPDU__
315 return normalize(sd->dPdu);
316 #else
317 return make_float3(0.0f, 0.0f, 0.0f);
318 #endif
319 }
320 }
321
322 /* Motion vector for motion pass */
323
primitive_motion_vector(KernelGlobals * kg,ShaderData * sd)324 ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
325 {
326 /* center position */
327 float3 center;
328
329 #ifdef __HAIR__
330 bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE;
331 if (is_curve_primitive) {
332 center = curve_motion_center_location(kg, sd);
333
334 if (!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
335 object_position_transform(kg, sd, ¢er);
336 }
337 }
338 else
339 #endif
340 center = sd->P;
341
342 float3 motion_pre = center, motion_post = center;
343
344 /* deformation motion */
345 AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION);
346
347 if (desc.offset != ATTR_STD_NOT_FOUND) {
348 /* get motion info */
349 int numverts, numkeys;
350 object_motion_info(kg, sd->object, NULL, &numverts, &numkeys);
351
352 /* lookup attributes */
353 motion_pre = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
354
355 desc.offset += (sd->type & PRIMITIVE_ALL_TRIANGLE) ? numverts : numkeys;
356 motion_post = primitive_surface_attribute_float3(kg, sd, desc, NULL, NULL);
357
358 #ifdef __HAIR__
359 if (is_curve_primitive && (sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
360 object_position_transform(kg, sd, &motion_pre);
361 object_position_transform(kg, sd, &motion_post);
362 }
363 #endif
364 }
365
366 /* object motion. note that depending on the mesh having motion vectors, this
367 * transformation was set match the world/object space of motion_pre/post */
368 Transform tfm;
369
370 tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_PRE);
371 motion_pre = transform_point(&tfm, motion_pre);
372
373 tfm = object_fetch_motion_pass_transform(kg, sd->object, OBJECT_PASS_MOTION_POST);
374 motion_post = transform_point(&tfm, motion_post);
375
376 float3 motion_center;
377
378 /* camera motion, for perspective/orthographic motion.pre/post will be a
379 * world-to-raster matrix, for panorama it's world-to-camera */
380 if (kernel_data.cam.type != CAMERA_PANORAMA) {
381 ProjectionTransform projection = kernel_data.cam.worldtoraster;
382 motion_center = transform_perspective(&projection, center);
383
384 projection = kernel_data.cam.perspective_pre;
385 motion_pre = transform_perspective(&projection, motion_pre);
386
387 projection = kernel_data.cam.perspective_post;
388 motion_post = transform_perspective(&projection, motion_post);
389 }
390 else {
391 tfm = kernel_data.cam.worldtocamera;
392 motion_center = normalize(transform_point(&tfm, center));
393 motion_center = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_center));
394 motion_center.x *= kernel_data.cam.width;
395 motion_center.y *= kernel_data.cam.height;
396
397 tfm = kernel_data.cam.motion_pass_pre;
398 motion_pre = normalize(transform_point(&tfm, motion_pre));
399 motion_pre = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
400 motion_pre.x *= kernel_data.cam.width;
401 motion_pre.y *= kernel_data.cam.height;
402
403 tfm = kernel_data.cam.motion_pass_post;
404 motion_post = normalize(transform_point(&tfm, motion_post));
405 motion_post = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_post));
406 motion_post.x *= kernel_data.cam.width;
407 motion_post.y *= kernel_data.cam.height;
408 }
409
410 motion_pre = motion_pre - motion_center;
411 motion_post = motion_center - motion_post;
412
413 return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
414 }
415
416 CCL_NAMESPACE_END
417