From 33cb124d77c3eeb91e707cf652eb40e6bc99108d Mon Sep 17 00:00:00 2001 From: Austin Morlan Date: Wed, 5 Sep 2018 18:48:27 -0700 Subject: [PATCH] Implement model-to-screen space transformations --- Makefile | 4 +- include/camera.h | 45 ++++++++++++++++ include/engine.h | 2 +- include/geometry.h | 17 ++++++ include/matrix.h | 80 ++++++++++++++++++++++++++++ include/point.h | 16 ++++++ include/transform.h | 17 ++++++ include/util.h | 9 ++++ src/engine.cpp | 123 +++++++++++++++++++++++++++++++++++++++++++- src/loader.cpp | 2 + src/main.cpp | 6 +-- src/transform.cpp | 104 +++++++++++++++++++++++++++++++++++++ 12 files changed, 418 insertions(+), 7 deletions(-) create mode 100644 include/camera.h create mode 100644 include/matrix.h create mode 100644 include/transform.h create mode 100644 src/transform.cpp diff --git a/Makefile b/Makefile index 6a0199b..9c1f2ea 100644 --- a/Makefile +++ b/Makefile @@ -36,10 +36,10 @@ WARNINGS_OFF=-Wno-missing-braces -Wno-gnu-anonymous-struct -Wno-old-style-cast\ CFLAGS=$(D) $(O) -std=c++11 $(WARNINGS_ON) $(WARNINGS_OFF) -I$(INCLUDE_DIR) LIBS=-lSDL2 -_HEADERS = engine.h loader.h geometry.h platform.h point.h util.h +_HEADERS = engine.h geometry.h loader.h platform.h point.h transform.h util.h HEADERS = $(patsubst %,$(INCLUDE_DIR)/%,$(_HEADERS)) -_OBJS = engine.o loader.o main.o platform.o +_OBJS = engine.o loader.o main.o platform.o transform.o OBJS = $(patsubst %,$(BUILD_DIR)/%,$(_OBJS)) $(BUILD_DIR)/%.o: $(SRC_DIR)/%.cpp $(HEADERS) diff --git a/include/camera.h b/include/camera.h new file mode 100644 index 0000000..09ae634 --- /dev/null +++ b/include/camera.h @@ -0,0 +1,45 @@ +#ifndef CAMERA_H + +#include "point.h" +#include "util.h" +#include + + +// STRUCTURE +struct Camera +{ + inline Camera(void) + { + position.x = 0.0f; + position.y = 0.0f; + position.z = 0.0f; + + rotation[0] = 0.0f; + rotation[1] = 0.0f; + rotation[2] = 0.0f; + + nearClip = 1.0f; + farClip = 1000.0f; + } + + inline void SetFOV(float fov, int winWidth, int winHeight) + { + xZoom = 1.0f / tanf(DEG_TO_RAD(fov/2.0f)); + yZoom = (xZoom * winWidth) / winHeight; + + xScale = (0.5f * winWidth) - 0.5f; + yScale = (0.5f * winHeight) - 0.5f; + } + + + Point position; + float rotation[3]; + float nearClip, farClip; + float xZoom, yZoom; + float xScale, yScale; +}; + + +#define CAMERA_H +#endif + diff --git a/include/engine.h b/include/engine.h index fda860b..5e49eb8 100644 --- a/include/engine.h +++ b/include/engine.h @@ -33,7 +33,7 @@ struct Engine_Buffer // FUNCTIONS -int Engine_Init(char *filename); +int Engine_Init(Engine_Buffer &buffer, char *filename); void Engine_Render(Engine_Buffer &buffer, uint32_t input); void Engine_Shutdown(void); diff --git a/include/geometry.h b/include/geometry.h index 8352526..a3959d4 100644 --- a/include/geometry.h +++ b/include/geometry.h @@ -11,7 +11,24 @@ struct Face struct Mesh { + inline Mesh(void) + { + position.x = 0.0f; + position.y = 0.0f; + position.z = 0.0f; + + rotation[0] = 0.0f; + rotation[1] = 0.0f; + rotation[2] = 0.0f; + + scale = 1.0f; + } + + Point position; + float rotation[3]; + float scale; std::vector verts; + std::vector vertsTransformed; std::vector faces; }; diff --git a/include/matrix.h b/include/matrix.h new file mode 100644 index 0000000..633ae19 --- /dev/null +++ b/include/matrix.h @@ -0,0 +1,80 @@ +#ifndef MATRIX_H + + +#include "point.h" + + +// STRUCTURE +struct Matrix +{ + inline Matrix(void) + { + e11 = 1.0; e12 = 0.0; e13 = 0.0; e14 = 0.0; + e21 = 0.0; e22 = 1.0; e23 = 0.0; e24 = 0.0; + e31 = 0.0; e32 = 0.0; e33 = 1.0; e34 = 0.0; + e41 = 0.0; e42 = 0.0; e43 = 0.0; e44 = 1.0; + } + + union + { + float e[4][4]; + + struct + { + float e11, e12, e13, e14; + float e21, e22, e23, e24; + float e31, e32, e33, e34; + float e41, e42, e43, e44; + }; + }; +}; + + +// OPERATORS +// m1 * m2 +inline Matrix operator*(Matrix m1, Matrix m2) +{ + Matrix result; + + for (int row = 0; row < 4; ++row) + { + for (int col = 0; col < 4; ++col) + { + float sum = 0.0; + + for (int i = 0; i < 4; ++i) + { + sum += m1.e[row][i] * m2.e[i][col]; + } + + result.e[row][col] = sum; + } + } + + return result; +} + +// v * m +inline Point operator*(Point v, Matrix m) +{ + Point result; + + for (int col = 0; col < 4; ++col) + { + float sum = 0.0; + + for (int row = 0; row < 4; ++row) + { + sum += v.e[row] * m.e[row][col]; + } + + result.e[col] = sum; + } + + return result; +} + + +#define MATRIX_H +#endif + diff --git a/include/point.h b/include/point.h index 9406bb4..58d524b 100644 --- a/include/point.h +++ b/include/point.h @@ -19,6 +19,22 @@ struct Point }; +// OPERATORS +// v / f +inline Point operator/(Point v, float f) +{ + Point result; + + float inverse = 1.0f / f; + + result.x = v.x * inverse; + result.y = v.y * inverse; + result.z = v.z * inverse; + + return result; +} + + #define POINT_H #endif diff --git a/include/transform.h b/include/transform.h new file mode 100644 index 0000000..431681b --- /dev/null +++ b/include/transform.h @@ -0,0 +1,17 @@ +#ifndef TRANSFORM_H + + +#include "matrix.h" + + +Matrix Transform_Translate(float x, float y, float z); +Matrix Transform_Rotate(float x, float y, float z); +Matrix Transform_Scale(float s); +Matrix Transform_View(Point &position, float rotation[]); +Matrix Transform_Perspective(float zoomX, float zoomY, float nearClip, float farClip); +Matrix Transform_Screen(float xScale, float yScale); + + +#define TRANSFORM_H +#endif + diff --git a/include/util.h b/include/util.h index 4c873f1..5bbb7c9 100644 --- a/include/util.h +++ b/include/util.h @@ -1,10 +1,19 @@ #ifndef UTIL_H +#include + + +// CONSTANTS +const float EPSILON_E3 = 1E-3f; + // MACROS #define SET_BIT(x, bit) (x |= (1UL << bit)) #define CLEAR_BIT(x, bit) (x &= ~(1UL << bit)) #define CHECK_BIT(x, bit) (x & (1UL << bit)) +#define DEG_TO_RAD(deg) ((deg * (float)M_PI) / 180.0f) +#define SWAP(a, b, temp) {temp = a; a = b; b = temp;} +#define FLOAT_EQUAL(a, b) ((fabsf(a - b) < EPSILON_E3) ? 1 : 0) #define UTIL_H diff --git a/src/engine.cpp b/src/engine.cpp index 4444180..d82ceb4 100644 --- a/src/engine.cpp +++ b/src/engine.cpp @@ -1,12 +1,23 @@ +#include "camera.h" #include "engine.h" #include "loader.h" +#include "matrix.h" +#include "transform.h" +#include "util.h" +#include // GLOBALS static Mesh mesh; +static Camera camera; -int Engine_Init(char *filename) +// PRIVATE PROTOTYPES +static void CheckInputs(uint32_t input); + + +// PUBLIC FUNCTIONS +int Engine_Init(Engine_Buffer &buffer, char *filename) { int result = LoadMesh(filename, mesh); @@ -15,14 +26,124 @@ int Engine_Init(char *filename) return -1; } + mesh.position.z = 250; + + camera.SetFOV(90.0f, buffer.width, buffer.height); + return 0; } void Engine_Render(Engine_Buffer &buffer, uint32_t input) { + CheckInputs(input); + + Matrix tTranslate = Transform_Translate( + mesh.position.x, mesh.position.y, mesh.position.z); + + Matrix tRotate = Transform_Rotate( + mesh.rotation[0], mesh.rotation[1], mesh.rotation[2]); + + Matrix tScale = Transform_Scale( + mesh.scale); + + Matrix tView = Transform_View( + camera.position, camera.rotation); + + Matrix tPersp = Transform_Perspective( + camera.xZoom, camera.yZoom, camera.nearClip, camera.farClip); + + for (size_t v = 0; v < mesh.verts.size(); ++v) + { + mesh.vertsTransformed[v] = + mesh.verts[v] * tScale * tRotate * tTranslate * tView * tPersp; + + mesh.vertsTransformed[v] = + mesh.vertsTransformed[v] / mesh.vertsTransformed[v].w; + } + + Matrix tScreen = Transform_Screen(camera.xScale, camera.yScale); + + for (size_t v = 0; v < mesh.verts.size(); ++v) + { + mesh.vertsTransformed[v] = mesh.vertsTransformed[v] * tScreen; + } + + for(size_t f = 0; f < mesh.faces.size(); ++f) + { + unsigned int v0 = mesh.faces[f].vertIndex[0]; + unsigned int v1 = mesh.faces[f].vertIndex[1]; + unsigned int v2 = mesh.faces[f].vertIndex[2]; + } } void Engine_Shutdown(void) { } + +// PRIVATE FUNCTIONS +static void CheckInputs(uint32_t input) +{ + if (CHECK_BIT(input, TRANSLATE_X_POS)) + { + mesh.position.x += 10; + } + else if (CHECK_BIT(input, TRANSLATE_X_NEG)) + { + mesh.position.x -= 10; + } + + if (CHECK_BIT(input, TRANSLATE_Z_POS)) + { + mesh.position.z += 10; + } + else if (CHECK_BIT(input, TRANSLATE_Z_NEG)) + { + mesh.position.z -= 10; + } + + if (CHECK_BIT(input, TRANSLATE_Y_POS)) + { + mesh.position.y += 10; + } + else if (CHECK_BIT(input, TRANSLATE_Y_NEG)) + { + mesh.position.y -= 10; + } + + if (CHECK_BIT(input, ROTATE_X_POS)) + { + mesh.rotation[0] += .10; + } + else if (CHECK_BIT(input, ROTATE_X_NEG)) + { + mesh.rotation[0] -= .10; + } + + if (CHECK_BIT(input, ROTATE_Z_POS)) + { + mesh.rotation[1] += .10; + } + else if (CHECK_BIT(input, ROTATE_Z_NEG)) + { + mesh.rotation[1] -= .10; + } + + if (CHECK_BIT(input, ROTATE_Y_POS)) + { + mesh.rotation[2] += .10; + } + else if (CHECK_BIT(input, ROTATE_Y_NEG)) + { + mesh.rotation[2] -= .10; + } + + if (CHECK_BIT(input, SCALE_UP)) + { + mesh.scale += 0.1f; + } + else if (CHECK_BIT(input, SCALE_DOWN)) + { + mesh.scale -= 0.1f; + } +} diff --git a/src/loader.cpp b/src/loader.cpp index 4f8197e..0184086 100644 --- a/src/loader.cpp +++ b/src/loader.cpp @@ -67,6 +67,8 @@ int LoadMesh(char *filename, Mesh &mesh) printf("Verts: %lu\n", mesh.verts.size()); printf("Faces: %lu\n", mesh.faces.size()); + mesh.vertsTransformed.resize(mesh.verts.size()); + fclose(fp); return 0; diff --git a/src/main.cpp b/src/main.cpp index 824401e..b8945c9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -6,8 +6,8 @@ // CONSTANTS -const unsigned int WINDOW_WIDTH = 800; -const unsigned int WINDOW_HEIGHT = 600; +const unsigned int WINDOW_WIDTH = 1920; +const unsigned int WINDOW_HEIGHT = 1080; const unsigned int WINDOW_FPS = 30; @@ -33,7 +33,7 @@ int main(int argc, char *argv[]) buffer.width = platform.surface->w; buffer.height = platform.surface->h; - result = Engine_Init(filename); + result = Engine_Init(buffer, filename); if (result < 0) { diff --git a/src/transform.cpp b/src/transform.cpp new file mode 100644 index 0000000..0a96c87 --- /dev/null +++ b/src/transform.cpp @@ -0,0 +1,104 @@ +#include "matrix.h" +#include "transform.h" +#include + + +// PUBLIC FUNCTIONS +Matrix Transform_Translate(float x, float y, float z) +{ + Matrix result; + + result.e41 = x; + result.e42 = y; + result.e43 = z; + + return result; +} + +Matrix Transform_Rotate(float x, float y, float z) +{ + // YXZ Euler rotation + float cosThetaY = cosf(y); + float sinThetaY = sinf(y); + + Matrix tRotateY; + + tRotateY.e11 = cosThetaY; + tRotateY.e13 = -sinThetaY; + tRotateY.e31 = sinThetaY; + tRotateY.e33 = cosThetaY; + + + float cosThetaX = cosf(x); + float sinThetaX = sinf(x); + + Matrix tRotateX; + + tRotateX.e22 = cosThetaX; + tRotateX.e23 = sinThetaX; + tRotateX.e32 = -sinThetaX; + tRotateX.e33 = cosThetaX; + + + float cosThetaZ = cosf(z); + float sinThetaZ = sinf(z); + + Matrix tRotateZ; + + tRotateZ.e11 = cosThetaZ; + tRotateZ.e12 = sinThetaZ; + tRotateZ.e21 = -sinThetaZ; + tRotateZ.e22 = cosThetaZ; + + + Matrix result = tRotateY * tRotateX * tRotateZ; + + return result; +} + +Matrix Transform_Scale(float s) +{ + Matrix result; + + result.e11 = s; + result.e22 = s; + result.e33 = s; + + return result; +} + +Matrix Transform_View(Point &position, float rotation[]) +{ + Matrix tInvTranslate = Transform_Translate(-position.x, -position.y, -position.z); + + Matrix tInvRotate = Transform_Rotate(-rotation[0], -rotation[1], -rotation[2]); + + Matrix result = tInvTranslate * tInvRotate; + + return result; +} + +Matrix Transform_Perspective(float zoomX, float zoomY, float nearClip, float farClip) +{ + Matrix result; + + result.e11 = zoomX; + result.e22 = zoomY; + result.e33 = (farClip + nearClip) / (farClip - nearClip); + result.e34 = 1; + result.e43 = (-2.0f * farClip * nearClip) / (farClip - nearClip); + + return result; +} + +Matrix Transform_Screen(float xScale, float yScale) +{ + Matrix result; + + result.e11 = xScale; + result.e41 = xScale; + result.e22 = -yScale; + result.e42 = yScale; + + return result; +}