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