1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110
|
// Copyright 2017 Intel Corporation
// SPDX-License-Identifier: Apache-2.0
#include "ArcballCamera.h"
ArcballCamera::ArcballCamera(const rkcommon::math::box3f &worldBounds,
const rkcommon::math::vec2i &windowSize)
: zoomSpeed(1),
invWindowSize(
rkcommon::math::vec2f(1.0) / rkcommon::math::vec2f(windowSize)),
centerTranslation(rkcommon::math::one),
translation(rkcommon::math::one),
rotation(rkcommon::math::one)
{
rkcommon::math::vec3f diag = worldBounds.size();
zoomSpeed = rkcommon::math::max(length(diag) / 150.0, 0.001);
diag = rkcommon::math::max(diag, rkcommon::math::vec3f(0.3f * length(diag)));
centerTranslation =
rkcommon::math::AffineSpace3f::translate(-worldBounds.center());
translation = rkcommon::math::AffineSpace3f::translate(
rkcommon::math::vec3f(0, 0, length(diag)));
updateCamera();
}
void ArcballCamera::rotate(
const rkcommon::math::vec2f &from, const rkcommon::math::vec2f &to)
{
rotation = screenToArcball(to) * screenToArcball(from) * rotation;
updateCamera();
}
void ArcballCamera::zoom(float amount)
{
amount *= zoomSpeed;
translation = rkcommon::math::AffineSpace3f::translate(
rkcommon::math::vec3f(0, 0, amount))
* translation;
updateCamera();
}
void ArcballCamera::pan(const rkcommon::math::vec2f &delta)
{
const rkcommon::math::vec3f t = rkcommon::math::vec3f(
-delta.x * invWindowSize.x, delta.y * invWindowSize.y, 0);
const rkcommon::math::vec3f worldt =
translation.p.z * xfmVector(invCamera, t);
centerTranslation =
rkcommon::math::AffineSpace3f::translate(worldt) * centerTranslation;
updateCamera();
}
rkcommon::math::vec3f ArcballCamera::eyePos() const
{
return xfmPoint(invCamera, rkcommon::math::vec3f(0, 0, 1));
}
rkcommon::math::vec3f ArcballCamera::center() const
{
return -centerTranslation.p;
}
rkcommon::math::vec3f ArcballCamera::lookDir() const
{
return xfmVector(invCamera, rkcommon::math::vec3f(0, 0, 1));
}
rkcommon::math::vec3f ArcballCamera::upDir() const
{
return xfmVector(invCamera, rkcommon::math::vec3f(0, 1, 0));
}
rkcommon::math::AffineSpace3f ArcballCamera::transform() const
{
return invCamera;
}
void ArcballCamera::updateCamera()
{
const rkcommon::math::AffineSpace3f rot =
rkcommon::math::LinearSpace3f(rotation);
const rkcommon::math::AffineSpace3f camera =
translation * rot * centerTranslation;
invCamera = rcp(camera);
}
void ArcballCamera::setRotation(rkcommon::math::quatf q)
{
rotation = q;
updateCamera();
}
void ArcballCamera::updateWindowSize(const rkcommon::math::vec2i &windowSize)
{
invWindowSize = rkcommon::math::vec2f(1) / rkcommon::math::vec2f(windowSize);
}
rkcommon::math::quatf ArcballCamera::screenToArcball(
const rkcommon::math::vec2f &p)
{
const float dist = dot(p, p);
// If we're on/in the sphere return the point on it
if (dist <= 1.f) {
return rkcommon::math::quatf(0, p.x, p.y, std::sqrt(1.f - dist));
} else {
// otherwise we project the point onto the sphere
const rkcommon::math::vec2f unitDir = normalize(p);
return rkcommon::math::quatf(0, unitDir.x, unitDir.y, 0);
}
}
|