#pragma once #include #include #include #include using namespace embree; /* camera settings */ struct Camera { enum Handedness { LEFT_HANDED, RIGHT_HANDED }; struct ISPCCamera { public: ISPCCamera(const AffineSpace3f& xfm) : xfm(xfm) { } public: AffineSpace3f xfm; float render_time = 0.0f; }; public: Camera() : from(0.0001f, 0.0001f, -3.0f), to(0, 0, 0), up(0, 1, 0), fov(90), handedness(RIGHT_HANDED) { } Camera(const Vec3fa& from, const Vec3fa& to, const Vec3fa& up, float fov, Handedness handedness) : from(from), to(to), up(up), fov(fov), handedness(handedness) { } // Camera (const SceneGraph::PerspectiveCameraData& cam, Handedness handedness) // : from(cam.from), to(cam.to), up(cam.up), fov(cam.fov), handedness(handedness) {} std::string str() const { std::stringstream stream; stream.precision(10); stream << "--vp " << from.x << " " << from.y << " " << from.z << " " << "--vi " << to.x << " " << to.y << " " << to.z << " " << "--vu " << up.x << " " << up.y << " " << up.z << " " << "--fov " << fov << " " << (handedness == LEFT_HANDED ? "--lefthanded" : "--righthanded"); return stream.str(); } AffineSpace3fa camera2world() { AffineSpace3fa local2world = AffineSpace3fa::lookat(from, to, up); if (!(local2world == local2world)) throw std::runtime_error("invalid camera specified"); if (handedness == RIGHT_HANDED) local2world.l.vx = -local2world.l.vx; return local2world; } AffineSpace3fa world2camera() { return rcp(camera2world()); } Vec3fa world2camera(const Vec3fa& p) { return xfmPoint(world2camera(), p); } Vec3fa camera2world(const Vec3fa& p) { return xfmPoint(camera2world(), p); } ISPCCamera getISPCCamera(size_t width, size_t height) { const float fovScale = 1.0f / tanf(deg2rad(0.5f * fov)); const AffineSpace3fa local2world = camera2world(); Vec3fa vx = local2world.l.vx; Vec3fa vy = -local2world.l.vy; Vec3fa vz = -0.5f * width * local2world.l.vx + 0.5f * height * local2world.l.vy + 0.5f * height * fovScale * local2world.l.vz; Vec3fa p = local2world.p; return ISPCCamera(AffineSpace3f(vx, vy, vz, p)); } void move(float dx, float dy, float dz) { AffineSpace3fa xfm = camera2world(); Vec3fa ds = xfmVector(xfm, Vec3fa(dx, dy, dz)); from += ds; to += ds; } void rotate(float dtheta, float dphi) { if (handedness == RIGHT_HANDED) dtheta *= -1.0f; const Vec3fa up1 = normalize(up); Vec3fa view1 = normalize(to - from); view1 = xfmVector(AffineSpace3fa::rotate(up1, dtheta), view1); const float phi = acosf(dot(view1, up1)); const float dphi2 = phi - clamp(phi - dphi, 0.001f * float(pi), 0.999f * float(pi)); view1 = xfmVector(AffineSpace3fa::rotate(cross(view1, up1), dphi2), view1); to = from + length(to - from) * view1; } void rotateOrbit(float dtheta, float dphi) { if (handedness == RIGHT_HANDED) dtheta *= -1.0f; const Vec3fa up1 = normalize(up); Vec3fa view1 = normalize(to - from); view1 = xfmVector(AffineSpace3fa::rotate(up1, dtheta), view1); const float phi = acosf(dot(view1, up1)); const float dphi2 = phi - clamp(phi - dphi, 0.001f * float(pi), 0.999f * float(pi)); view1 = xfmVector(AffineSpace3fa::rotate(cross(view1, up1), dphi2), view1); from = to - length(to - from) * view1; } void dolly(float ds) { float dollySpeed = 0.01f; float k = powf((1.0f - dollySpeed), ds); from += length(to - from) * (1 - k) * normalize(to - from); } public: Vec3fa from; //!< position of camera Vec3fa to; //!< look at point Vec3fa up; //!< up vector float fov; //!< field of view Handedness handedness; }; typedef Camera::ISPCCamera ISPCCamera;