Permalink
Browse files

WIP: adding arcball style camera controls. This doesn't work yet!

It compiles but is full of bugs. This checkin is just so I've got a safety net...
  • Loading branch information...
1 parent 756796a commit eae56f51b32ba0c7f7ff5bc366da4a759a3c5a0d @vilya committed Aug 10, 2010
Showing with 179 additions and 1 deletion.
  1. +2 −1 example/Makefile
  2. +120 −0 example/arcball.cpp
  3. +29 −0 src/vgl_ray3.h
  4. +28 −0 src/vgl_vec3.h
View
@@ -31,13 +31,14 @@ LIBS := -L$(DIST)/lib -lvgl
endif
EXAMPLE_APPS := \
+ $(BIN)/arcball \
$(BIN)/basic \
$(BIN)/example \
$(BIN)/imageview \
$(BIN)/styled
-.PRECIOUS: $(OBJ)/basic.o $(OBJ)/example.o
+.PRECIOUS: $(OBJ)/arcball.o $(OBJ)/basic.o $(OBJ)/example.o $(OBJ)/imageview.o $(OBJ)/styled.o
.PHONY: debug
View
@@ -0,0 +1,120 @@
+#include "vgl.h"
+
+class ArcballRenderer : public vgl::Renderer
+{
+public:
+ ArcballRenderer() {}
+
+ virtual void setup() {
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_LIGHT0);
+ glShadeModel(GL_SMOOTH);
+ }
+
+ virtual void render() {
+ static const float kTeapotColor[] = { 0.6, 0.6, 0.6, 1.0 };
+ static const float kSphereColor[] = { 0.3, 0.3, 0.8, 0.5 };
+
+ glEnable(GL_LIGHTING);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, kTeapotColor);
+ glutSolidTeapot(0.5);
+
+ glDisable(GL_LIGHTING);
+ glColor4fv(kSphereColor);
+ glutWireSphere(1, 20, 20);
+ }
+};
+
+
+class ArcballCamera : public vgl::Camera
+{
+public:
+ ArcballCamera(const vgl::Vec3f& pos, const vgl::Vec3f& target, const vgl::Vec3f& up,
+ float left, float right, float bottom, float top, float aperture,
+ unsigned int pixelWidth, unsigned int pixelHeight) :
+ vgl::Camera(pos, target, up, left, right, bottom, top, aperture, pixelWidth, pixelHeight)
+ {}
+
+
+ vgl::Vec3f unproject(double x, double y, double z = 0)
+ {
+ vgl::Matrix4d projectionMatrix;
+ vgl::Matrix4d modelViewMatrix;
+ vgl::Vec4i viewportMatrix;
+
+ glGetDoublev(GL_PROJECTION_MATRIX, projectionMatrix.data);
+ glGetDoublev(GL_MODELVIEW_MATRIX, modelViewMatrix.data);
+ glGetIntegerv(GL_VIEWPORT, viewportMatrix.data);
+
+ vgl::Vec3d point;
+ gluUnProject(x, y, z,
+ modelViewMatrix.data, projectionMatrix.data, viewportMatrix.data,
+ &point.x, &point.y, &point.z);
+
+ return vgl::Vec3f((float)point.x, (float)point.y, (float)point.z);
+ }
+
+
+ void arcballRoll(int prevX, int prevY, int currX, int currY)
+ {
+ vgl::Vec3f prev = unproject(prevX, prevY);
+ vgl::Vec3f curr = unproject(currX, currY);
+
+ float sphereRadius = std::tan(_aperture / 2.0f) * length(_target - _pos);
+
+ vgl::Ray3f prevRay(_pos, prev - _pos);
+ vgl::Ray3f currRay(_pos, prev - _pos);
+
+ vgl::Vec3f prevHit, currHit;
+ if ( intersectRaySphere(prevRay, _target, sphereRadius, prevHit) &&
+ intersectRaySphere(currRay, _target, sphereRadius, currHit) )
+ {
+ vgl::Vec3f axisOfRotation = cross(prevHit - _target, currHit - _target);
+ float angleOfRotation = std::acos(dot(currHit, prevHit));
+
+ _pos = rotate(_pos - _target, axisOfRotation, angleOfRotation) + _target;
+ }
+ }
+};
+
+
+class ArcballViewer : public vgl::Viewer
+{
+public:
+ ArcballViewer(int width, int height,
+ vgl::Camera* camera, vgl::Renderer* renderer) :
+ vgl::Viewer("Arcball Test", width, height, camera, renderer)
+ {}
+
+ virtual void actionHandler(int action) {
+ if (action != ACTION_ROLL_CAMERA)
+ vgl::Viewer::actionHandler(action);
+ else
+ arcballRoll();
+ }
+
+ void arcballRoll() {
+ ArcballCamera* cam = dynamic_cast<ArcballCamera*>(_camera);
+ if (cam == NULL)
+ return;
+
+ cam->arcballRoll(_prevMouseX, (_height - 1) - _prevMouseY, _mouseX, (_height - 1) - _mouseY);
+ glutPostRedisplay();
+ }
+};
+
+
+int main(int argc, char** argv)
+{
+ const int kWidth = 800;
+ const int kHeight = 600;
+
+ ArcballCamera camera(
+ vgl::Vec3f(0, 0, 5), vgl::Vec3f(0, 0, 0), vgl::Vec3f(0, 1, 0),
+ -1, 1, -1, 1, 30, kWidth, kHeight);
+ ArcballRenderer renderer;
+ ArcballViewer viewer(kWidth, kHeight, &camera, &renderer);
+ viewer.run();
+ return 0;
+}
+
View
@@ -54,6 +54,35 @@ Ray3<Num> refract(const Ray3<Num>& r, const Vec3<Num>& hitpos, const Vec3<Num>&
}
+template <typename Num>
+bool intersectRaySphere(const Ray3<Num>& ray, const Vec3<Num>& sphereCenter, Num sphereRadius, Vec3<Num>& hitPoint)
+{
+ const Num kMinT = 1e-4;
+ const Num kMaxT = 1e10;
+
+ Vec3<Num> m(ray.o - sphereCenter);
+
+ Num a = dot(ray.d, ray.d);
+ Num b = 2 * dot(ray.d, m);
+ Num c = dot(m, m) - sphereRadius * sphereRadius;
+
+ Num discriminant = b * b - 4 * a * c;
+ if (discriminant > 0) {
+ float sqrt_discriminant = std::sqrt(discriminant);
+ float t = (-b - sqrt_discriminant) / (2 * a);
+ if (t < kMinT)
+ t = (-b + sqrt_discriminant) / (2 * a);
+ if (t < kMinT || t > kMaxT)
+ return false;
+
+ hitPoint = evaluate(ray, t);
+ return true;
+ }
+
+ return false;
+}
+
+
} // namespace vgl
#endif // vgl_ray_h
View
@@ -258,6 +258,34 @@ Vec3<Num> rotateZ(const Vec3<Num>& a, Num radians)
}
+template <typename Num>
+Vec3<Num> rotate(const Vec3<Num>& a, const Vec3<Num>& axis, Num radians)
+{
+ Num c = std::cos(radians);
+ Num s = std::cos(radians);
+
+ Vec3<Num> n = norm(axis);
+ Num x = n.x;
+ Num y = n.y;
+ Num z = n.z;
+
+ Vec3<Num> out(
+ ( (sqr(x) * (1 - c) + c) * a.x +
+ (x * y * (1 - c) - z * s) * a.y +
+ (x * z * (1 - c) + y * s) * a.z ),
+
+ ( (y * x * (1 - c) + z * s) * a.x +
+ (sqr(y) * (1 - c) + c) * a.y +
+ (y * z * (1 - c) - x * s) * a.z ),
+
+ ( (x * z * (1 - c) - y * s) * a.x +
+ (y * z * (1 - c) + x * s) * a.y +
+ (sqr(z) * (1 - c) + c) * a.z )
+ );
+ return out;
+}
+
+
} // namespace vgl
#endif // vgl_vec3_h

0 comments on commit eae56f5

Please sign in to comment.