Get an FPS cam kind of working! (no mouse input yet)

This commit is contained in:
Ben Visness
2018-06-30 22:17:00 +02:00
parent 8332a2d907
commit fabad91c39
6 changed files with 139 additions and 50 deletions

35
example/src/FPSCam.h Normal file
View File

@@ -0,0 +1,35 @@
#include <stdio.h>
#ifndef HMME_FPSCAM_H
#define HMME_FPSCAM_H
#include "Entity.h"
#include "FollowCam.h"
#include "HandmadeMath.h"
#include "debug.h"
class FPSCam : public Entity {
public:
FollowCam cam = FollowCam(0); // TODO: Why on earth is this necessary?? Remove this and fix the error.
Entity target;
FPSCam() {
target = Entity();
target.position = HMM_Vec3(1.0f, 0.0f, 0.0f);
cam = FollowCam(&target);
AddChild(&target);
AddChild(&cam);
}
float x = 0;
void Tick(float deltaSeconds) override {
x += deltaSeconds;
rotation *= HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 1.0f, 0.0f), deltaSeconds * HMM_ToRadians(45.0f));
}
};
#endif

View File

@@ -16,27 +16,34 @@ public:
target = t;
}
// HI BEN HERE IS YOUR STREAM OF CONSCIOUSNESS
//
// Up is wonky. Really this whole thing is a little wonky, although it's
// gotten pretty close. You need to figure out how to directly calculate the
// axis and angle so you don't have to do this in two steps. Then it should
// Just Work.
//
// Although you may have to figure out how to make the camera keep a consistent up vector.
//
// Actually that shouldn't be too hard, because once you have a quaternion
// LookAt thing, you can just always pass world up to it.
void Tick(float deltaSeconds) override {
// TODO: Find a way to do this rotation routine in a single quaternion. Maybe that
// just means finding a correct method, then doing some quaternion multiplication
// on paper to see how the axis and angle shake out.
rotation = GetLookAtRotation();
}
hmm_quaternion GetLookAtRotation() {
hmm_vec3 fwd = (parentModelMatrix * HMM_Vec4(1.0f, 0.0f, 0.0f, 0.0f)).XYZ;
hmm_vec3 up = (parentModelMatrix * HMM_Vec4(0.0f, 1.0f, 0.0f, 0.0f)).XYZ;
hmm_vec3 to = target->worldPosition() - worldPosition();
hmm_quaternion justPointAt = HMM_QuaternionFromAxisAngle(
HMM_Cross(fwd, to),
HMM_ACosF(HMM_Dot(HMM_Normalize(fwd), HMM_Normalize(to)))
);
hmm_vec3 pointAxis = HMM_Cross(fwd, to);
hmm_quaternion justPointAt;
// TODO: proper epsilon! and probably implement some kind of nan
// protection because a single nan ruins everything.
if (HMM_ABS(HMM_Length(pointAxis)) < 0.0001f) {
// Already pointing at the thing!
justPointAt = HMM_Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
} else {
justPointAt = HMM_QuaternionFromAxisAngle(
pointAxis,
HMM_ACosF(HMM_Dot(HMM_Normalize(fwd), HMM_Normalize(to)))
);
}
hmm_vec3 newUp = (HMM_QuaternionToMat4(justPointAt) * HMM_Vec4v(up, 0.0f)).XYZ;
hmm_quaternion backUpright = HMM_QuaternionFromAxisAngle(
to,
@@ -49,7 +56,8 @@ public:
// add the vector projection stuff that we somehow have left out!
-HMM_ACosF(HMM_Dot(HMM_Normalize(newUp), HMM_Vec3(0.0f, 1.0f, 0.0f)))
);
rotation = backUpright * justPointAt;
return backUpright * justPointAt;
// BEN
//

View File

@@ -18,9 +18,11 @@ void printQuaternion(hmm_quaternion q) {
}
void printMat4(hmm_mat4 m) {
printf("/\n");
for (int r = 0; r < 4; r++) {
printf("| %f\t%f\t%f\t%f |\n", m[0][r], m[1][r], m[2][r], m[3][r]);
}
printf("\\\n");
}
#endif

View File

@@ -11,7 +11,7 @@
#include "Entity.h"
#include "Cube.h"
#include "MeshRenderComponent.h"
#include "FollowCam.h"
#include "FPSCam.h"
void TickTree(Entity *e, float deltaSeconds);
void ComputeModelMatrices(Entity *ep, hmm_mat4 parentModelMatrix);
@@ -74,10 +74,10 @@ int main()
monkey.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
monkey.renderComponent = new MeshRenderComponent("MonkeySmooth.obj");
FollowCam cam = FollowCam(&monkey);
cam.position = HMM_Vec3(-3.0f, -1.0f, 0.0f);
// cam.position = HMM_Vec3(3.0f, 3.0f, 5.0f);
// cam.rotation = HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 1.0f, 0.0f), HMM_ToRadians(90.0f));
FPSCam fpsCam = FPSCam();
fpsCam.position = HMM_Vec3(-3.0f, 1.0f, 1.0f);
Entity *cam = &fpsCam.cam;
// Cube c = Cube();
// monkey.position = HMM_Vec3(2.1f, 0.0f, 0.0f);
@@ -88,7 +88,7 @@ int main()
Entity root = Entity();
root.AddChild(&c1);
root.AddChild(&cam);
root.AddChild(&fpsCam);
Entity axes = Entity();
axes.renderComponent = new MeshRenderComponent("Axes.obj");
@@ -114,8 +114,8 @@ int main()
ComputeModelMatrices(&root, HMM_Mat4d(1.0f));
// Render!
hmm_mat4 projection = cam.projectionMatrix();
hmm_mat4 view = cam.viewMatrix();
hmm_mat4 projection = cam->projectionMatrix();
hmm_mat4 view = cam->viewMatrix();
hmm_mat4 vp = projection * view;
auto it = EntityIterator(&root);
@@ -143,7 +143,7 @@ int main()
glfwPollEvents();
} while (
// Check if the ESC key was pressed or the window was closed
glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS
glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS
&& glfwWindowShouldClose(window) == 0
);
}

