diff --git a/example/src/Entity.h b/example/src/Entity.h index f503990..20c39a6 100644 --- a/example/src/Entity.h +++ b/example/src/Entity.h @@ -23,7 +23,40 @@ public: RenderComponent *renderComponent = NULL; + struct CameraInfo { + float fov = 90.0f; + float aspect = 1024.0f / 768.0f; + float near = 0.1f; + float far = 100.0f; + }; + CameraInfo camera; + + hmm_mat4 projectionMatrix() { + return HMM_Perspective(camera.fov, camera.aspect, camera.near, camera.far); + } + + hmm_mat4 viewMatrix() { + return HMM_LookAt(worldPosition(), worldPosition() + forward(), up()); + } + + hmm_vec3 worldPosition() { + return (modelMatrix * HMM_Vec4(0.0f, 0.0f, 0.0f, 1.0f)).XYZ; + } + + hmm_vec3 up() { + return (modelMatrix * HMM_Vec4(0.0f, 1.0f, 0.0f, 1.0f)).XYZ - worldPosition(); + } + + hmm_vec3 forward() { + return (modelMatrix * HMM_Vec4(1.0f, 0.0f, 0.0f, 1.0f)).XYZ - worldPosition(); + } + + hmm_vec3 right() { + return (modelMatrix * HMM_Vec4(0.0f, 0.0f, 1.0f, 1.0f)).XYZ - worldPosition(); + } + // Context for rendering and stuff + hmm_mat4 parentModelMatrix; hmm_mat4 modelMatrix; }; diff --git a/example/src/FollowCam.h b/example/src/FollowCam.h new file mode 100644 index 0000000..4fb1176 --- /dev/null +++ b/example/src/FollowCam.h @@ -0,0 +1,58 @@ +#include + +#ifndef HMME_FOLLOWCAM_H +#define HMME_FOLLOWCAM_H + +#include "Entity.h" +#include "HandmadeMath.h" + +class FollowCam : public Entity { +public: + Entity *target; + + FollowCam(Entity *t) { + 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 { + // rotation = HMM_QuaternionFromAxisAngle(target->worldPosition() - worldPosition(), 0.0f); + // rotation = HMM_QuaternionFromAxisAngle(HMM_Vec3(0.0f, 1.0f, 0.0f), HMM_ToRadians(0.0f)); + // rotation = HMM_Qu + + 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(); + float dot = HMM_DotVec3(fwd, HMM_NormalizeVec3(to)); + + if (HMM_ABS(dot - 1.0f) < 0.000001f) { + // do nothing to the rotation + } else if (HMM_ABS(dot + 1.0f) < 0.000001f) { + // rotate 180 I guess but for now do nothing + } else { + hmm_vec3 cross = HMM_Normalize(HMM_Cross(fwd, to)); + + rotation = HMM_QuaternionFromAxisAngle( + cross, + HMM_ACOSF(dot) + ); + rotation *= HMM_QuaternionFromAxisAngle( + HMM_Vec3(1.0f, 0.0f, 0.0f), + -HMM_ACOSF(HMM_DotVec3(cross, up)) + ); + } + } +}; + +#endif diff --git a/example/src/main.cpp b/example/src/main.cpp index 1262367..5e7a054 100644 --- a/example/src/main.cpp +++ b/example/src/main.cpp @@ -11,6 +11,7 @@ #include "Entity.h" #include "Cube.h" #include "MeshRenderComponent.h" +#include "FollowCam.h" void TickTree(Entity *e, float deltaSeconds); void ComputeModelMatrices(Entity *ep, hmm_mat4 parentModelMatrix); @@ -67,17 +68,27 @@ int main() // Accept fragment if it closer to the camera than the former one glDepthFunc(GL_LESS); - Cube root = Cube(); + Cube c1 = Cube(); - Entity child = Entity(); - child.position = HMM_Vec3(2.1f, 0.0f, 0.0f); - child.renderComponent = new MeshRenderComponent("MonkeySmooth.obj"); + Entity monkey = Entity(); + 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, 3.0f, 4.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)); // Cube c = Cube(); - // child.position = HMM_Vec3(2.1f, 0.0f, 0.0f); + // monkey.position = HMM_Vec3(2.1f, 0.0f, 0.0f); - // child.AddChild(&c); - root.AddChild(&child); + // monkey.AddChild(&c); + + c1.AddChild(&monkey); + + Entity root = Entity(); + root.AddChild(&c1); + root.AddChild(&cam); bool hasTicked = false; high_resolution_clock::time_point lastTickTime; @@ -85,10 +96,6 @@ int main() do { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - hmm_mat4 projection = HMM_Perspective(90.0f, 1024.0f / 768.0f, 0.1f, 100.0f); - hmm_mat4 view = HMM_LookAt(HMM_Vec3(3.0f, 3.0f, 4.0f), HMM_Vec3(0.0f, 0.0f, 0.0f), HMM_Vec3(0.0f, 1.0f, 0.0f)); - hmm_mat4 vp = projection * view; - // Tick auto now = high_resolution_clock::now(); if (hasTicked) { @@ -103,6 +110,10 @@ int main() ComputeModelMatrices(&root, HMM_Mat4d(1.0f)); // Render! + hmm_mat4 projection = cam.projectionMatrix(); + hmm_mat4 view = cam.viewMatrix(); + hmm_mat4 vp = projection * view; + auto it = EntityIterator(&root); while (it.HasNext()) { Entity *e = it.Next(); @@ -142,6 +153,7 @@ void TickTree(Entity *e, float deltaSeconds) { } void ComputeModelMatrices(Entity *e, hmm_mat4 parentModelMatrix) { + e->parentModelMatrix = parentModelMatrix; e->modelMatrix = parentModelMatrix * HMM_Translate(e->position) * HMM_QuaternionToMat4(e->rotation) * HMM_Scale(e->scale); for (int i = 0; i < e->children.size(); i++) {