Fermat
camera.h
1 /*
2  * Fermat
3  *
4  * Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  * * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * * Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * * Neither the name of the NVIDIA CORPORATION nor the
14  * names of its contributors may be used to endorse or promote products
15  * derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL NVIDIA CORPORATION BE LIABLE FOR ANY
21  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #pragma once
30 
31 #include "types.h"
32 
33 #include <optixu/optixu_matrix.h>
34 
35 #include <cugar/linalg/vector.h>
36 
39 
43 
46 struct Camera
47 {
48  float3 eye;
49  float3 aim;
50  float3 up;
51  float3 dx;
52  float fov;
53 
54 #if !defined(OPTIX_COMPILATION)
55  FERMAT_HOST_DEVICE Camera() :
56  fov(60.0f * float(M_PI) / 180.0f)
57  {
58  eye = make_float3(0, -1, 0);
59  aim = make_float3(0, 0, 0);
60  up = make_float3(0, 0, 1);
61  dx = make_float3(1, 0, 0);
62  }
63 #endif
64 
65  FERMAT_HOST_DEVICE Camera rotate(const float2 rot) const
66  {
67  Camera r;
68  optix::Matrix<4, 4> rot_X = optix::Matrix<4, 4>::rotate(rot.x, dx);
69  //optix::Matrix<4, 4> rot_Y = optix::Matrix<4, 4>::rotate(rot.y, up);
70  optix::Matrix<4, 4> rot_Y = optix::Matrix<4, 4>::rotate(rot.y, make_float3(0,1,0));
71 
72  const float4 heye = make_float4(eye.x, eye.y, eye.z, 1.0f);
73  const float4 haim = make_float4(aim.x, aim.y, aim.z, 1.0f);
74  const float4 hup = make_float4(up.x, up.y, up.z, 0.0f);
75  const float4 hdx = make_float4(dx.x, dx.y, dx.z, 0.0f);
76  const float4 tdir = rot_Y * rot_X * (heye - haim);
77  const float4 teye = haim + tdir;
78  const float4 tup = rot_Y * rot_X * hup;
79  const float4 tdx = rot_Y * rot_X * hdx;
80 
81  r.eye = make_float3(teye.x, teye.y, teye.z);
82  r.aim = aim;
83  r.up = make_float3(tup.x, tup.y, tup.z);
84  r.dx = make_float3(tdx.x, tdx.y, tdx.z);
85  r.fov = fov;
86  return r;
87  }
88  FERMAT_HOST_DEVICE Camera walk(const float delta) const
89  {
90  Camera r;
91  r.eye = eye + (aim - eye)*delta;
92  r.aim = aim + (aim - eye)*delta;
93  r.up = up;
94  r.dx = normalize(cross(r.aim - r.eye, r.up));
95  r.fov = fov;
96  return r;
97  }
98  FERMAT_HOST_DEVICE Camera pan(const float2 delta) const
99  {
100  Camera r;
101  r.eye = eye + up*delta.y - dx * delta.x;
102  r.aim = aim + up*delta.y - dx * delta.x;
103  r.up = up;
104  r.dx = dx;
105  r.fov = fov;
106  return r;
107  }
108  FERMAT_HOST_DEVICE Camera zoom(const float delta) const
109  {
110  Camera r;
111  r.eye = eye;
112  r.aim = aim;
113  r.up = up;
114  r.dx = dx;
115  r.fov = fov * (1.0f + delta);
116  r.fov = fmaxf(fminf(r.fov, float(M_PI) - 0.1f), 0.05f);
117  return r;
118  }
119 
120  // return the image plane distance needed to have pixels with unit area
121  FERMAT_HOST_DEVICE
122  float square_pixel_focal_length(
123  const uint32 res_x,
124  const uint32 res_y) const
125  {
126  const float t = tanf(fov / 2);
127  return (float(res_x * res_y) / 4.0f) / (t*t);
128  }
129 
130  // return the image plane distance needed to have screen with unit area
131  FERMAT_HOST_DEVICE
132  float square_screen_focal_length() const
133  {
134  const float t = tanf(fov / 2);
135  return (1.0f / 4.0f) / (t*t);
136  }
137 };
138 
141 FERMAT_HOST_DEVICE
142 inline void camera_frame(cugar::Vector3f eye, cugar::Vector3f lookat, cugar::Vector3f up, float hfov, float aspect_ratio, cugar::Vector3f& U, cugar::Vector3f& V, cugar::Vector3f& W)
143 {
144  float ulen, vlen, wlen;
145  W.x = lookat.x - eye.x;
146  W.y = lookat.y - eye.y;
147  W.z = lookat.z - eye.z;
148 
149  wlen = sqrtf(cugar::dot(W, W));
150 
151  U = cugar::normalize(cugar::cross(W, up));
152  V = cugar::normalize(cugar::cross(U, W));
153 
154  ulen = wlen * tanf(hfov / 2.0f);
155  U.x *= ulen;
156  U.y *= ulen;
157  U.z *= ulen;
158 
159  vlen = ulen / aspect_ratio;
160  V.x *= vlen;
161  V.y *= vlen;
162  V.z *= vlen;
163 }
164 
167 FERMAT_HOST_DEVICE
168 inline void camera_frame(const Camera camera, float aspect_ratio, cugar::Vector3f& U, cugar::Vector3f& V, cugar::Vector3f& W)
169 {
170  camera_frame(camera.eye, camera.aim, camera.up, camera.fov, aspect_ratio, U, V, W);
171 }
172 
175 FERMAT_HOST_DEVICE
177  const cugar::Vector2f ndc,
178  const cugar::Vector3f U,
179  const cugar::Vector3f V,
180  const cugar::Vector3f W)
181 {
182  const cugar::Vector2f d = ndc * 2.f - 1.f;
183 
184  return d.x*U + d.y*V + W;
185 }
186 
189 FERMAT_HOST_DEVICE
190 inline cugar::Vector2f invert_camera_sampler(const cugar::Vector3f& U, const cugar::Vector3f& V, const cugar::Vector3f& W, const float W_len, const cugar::Vector3f out)
191 {
192  const float t = cugar::dot(out, cugar::Vector3f(W)) / (W_len*W_len);
193  if (t < 0.0f)
194  return cugar::Vector2f(-1.0f); // out of bounds
195 
196  const cugar::Vector3f I = out / t - W;
197  const float Ix = dot(I, U) / cugar::square_length(U);
198  const float Iy = dot(I, V) / cugar::square_length(V);
199 
200  return cugar::Vector2f( Ix*0.5f + 0.5f, Iy*0.5f + 0.5f );
201 }
202 
205 FERMAT_HOST_DEVICE
206 inline float camera_direction_pdf(const cugar::Vector3f& U, const cugar::Vector3f& V, const cugar::Vector3f& W, const float W_len, const float square_focal_length, const cugar::Vector3f out, float* out_x = 0, float* out_y = 0)
207 {
208  const float t = cugar::dot(out, cugar::Vector3f(W)) / (W_len*W_len);
209  if (t < 0.0f)
210  return 0.0f;
211 
212  const cugar::Vector3f I = out / t - W;
213  const float Ix = dot(I, U) / cugar::square_length(U);
214  const float Iy = dot(I, V) / cugar::square_length(V);
215 
216  if (Ix >= -1.0f && Ix <= 1.0f &&
217  Iy >= -1.0f && Iy <= 1.0f)
218  {
219  if (out_x) *out_x = Ix;
220  if (out_y) *out_y = Iy;
221 
222  const float cos_theta = dot(out, W) / W_len;
223  return square_focal_length / (cos_theta * cos_theta * cos_theta * cos_theta);
224  }
225 
226  return 0.0f;
227 }
228 
231 FERMAT_HOST_DEVICE
232 inline float camera_direction_pdf(const cugar::Vector3f& U, const cugar::Vector3f& V, const cugar::Vector3f& W, const float W_len, const float square_focal_length, const cugar::Vector3f out, bool projected = false)
233 {
234  const float t = cugar::dot(out, cugar::Vector3f(W)) / (W_len*W_len);
235  if (t < 0.0f)
236  return 0.0f;
237 
238  const cugar::Vector3f I = out / t - W;
239  const float Ix = dot(I, U) / cugar::square_length(U);
240  const float Iy = dot(I, V) / cugar::square_length(V);
241 
242  if (Ix >= -1.0f && Ix <= 1.0f &&
243  Iy >= -1.0f && Iy <= 1.0f)
244  {
245  const float cos_theta = dot(out, W) / W_len;
246  return projected ?
247  square_focal_length / (cos_theta * cos_theta * cos_theta * cos_theta) :
248  square_focal_length / (cos_theta * cos_theta * cos_theta);
249  }
250 
251  return 0.0f;
252 }
253 
257 {
260  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
262 
265  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
266  CameraSampler(const Camera& camera, const float aspect_ratio)
267  {
268  camera_frame( camera, aspect_ratio, U, V, W );
269 
270  W_len = cugar::length(W);
271 
272  square_focal_length = camera.square_screen_focal_length();
273  }
274 
277  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
279  {
280  return sample_camera_direction( ndc, U, V, W );
281  }
282 
285  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
286  float pdf(const cugar::Vector3f out, const bool projected = false) const
287  {
288  return camera_direction_pdf( U, V, W, W_len, square_focal_length, out, projected );
289  }
290 
293  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
294  float W_e(const cugar::Vector3f out) const
295  {
296  return camera_direction_pdf( U, V, W, W_len, square_focal_length, out, true );
297  }
298 
304  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
306  {
307  return invert_camera_sampler( U, V, W, W_len, out );
308  }
309 
315  FERMAT_HOST_DEVICE FERMAT_FORCEINLINE
316  cugar::Vector2f invert(const cugar::Vector3f out, float* pdf_proj) const
317  {
318  const cugar::Vector2f ndc = invert_camera_sampler( U, V, W, W_len, out );
319 
320  if (ndc.x >= 0.0f && ndc.x <= 1.0f &&
321  ndc.y >= 0.0f && ndc.y <= 1.0f)
322  {
323  const float cos_theta = dot(out, W) / W_len;
324  *pdf_proj = square_focal_length / (cos_theta * cos_theta * cos_theta * cos_theta);
325  }
326  else
327  *pdf_proj = 0.0f;
328 
329  return ndc;
330  }
331 
332  cugar::Vector3f U; // camera space +X axis in world coords
333  cugar::Vector3f V; // camera space +Y axis in world coords
334  cugar::Vector3f W; // camera space +Z axis in world coords
335  float W_len; // precomputed length of the W vector
336  float square_focal_length; // square focal length
337 };
338 
339 
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE float pdf(const cugar::Vector3f out, const bool projected=false) const
Definition: camera.h:286
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE float W_e(const cugar::Vector3f out) const
Definition: camera.h:294
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE cugar::Vector2f invert(const cugar::Vector3f out, float *pdf_proj) const
Definition: camera.h:316
FERMAT_HOST_DEVICE cugar::Vector2f invert_camera_sampler(const cugar::Vector3f &U, const cugar::Vector3f &V, const cugar::Vector3f &W, const float W_len, const cugar::Vector3f out)
Definition: camera.h:190
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE cugar::Vector3f sample_direction(const cugar::Vector2f ndc) const
Definition: camera.h:278
Definition: camera.h:256
FERMAT_HOST_DEVICE void camera_frame(cugar::Vector3f eye, cugar::Vector3f lookat, cugar::Vector3f up, float hfov, float aspect_ratio, cugar::Vector3f &U, cugar::Vector3f &V, cugar::Vector3f &W)
Definition: camera.h:142
Definition: camera.h:46
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE CameraSampler(const Camera &camera, const float aspect_ratio)
Definition: camera.h:266
FERMAT_HOST_DEVICE cugar::Vector3f sample_camera_direction(const cugar::Vector2f ndc, const cugar::Vector3f U, const cugar::Vector3f V, const cugar::Vector3f W)
Definition: camera.h:176
FERMAT_HOST_DEVICE float camera_direction_pdf(const cugar::Vector3f &U, const cugar::Vector3f &V, const cugar::Vector3f &W, const float W_len, const float square_focal_length, const cugar::Vector3f out, float *out_x=0, float *out_y=0)
Definition: camera.h:206
CUGAR_FORCEINLINE CUGAR_HOST_DEVICE uint32 length(const vector_view< Iterator > &vec)
Definition: vector_view.h:228
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE cugar::Vector2f invert(const cugar::Vector3f out) const
Definition: camera.h:305
FERMAT_HOST_DEVICE FERMAT_FORCEINLINE CameraSampler()
Definition: camera.h:261