View File

@@ -80,29 +80,59 @@ TEST(QuaternionOps, ToMat4)
{
const float abs_error = 0.0001f;
hmm_quaternion rot = HMM_Quaternion(0.707107f, 0.0f, 0.0f, 0.707107f);
{
// Identity quaternion
hmm_quaternion rot = HMM_Quaternion(0.0f, 0.0f, 0.0f, 1.0f);
hmm_mat4 result = HMM_QuaternionToMat4(rot);
hmm_mat4 result = HMM_QuaternionToMat4(rot);
EXPECT_NEAR(result.Elements[0][0], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[0][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][0], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[0][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][2], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[1][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][1], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[1][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][1], -1.0f, abs_error);
EXPECT_NEAR(result.Elements[2][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][2], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[2][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[3][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error);
}
{
// Straightforward 90 degree rotation
hmm_quaternion rot = HMM_Quaternion(0.707107f, 0.0f, 0.0f, 0.707107f);
hmm_mat4 result = HMM_QuaternionToMat4(rot);
EXPECT_NEAR(result.Elements[0][0], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[0][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[0][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[1][2], 1.0f, abs_error);
EXPECT_NEAR(result.Elements[1][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][1], -1.0f, abs_error);
EXPECT_NEAR(result.Elements[2][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[2][3], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][0], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][1], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][2], 0.0f, abs_error);
EXPECT_NEAR(result.Elements[3][3], 1.0f, abs_error);
}
}
TEST(QuaternionOps, FromAxisAngle)

View File

@@ -136,14 +136,28 @@ TEST(VectorOps, NormalizeZero)
TEST(VectorOps, Cross)
{
hmm_vec3 v1 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v2 = HMM_Vec3(4.0f, 5.0f, 6.0f);
{
// Normal cross
hmm_vec3 v1 = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 v2 = HMM_Vec3(4.0f, 5.0f, 6.0f);
hmm_vec3 result = HMM_Cross(v1, v2);
hmm_vec3 result = HMM_Cross(v1, v2);
EXPECT_FLOAT_EQ(result.X, -3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, -3.0f);
EXPECT_FLOAT_EQ(result.X, -3.0f);
EXPECT_FLOAT_EQ(result.Y, 6.0f);
EXPECT_FLOAT_EQ(result.Z, -3.0f);
}
{
// Vector with itself
hmm_vec3 v = HMM_Vec3(1.0f, 2.0f, 3.0f);
hmm_vec3 result = HMM_Cross(v, v);
EXPECT_FLOAT_EQ(result.X, 0.0f);
EXPECT_FLOAT_EQ(result.Y, 0.0f);
EXPECT_FLOAT_EQ(result.Z, 0.0f);
}
}
TEST(VectorOps, DotVec2)