1// Copyright 2009-2021 Intel Corporation
2// SPDX-License-Identifier: Apache-2.0
3
4#include "Camera.ih"
5#include "common/MotionTransform.ih"
6#include "math/sampling.ih"
7#include "ospray/OSPEnums.h"
8
9struct PanoramicCamera
10{
11  Camera super;
12
13  vec3f org;
14  linear3f frame; // union: precomputed frame; or (xxx, up, -dir) if motion blur
15  int stereoMode;
16  float ipd_offset; // half of the interpupillary distance
17};
18
19void PanoramicCamera_initRay(const Camera *uniform _self,
20    varying Ray &ray,
21    const varying CameraSample &sample)
22{
23  const PanoramicCamera *uniform self = (const PanoramicCamera *uniform)_self;
24
25  vec2f screen = sample.screen;
26
27  varying float *uniform split =
28      self->stereoMode == OSP_STEREO_SIDE_BY_SIDE ? &screen.x : &screen.y;
29  float offset = 0.f;
30  switch (self->stereoMode) {
31  case OSP_STEREO_LEFT:
32    offset = -self->ipd_offset;
33    break;
34  case OSP_STEREO_RIGHT:
35    offset = self->ipd_offset;
36    break;
37  case OSP_STEREO_SIDE_BY_SIDE:
38  case OSP_STEREO_TOP_BOTTOM:
39    *split *= 2.f;
40    if (*split < 1.f) {
41      offset = -self->ipd_offset;
42    } else {
43      offset = self->ipd_offset;
44      *split -= 1.f;
45    }
46    break;
47  }
48
49  screen = Camera_subRegion(_self, screen);
50
51  const float phi = two_pi * screen.x;
52  const float theta = M_PI * screen.y;
53
54  float sinTheta, cosTheta;
55  sincos(theta, &sinTheta, &cosTheta);
56  const vec3f localDir = cartesian(phi, sinTheta, cosTheta);
57
58  const float time = Camera_shutterTime(_self, screen, sample.time);
59
60  // transform to camera- and then to world-space
61  vec3f dir;
62  vec3f org;
63  if (self->super.motionBlur) {
64    const affine3f xfm = getInterpolatedTransform(self->super.geom, time);
65
66    // we cannot just transform the final org & dir, because interpolated
67    // transforms can scale (even if original transforms are without scale)
68    linear3f frameMB;
69    frameMB.vz = normalize(xfmVector(xfm, self->frame.vz));
70    frameMB.vx = normalize(cross(xfmVector(xfm, self->frame.vy), frameMB.vz));
71    frameMB.vy = cross(frameMB.vz, frameMB.vx);
72
73    dir = frameMB * make_vec3f(-localDir.y, -localDir.z, localDir.x);
74    org = xfmPoint(xfm, self->org) + offset * cross(dir, frameMB.vy);
75  } else {
76    dir = self->frame * make_vec3f(-localDir.y, -localDir.z, localDir.x);
77    org = self->org + offset * cross(dir, self->frame.vy);
78  }
79
80  setRay(ray, org, dir, self->super.nearClip, inf, time);
81}
82
83export void *uniform PanoramicCamera_create()
84{
85  PanoramicCamera *uniform self = uniform new PanoramicCamera;
86  self->super.initRay = PanoramicCamera_initRay;
87  self->stereoMode = OSP_STEREO_NONE;
88  self->ipd_offset = 0.f;
89  return self;
90}
91
92export void PanoramicCamera_set(void *uniform _self,
93    const uniform vec3f &org,
94    const uniform vec3f &dir,
95    const uniform vec3f &up,
96    const uniform int stereoMode,
97    const uniform float ipd)
98{
99  PanoramicCamera *uniform self = (PanoramicCamera * uniform) _self;
100
101  self->org = org;
102
103  if (self->super.motionBlur) {
104    self->frame.vz = neg(dir);
105    self->frame.vy = up;
106  } else {
107    self->frame.vz = neg(normalize(dir));
108    self->frame.vx = normalize(cross(up, self->frame.vz));
109    self->frame.vy = cross(self->frame.vz, self->frame.vx);
110  }
111
112  self->stereoMode = stereoMode;
113  self->ipd_offset = 0.5f * ipd;
114  // flip offset to have left eye at top (image coord origin at lower left)
115  if (stereoMode == OSP_STEREO_TOP_BOTTOM)
116    self->ipd_offset = -self->ipd_offset;
117}
118