60a1e483b847056ba968a697af07e10df02e96ef
[blender.git] / intern / cycles / kernel / geom / geom_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 /* Primitive Utilities
18  *
19  * Generic functions to look up mesh, curve and volume primitive attributes for
20  * shading and render passes. */
21
22 CCL_NAMESPACE_BEGIN
23
24 /* Generic primitive attribute reading functions */
25
26 ccl_device_inline float primitive_attribute_float(KernelGlobals *kg,
27                                                   const ShaderData *sd,
28                                                   const AttributeDescriptor desc,
29                                                   float *dx, float *dy)
30 {
31         if(sd->type & PRIMITIVE_ALL_TRIANGLE) {
32                 if(subd_triangle_patch(kg, sd) == ~0)
33                         return triangle_attribute_float(kg, sd, desc, dx, dy);
34                 else
35                         return subd_triangle_attribute_float(kg, sd, desc, dx, dy);
36         }
37 #ifdef __HAIR__
38         else if(sd->type & PRIMITIVE_ALL_CURVE) {
39                 return curve_attribute_float(kg, sd, desc, dx, dy);
40         }
41 #endif
42 #ifdef __VOLUME__
43         else if(sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
44                 return volume_attribute_float(kg, sd, desc, dx, dy);
45         }
46 #endif
47         else {
48                 if(dx) *dx = 0.0f;
49                 if(dy) *dy = 0.0f;
50                 return 0.0f;
51         }
52 }
53
54 ccl_device_inline float3 primitive_attribute_float3(KernelGlobals *kg,
55                                                     const ShaderData *sd,
56                                                     const AttributeDescriptor desc,
57                                                     float3 *dx, float3 *dy)
58 {
59         if(sd->type & PRIMITIVE_ALL_TRIANGLE) {
60                 if(subd_triangle_patch(kg, sd) == ~0)
61                         return triangle_attribute_float3(kg, sd, desc, dx, dy);
62                 else
63                         return subd_triangle_attribute_float3(kg, sd, desc, dx, dy);
64         }
65 #ifdef __HAIR__
66         else if(sd->type & PRIMITIVE_ALL_CURVE) {
67                 return curve_attribute_float3(kg, sd, desc, dx, dy);
68         }
69 #endif
70 #ifdef __VOLUME__
71         else if(sd->object != OBJECT_NONE && desc.element == ATTR_ELEMENT_VOXEL) {
72                 return volume_attribute_float3(kg, sd, desc, dx, dy);
73         }
74 #endif
75         else {
76                 if(dx) *dx = make_float3(0.0f, 0.0f, 0.0f);
77                 if(dy) *dy = make_float3(0.0f, 0.0f, 0.0f);
78                 return make_float3(0.0f, 0.0f, 0.0f);
79         }
80 }
81
82 /* Default UV coordinate */
83
84 ccl_device_inline float3 primitive_uv(KernelGlobals *kg, ShaderData *sd)
85 {
86         const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_UV);
87
88         if(desc.offset == ATTR_STD_NOT_FOUND)
89                 return make_float3(0.0f, 0.0f, 0.0f);
90
91         float3 uv = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
92         uv.z = 1.0f;
93         return uv;
94 }
95
96 /* Ptex coordinates */
97
98 ccl_device bool primitive_ptex(KernelGlobals *kg, ShaderData *sd, float2 *uv, int *face_id)
99 {
100         /* storing ptex data as attributes is not memory efficient but simple for tests */
101         const AttributeDescriptor desc_face_id = find_attribute(kg, sd, ATTR_STD_PTEX_FACE_ID);
102         const AttributeDescriptor desc_uv = find_attribute(kg, sd, ATTR_STD_PTEX_UV);
103
104         if(desc_face_id.offset == ATTR_STD_NOT_FOUND || desc_uv.offset == ATTR_STD_NOT_FOUND)
105                 return false;
106
107         float3 uv3 = primitive_attribute_float3(kg, sd, desc_uv, NULL, NULL);
108         float face_id_f = primitive_attribute_float(kg, sd, desc_face_id, NULL, NULL);
109
110         *uv = make_float2(uv3.x, uv3.y);
111         *face_id = (int)face_id_f;
112
113         return true;
114 }
115
116 /* Surface tangent */
117
118 ccl_device float3 primitive_tangent(KernelGlobals *kg, ShaderData *sd)
119 {
120 #ifdef __HAIR__
121         if(sd->type & PRIMITIVE_ALL_CURVE)
122 #  ifdef __DPDU__
123                 return normalize(sd->dPdu);
124 #  else
125                 return make_float3(0.0f, 0.0f, 0.0f);
126 #  endif
127 #endif
128
129         /* try to create spherical tangent from generated coordinates */
130         const AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_GENERATED);
131
132         if(desc.offset != ATTR_STD_NOT_FOUND) {
133                 float3 data = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
134                 data = make_float3(-(data.y - 0.5f), (data.x - 0.5f), 0.0f);
135                 object_normal_transform(kg, sd, &data);
136                 return cross(sd->N, normalize(cross(data, sd->N)));
137         }
138         else {
139                 /* otherwise use surface derivatives */
140 #ifdef __DPDU__
141                 return normalize(sd->dPdu);
142 #else
143                 return make_float3(0.0f, 0.0f, 0.0f);
144 #endif
145         }
146 }
147
148 /* Motion vector for motion pass */
149
150 ccl_device_inline float4 primitive_motion_vector(KernelGlobals *kg, ShaderData *sd)
151 {
152         /* center position */
153         float3 center;
154
155 #ifdef __HAIR__
156         bool is_curve_primitive = sd->type & PRIMITIVE_ALL_CURVE;
157         if(is_curve_primitive) {
158                 center = curve_motion_center_location(kg, sd);
159
160                 if(!(sd->object_flag & SD_OBJECT_TRANSFORM_APPLIED)) {
161                         object_position_transform(kg, sd, &center);
162                 }
163         }
164         else
165 #endif
166                 center = sd->P;
167
168         float3 motion_pre = center, motion_post = center;
169
170         /* deformation motion */
171         AttributeDescriptor desc = find_attribute(kg, sd, ATTR_STD_MOTION_VERTEX_POSITION);
172
173         if(desc.offset != ATTR_STD_NOT_FOUND) {
174                 /* get motion info */
175                 int numverts, numkeys;
176                 object_motion_info(kg, sd->object, NULL, &numverts, &numkeys);
177
178                 /* lookup attributes */
179                 motion_pre = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
180
181                 desc.offset += (sd->type & PRIMITIVE_ALL_TRIANGLE)? numverts: numkeys;
182                 motion_post = primitive_attribute_float3(kg, sd, desc, NULL, NULL);
183
184 #ifdef __HAIR__
185                 if(is_curve_primitive && (sd->object_flag & SD_OBJECT_HAS_VERTEX_MOTION) == 0) {
186                         object_position_transform(kg, sd, &motion_pre);
187                         object_position_transform(kg, sd, &motion_post);
188                 }
189 #endif
190         }
191
192         /* object motion. note that depending on the mesh having motion vectors, this
193          * transformation was set match the world/object space of motion_pre/post */
194         Transform tfm;
195         
196         tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_PRE);
197         motion_pre = transform_point(&tfm, motion_pre);
198
199         tfm = object_fetch_vector_transform(kg, sd->object, OBJECT_VECTOR_MOTION_POST);
200         motion_post = transform_point(&tfm, motion_post);
201
202         float3 motion_center;
203
204         /* camera motion, for perspective/orthographic motion.pre/post will be a
205          * world-to-raster matrix, for panorama it's world-to-camera */
206         if(kernel_data.cam.type != CAMERA_PANORAMA) {
207                 tfm = kernel_data.cam.worldtoraster;
208                 motion_center = transform_perspective(&tfm, center);
209
210                 tfm = kernel_data.cam.motion.pre;
211                 motion_pre = transform_perspective(&tfm, motion_pre);
212
213                 tfm = kernel_data.cam.motion.post;
214                 motion_post = transform_perspective(&tfm, motion_post);
215         }
216         else {
217                 tfm = kernel_data.cam.worldtocamera;
218                 motion_center = normalize(transform_point(&tfm, center));
219                 motion_center = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_center));
220                 motion_center.x *= kernel_data.cam.width;
221                 motion_center.y *= kernel_data.cam.height;
222
223                 tfm = kernel_data.cam.motion.pre;
224                 motion_pre = normalize(transform_point(&tfm, motion_pre));
225                 motion_pre = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_pre));
226                 motion_pre.x *= kernel_data.cam.width;
227                 motion_pre.y *= kernel_data.cam.height;
228
229                 tfm = kernel_data.cam.motion.post;
230                 motion_post = normalize(transform_point(&tfm, motion_post));
231                 motion_post = float2_to_float3(direction_to_panorama(&kernel_data.cam, motion_post));
232                 motion_post.x *= kernel_data.cam.width;
233                 motion_post.y *= kernel_data.cam.height;
234         }
235
236         motion_pre = motion_pre - motion_center;
237         motion_post = motion_center - motion_post;
238
239         return make_float4(motion_pre.x, motion_pre.y, motion_post.x, motion_post.y);
240 }
241
242 CCL_NAMESPACE_END
243