32900f7f27a63ca53886a21882603f551672f4bd
[blender-staging.git] / intern / cycles / kernel / geom / geom_object.h
1 /*
2  * Licensed under the Apache License, Version 2.0 (the "License");
3  * you may not use this file except in compliance with the License.
4  * You may obtain a copy of the License at
5  *
6  * http://www.apache.org/licenses/LICENSE-2.0
7  *
8  * Unless required by applicable law or agreed to in writing, software
9  * distributed under the License is distributed on an "AS IS" BASIS,
10  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11  * See the License for the specific language governing permissions and
12  * limitations under the License.
13  */
14
15 /* Object Primitive
16  *
17  * All mesh and curve primitives are part of an object. The same mesh and curves
18  * may be instanced multiple times by different objects.
19  *
20  * If the mesh is not instanced multiple times, the object will not be explicitly
21  * stored as a primitive in the BVH, rather the bare triangles are curved are
22  * directly primitives in the BVH with world space locations applied, and the object
23  * ID is looked up afterwards. */
24
25 CCL_NAMESPACE_BEGIN
26
27 /* Object attributes, for now a fixed size and contents */
28
29 enum ObjectTransform {
30         OBJECT_TRANSFORM = 0,
31         OBJECT_TRANSFORM_MOTION_PRE = 0,
32         OBJECT_INVERSE_TRANSFORM = 4,
33         OBJECT_TRANSFORM_MOTION_POST = 4,
34         OBJECT_PROPERTIES = 8,
35         OBJECT_DUPLI = 9
36 };
37
38 enum ObjectVectorTransform {
39         OBJECT_VECTOR_MOTION_PRE = 0,
40         OBJECT_VECTOR_MOTION_POST = 3
41 };
42
43 /* Object to world space transformation */
44
45 ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg, int object, enum ObjectTransform type)
46 {
47         int offset = object*OBJECT_SIZE + (int)type;
48
49         Transform tfm;
50         tfm.x = kernel_tex_fetch(__objects, offset + 0);
51         tfm.y = kernel_tex_fetch(__objects, offset + 1);
52         tfm.z = kernel_tex_fetch(__objects, offset + 2);
53         tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
54
55         return tfm;
56 }
57
58 /* Object to world space transformation for motion vectors */
59
60 ccl_device_inline Transform object_fetch_vector_transform(KernelGlobals *kg, int object, enum ObjectVectorTransform type)
61 {
62         int offset = object*OBJECT_VECTOR_SIZE + (int)type;
63
64         Transform tfm;
65         tfm.x = kernel_tex_fetch(__objects_vector, offset + 0);
66         tfm.y = kernel_tex_fetch(__objects_vector, offset + 1);
67         tfm.z = kernel_tex_fetch(__objects_vector, offset + 2);
68         tfm.w = make_float4(0.0f, 0.0f, 0.0f, 1.0f);
69
70         return tfm;
71 }
72
73 /* Motion blurred object transformations */
74
75 #ifdef __OBJECT_MOTION__
76 ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg, int object, float time)
77 {
78         DecompMotionTransform motion;
79
80         int offset = object*OBJECT_SIZE + (int)OBJECT_TRANSFORM_MOTION_PRE;
81
82         motion.mid.x = kernel_tex_fetch(__objects, offset + 0);
83         motion.mid.y = kernel_tex_fetch(__objects, offset + 1);
84         motion.mid.z = kernel_tex_fetch(__objects, offset + 2);
85         motion.mid.w = kernel_tex_fetch(__objects, offset + 3);
86
87         motion.pre_x = kernel_tex_fetch(__objects, offset + 4);
88         motion.pre_y = kernel_tex_fetch(__objects, offset + 5);
89         motion.post_x = kernel_tex_fetch(__objects, offset + 6);
90         motion.post_y = kernel_tex_fetch(__objects, offset + 7);
91
92         Transform tfm;
93         transform_motion_interpolate(&tfm, &motion, time);
94
95         return tfm;
96 }
97
98 ccl_device_inline Transform object_fetch_transform_motion_test(KernelGlobals *kg, int object, float time, Transform *itfm)
99 {
100         int object_flag = kernel_tex_fetch(__object_flag, object);
101
102         if(object_flag & SD_OBJECT_MOTION) {
103                 /* if we do motion blur */
104                 Transform tfm = object_fetch_transform_motion(kg, object, time);
105
106                 if(itfm)
107                         *itfm = transform_quick_inverse(tfm);
108
109                 return tfm;
110         }
111         else {
112                 Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
113                 if(itfm)
114                         *itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
115
116                 return tfm;
117         }
118 }
119 #endif
120
121 /* Transform position from object to world space */
122
123 ccl_device_inline void object_position_transform(KernelGlobals *kg, const ShaderData *sd, float3 *P)
124 {
125 #ifdef __OBJECT_MOTION__
126         *P = transform_point_auto(&ccl_fetch(sd, ob_tfm), *P);
127 #else
128         Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
129         *P = transform_point(&tfm, *P);
130 #endif
131 }
132
133 /* Transform position from world to object space */
134
135 ccl_device_inline void object_inverse_position_transform(KernelGlobals *kg, const ShaderData *sd, float3 *P)
136 {
137 #ifdef __OBJECT_MOTION__
138         *P = transform_point_auto(&ccl_fetch(sd, ob_itfm), *P);
139 #else
140         Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_INVERSE_TRANSFORM);
141         *P = transform_point(&tfm, *P);
142 #endif
143 }
144
145 /* Transform normal from world to object space */
146
147 ccl_device_inline void object_inverse_normal_transform(KernelGlobals *kg, const ShaderData *sd, float3 *N)
148 {
149 #ifdef __OBJECT_MOTION__
150         *N = normalize(transform_direction_transposed_auto(&ccl_fetch(sd, ob_tfm), *N));
151 #else
152         Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
153         *N = normalize(transform_direction_transposed(&tfm, *N));
154 #endif
155 }
156
157 /* Transform normal from object to world space */
158
159 ccl_device_inline void object_normal_transform(KernelGlobals *kg, const ShaderData *sd, float3 *N)
160 {
161 #ifdef __OBJECT_MOTION__
162         *N = normalize(transform_direction_transposed_auto(&ccl_fetch(sd, ob_itfm), *N));
163 #else
164         Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_INVERSE_TRANSFORM);
165         *N = normalize(transform_direction_transposed(&tfm, *N));
166 #endif
167 }
168
169 /* Transform direction vector from object to world space */
170
171 ccl_device_inline void object_dir_transform(KernelGlobals *kg, const ShaderData *sd, float3 *D)
172 {
173 #ifdef __OBJECT_MOTION__
174         *D = transform_direction_auto(&ccl_fetch(sd, ob_tfm), *D);
175 #else
176         Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
177         *D = transform_direction(&tfm, *D);
178 #endif
179 }
180
181 /* Transform direction vector from world to object space */
182
183 ccl_device_inline void object_inverse_dir_transform(KernelGlobals *kg, const ShaderData *sd, float3 *D)
184 {
185 #ifdef __OBJECT_MOTION__
186         *D = transform_direction_auto(&ccl_fetch(sd, ob_itfm), *D);
187 #else
188         Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_INVERSE_TRANSFORM);
189         *D = transform_direction(&tfm, *D);
190 #endif
191 }
192
193 /* Object center position */
194
195 ccl_device_inline float3 object_location(KernelGlobals *kg, const ShaderData *sd)
196 {
197         if(ccl_fetch(sd, object) == OBJECT_NONE)
198                 return make_float3(0.0f, 0.0f, 0.0f);
199
200 #ifdef __OBJECT_MOTION__
201         return make_float3(ccl_fetch(sd, ob_tfm).x.w, ccl_fetch(sd, ob_tfm).y.w, ccl_fetch(sd, ob_tfm).z.w);
202 #else
203         Transform tfm = object_fetch_transform(kg, ccl_fetch(sd, object), OBJECT_TRANSFORM);
204         return make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
205 #endif
206 }
207
208 /* Total surface area of object */
209
210 ccl_device_inline float object_surface_area(KernelGlobals *kg, int object)
211 {
212         int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
213         float4 f = kernel_tex_fetch(__objects, offset);
214         return f.x;
215 }
216
217 /* Pass ID number of object */
218
219 ccl_device_inline float object_pass_id(KernelGlobals *kg, int object)
220 {
221         if(object == OBJECT_NONE)
222                 return 0.0f;
223
224         int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
225         float4 f = kernel_tex_fetch(__objects, offset);
226         return f.y;
227 }
228
229 /* Per object random number for shader variation */
230
231 ccl_device_inline float object_random_number(KernelGlobals *kg, int object)
232 {
233         if(object == OBJECT_NONE)
234                 return 0.0f;
235
236         int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
237         float4 f = kernel_tex_fetch(__objects, offset);
238         return f.z;
239 }
240
241 /* Particle ID from which this object was generated */
242
243 ccl_device_inline int object_particle_id(KernelGlobals *kg, int object)
244 {
245         if(object == OBJECT_NONE)
246                 return 0;
247
248         int offset = object*OBJECT_SIZE + OBJECT_PROPERTIES;
249         float4 f = kernel_tex_fetch(__objects, offset);
250         return __float_as_uint(f.w);
251 }
252
253 /* Generated texture coordinate on surface from where object was instanced */
254
255 ccl_device_inline float3 object_dupli_generated(KernelGlobals *kg, int object)
256 {
257         if(object == OBJECT_NONE)
258                 return make_float3(0.0f, 0.0f, 0.0f);
259
260         int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
261         float4 f = kernel_tex_fetch(__objects, offset);
262         return make_float3(f.x, f.y, f.z);
263 }
264
265 /* UV texture coordinate on surface from where object was instanced */
266
267 ccl_device_inline float3 object_dupli_uv(KernelGlobals *kg, int object)
268 {
269         if(object == OBJECT_NONE)
270                 return make_float3(0.0f, 0.0f, 0.0f);
271
272         int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
273         float4 f = kernel_tex_fetch(__objects, offset + 1);
274         return make_float3(f.x, f.y, 0.0f);
275 }
276
277 /* Information about mesh for motion blurred triangles and curves */
278
279 ccl_device_inline void object_motion_info(KernelGlobals *kg, int object, int *numsteps, int *numverts, int *numkeys)
280 {
281         int offset = object*OBJECT_SIZE + OBJECT_DUPLI;
282
283         if(numkeys) {
284                 float4 f = kernel_tex_fetch(__objects, offset);
285                 *numkeys = __float_as_int(f.w);
286         }
287
288         float4 f = kernel_tex_fetch(__objects, offset + 1);
289         if(numsteps)
290                 *numsteps = __float_as_int(f.z);
291         if(numverts)
292                 *numverts = __float_as_int(f.w);
293 }
294
295 /* Offset to an objects patch map */
296
297 ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
298 {
299         if(object == OBJECT_NONE)
300                 return 0;
301
302         int offset = object*OBJECT_SIZE + 11;
303         float4 f = kernel_tex_fetch(__objects, offset);
304         return __float_as_uint(f.x);
305 }
306
307 /* Pass ID for shader */
308
309 ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
310 {
311         return kernel_tex_fetch(__shader_flag, (ccl_fetch(sd, shader) & SHADER_MASK)*SHADER_SIZE + 1);
312 }
313
314 /* Particle data from which object was instanced */
315
316 ccl_device_inline float particle_index(KernelGlobals *kg, int particle)
317 {
318         int offset = particle*PARTICLE_SIZE;
319         float4 f = kernel_tex_fetch(__particles, offset + 0);
320         return f.x;
321 }
322
323 ccl_device float particle_age(KernelGlobals *kg, int particle)
324 {
325         int offset = particle*PARTICLE_SIZE;
326         float4 f = kernel_tex_fetch(__particles, offset + 0);
327         return f.y;
328 }
329
330 ccl_device float particle_lifetime(KernelGlobals *kg, int particle)
331 {
332         int offset = particle*PARTICLE_SIZE;
333         float4 f = kernel_tex_fetch(__particles, offset + 0);
334         return f.z;
335 }
336
337 ccl_device float particle_size(KernelGlobals *kg, int particle)
338 {
339         int offset = particle*PARTICLE_SIZE;
340         float4 f = kernel_tex_fetch(__particles, offset + 0);
341         return f.w;
342 }
343
344 ccl_device float4 particle_rotation(KernelGlobals *kg, int particle)
345 {
346         int offset = particle*PARTICLE_SIZE;
347         float4 f = kernel_tex_fetch(__particles, offset + 1);
348         return f;
349 }
350
351 ccl_device float3 particle_location(KernelGlobals *kg, int particle)
352 {
353         int offset = particle*PARTICLE_SIZE;
354         float4 f = kernel_tex_fetch(__particles, offset + 2);
355         return make_float3(f.x, f.y, f.z);
356 }
357
358 ccl_device float3 particle_velocity(KernelGlobals *kg, int particle)
359 {
360         int offset = particle*PARTICLE_SIZE;
361         float4 f2 = kernel_tex_fetch(__particles, offset + 2);
362         float4 f3 = kernel_tex_fetch(__particles, offset + 3);
363         return make_float3(f2.w, f3.x, f3.y);
364 }
365
366 ccl_device float3 particle_angular_velocity(KernelGlobals *kg, int particle)
367 {
368         int offset = particle*PARTICLE_SIZE;
369         float4 f3 = kernel_tex_fetch(__particles, offset + 3);
370         float4 f4 = kernel_tex_fetch(__particles, offset + 4);
371         return make_float3(f3.z, f3.w, f4.x);
372 }
373
374 /* Object intersection in BVH */
375
376 ccl_device_inline float3 bvh_clamp_direction(float3 dir)
377 {
378         /* clamp absolute values by exp2f(-80.0f) to avoid division by zero when calculating inverse direction */
379 #if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
380         const ssef oopes(8.271806E-25f,8.271806E-25f,8.271806E-25f,0.0f);
381         const ssef mask = _mm_cmpgt_ps(fabs(dir), oopes);
382         const ssef signdir = signmsk(dir.m128) | oopes;
383 #  ifndef __KERNEL_AVX__
384         ssef res = mask & ssef(dir);
385         res = _mm_or_ps(res,_mm_andnot_ps(mask, signdir));
386 #  else
387         ssef res = _mm_blendv_ps(signdir, dir, mask);
388 #  endif
389         return float3(res);
390 #else  /* __KERNEL_SSE__ && __KERNEL_SSE2__ */
391         const float ooeps = 8.271806E-25f;
392         return make_float3((fabsf(dir.x) > ooeps)? dir.x: copysignf(ooeps, dir.x),
393                            (fabsf(dir.y) > ooeps)? dir.y: copysignf(ooeps, dir.y),
394                            (fabsf(dir.z) > ooeps)? dir.z: copysignf(ooeps, dir.z));
395 #endif  /* __KERNEL_SSE__ && __KERNEL_SSE2__ */
396 }
397
398 ccl_device_inline float3 bvh_inverse_direction(float3 dir)
399 {
400         /* TODO(sergey): Currently disabled, gives speedup but causes precision issues. */
401 #if defined(__KERNEL_SSE__) && 0
402         return rcp(dir);
403 #else
404         return 1.0f / dir;
405 #endif
406 }
407
408 /* Transform ray into object space to enter static object in BVH */
409
410 ccl_device_inline void bvh_instance_push(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t)
411 {
412         Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
413
414         *P = transform_point(&tfm, ray->P);
415
416         float len;
417         *dir = bvh_clamp_direction(normalize_len(transform_direction(&tfm, ray->D), &len));
418         *idir = bvh_inverse_direction(*dir);
419
420         if(*t != FLT_MAX)
421                 *t *= len;
422 }
423
424 #ifdef __QBVH__
425 /* Same as above, but optimized for QBVH scene intersection,
426  * which needs to modify two max distances.
427  *
428  * TODO(sergey): Investigate if passing NULL instead of t1 gets optimized
429  * so we can avoid having this duplication.
430  */
431 ccl_device_inline void qbvh_instance_push(KernelGlobals *kg,
432                                           int object,
433                                           const Ray *ray,
434                                           float3 *P,
435                                           float3 *dir,
436                                           float3 *idir,
437                                           float *t,
438                                           float *t1)
439 {
440         Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
441
442         *P = transform_point(&tfm, ray->P);
443
444         float len;
445         *dir = bvh_clamp_direction(normalize_len(transform_direction(&tfm, ray->D), &len));
446         *idir = bvh_inverse_direction(*dir);
447
448         if(*t != FLT_MAX)
449                 *t *= len;
450
451         if(*t1 != -FLT_MAX)
452                 *t1 *= len;
453 }
454 #endif
455
456 /* Transorm ray to exit static object in BVH */
457
458 ccl_device_inline void bvh_instance_pop(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, ccl_addr_space float *t)
459 {
460         if(*t != FLT_MAX) {
461                 Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
462                 *t /= len(transform_direction(&tfm, ray->D));
463         }
464
465         *P = ray->P;
466         *dir = bvh_clamp_direction(ray->D);
467         *idir = bvh_inverse_direction(*dir);
468 }
469
470 /* Same as above, but returns scale factor to apply to multiple intersection distances */
471
472 ccl_device_inline void bvh_instance_pop_factor(KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float *t_fac)
473 {
474         Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
475         *t_fac = 1.0f / len(transform_direction(&tfm, ray->D));
476
477         *P = ray->P;
478         *dir = bvh_clamp_direction(ray->D);
479         *idir = bvh_inverse_direction(*dir);
480 }
481
482
483 #ifdef __OBJECT_MOTION__
484 /* Transform ray into object space to enter motion blurred object in BVH */
485
486 ccl_device_inline void bvh_instance_motion_push(KernelGlobals *kg,
487                                                 int object,
488                                                 const Ray *ray,
489                                                 float3 *P,
490                                                 float3 *dir,
491                                                 float3 *idir,
492                                                 ccl_addr_space float *t,
493                                                 Transform *itfm)
494 {
495         object_fetch_transform_motion_test(kg, object, ray->time, itfm);
496
497         *P = transform_point(itfm, ray->P);
498
499         float len;
500         *dir = bvh_clamp_direction(normalize_len(transform_direction(itfm, ray->D), &len));
501         *idir = bvh_inverse_direction(*dir);
502
503         if(*t != FLT_MAX)
504                 *t *= len;
505 }
506
507 #ifdef __QBVH__
508 /* Same as above, but optimized for QBVH scene intersection,
509  * which needs to modify two max distances.
510  *
511  * TODO(sergey): Investigate if passing NULL instead of t1 gets optimized
512  * so we can avoid having this duplication.
513  */
514 ccl_device_inline void qbvh_instance_motion_push(KernelGlobals *kg,
515                                                  int object,
516                                                  const Ray *ray,
517                                                  float3 *P,
518                                                  float3 *dir,
519                                                  float3 *idir,
520                                                  float *t,
521                                                  float *t1,
522                                                  Transform *itfm)
523 {
524         object_fetch_transform_motion_test(kg, object, ray->time, itfm);
525
526         *P = transform_point(itfm, ray->P);
527
528         float len;
529         *dir = bvh_clamp_direction(normalize_len(transform_direction(itfm, ray->D), &len));
530         *idir = bvh_inverse_direction(*dir);
531
532         if(*t != FLT_MAX)
533                 *t *= len;
534
535         if(*t1 != -FLT_MAX)
536                 *t1 *= len;
537 }
538 #endif
539
540 /* Transorm ray to exit motion blurred object in BVH */
541
542 ccl_device_inline void bvh_instance_motion_pop(KernelGlobals *kg,
543                                                int object,
544                                                const Ray *ray,
545                                                float3 *P,
546                                                float3 *dir,
547                                                float3 *idir,
548                                                ccl_addr_space float *t,
549                                                Transform *itfm)
550 {
551         if(*t != FLT_MAX) {
552                 *t /= len(transform_direction(itfm, ray->D));
553         }
554
555         *P = ray->P;
556         *dir = bvh_clamp_direction(ray->D);
557         *idir = bvh_inverse_direction(*dir);
558 }
559
560 /* Same as above, but returns scale factor to apply to multiple intersection distances */
561
562 ccl_device_inline void bvh_instance_motion_pop_factor(KernelGlobals *kg,
563                                                       int object,
564                                                       const Ray *ray,
565                                                       float3 *P,
566                                                       float3 *dir,
567                                                       float3 *idir,
568                                                       float *t_fac,
569                                                       Transform *itfm)
570 {
571         *t_fac = 1.0f / len(transform_direction(itfm, ray->D));
572         *P = ray->P;
573         *dir = bvh_clamp_direction(ray->D);
574         *idir = bvh_inverse_direction(*dir);
575 }
576
577 #endif
578
579 /* TODO(sergey): This is only for until we've got OpenCL 2.0
580  * on all devices we consider supported. It'll be replaced with
581  * generic address space.
582  */
583
584 #ifdef __KERNEL_OPENCL__
585 ccl_device_inline void object_position_transform_addrspace(KernelGlobals *kg,
586                                                          const ShaderData *sd,
587                                                          ccl_addr_space float3 *P)
588 {
589         float3 private_P = *P;
590         object_position_transform(kg, sd, &private_P);
591         *P = private_P;
592 }
593
594 ccl_device_inline void object_dir_transform_addrspace(KernelGlobals *kg,
595                                                       const ShaderData *sd,
596                                                       ccl_addr_space float3 *D)
597 {
598         float3 private_D = *D;
599         object_dir_transform(kg, sd, &private_D);
600         *D = private_D;
601 }
602
603 ccl_device_inline void object_normal_transform_addrspace(KernelGlobals *kg,
604                                                          const ShaderData *sd,
605                                                          ccl_addr_space float3 *N)
606 {
607         float3 private_N = *N;
608         object_normal_transform(kg, sd, &private_N);
609         *N = private_N;
610 }
611 #endif
612
613 #ifndef __KERNEL_OPENCL__
614 #  define object_position_transform_auto object_position_transform
615 #  define object_dir_transform_auto object_dir_transform
616 #  define object_normal_transform_auto object_normal_transform
617 #else
618 #  define object_position_transform_auto object_position_transform_addrspace
619 #  define object_dir_transform_auto object_dir_transform_addrspace
620 #  define object_normal_transform_auto object_normal_transform_addrspace
621 #endif
622
623 CCL_NAMESPACE_END
624