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, &center);
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