引言
上一节我们为引擎提供了自己的键鼠映射,今天我们来聊聊之后的渲染部分的数学基础。
渲染是非常依赖数学的,所以如果想在屏幕上画些什么我们必须拥有一个数学库。
老实说现在有许多优秀的第三方数学库,在我的专业工作中也常常用到。从技术上讲,自己编写的数学库维持最低限度的启动和运行实际上并不难,你可能会编写基础的类如向量、矩阵等等;显然它也需要一些实用方法如基本的运算。
自己做起来很容易,但是如果您想编写一个好的数学库是非常困难的。因为为了使运算快速、为了以一种高效的方式编写它,我们需要非常特殊的编程技巧或者底层功底(涉及到寄存器和汇编代码)。
GLM 库
遗憾的是对于这个系列而言我们谈论的大多是 C++,如何建立一个高效数学库并不在我们的考量范围内。因此我们会使用称为 OpenGL Mathematics(简称 glm)的支持库:
它是一个用于图形的 C++ 数学库,虽然名字带着 OpenGL,但请注意它与 OpenGL 无关,只是语法近似于 OpenGL 的数学库。
现在让我们引入该库:
cd Infinite git submodule add https://github.com/g-truc/glm Infinite/vendor/glm
|
预生成文件
在项目 Infinite
的预生成文件 premake5.lua
中加入 glm
:
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 示例代码:
#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; }
|
#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(); }
|
加入示例代码后如成功启动则代表引入成功,测试完毕删除示例代码。