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