ClangFormat: apply to source, most of intern
[blender.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_INVERSE_TRANSFORM = 1,
32 };
33
34 enum ObjectVectorTransform { OBJECT_PASS_MOTION_PRE = 0, OBJECT_PASS_MOTION_POST = 1 };
35
36 /* Object to world space transformation */
37
38 ccl_device_inline Transform object_fetch_transform(KernelGlobals *kg,
39                                                    int object,
40                                                    enum ObjectTransform type)
41 {
42   if (type == OBJECT_INVERSE_TRANSFORM) {
43     return kernel_tex_fetch(__objects, object).itfm;
44   }
45   else {
46     return kernel_tex_fetch(__objects, object).tfm;
47   }
48 }
49
50 /* Lamp to world space transformation */
51
52 ccl_device_inline Transform lamp_fetch_transform(KernelGlobals *kg, int lamp, bool inverse)
53 {
54   if (inverse) {
55     return kernel_tex_fetch(__lights, lamp).itfm;
56   }
57   else {
58     return kernel_tex_fetch(__lights, lamp).tfm;
59   }
60 }
61
62 /* Object to world space transformation for motion vectors */
63
64 ccl_device_inline Transform object_fetch_motion_pass_transform(KernelGlobals *kg,
65                                                                int object,
66                                                                enum ObjectVectorTransform type)
67 {
68   int offset = object * OBJECT_MOTION_PASS_SIZE + (int)type;
69   return kernel_tex_fetch(__object_motion_pass, offset);
70 }
71
72 /* Motion blurred object transformations */
73
74 #ifdef __OBJECT_MOTION__
75 ccl_device_inline Transform object_fetch_transform_motion(KernelGlobals *kg,
76                                                           int object,
77                                                           float time)
78 {
79   const uint motion_offset = kernel_tex_fetch(__objects, object).motion_offset;
80   const ccl_global DecomposedTransform *motion = &kernel_tex_fetch(__object_motion, motion_offset);
81   const uint num_steps = kernel_tex_fetch(__objects, object).numsteps * 2 + 1;
82
83   Transform tfm;
84 #  ifdef __EMBREE__
85   if (kernel_data.bvh.scene) {
86     transform_motion_array_interpolate_straight(&tfm, motion, num_steps, time);
87   }
88   else
89 #  endif
90     transform_motion_array_interpolate(&tfm, motion, num_steps, time);
91
92   return tfm;
93 }
94
95 ccl_device_inline Transform object_fetch_transform_motion_test(KernelGlobals *kg,
96                                                                int object,
97                                                                float time,
98                                                                Transform *itfm)
99 {
100   int object_flag = kernel_tex_fetch(__object_flag, object);
101   if (object_flag & SD_OBJECT_MOTION) {
102     /* if we do motion blur */
103     Transform tfm = object_fetch_transform_motion(kg, object, time);
104
105     if (itfm)
106       *itfm = transform_quick_inverse(tfm);
107
108     return tfm;
109   }
110   else {
111     Transform tfm = object_fetch_transform(kg, object, OBJECT_TRANSFORM);
112     if (itfm)
113       *itfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
114
115     return tfm;
116   }
117 }
118 #endif
119
120 /* Transform position from object to world space */
121
122 ccl_device_inline void object_position_transform(KernelGlobals *kg,
123                                                  const ShaderData *sd,
124                                                  float3 *P)
125 {
126 #ifdef __OBJECT_MOTION__
127   *P = transform_point_auto(&sd->ob_tfm, *P);
128 #else
129   Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
130   *P = transform_point(&tfm, *P);
131 #endif
132 }
133
134 /* Transform position from world to object space */
135
136 ccl_device_inline void object_inverse_position_transform(KernelGlobals *kg,
137                                                          const ShaderData *sd,
138                                                          float3 *P)
139 {
140 #ifdef __OBJECT_MOTION__
141   *P = transform_point_auto(&sd->ob_itfm, *P);
142 #else
143   Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
144   *P = transform_point(&tfm, *P);
145 #endif
146 }
147
148 /* Transform normal from world to object space */
149
150 ccl_device_inline void object_inverse_normal_transform(KernelGlobals *kg,
151                                                        const ShaderData *sd,
152                                                        float3 *N)
153 {
154 #ifdef __OBJECT_MOTION__
155   if ((sd->object != OBJECT_NONE) || (sd->type == PRIMITIVE_LAMP)) {
156     *N = normalize(transform_direction_transposed_auto(&sd->ob_tfm, *N));
157   }
158 #else
159   if (sd->object != OBJECT_NONE) {
160     Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
161     *N = normalize(transform_direction_transposed(&tfm, *N));
162   }
163   else if (sd->type == PRIMITIVE_LAMP) {
164     Transform tfm = lamp_fetch_transform(kg, sd->lamp, false);
165     *N = normalize(transform_direction_transposed(&tfm, *N));
166   }
167 #endif
168 }
169
170 /* Transform normal from object to world space */
171
172 ccl_device_inline void object_normal_transform(KernelGlobals *kg, const ShaderData *sd, float3 *N)
173 {
174 #ifdef __OBJECT_MOTION__
175   *N = normalize(transform_direction_transposed_auto(&sd->ob_itfm, *N));
176 #else
177   Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
178   *N = normalize(transform_direction_transposed(&tfm, *N));
179 #endif
180 }
181
182 /* Transform direction vector from object to world space */
183
184 ccl_device_inline void object_dir_transform(KernelGlobals *kg, const ShaderData *sd, float3 *D)
185 {
186 #ifdef __OBJECT_MOTION__
187   *D = transform_direction_auto(&sd->ob_tfm, *D);
188 #else
189   Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
190   *D = transform_direction(&tfm, *D);
191 #endif
192 }
193
194 /* Transform direction vector from world to object space */
195
196 ccl_device_inline void object_inverse_dir_transform(KernelGlobals *kg,
197                                                     const ShaderData *sd,
198                                                     float3 *D)
199 {
200 #ifdef __OBJECT_MOTION__
201   *D = transform_direction_auto(&sd->ob_itfm, *D);
202 #else
203   Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_INVERSE_TRANSFORM);
204   *D = transform_direction(&tfm, *D);
205 #endif
206 }
207
208 /* Object center position */
209
210 ccl_device_inline float3 object_location(KernelGlobals *kg, const ShaderData *sd)
211 {
212   if (sd->object == OBJECT_NONE)
213     return make_float3(0.0f, 0.0f, 0.0f);
214
215 #ifdef __OBJECT_MOTION__
216   return make_float3(sd->ob_tfm.x.w, sd->ob_tfm.y.w, sd->ob_tfm.z.w);
217 #else
218   Transform tfm = object_fetch_transform(kg, sd->object, OBJECT_TRANSFORM);
219   return make_float3(tfm.x.w, tfm.y.w, tfm.z.w);
220 #endif
221 }
222
223 /* Total surface area of object */
224
225 ccl_device_inline float object_surface_area(KernelGlobals *kg, int object)
226 {
227   return kernel_tex_fetch(__objects, object).surface_area;
228 }
229
230 /* Pass ID number of object */
231
232 ccl_device_inline float object_pass_id(KernelGlobals *kg, int object)
233 {
234   if (object == OBJECT_NONE)
235     return 0.0f;
236
237   return kernel_tex_fetch(__objects, object).pass_id;
238 }
239
240 /* Per lamp random number for shader variation */
241
242 ccl_device_inline float lamp_random_number(KernelGlobals *kg, int lamp)
243 {
244   if (lamp == LAMP_NONE)
245     return 0.0f;
246
247   return kernel_tex_fetch(__lights, lamp).random;
248 }
249
250 /* Per object random number for shader variation */
251
252 ccl_device_inline float object_random_number(KernelGlobals *kg, int object)
253 {
254   if (object == OBJECT_NONE)
255     return 0.0f;
256
257   return kernel_tex_fetch(__objects, object).random_number;
258 }
259
260 /* Particle ID from which this object was generated */
261
262 ccl_device_inline int object_particle_id(KernelGlobals *kg, int object)
263 {
264   if (object == OBJECT_NONE)
265     return 0;
266
267   return kernel_tex_fetch(__objects, object).particle_index;
268 }
269
270 /* Generated texture coordinate on surface from where object was instanced */
271
272 ccl_device_inline float3 object_dupli_generated(KernelGlobals *kg, int object)
273 {
274   if (object == OBJECT_NONE)
275     return make_float3(0.0f, 0.0f, 0.0f);
276
277   const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
278   return make_float3(
279       kobject->dupli_generated[0], kobject->dupli_generated[1], kobject->dupli_generated[2]);
280 }
281
282 /* UV texture coordinate on surface from where object was instanced */
283
284 ccl_device_inline float3 object_dupli_uv(KernelGlobals *kg, int object)
285 {
286   if (object == OBJECT_NONE)
287     return make_float3(0.0f, 0.0f, 0.0f);
288
289   const ccl_global KernelObject *kobject = &kernel_tex_fetch(__objects, object);
290   return make_float3(kobject->dupli_uv[0], kobject->dupli_uv[1], 0.0f);
291 }
292
293 /* Information about mesh for motion blurred triangles and curves */
294
295 ccl_device_inline void object_motion_info(
296     KernelGlobals *kg, int object, int *numsteps, int *numverts, int *numkeys)
297 {
298   if (numkeys) {
299     *numkeys = kernel_tex_fetch(__objects, object).numkeys;
300   }
301
302   if (numsteps)
303     *numsteps = kernel_tex_fetch(__objects, object).numsteps;
304   if (numverts)
305     *numverts = kernel_tex_fetch(__objects, object).numverts;
306 }
307
308 /* Offset to an objects patch map */
309
310 ccl_device_inline uint object_patch_map_offset(KernelGlobals *kg, int object)
311 {
312   if (object == OBJECT_NONE)
313     return 0;
314
315   return kernel_tex_fetch(__objects, object).patch_map_offset;
316 }
317
318 /* Pass ID for shader */
319
320 ccl_device int shader_pass_id(KernelGlobals *kg, const ShaderData *sd)
321 {
322   return kernel_tex_fetch(__shaders, (sd->shader & SHADER_MASK)).pass_id;
323 }
324
325 /* Cryptomatte ID */
326
327 ccl_device_inline float object_cryptomatte_id(KernelGlobals *kg, int object)
328 {
329   if (object == OBJECT_NONE)
330     return 0.0f;
331
332   return kernel_tex_fetch(__objects, object).cryptomatte_object;
333 }
334
335 ccl_device_inline float object_cryptomatte_asset_id(KernelGlobals *kg, int object)
336 {
337   if (object == OBJECT_NONE)
338     return 0;
339
340   return kernel_tex_fetch(__objects, object).cryptomatte_asset;
341 }
342
343 /* Particle data from which object was instanced */
344
345 ccl_device_inline uint particle_index(KernelGlobals *kg, int particle)
346 {
347   return kernel_tex_fetch(__particles, particle).index;
348 }
349
350 ccl_device float particle_age(KernelGlobals *kg, int particle)
351 {
352   return kernel_tex_fetch(__particles, particle).age;
353 }
354
355 ccl_device float particle_lifetime(KernelGlobals *kg, int particle)
356 {
357   return kernel_tex_fetch(__particles, particle).lifetime;
358 }
359
360 ccl_device float particle_size(KernelGlobals *kg, int particle)
361 {
362   return kernel_tex_fetch(__particles, particle).size;
363 }
364
365 ccl_device float4 particle_rotation(KernelGlobals *kg, int particle)
366 {
367   return kernel_tex_fetch(__particles, particle).rotation;
368 }
369
370 ccl_device float3 particle_location(KernelGlobals *kg, int particle)
371 {
372   return float4_to_float3(kernel_tex_fetch(__particles, particle).location);
373 }
374
375 ccl_device float3 particle_velocity(KernelGlobals *kg, int particle)
376 {
377   return float4_to_float3(kernel_tex_fetch(__particles, particle).velocity);
378 }
379
380 ccl_device float3 particle_angular_velocity(KernelGlobals *kg, int particle)
381 {
382   return float4_to_float3(kernel_tex_fetch(__particles, particle).angular_velocity);
383 }
384
385 /* Object intersection in BVH */
386
387 ccl_device_inline float3 bvh_clamp_direction(float3 dir)
388 {
389   /* clamp absolute values by exp2f(-80.0f) to avoid division by zero when calculating inverse direction */
390 #if defined(__KERNEL_SSE__) && defined(__KERNEL_SSE2__)
391   const ssef oopes(8.271806E-25f, 8.271806E-25f, 8.271806E-25f, 0.0f);
392   const ssef mask = _mm_cmpgt_ps(fabs(dir), oopes);
393   const ssef signdir = signmsk(dir.m128) | oopes;
394 #  ifndef __KERNEL_AVX__
395   ssef res = mask & ssef(dir);
396   res = _mm_or_ps(res, _mm_andnot_ps(mask, signdir));
397 #  else
398   ssef res = _mm_blendv_ps(signdir, dir, mask);
399 #  endif
400   return float3(res);
401 #else  /* __KERNEL_SSE__ && __KERNEL_SSE2__ */
402   const float ooeps = 8.271806E-25f;
403   return make_float3((fabsf(dir.x) > ooeps) ? dir.x : copysignf(ooeps, dir.x),
404                      (fabsf(dir.y) > ooeps) ? dir.y : copysignf(ooeps, dir.y),
405                      (fabsf(dir.z) > ooeps) ? dir.z : copysignf(ooeps, dir.z));
406 #endif /* __KERNEL_SSE__ && __KERNEL_SSE2__ */
407 }
408
409 ccl_device_inline float3 bvh_inverse_direction(float3 dir)
410 {
411   return rcp(dir);
412 }
413
414 /* Transform ray into object space to enter static object in BVH */
415
416 ccl_device_inline float bvh_instance_push(
417     KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float t)
418 {
419   Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
420
421   *P = transform_point(&tfm, ray->P);
422
423   float len;
424   *dir = bvh_clamp_direction(normalize_len(transform_direction(&tfm, ray->D), &len));
425   *idir = bvh_inverse_direction(*dir);
426
427   if (t != FLT_MAX) {
428     t *= len;
429   }
430
431   return t;
432 }
433
434 #ifdef __QBVH__
435 /* Same as above, but optimized for QBVH scene intersection,
436  * which needs to modify two max distances.
437  *
438  * TODO(sergey): Investigate if passing NULL instead of t1 gets optimized
439  * so we can avoid having this duplication.
440  */
441 ccl_device_inline void qbvh_instance_push(KernelGlobals *kg,
442                                           int object,
443                                           const Ray *ray,
444                                           float3 *P,
445                                           float3 *dir,
446                                           float3 *idir,
447                                           float *t,
448                                           float *t1)
449 {
450   Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
451
452   *P = transform_point(&tfm, ray->P);
453
454   float len;
455   *dir = bvh_clamp_direction(normalize_len(transform_direction(&tfm, ray->D), &len));
456   *idir = bvh_inverse_direction(*dir);
457
458   if (*t != FLT_MAX)
459     *t *= len;
460
461   if (*t1 != -FLT_MAX)
462     *t1 *= len;
463 }
464 #endif
465
466 /* Transorm ray to exit static object in BVH */
467
468 ccl_device_inline float bvh_instance_pop(
469     KernelGlobals *kg, int object, const Ray *ray, float3 *P, float3 *dir, float3 *idir, float t)
470 {
471   if (t != FLT_MAX) {
472     Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
473     t /= len(transform_direction(&tfm, ray->D));
474   }
475
476   *P = ray->P;
477   *dir = bvh_clamp_direction(ray->D);
478   *idir = bvh_inverse_direction(*dir);
479
480   return t;
481 }
482
483 /* Same as above, but returns scale factor to apply to multiple intersection distances */
484
485 ccl_device_inline void bvh_instance_pop_factor(KernelGlobals *kg,
486                                                int object,
487                                                const Ray *ray,
488                                                float3 *P,
489                                                float3 *dir,
490                                                float3 *idir,
491                                                float *t_fac)
492 {
493   Transform tfm = object_fetch_transform(kg, object, OBJECT_INVERSE_TRANSFORM);
494   *t_fac = 1.0f / len(transform_direction(&tfm, ray->D));
495
496   *P = ray->P;
497   *dir = bvh_clamp_direction(ray->D);
498   *idir = bvh_inverse_direction(*dir);
499 }
500
501 #ifdef __OBJECT_MOTION__
502 /* Transform ray into object space to enter motion blurred object in BVH */
503
504 ccl_device_inline float bvh_instance_motion_push(KernelGlobals *kg,
505                                                  int object,
506                                                  const Ray *ray,
507                                                  float3 *P,
508                                                  float3 *dir,
509                                                  float3 *idir,
510                                                  float t,
511                                                  Transform *itfm)
512 {
513   object_fetch_transform_motion_test(kg, object, ray->time, itfm);
514
515   *P = transform_point(itfm, ray->P);
516
517   float len;
518   *dir = bvh_clamp_direction(normalize_len(transform_direction(itfm, ray->D), &len));
519   *idir = bvh_inverse_direction(*dir);
520
521   if (t != FLT_MAX) {
522     t *= len;
523   }
524
525   return t;
526 }
527
528 #  ifdef __QBVH__
529 /* Same as above, but optimized for QBVH scene intersection,
530  * which needs to modify two max distances.
531  *
532  * TODO(sergey): Investigate if passing NULL instead of t1 gets optimized
533  * so we can avoid having this duplication.
534  */
535 ccl_device_inline void qbvh_instance_motion_push(KernelGlobals *kg,
536                                                  int object,
537                                                  const Ray *ray,
538                                                  float3 *P,
539                                                  float3 *dir,
540                                                  float3 *idir,
541                                                  float *t,
542                                                  float *t1,
543                                                  Transform *itfm)
544 {
545   object_fetch_transform_motion_test(kg, object, ray->time, itfm);
546
547   *P = transform_point(itfm, ray->P);
548
549   float len;
550   *dir = bvh_clamp_direction(normalize_len(transform_direction(itfm, ray->D), &len));
551   *idir = bvh_inverse_direction(*dir);
552
553   if (*t != FLT_MAX)
554     *t *= len;
555
556   if (*t1 != -FLT_MAX)
557     *t1 *= len;
558 }
559 #  endif
560
561 /* Transorm ray to exit motion blurred object in BVH */
562
563 ccl_device_inline float bvh_instance_motion_pop(KernelGlobals *kg,
564                                                 int object,
565                                                 const Ray *ray,
566                                                 float3 *P,
567                                                 float3 *dir,
568                                                 float3 *idir,
569                                                 float t,
570                                                 Transform *itfm)
571 {
572   if (t != FLT_MAX) {
573     t /= len(transform_direction(itfm, ray->D));
574   }
575
576   *P = ray->P;
577   *dir = bvh_clamp_direction(ray->D);
578   *idir = bvh_inverse_direction(*dir);
579
580   return t;
581 }
582
583 /* Same as above, but returns scale factor to apply to multiple intersection distances */
584
585 ccl_device_inline void bvh_instance_motion_pop_factor(KernelGlobals *kg,
586                                                       int object,
587                                                       const Ray *ray,
588                                                       float3 *P,
589                                                       float3 *dir,
590                                                       float3 *idir,
591                                                       float *t_fac,
592                                                       Transform *itfm)
593 {
594   *t_fac = 1.0f / len(transform_direction(itfm, ray->D));
595   *P = ray->P;
596   *dir = bvh_clamp_direction(ray->D);
597   *idir = bvh_inverse_direction(*dir);
598 }
599
600 #endif
601
602 /* TODO(sergey): This is only for until we've got OpenCL 2.0
603  * on all devices we consider supported. It'll be replaced with
604  * generic address space.
605  */
606
607 #ifdef __KERNEL_OPENCL__
608 ccl_device_inline void object_position_transform_addrspace(KernelGlobals *kg,
609                                                            const ShaderData *sd,
610                                                            ccl_addr_space float3 *P)
611 {
612   float3 private_P = *P;
613   object_position_transform(kg, sd, &private_P);
614   *P = private_P;
615 }
616
617 ccl_device_inline void object_dir_transform_addrspace(KernelGlobals *kg,
618                                                       const ShaderData *sd,
619                                                       ccl_addr_space float3 *D)
620 {
621   float3 private_D = *D;
622   object_dir_transform(kg, sd, &private_D);
623   *D = private_D;
624 }
625
626 ccl_device_inline void object_normal_transform_addrspace(KernelGlobals *kg,
627                                                          const ShaderData *sd,
628                                                          ccl_addr_space float3 *N)
629 {
630   float3 private_N = *N;
631   object_normal_transform(kg, sd, &private_N);
632   *N = private_N;
633 }
634 #endif
635
636 #ifndef __KERNEL_OPENCL__
637 #  define object_position_transform_auto object_position_transform
638 #  define object_dir_transform_auto object_dir_transform
639 #  define object_normal_transform_auto object_normal_transform
640 #else
641 #  define object_position_transform_auto object_position_transform_addrspace
642 #  define object_dir_transform_auto object_dir_transform_addrspace
643 #  define object_normal_transform_auto object_normal_transform_addrspace
644 #endif
645
646 CCL_NAMESPACE_END