205 lines
4.8 KiB
C++

// File: Viewer.cpp
// Author: mankyu sung
#include <iostream>
#include "Viewer.h"
#include <glm/gtc/quaternion.hpp>
static float DEFAULT_TRANSLATE_SPEED = 0.5;
static float DEFAULT_ZOOM_FRACTION = 2.5;
static float DEFAULT_ROTATE_SPEED = 2.0;
using namespace std;
Viewer::Viewer(
const glm::vec3 &viewPoint, const glm::vec3 &viewCenter, const glm::vec3 &upVector,
float fieldOfView, float aspectRatio
) :
m_viewPoint(viewPoint),
m_viewCenter(viewCenter),
m_upVector(upVector),
m_fieldOfView(fieldOfView),
m_aspectRatio(aspectRatio),
m_translateSpeed(DEFAULT_TRANSLATE_SPEED),
m_zoomFraction(DEFAULT_ZOOM_FRACTION),
m_rotateSpeed(DEFAULT_ROTATE_SPEED)
{
m_upVector = glm::normalize(m_upVector);
getFrustrumInfo();
}
void Viewer::translate(float changeHoriz, float changeVert, bool inImagePlane) {
glm::vec3 translateVec;
if (inImagePlane) {
translateVec = (m_imagePlaneHorizDir * (m_displayWidth * changeHoriz)) + (m_imagePlaneVertDir * (changeVert * m_displayHeight));
}
else {
translateVec = (m_viewCenter - m_viewPoint) * changeVert;
}
translateVec *= m_translateSpeed;
m_viewPoint += translateVec;
m_viewCenter += translateVec;
}
void Viewer::zoom(float changeVert) {
float scaleFactor = powf(2.0, -changeVert * m_zoomFraction);
m_viewPoint = m_viewCenter + (m_viewPoint - m_viewCenter) * scaleFactor;
getFrustrumInfo();
}
const float pi = glm::pi<float>();
glm::quat setFromAxisAngle(glm::vec3 & axis, float angle) {
float cosAng = cosf(angle / 2.0f);
float sinAng = sinf(angle / 2.0f);
float norm = sqrt(axis.x * axis.x + axis.y * axis.y + axis.z * axis.z);
glm::quat res;
res.x = axis.x / norm;
res.y = axis.y / norm;
res.z = axis.z / norm;
res.w = cosAng; //w
res.x *= sinAng; //x
res.y *= sinAng; //y
res.z *= sinAng; //z
return res;
}
void makeOrthogonalTo(glm::vec3 & vec1, glm::vec3 & vec2) {
float length = glm::length(vec2);
if (length == 0) {
std::cout << "Warning: called MathVec3D::makeOrthogonalTo with zero vector as the argument. Doing nothing." << std::endl;
}
else {
float scale = (vec1.x * vec2.x + vec1.y * vec2.y + vec1.z * vec2.z) / (length * length);
vec1.x -= scale * vec2.x;
vec1.y -= scale * vec2.y;
vec1.z -= scale * vec2.z;
}
}
void Viewer::rotate(float changeHoriz, float changeVert) {
float horizRotAngle = m_rotateSpeed * changeVert;
float vertRotAngle = -m_rotateSpeed * changeHoriz;
glm::quat horizRot;
horizRot = setFromAxisAngle(m_imagePlaneHorizDir, horizRotAngle);
glm::quat vertRot;
vertRot = setFromAxisAngle(m_imagePlaneVertDir, vertRotAngle);
glm::quat totalRot = horizRot * vertRot;
glm::vec3 viewVec = m_viewPoint - m_viewCenter;
viewVec = totalRot * viewVec;
m_viewPoint = m_viewCenter + viewVec;
getFrustrumInfo();
}
void Viewer::centerAt(const glm::vec3 &pos) {
m_viewPoint += (pos - m_viewCenter);
m_viewCenter = pos;
getFrustrumInfo();
}
void Viewer::lookFrom(const glm::vec3 &pos) {
m_viewPoint = pos;
getFrustrumInfo();
}
glm::vec3 Viewer::getViewPoint() const {
return( m_viewPoint );
}
glm::vec3 Viewer::getViewCenter() const {
return( m_viewCenter );
}
glm::vec3 Viewer::getUpVector() const {
return( m_upVector );
}
float Viewer::getFieldOfView() const {
return( m_fieldOfView );
}
float Viewer::getAspectRatio() const {
return( m_aspectRatio );
}
glm::vec3 Viewer::getViewDir() const {
return( m_viewDir );
}
glm::vec3 Viewer::getImagePlaneHorizDir() const {
return( m_imagePlaneHorizDir );
}
glm::vec3 Viewer::getImagePlaneVertDir() const {
return( m_imagePlaneVertDir );
}
void Viewer::setAspectRatio(float aspectRatio) {
if( m_aspectRatio != aspectRatio ) {
m_aspectRatio = aspectRatio;
getFrustrumInfo();
}
}
void Viewer::setFieldOfView(float fieldOfView) {
if( m_fieldOfView != fieldOfView ) {
m_fieldOfView = fieldOfView;
getFrustrumInfo();
}
}
void Viewer::setTranslateSpeed(float translateSpeed) {
m_translateSpeed = translateSpeed;
}
void Viewer::setZoomFraction(float zoomFraction) {
m_zoomFraction = zoomFraction;
}
void Viewer::setRotateSpeed(float rotateSpeed) {
m_rotateSpeed = rotateSpeed;
}
void Viewer::getFrustrumInfo() {
// Get the viewing direction
m_viewDir = m_viewCenter - m_viewPoint;
m_viewDir = glm::normalize(m_viewDir);
// Get the vertical image-plane direction (the projection of the up vector into the view plane)
m_imagePlaneVertDir = m_upVector;
makeOrthogonalTo(m_imagePlaneVertDir, m_viewDir);
m_imagePlaneVertDir = glm::normalize(m_imagePlaneVertDir);
// Get the horizontal image-plane direction
m_imagePlaneHorizDir = glm::cross(m_viewDir, m_imagePlaneVertDir);
m_imagePlaneHorizDir = glm::normalize(m_imagePlaneHorizDir);
// Get the view plane width and height at the view center.
m_displayHeight = float(2.0 * glm::length(m_viewCenter-m_viewPoint) * tan(0.5*m_fieldOfView));
m_displayWidth = m_displayHeight * m_aspectRatio;
}