4a06dff84bfba5c307c9fe58791459dd3931033f
[blender.git] / intern / cycles / kernel / kernel_primitive.h
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 #ifndef __KERNEL_ATTRIBUTE_CL__
18 #define __KERNEL_ATTRIBUTE_CL__
19
20 CCL_NAMESPACE_BEGIN
21
22 /* attribute lookup */
23
24 __device_inline int find_attribute(KernelGlobals *kg, ShaderData *sd, uint id, AttributeElement *elem)
25 {
26         if(sd->object == ~0)
27                 return (int)ATTR_STD_NOT_FOUND;
28
29 #ifdef __OSL__
30         if (kg->osl) {
31                 return OSLShader::find_attribute(kg, sd, id, elem);
32         }
33         else
34 #endif
35         {
36                 /* for SVM, find attribute by unique id */
37                 uint attr_offset = sd->object*kernel_data.bvh.attributes_map_stride;
38 #ifdef __HAIR__
39                 attr_offset = (sd->segment == ~0)? attr_offset: attr_offset + ATTR_PRIM_CURVE;
40 #endif
41                 uint4 attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
42                 
43                 while(attr_map.x != id) {
44                         attr_offset += ATTR_PRIM_TYPES;
45                         attr_map = kernel_tex_fetch(__attributes_map, attr_offset);
46                 }
47
48                 *elem = (AttributeElement)attr_map.y;
49                 
50                 /* return result */
51                 return (attr_map.y == ATTR_ELEMENT_NONE) ? (int)ATTR_STD_NOT_FOUND : (int)attr_map.z;
52         }
53 }
54
55 __device float primitive_attribute_float(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float *dx, float *dy)
56 {
57 #ifdef __HAIR__
58         if(sd->segment == ~0)
59 #endif
60                 return triangle_attribute_float(kg, sd, elem, offset, dx, dy);
61 #ifdef __HAIR__
62         else
63                 return curve_attribute_float(kg, sd, elem, offset, dx, dy);
64 #endif
65 }
66
67 __device float3 primitive_attribute_float3(KernelGlobals *kg, const ShaderData *sd, AttributeElement elem, int offset, float3 *dx, float3 *dy)
68 {
69 #ifdef __HAIR__
70         if(sd->segment == ~0)
71 #endif
72                 return triangle_attribute_float3(kg, sd, elem, offset, dx, dy);
73 #ifdef __HAIR__
74         else
75                 return curve_attribute_float3(kg, sd, elem, offset, dx, dy);
76 #endif
77 }
78
79 __device float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
80 {
81         AttributeElement elem_uv;
82         int offset_uv = find_attribute(kg, sd, ATTR_STD_UV, &elem_uv);
83
84         if(offset_uv == ATTR_STD_NOT_FOUND)
85                 return make_float3(0.0f, 0.0f, 0.0f);
86
87         float3 uv = primitive_attribute_float3(kg, sd, elem_uv, offset_uv, NULL, NULL);
88         uv.z = 1.0f;
89         return uv;
90 }
91
92 __device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
93 {
94 #ifdef __HAIR__
95         if(sd->segment != ~0)
96                 return normalize(sd->dPdu);
97 #endif
98
99         /* try to create spherical tangent from generated coordinates */
100         AttributeElement attr_elem;
101         int attr_offset = find_attribute(kg, sd, ATTR_STD_GENERATED, &attr_elem);
102
103         if(attr_offset != ATTR_STD_NOT_FOUND) {
104                 float3 data = primitive_attribute_float3(kg, sd, attr_elem, attr_offset, NULL, NULL);
105                 data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
106                 object_normal_transform(kg, sd, &data);
107                 return cross(sd->N, normalize(cross(data, sd->N)));
108         }
109         else {
110                 /* otherwise use surface derivatives */
111                 return normalize(sd->dPdu);
112         }
113 }
114
115 /* motion */
116
117 __device float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
118 {
119         float3 motion_pre = sd->P, motion_post = sd->P;
120
121         /* deformation motion */
122         AttributeElement elem_pre, elem_post;
123         int offset_pre = find_attribute(kg, sd, ATTR_STD_MOTION_PRE, &elem_pre);
124         int offset_post = find_attribute(kg, sd, ATTR_STD_MOTION_POST, &elem_post);
125
126         if(offset_pre != ATTR_STD_NOT_FOUND)
127                 motion_pre = primitive_attribute_float3(kg, sd, elem_pre, offset_pre, NULL, NULL);
128         if(offset_post != ATTR_STD_NOT_FOUND)
129                 motion_post = primitive_attribute_float3(kg, sd, elem_post, offset_post, NULL, NULL);
130
131         /* object motion. note that depending on the mesh having motion vectors, this
132          * transformation was set match the world/object space of motion_pre/post */
133         Transform tfm;
134         
135         tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
136         motion_pre = transform_point(&tfm, motion_pre);
137
138         tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
139         motion_post = transform_point(&tfm, motion_post);
140
141         float3 P;
142
143         /* camera motion, for perspective/orthographic motion.pre/post will be a
144          * world-to-raster matrix, for panorama it's world-to-camera */
145         if (kernel_data.cam.type != CAMERA_PANORAMA) {
146                 tfm = kernel_data.cam.worldtoraster;
147                 P = transform_perspective(&tfm, sd->P);
148
149                 tfm = kernel_data.cam.motion.pre;
150                 motion_pre = transform_perspective(&tfm, motion_pre);
151
152                 tfm = kernel_data.cam.motion.post;
153                 motion_post = transform_perspective(&tfm, motion_post);
154         }
155         else {
156                 tfm = kernel_data.cam.worldtocamera;
157                 P = normalize(transform_point(&tfm, sd->P));
158                 P = float2_to_float3(direction_to_panorama(kg, P));
159                 P.x *= kernel_data.cam.width;
160                 P.y *= kernel_data.cam.height;
161
162                 tfm = kernel_data.cam.motion.pre;
163                 motion_pre = normalize(transform_point(&tfm, motion_pre));
164                 motion_pre = float2_to_float3(direction_to_panorama(kg, motion_pre));
165                 motion_pre.x *= kernel_data.cam.width;
166                 motion_pre.y *= kernel_data.cam.height;
167
168                 tfm = kernel_data.cam.motion.post;
169                 motion_post = normalize(transform_point(&tfm, motion_post));
170                 motion_post = float2_to_float3(direction_to_panorama(kg, motion_post));
171                 motion_post.x *= kernel_data.cam.width;
172                 motion_post.y *= kernel_data.cam.height;
173         }
174
175         motion_pre = motion_pre - P;
176         motion_post = P - motion_post;
177
178         return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
179 }
180
181 CCL_NAMESPACE_END
182
183 #endif /* __KERNEL_ATTRIBUTE_CL__ */