You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
145 lines
4.0 KiB
145 lines
4.0 KiB
|
|
#include <GL/gl3w.h> |
|
|
|
#include "camera.h" |
|
|
|
// TODO: add these props to scene json |
|
#define MOVE_SPEED 5.f |
|
#define ROTATE_SPEED 0.005f |
|
#define CAMERA_Z_CLAMP_ANGLE 85.f |
|
#define FOV 60.f |
|
#define ASPECT_RATIO 16.f/9.f |
|
#define NEAR_CLIP_PLANE 20.f |
|
|
|
|
|
void |
|
cameraInitPerspective(camera& cam, glm::vec3 position, glm::vec3 target, glm::vec3 world_up) |
|
{ |
|
cam.position = position; |
|
cam.target = target; |
|
cam.world_up = world_up; |
|
cam.projection = glm::infinitePerspective(glm::radians(FOV), ASPECT_RATIO, NEAR_CLIP_PLANE); |
|
|
|
cam.forward = glm::normalize(target - position); |
|
cam.left = glm::normalize(glm::cross(cam.world_up, cam.forward)); |
|
cam.up = glm::normalize(glm::cross(cam.forward, cam.left)); |
|
|
|
cam.hAngle = glm::atan(cam.forward.x, cam.forward.y); |
|
// NOTE: using pythagoras' to get absolute value of relative axis for vAngle component |
|
real32 len = glm::sqrt(glm::pow(cam.forward.y, 2) + glm::pow(cam.forward.x, 2)); |
|
cam.vAngle = glm::atan(cam.forward.z, len); |
|
|
|
cam.view = glm::lookAt(cam.position, cam.position + cam.forward, cam.up); |
|
cam.model = glm::mat4(1.0f); |
|
cam.MVP = cam.projection * cam.view * cam.model; |
|
} |
|
|
|
void |
|
cameraInitOrthographic(/*camera& cam, */) |
|
{ |
|
#if 0 |
|
// left, right, bottom, top, zNear, zFar |
|
cam.projection = glm::ortho(0.f, 1280.0f, 0.f, 720.0f, 0.1f, 100.0f); |
|
cam.view = glm::lookAt( |
|
glm::vec3(0.0f, 0.0f, 1.0f), // camera position |
|
glm::vec3(0.0f, 0.0f, 0.0f), // look at position |
|
glm::vec3(0,1,0) // "up" vector |
|
); |
|
|
|
cam.model = glm::mat4(1.0f); |
|
cam.MVP = cam.projection * cam.view * cam.model; |
|
#endif |
|
} |
|
|
|
v2f |
|
cameraUnproject(camera& cam, int x, int y, int vp_width, int vp_height) |
|
{ |
|
// NOTE: using depth buffer may not be as accurate as doing ray-cast |
|
GLfloat depth; |
|
glReadPixels(x, y, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth); |
|
glm::vec4 viewport = glm::vec4(0, 0, vp_width, vp_height); |
|
glm::vec3 wincoord = glm::vec3(x, y, depth); |
|
glm::vec3 vU = glm::unProject(wincoord, cam.view, cam.projection, viewport); |
|
v2f v(vU.x, vU.y); |
|
|
|
return v; |
|
} |
|
|
|
void |
|
cameraMove(camera& cam, bool up, bool left, bool down, bool right, bool forward, bool backward) |
|
{ |
|
if (!up && !left && !down && !right && !forward && !backward) |
|
return; |
|
|
|
glm::vec3 f = cam.forward; |
|
glm::vec3 u = cam.up; |
|
glm::vec3 old = cam.position; |
|
glm::vec3 &p = cam.position; |
|
glm::vec3 v(0.f); // normalized direction |
|
|
|
// TODO: still seems like we're adding magnitude when moving in 2 directions |
|
#if 0 |
|
if (forward) v = glm::normalize(v + f); |
|
if (backward) v = glm::normalize(v - f); |
|
if (up) v = glm::normalize(v + u); |
|
if (down) v = glm::normalize(v - u); |
|
if (left) v -= glm::normalize(glm::cross(f, u)); |
|
if (right) v -= glm::normalize(glm::cross(u, f)); |
|
#else |
|
if (forward) v += f; |
|
if (backward) v -= f; |
|
if (up) v += u; |
|
if (down) v -= u; |
|
if (left) v -= glm::cross(f, u); |
|
if (right) v -= glm::cross(u, f); |
|
#endif |
|
|
|
p += (v * MOVE_SPEED); |
|
glm::vec3 diff = old - p; |
|
cam.view = glm::translate(cam.view, diff); |
|
cam.MVP = cam.projection * cam.view * cam.model; |
|
} |
|
|
|
void |
|
cameraRotate(camera& cam, int32 xrel, int32 yrel) |
|
{ |
|
float &h = cam.hAngle; |
|
float &v = cam.vAngle; |
|
h += ROTATE_SPEED * xrel; |
|
v -= ROTATE_SPEED * yrel; |
|
|
|
// clamp vAngle to prevent gimbal lock |
|
float a = glm::radians(CAMERA_Z_CLAMP_ANGLE); |
|
if (v < (-1 * a)) v = (-1 * a); |
|
if (v > a) v = a; |
|
|
|
cam.forward = glm::vec3( |
|
glm::cos(v) * glm::sin(h), |
|
glm::cos(v) * glm::cos(h), |
|
glm::sin(v) |
|
); |
|
|
|
glm::normalize(cam.forward); |
|
cam.left = glm::normalize(glm::cross(cam.forward, cam.world_up)); |
|
cam.up = glm::normalize(glm::cross(cam.left, cam.forward)); |
|
|
|
cam.view = glm::lookAt(cam.position, cam.position + cam.forward, cam.up); |
|
cam.MVP = cam.projection * cam.view * cam.model; |
|
} |
|
|
|
void |
|
cameraRoll(camera& cam, bool CW, bool CCW) |
|
{ |
|
if ((!CW && !CCW) || (CW && CCW)) |
|
return; |
|
|
|
float a = 0.005f; |
|
if (CW) a *= 1; |
|
if (CCW) a *= -1; |
|
glm::mat4 m = glm::rotate(glm::mat4(1.f), a, cam.forward); |
|
glm::vec4 v(cam.up.x, cam.up.y, cam.up.z, 0); |
|
v = v * m; |
|
cam.up = glm::vec3(v.x, v.y, v.z); |
|
cam.view *= m; |
|
cam.MVP = cam.projection * cam.view * cam.model; |
|
}
|
|
|