![]()
引言
上一节我们为引擎提供了自己的键鼠映射,今天我们来聊聊之后的渲染部分的数学基础。
渲染是非常依赖数学的,所以如果想在屏幕上画些什么我们必须拥有一个数学库。
老实说现在有许多优秀的第三方数学库,在我的专业工作中也常常用到。从技术上讲,自己编写的数学库维持最低限度的启动和运行实际上并不难,你可能会编写基础的类如向量、矩阵等等;显然它也需要一些实用方法如基本的运算。
自己做起来很容易,但是如果您想编写一个好的数学库是非常困难的。因为为了使运算快速、为了以一种高效的方式编写它,我们需要非常特殊的编程技巧或者底层功底(涉及到寄存器和汇编代码)。
GLM 库
遗憾的是对于这个系列而言我们谈论的大多是 C++,如何建立一个高效数学库并不在我们的考量范围内。因此我们会使用称为 OpenGL Mathematics(简称 glm)的支持库:
![]()
它是一个用于图形的 C++ 数学库,虽然名字带着 OpenGL,但请注意它与 OpenGL 无关,只是语法近似于 OpenGL 的数学库。
现在让我们引入该库:
1 2
| cd Infinite git submodule add https://github.com/g-truc/glm Infinite/vendor/glm
|
![]()
预生成文件
在项目 Infinite 的预生成文件 premake5.lua 中加入 glm:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
| workspace "Infinite" architecture "x64" startproject "Sandbox"
configurations { "Debug", "Release", "Dist" }
outputdir = "%{cfg.buildcfg}-%{cfg.system}-%{cfg.architecture}"
-- Include directories relative to root folder (solution directory) IncludeDir = {} IncludeDir["GLFW"] = "Infinite/vendor/GLFW/include" IncludeDir["GLAD"] = "Infinite/vendor/GLAD/include" IncludeDir["ImGui"] = "Infinite/vendor/imgui/include" +IncludeDir["glm"] = "Infinite/vendor/glm"
include "Infinite/vendor/GLFW" include "Infinite/vendor/GLAD" include "Infinite/vendor/imgui"
project "Infinite" location "Infinite" kind "SharedLib" language "C++" staticruntime "off"
targetdir ("bin/" .. outputdir .. "/%{prj.name}") objdir ("bin-int/" .. outputdir .. "/%{prj.name}")
pchheader "ifnpch.h" pchsource "Infinite/src/ifnpch.cpp"
files { "%{prj.name}/src/**.h", "%{prj.name}/src/**.cpp", + "%{prj.name}/vendor/glm/glm/**.hpp", + "%{prj.name}/vendor/glm/glm/**.inl", }
includedirs { "%{prj.name}/src", "%{prj.name}/vendor/spdlog/include", "%{IncludeDir.GLFW}", "%{IncludeDir.GLAD}", "%{IncludeDir.ImGui}", + "%{IncludeDir.glm}" }
links { "GLFW", "GLAD", "ImGui", "opengl32.lib" }
filter "system:windows" cppdialect "C++17" systemversion "latest"
defines { "IFN_PLATFORM_WINDOWS", "IFN_BUILD_DLL", "GLFW_INCLUDE_NONE" }
postbuildcommands { ("{COPY} %{cfg.buildtarget.relpath} \"../bin/" .. outputdir .. "/Sandbox/\"") }
filter "configurations:Debug" defines "IFN_DEBUG" runtime "Debug" symbols "On"
filter "configurations:Release" defines "IFN_RELEASE" runtime "Release" optimize "On"
filter "configurations:Dist" defines "IFN_DIST" runtime "Release" optimize "On"
project "Sandbox" location "Sandbox" kind "ConsoleApp" staticruntime "off"
language "C++"
targetdir ("bin/" .. outputdir .. "/%{prj.name}") objdir ("bin-int/" .. outputdir .. "/%{prj.name}")
files { "%{prj.name}/src/**.h", "%{prj.name}/src/**.cpp" }
includedirs { "Infinite/vendor/spdlog/include", "Infinite/src/Infinite", "Infinite/src/Events", "Infinite/src/**.h", "Infinite/src/**.cpp", + "%{IncludeDir.glm}" }
links { "Infinite" }
filter "system:windows" cppdialect "C++17" systemversion "latest"
defines { "IFN_PLATFORM_WINDOWS" }
filter "configurations:Debug" defines "IFN_DEBUG" runtime "Debug" symbols "On"
filter "configurations:Release" defines "IFN_RELEASE" runtime "Release" optimize "On"
filter "configurations:Dist" defines "IFN_DIST" runtime "Release" optimize "On"
|
重新生成项目后打开 VisualStudio,在 vendor 下可以看到 glm:
![]()
所有的 .hpp 和 .inl 文件都显示可用:
![]()
调试
我们在 SandboxApp.cpp 中放置一段 glm 示例代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <glm/vec3.hpp> #include <glm/vec4.hpp> #include <glm/mat4x4.hpp> #include <glm/gtc/matrix_transform.hpp> glm::mat4 camera(float Translate, glm::vec2 const & Rotate) { glm::mat4 Projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.f); glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate)); View = glm::rotate(View, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f)); View = glm::rotate(View, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f)); glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f)); return Projection * View * Model; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include <Infinite.h>
+#include <glm/vec3.hpp> // glm::vec3 +#include <glm/vec4.hpp> // glm::vec4 +#include <glm/mat4x4.hpp> // glm::mat4 +#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective +glm::mat4 camera(float Translate, glm::vec2 const & Rotate) +{ + glm::mat4 Projection = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 100.f); + glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate)); + View = glm::rotate(View, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f)); + View = glm::rotate(View, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f)); + glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f)); + return Projection * View * Model; +}
class ExampleLayer : public Infinite::Layer { public: ExampleLayer() : Layer("Example") { + auto cam = camera(5.0f, { 0.5f, 0.5f }); }
void OnUpdate() override { // IFN_INFO("ExampleLayer::Update");
if (Infinite::Input::IsKeyPressed(IFN_KEY_TAB)) IFN_INFO("Tab key is pressed (poll)!"); }
void OnEvent(Infinite::Event& event) override { if (event.GetEventType() == Infinite::EventType::KeyPressed) { Infinite::KeyPressedEvent& e = (Infinite::KeyPressedEvent&)event; if (Infinite::Input::IsKeyPressed(IFN_KEY_TAB)) IFN_INFO("Tab key is pressed (event)!");
IFN_TRACE("{0}", (char)e.GetKeyCode()); } }
};
class Sandbox : public Infinite::Application { public: Sandbox() { PushLayer(new ExampleLayer()); PushOverlay(new Infinite::ImGuiLayer()); } ~Sandbox() {} };
Infinite::Application* Infinite::CreateApplication() { return new Sandbox(); }
|
加入示例代码后如成功启动则代表引入成功,测试完毕删除示例代码。