Fix for attribute lookup in OSL. This uses a map in the OSL globals instead of the...
[blender.git] / intern / cycles / kernel / kernel_triangle.h
1 /*
2  * Copyright 2011, Blender Foundation.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  */
18
19 #include "kernel_projection.h"
20
21 #include "util_param.h"
22
23 CCL_NAMESPACE_BEGIN
24
25 /* Point on triangle for Moller-Trumbore triangles */
26 __device_inline float3 triangle_point_MT(KernelGlobals *kg, int tri_index, float u, float v)
27 {
28         /* load triangle vertices */
29         float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, tri_index));
30
31         float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
32         float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
33         float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
34
35         /* compute point */
36         float t = 1.0f - u - v;
37         return (u*v0 + v*v1 + t*v2);
38 }
39
40 /* Sample point on triangle */
41 __device_inline float3 triangle_sample_MT(KernelGlobals *kg, int tri_index, float randu, float randv)
42 {
43         /* compute point */
44         randu = sqrtf(randu);
45
46         float u = 1.0f - randu;
47         float v = randv*randu;
48
49         return triangle_point_MT(kg, tri_index, u, v);
50 }
51
52 /* Normal for Moller-Trumbore triangles */
53 __device_inline float3 triangle_normal_MT(KernelGlobals *kg, int tri_index, int *shader)
54 {
55 #if 0
56         /* load triangle vertices */
57         float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, tri_index));
58
59         float3 v0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
60         float3 v1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
61         float3 v2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
62
63         /* compute normal */
64         return normalize(cross(v2 - v0, v1 - v0));
65 #else
66         float4 Nm = kernel_tex_fetch(__tri_normal, tri_index);
67         *shader = __float_as_int(Nm.w);
68         return make_float3(Nm.x, Nm.y, Nm.z);
69 #endif
70 }
71
72 __device_inline float3 triangle_smooth_normal(KernelGlobals *kg, int tri_index, float u, float v)
73 {
74         /* load triangle vertices */
75         float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, tri_index));
76
77         float3 n0 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.x)));
78         float3 n1 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.y)));
79         float3 n2 = float4_to_float3(kernel_tex_fetch(__tri_vnormal, __float_as_int(tri_vindex.z)));
80
81         return normalize((1.0f - u - v)*n2 + u*n0 + v*n1);
82 }
83
84 __device_inline void triangle_dPdudv(KernelGlobals *kg, float3 *dPdu, float3 *dPdv, int tri)
85 {
86         /* fetch triangle vertex coordinates */
87         float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, tri));
88
89         float3 p0 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.x)));
90         float3 p1 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.y)));
91         float3 p2 = float4_to_float3(kernel_tex_fetch(__tri_verts, __float_as_int(tri_vindex.z)));
92
93         /* compute derivatives of P w.r.t. uv */
94         *dPdu = (p0 - p2);
95         *dPdv = (p1 - p2);
96 }
97
98 /* attributes */
99
100 __device float triangle_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
101 {
102         if(elem == ATTR_ELEMENT_FACE) {
103                 if(dx) *dx = 0.0f;
104                 if(dy) *dy = 0.0f;
105
106                 return kernel_tex_fetch(__attributes_float, offset + sd->prim);
107         }
108         else if(elem == ATTR_ELEMENT_VERTEX) {
109                 float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
110
111                 float f0 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.x));
112                 float f1 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.y));
113                 float f2 = kernel_tex_fetch(__attributes_float, offset + __float_as_int(tri_vindex.z));
114
115 #ifdef __RAY_DIFFERENTIALS__
116                 if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
117                 if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
118 #endif
119
120                 return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
121         }
122         else if(elem == ATTR_ELEMENT_CORNER) {
123                 int tri = offset + sd->prim*3;
124                 float f0 = kernel_tex_fetch(__attributes_float, tri + 0);
125                 float f1 = kernel_tex_fetch(__attributes_float, tri + 1);
126                 float f2 = kernel_tex_fetch(__attributes_float, tri + 2);
127
128 #ifdef __RAY_DIFFERENTIALS__
129                 if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
130                 if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
131 #endif
132
133                 return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
134         }
135         else {
136                 if(dx) *dx = 0.0f;
137                 if(dy) *dy = 0.0f;
138
139                 return 0.0f;
140         }
141 }
142
143 __device float3 triangle_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
144 {
145         if(elem == ATTR_ELEMENT_FACE) {
146                 if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
147                 if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
148
149                 return float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + sd->prim));
150         }
151         else if(elem == ATTR_ELEMENT_VERTEX) {
152                 float3 tri_vindex = float4_to_float3(kernel_tex_fetch(__tri_vindex, sd->prim));
153
154                 float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.x)));
155                 float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.y)));
156                 float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, offset + __float_as_int(tri_vindex.z)));
157
158 #ifdef __RAY_DIFFERENTIALS__
159                 if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
160                 if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
161 #endif
162
163                 return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
164         }
165         else if(elem == ATTR_ELEMENT_CORNER) {
166                 int tri = offset + sd->prim*3;
167                 float3 f0 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 0));
168                 float3 f1 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 1));
169                 float3 f2 = float4_to_float3(kernel_tex_fetch(__attributes_float3, tri + 2));
170
171 #ifdef __RAY_DIFFERENTIALS__
172                 if(dx) *dx = sd->du.dx*f0 + sd->dv.dx*f1 - (sd->du.dx + sd->dv.dx)*f2;
173                 if(dy) *dy = sd->du.dy*f0 + sd->dv.dy*f1 - (sd->du.dy + sd->dv.dy)*f2;
174 #endif
175
176                 return sd->u*f0 + sd->v*f1 + (1.0f - sd->u - sd->v)*f2;
177         }
178         else {
179                 if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
180                 if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
181
182                 return make_float3(0.0f, 0.0f, 0.0f);
183         }
184 }
185
186 /* motion */
187
188 /* note: declared in kernel.h, have to add it here because kernel.h is not available */
189 bool kernel_osl_use(KernelGlobals *kg);
190
191 __device int triangle_find_attribute(KernelGlobals *kg, ShaderData *sd, uint id)
192 {
193
194 #ifdef __OSL__
195         if (kernel_osl_use(kg)) {
196                 /* for OSL, a hash map is used to lookup the attribute by name. */
197                 OSLGlobals::AttributeMap &attr_map = kg->osl.attribute_map[sd->object];
198                 ustring stdname = ustring(std::string("std::") + attribute_standard_name((AttributeStandard)id).c_str());
199                 OSLGlobals::AttributeMap::const_iterator it = attr_map.find(stdname);
200                 if (it != attr_map.end()) {
201                         const OSLGlobals::Attribute &osl_attr = it->second;
202                         /* return result */
203                         return (osl_attr.elem == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : osl_attr.offset;
204                 }
205                 else
206                         return (int)ATTR_STD_NOT_FOUND;
207         }
208         else
209 #endif
210         {
211                 /* for SVM, find attribute by unique id */
212                 uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
213                 uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
214                 
215                 while(attr_map.x != id)
216                         attr_map = kernel_tex_fetch(__attributes_map, ++attr_offset);
217                 
218                 /* return result */
219                 return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : attr_map.z;
220         }
221 }
222
223 __device float4 triangle_motion_vector(KernelGlobals *kg, ShaderData *sd)
224 {
225         float3 motion_pre = sd->P, motion_post = sd->P;
226
227         /* deformation motion */
228         int offset_pre = triangle_find_attribute(kg, sd, ATTR_STD_MOTION_PRE);
229         int offset_post = triangle_find_attribute(kg, sd, ATTR_STD_MOTION_POST);
230
231         if(offset_pre != ATTR_STD_NOT_FOUND)
232                 motion_pre = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_pre, NULL, NULL);
233         if(offset_post != ATTR_STD_NOT_FOUND)
234                 motion_post = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_VERTEX, offset_post, NULL, NULL);
235
236         /* object motion. note that depending on the mesh having motion vectors, this
237          * transformation was set match the world/object space of motion_pre/post */
238         Transform tfm;
239         
240         tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_TRANSFORM_MOTION_PRE);
241         motion_pre = transform_point(&tfm, motion_pre);
242
243         tfm = object_fetch_transform(kg, sd->object, TIME_INVALID, OBJECT_TRANSFORM_MOTION_POST);
244         motion_post = transform_point(&tfm, motion_post);
245
246         float3 P;
247
248         /* camera motion, for perspective/orthographic motion.pre/post will be a
249          * world-to-raster matrix, for panorama it's world-to-camera */
250         if (kernel_data.cam.type != CAMERA_PANORAMA) {
251                 tfm = kernel_data.cam.worldtoraster;
252                 P = transform_perspective(&tfm, sd->P);
253
254                 tfm = kernel_data.cam.motion.pre;
255                 motion_pre = transform_perspective(&tfm, motion_pre);
256
257                 tfm = kernel_data.cam.motion.post;
258                 motion_post = transform_perspective(&tfm, motion_post);
259         }
260         else {
261                 tfm = kernel_data.cam.worldtocamera;
262                 P = normalize(transform_point(&tfm, sd->P));
263                 P = float2_to_float3(direction_to_panorama(kg, P));
264                 P.x *= kernel_data.cam.width;
265                 P.y *= kernel_data.cam.height;
266
267                 tfm = kernel_data.cam.motion.pre;
268                 motion_pre = normalize(transform_point(&tfm, motion_pre));
269                 motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre));
270                 motion_pre.x *= kernel_data.cam.width;
271                 motion_pre.y *= kernel_data.cam.height;
272
273                 tfm = kernel_data.cam.motion.post;
274                 motion_post = normalize(transform_point(&tfm, motion_post));
275                 motion_post = float2_to_float3(direction_to_panorama(kg, motion_post));
276                 motion_post.x *= kernel_data.cam.width;
277                 motion_post.y *= kernel_data.cam.height;
278         }
279
280         motion_pre = motion_pre - P;
281         motion_post = P - motion_post;
282
283         return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
284 }
285
286 __device float3 triangle_uv(KernelGlobals *kg, ShaderData *sd)
287 {
288         int offset_uv = triangle_find_attribute(kg, sd, ATTR_STD_UV);
289
290         if(offset_uv == ATTR_STD_NOT_FOUND)
291                 return make_float3(0.0f, 0.0f, 0.0f);
292
293         float3 uv = triangle_attribute_float3(kg, sd, ATTR_ELEMENT_CORNER, offset_uv, NULL, NULL);
294         uv.z = 1.0f;
295         return uv;
296 }
297
298 CCL_NAMESPACE_END
299