mirror of
https://github.com/HandmadeMath/HandmadeMath.git
synced 2025-12-28 15:44:33 +00:00
Get an FPS cam kind of working! (no mouse input yet)
This commit is contained in:
35
example/src/FPSCam.h
Normal file
35
example/src/FPSCam.h
Normal 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
|
||||
@@ -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
|
||||
//
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user