1 /*
2 * Parts adapted from Open Shading Language with this license:
3 *
4 * Copyright (c) 2009-2010 Sony Pictures Imageworks Inc., et al.
5 * All Rights Reserved.
6 *
7 * Modifications Copyright 2011, Blender Foundation.
8 *
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions are
11 * met:
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * * Neither the name of Sony Pictures Imageworks nor the names of its
18 * contributors may be used to endorse or promote products derived from
19 * this software without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 #ifndef __KERNEL_PROJECTION_CL__
34 #define __KERNEL_PROJECTION_CL__
35
36 CCL_NAMESPACE_BEGIN
37
38 /* Spherical coordinates <-> Cartesian direction */
39
direction_to_spherical(float3 dir)40 ccl_device float2 direction_to_spherical(float3 dir)
41 {
42 float theta = safe_acosf(dir.z);
43 float phi = atan2f(dir.x, dir.y);
44
45 return make_float2(theta, phi);
46 }
47
spherical_to_direction(float theta,float phi)48 ccl_device float3 spherical_to_direction(float theta, float phi)
49 {
50 float sin_theta = sinf(theta);
51 return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta));
52 }
53
54 /* Equirectangular coordinates <-> Cartesian direction */
55
direction_to_equirectangular_range(float3 dir,float4 range)56 ccl_device float2 direction_to_equirectangular_range(float3 dir, float4 range)
57 {
58 if (is_zero(dir))
59 return make_float2(0.0f, 0.0f);
60
61 float u = (atan2f(dir.y, dir.x) - range.y) / range.x;
62 float v = (acosf(dir.z / len(dir)) - range.w) / range.z;
63
64 return make_float2(u, v);
65 }
66
equirectangular_range_to_direction(float u,float v,float4 range)67 ccl_device float3 equirectangular_range_to_direction(float u, float v, float4 range)
68 {
69 float phi = range.x * u + range.y;
70 float theta = range.z * v + range.w;
71 float sin_theta = sinf(theta);
72 return make_float3(sin_theta * cosf(phi), sin_theta * sinf(phi), cosf(theta));
73 }
74
direction_to_equirectangular(float3 dir)75 ccl_device float2 direction_to_equirectangular(float3 dir)
76 {
77 return direction_to_equirectangular_range(dir, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F));
78 }
79
equirectangular_to_direction(float u,float v)80 ccl_device float3 equirectangular_to_direction(float u, float v)
81 {
82 return equirectangular_range_to_direction(u, v, make_float4(-M_2PI_F, M_PI_F, -M_PI_F, M_PI_F));
83 }
84
85 /* Fisheye <-> Cartesian direction */
86
direction_to_fisheye(float3 dir,float fov)87 ccl_device float2 direction_to_fisheye(float3 dir, float fov)
88 {
89 float r = atan2f(sqrtf(dir.y * dir.y + dir.z * dir.z), dir.x) / fov;
90 float phi = atan2f(dir.z, dir.y);
91
92 float u = r * cosf(phi) + 0.5f;
93 float v = r * sinf(phi) + 0.5f;
94
95 return make_float2(u, v);
96 }
97
fisheye_to_direction(float u,float v,float fov)98 ccl_device float3 fisheye_to_direction(float u, float v, float fov)
99 {
100 u = (u - 0.5f) * 2.0f;
101 v = (v - 0.5f) * 2.0f;
102
103 float r = sqrtf(u * u + v * v);
104
105 if (r > 1.0f)
106 return make_float3(0.0f, 0.0f, 0.0f);
107
108 float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
109 float theta = r * fov * 0.5f;
110
111 if (v < 0.0f)
112 phi = -phi;
113
114 return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
115 }
116
direction_to_fisheye_equisolid(float3 dir,float lens,float width,float height)117 ccl_device float2 direction_to_fisheye_equisolid(float3 dir, float lens, float width, float height)
118 {
119 float theta = safe_acosf(dir.x);
120 float r = 2.0f * lens * sinf(theta * 0.5f);
121 float phi = atan2f(dir.z, dir.y);
122
123 float u = r * cosf(phi) / width + 0.5f;
124 float v = r * sinf(phi) / height + 0.5f;
125
126 return make_float2(u, v);
127 }
128
129 ccl_device_inline float3
fisheye_equisolid_to_direction(float u,float v,float lens,float fov,float width,float height)130 fisheye_equisolid_to_direction(float u, float v, float lens, float fov, float width, float height)
131 {
132 u = (u - 0.5f) * width;
133 v = (v - 0.5f) * height;
134
135 float rmax = 2.0f * lens * sinf(fov * 0.25f);
136 float r = sqrtf(u * u + v * v);
137
138 if (r > rmax)
139 return make_float3(0.0f, 0.0f, 0.0f);
140
141 float phi = safe_acosf((r != 0.0f) ? u / r : 0.0f);
142 float theta = 2.0f * asinf(r / (2.0f * lens));
143
144 if (v < 0.0f)
145 phi = -phi;
146
147 return make_float3(cosf(theta), -cosf(phi) * sinf(theta), sinf(phi) * sinf(theta));
148 }
149
150 /* Mirror Ball <-> Cartesion direction */
151
mirrorball_to_direction(float u,float v)152 ccl_device float3 mirrorball_to_direction(float u, float v)
153 {
154 /* point on sphere */
155 float3 dir;
156
157 dir.x = 2.0f * u - 1.0f;
158 dir.z = 2.0f * v - 1.0f;
159
160 if (dir.x * dir.x + dir.z * dir.z > 1.0f)
161 return make_float3(0.0f, 0.0f, 0.0f);
162
163 dir.y = -sqrtf(max(1.0f - dir.x * dir.x - dir.z * dir.z, 0.0f));
164
165 /* reflection */
166 float3 I = make_float3(0.0f, -1.0f, 0.0f);
167
168 return 2.0f * dot(dir, I) * dir - I;
169 }
170
direction_to_mirrorball(float3 dir)171 ccl_device float2 direction_to_mirrorball(float3 dir)
172 {
173 /* inverse of mirrorball_to_direction */
174 dir.y -= 1.0f;
175
176 float div = 2.0f * sqrtf(max(-0.5f * dir.y, 0.0f));
177 if (div > 0.0f)
178 dir /= div;
179
180 float u = 0.5f * (dir.x + 1.0f);
181 float v = 0.5f * (dir.z + 1.0f);
182
183 return make_float2(u, v);
184 }
185
panorama_to_direction(ccl_constant KernelCamera * cam,float u,float v)186 ccl_device_inline float3 panorama_to_direction(ccl_constant KernelCamera *cam, float u, float v)
187 {
188 switch (cam->panorama_type) {
189 case PANORAMA_EQUIRECTANGULAR:
190 return equirectangular_range_to_direction(u, v, cam->equirectangular_range);
191 case PANORAMA_MIRRORBALL:
192 return mirrorball_to_direction(u, v);
193 case PANORAMA_FISHEYE_EQUIDISTANT:
194 return fisheye_to_direction(u, v, cam->fisheye_fov);
195 case PANORAMA_FISHEYE_EQUISOLID:
196 default:
197 return fisheye_equisolid_to_direction(
198 u, v, cam->fisheye_lens, cam->fisheye_fov, cam->sensorwidth, cam->sensorheight);
199 }
200 }
201
direction_to_panorama(ccl_constant KernelCamera * cam,float3 dir)202 ccl_device_inline float2 direction_to_panorama(ccl_constant KernelCamera *cam, float3 dir)
203 {
204 switch (cam->panorama_type) {
205 case PANORAMA_EQUIRECTANGULAR:
206 return direction_to_equirectangular_range(dir, cam->equirectangular_range);
207 case PANORAMA_MIRRORBALL:
208 return direction_to_mirrorball(dir);
209 case PANORAMA_FISHEYE_EQUIDISTANT:
210 return direction_to_fisheye(dir, cam->fisheye_fov);
211 case PANORAMA_FISHEYE_EQUISOLID:
212 default:
213 return direction_to_fisheye_equisolid(
214 dir, cam->fisheye_lens, cam->sensorwidth, cam->sensorheight);
215 }
216 }
217
spherical_stereo_transform(ccl_constant KernelCamera * cam,float3 * P,float3 * D)218 ccl_device_inline void spherical_stereo_transform(ccl_constant KernelCamera *cam,
219 float3 *P,
220 float3 *D)
221 {
222 float interocular_offset = cam->interocular_offset;
223
224 /* Interocular offset of zero means either non stereo, or stereo without
225 * spherical stereo. */
226 kernel_assert(interocular_offset != 0.0f);
227
228 if (cam->pole_merge_angle_to > 0.0f) {
229 const float pole_merge_angle_from = cam->pole_merge_angle_from,
230 pole_merge_angle_to = cam->pole_merge_angle_to;
231 float altitude = fabsf(safe_asinf((*D).z));
232 if (altitude > pole_merge_angle_to) {
233 interocular_offset = 0.0f;
234 }
235 else if (altitude > pole_merge_angle_from) {
236 float fac = (altitude - pole_merge_angle_from) /
237 (pole_merge_angle_to - pole_merge_angle_from);
238 float fade = cosf(fac * M_PI_2_F);
239 interocular_offset *= fade;
240 }
241 }
242
243 float3 up = make_float3(0.0f, 0.0f, 1.0f);
244 float3 side = normalize(cross(*D, up));
245 float3 stereo_offset = side * interocular_offset;
246
247 *P += stereo_offset;
248
249 /* Convergence distance is FLT_MAX in the case of parallel convergence mode,
250 * no need to modify direction in this case either. */
251 const float convergence_distance = cam->convergence_distance;
252
253 if (convergence_distance != FLT_MAX) {
254 float3 screen_offset = convergence_distance * (*D);
255 *D = normalize(screen_offset - stereo_offset);
256 }
257 }
258
259 CCL_NAMESPACE_END
260
261 #endif /* __KERNEL_PROJECTION_CL__ */
262