-
Notifications
You must be signed in to change notification settings - Fork 177
/
ArcballCamera.cpp
105 lines (91 loc) · 3.05 KB
/
ArcballCamera.cpp
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
// Copyright 2017-2020 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));
}
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::quaternionf q)
{
rotation = q;
updateCamera();
}
void ArcballCamera::updateWindowSize(const rkcommon::math::vec2i &windowSize)
{
invWindowSize = rkcommon::math::vec2f(1) / rkcommon::math::vec2f(windowSize);
}
rkcommon::math::quaternionf 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::quaternionf(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::quaternionf(0, unitDir.x, unitDir.y, 0);
}
}