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