Cycles: Remove ccl_fetch and SOA
[blender.git] / intern / cycles / kernel / geom / geom_motion_triangle_intersect.h
1 /*
2  * Copyright 2011-2016 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 /* Motion Triangle Primitive
18  *
19  * These are stored as regular triangles, plus extra positions and normals at
20  * times other than the frame center. Computing the triangle vertex positions
21  * or normals at a given ray time is a matter of interpolation of the two steps
22  * between which the ray time lies.
23  *
24  * The extra positions and normals are stored as ATTR_STD_MOTION_VERTEX_POSITION
25  * and ATTR_STD_MOTION_VERTEX_NORMAL mesh attributes.
26  */
27
28 CCL_NAMESPACE_BEGIN
29
30 /* Refine triangle intersection to more precise hit point. For rays that travel
31  * far the precision is often not so good, this reintersects the primitive from
32  * a closer distance.
33  */
34
35 ccl_device_inline float3 motion_triangle_refine(KernelGlobals *kg,
36                                                 ShaderData *sd,
37                                                 const Intersection *isect,
38                                                 const Ray *ray,
39                                                 float3 verts[3])
40 {
41         float3 P = ray->P;
42         float3 D = ray->D;
43         float t = isect->t;
44
45 #ifdef __INTERSECTION_REFINE__
46         if(isect->object != OBJECT_NONE) {
47                 if(UNLIKELY(t == 0.0f)) {
48                         return P;
49                 }
50 #  ifdef __OBJECT_MOTION__
51                 Transform tfm = sd->ob_itfm;
52 #  else
53                 Transform tfm = object_fetch_transform(kg,
54                                                        isect->object,
55                                                        OBJECT_INVERSE_TRANSFORM);
56 #  endif
57
58                 P = transform_point(&tfm, P);
59                 D = transform_direction(&tfm, D*t);
60                 D = normalize_len(D, &t);
61         }
62
63         P = P + D*t;
64
65         /* Compute refined intersection distance. */
66         const float3 e1 = verts[0] - verts[2];
67         const float3 e2 = verts[1] - verts[2];
68         const float3 s1 = cross(D, e2);
69
70         const float invdivisor = 1.0f/dot(s1, e1);
71         const float3 d = P - verts[2];
72         const float3 s2 = cross(d, e1);
73         float rt = dot(e2, s2)*invdivisor;
74
75         /* Compute refined position. */
76         P = P + D*rt;
77
78         if(isect->object != OBJECT_NONE) {
79 #  ifdef __OBJECT_MOTION__
80                 Transform tfm = sd->ob_tfm;
81 #  else
82                 Transform tfm = object_fetch_transform(kg,
83                                                        isect->object,
84                                                        OBJECT_TRANSFORM);
85 #  endif
86
87                 P = transform_point(&tfm, P);
88         }
89
90         return P;
91 #else
92         return P + D*t;
93 #endif
94 }
95
96 /* Same as above, except that isect->t is assumed to be in object space
97  * for instancing.
98  */
99
100 #ifdef __SUBSURFACE__
101 #  if defined(__KERNEL_CUDA__) && (defined(i386) || defined(_M_IX86))
102 ccl_device_noinline
103 #  else
104 ccl_device_inline
105 #  endif
106 float3 motion_triangle_refine_subsurface(KernelGlobals *kg,
107                                          ShaderData *sd,
108                                          const Intersection *isect,
109                                          const Ray *ray,
110                                          float3 verts[3])
111 {
112         float3 P = ray->P;
113         float3 D = ray->D;
114         float t = isect->t;
115
116 #  ifdef __INTERSECTION_REFINE__
117         if(isect->object != OBJECT_NONE) {
118 #    ifdef __OBJECT_MOTION__
119                 Transform tfm = sd->ob_itfm;
120 #    else
121                 Transform tfm = object_fetch_transform(kg,
122                                                        isect->object,
123                                                        OBJECT_INVERSE_TRANSFORM);
124 #    endif
125
126                 P = transform_point(&tfm, P);
127                 D = transform_direction(&tfm, D);
128                 D = normalize(D);
129         }
130
131         P = P + D*t;
132
133         /* compute refined intersection distance */
134         const float3 e1 = verts[0] - verts[2];
135         const float3 e2 = verts[1] - verts[2];
136         const float3 s1 = cross(D, e2);
137
138         const float invdivisor = 1.0f/dot(s1, e1);
139         const float3 d = P - verts[2];
140         const float3 s2 = cross(d, e1);
141         float rt = dot(e2, s2)*invdivisor;
142
143         P = P + D*rt;
144
145         if(isect->object != OBJECT_NONE) {
146 #    ifdef __OBJECT_MOTION__
147                 Transform tfm = sd->ob_tfm;
148 #    else
149                 Transform tfm = object_fetch_transform(kg,
150                                                        isect->object,
151                                                        OBJECT_TRANSFORM);
152 #    endif
153
154                 P = transform_point(&tfm, P);
155         }
156
157         return P;
158 #  else  /* __INTERSECTION_REFINE__ */
159         return P + D*t;
160 #  endif  /* __INTERSECTION_REFINE__ */
161 }
162 #endif  /* __SUBSURFACE__ */
163
164
165 /* Ray intersection. We simply compute the vertex positions at the given ray
166  * time and do a ray intersection with the resulting triangle.
167  */
168
169 ccl_device_inline bool motion_triangle_intersect(KernelGlobals *kg,
170                                                  Intersection *isect,
171                                                  float3 P,
172                                                  float3 dir,
173                                                  float time,
174                                                  uint visibility,
175                                                  int object,
176                                                  int prim_addr)
177 {
178         /* Primitive index for vertex location lookup. */
179         int prim = kernel_tex_fetch(__prim_index, prim_addr);
180         int fobject = (object == OBJECT_NONE)
181                           ? kernel_tex_fetch(__prim_object, prim_addr)
182                           : object;
183         /* Get vertex locations for intersection. */
184         float3 verts[3];
185         motion_triangle_vertices(kg, fobject, prim, time, verts);
186         /* Ray-triangle intersection, unoptimized. */
187         float t, u, v;
188         if(ray_triangle_intersect_uv(P,
189                                      dir,
190                                      isect->t,
191                                      verts[2], verts[0], verts[1],
192                                      &u, &v, &t))
193         {
194 #ifdef __VISIBILITY_FLAG__
195                 /* Visibility flag test. we do it here under the assumption
196                  * that most triangles are culled by node flags.
197                  */
198                 if(kernel_tex_fetch(__prim_visibility, prim_addr) & visibility)
199 #endif
200                 {
201                         isect->t = t;
202                         isect->u = u;
203                         isect->v = v;
204                         isect->prim = prim_addr;
205                         isect->object = object;
206                         isect->type = PRIMITIVE_MOTION_TRIANGLE;
207                         return true;
208                 }
209         }
210         return false;
211 }
212
213 /* Special ray intersection routines for subsurface scattering. In that case we
214  * only want to intersect with primitives in the same object, and if case of
215  * multiple hits we pick a single random primitive as the intersection point.
216  */
217 #ifdef __SUBSURFACE__
218 ccl_device_inline void motion_triangle_intersect_subsurface(
219         KernelGlobals *kg,
220         SubsurfaceIntersection *ss_isect,
221         float3 P,
222         float3 dir,
223         float time,
224         int object,
225         int prim_addr,
226         float tmax,
227         uint *lcg_state,
228         int max_hits)
229 {
230         /* Primitive index for vertex location lookup. */
231         int prim = kernel_tex_fetch(__prim_index, prim_addr);
232         int fobject = (object == OBJECT_NONE)
233                           ? kernel_tex_fetch(__prim_object, prim_addr)
234                           : object;
235         /* Get vertex locations for intersection. */
236         float3 verts[3];
237         motion_triangle_vertices(kg, fobject, prim, time, verts);
238         /* Ray-triangle intersection, unoptimized. */
239         float t, u, v;
240         if(ray_triangle_intersect_uv(P,
241                                      dir,
242                                      tmax,
243                                      verts[2], verts[0], verts[1],
244                                      &u, &v, &t))
245         {
246                 for(int i = min(max_hits, ss_isect->num_hits) - 1; i >= 0; --i) {
247                         if(ss_isect->hits[i].t == t) {
248                                 return;
249                         }
250                 }
251                 ss_isect->num_hits++;
252                 int hit;
253                 if(ss_isect->num_hits <= max_hits) {
254                         hit = ss_isect->num_hits - 1;
255                 }
256                 else {
257                         /* Reservoir sampling: if we are at the maximum number of
258                          * hits, randomly replace element or skip it.
259                          */
260                         hit = lcg_step_uint(lcg_state) % ss_isect->num_hits;
261
262                         if(hit >= max_hits)
263                                 return;
264                 }
265                 /* Record intersection. */
266                 Intersection *isect = &ss_isect->hits[hit];
267                 isect->t = t;
268                 isect->u = u;
269                 isect->v = v;
270                 isect->prim = prim_addr;
271                 isect->object = object;
272                 isect->type = PRIMITIVE_MOTION_TRIANGLE;
273                 /* Record geometric normal. */
274                 ss_isect->Ng[hit] = normalize(cross(verts[1] - verts[0],
275                                                     verts[2] - verts[0]));
276         }
277 }
278 #endif  /* __SUBSURFACE__ */
279
280 CCL_NAMESPACE_END