Просмотр исходного кода

feat: 添加相机的测试,并添加相机的移动属性

nicetry12138 10 месяцев назад
Родитель
Сommit
11cd4bb6ea

BIN
图形学/OpenGL学习/Image/030.png


BIN
图形学/OpenGL学习/Image/031.png


+ 69 - 0
图形学/OpenGL学习/OpenGLDemo.md

@@ -455,4 +455,73 @@ m_Tex2.Bind(1);
 
 ## 坐标系统
 
+`MVP` 矩阵 Module、View、Projection
+
+模型的顶点坐标的原点一般是模型的中心点,通过 Module 矩阵得到顶点的世界坐标
+
+得到世界坐标之后,将其转换成观察空间,也就是以相机为原点的坐标系下
+
+最后通过 Projectin 将顶点坐标进行裁剪,对于空间外的点剔除
+
+### 相机坐标
+
+相机需要定位朝向和坐标,以此来确定视图矩阵
+
+坐标无需多言,由 3 个 float 组成的结构体
+
+```cpp
+glm::vec3(0.0f, 0.0f, 3.0f);
+```
+
+`OpenGL` 是右手坐标系, X 轴正方向向右,Y轴正方向向上,Z轴正方向垂直屏幕向外
+
+所以,如果想要看到位于(0,0) 坐标的物体,并且相机向后移动的时候,物体缩小,一般是让相机沿着 Z 轴正方向移动
+
+接下来就是确定相机的朝向
+
+通过两个向量就可以确定相机的朝向,一个是 `LoopAt` 一个是 `Up Vector`
+
+确定 `LookAt` 的坐标点,通过 `LookAt` 坐标减去 相机坐标 得到一个方向向量,该向量就是相机朝向,通过这个向量可以确定相机朝向中的 `Yaw` 和 `Pitch`
+
+`Up Vector` 表示相机向上的向量,通过这个向量,确定相机朝向的 `Rall`
+
+不过有的时候,也可以需要知道相机的 `Right Vector`,不过这个比较好计算,通过 `Look` 和 `Up Vector` 通过**叉乘**便可以计算出 `Right Vector`
+
+```cpp
+// 计算 LookAt Vector
+glm::vec3 cameraTarget = glm::vec3(0.0f, 0.0f, 0.0f);
+glm::vec3 cameraDirection = glm::normalize(cameraPos - cameraTarget);
+
+// 定义 Up Vector
+glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f);
+
+// 计算 Right Vector
+glm::vec3 cameraRight = glm::normalize(glm::cross(up, cameraDirection));
+```
+
+通过上面计算的向量和坐标,可以计算得到 View 矩阵
+
+```cpp
+glm::mat4 view;
+						// 相机坐标					 	目标坐标							Up Vector
+view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f),  glm::vec3(0.0f, 0.0f, 0.0f),  glm::vec3(0.0f, 1.0f, 0.0f));
+```
+
+记住,`OpenGL` 的坐标系是右手坐标系,y轴向上,x轴向左,z轴垂直屏幕向外
+
+![](Image/030.png)
+
+所以 `direction.y = sin(pitch)`
+
+![](Image/031.png)
+
+在计算 `xz` 轴是,向量长度是 `cos(pitch)` 
+
+对应的点的坐标是 
+
+- `direction.x = cos(pitch) * cos(yaw)`
+- `direction.z = cos(pitch) * sin(yaw)`
+
+注意:此时 `Camera Up Vector` 保持不变,因为 `Up Vector` 是用于控制 `Roll` 的,一般不会变化
+
 

+ 2 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/OpenGLDemo.vcxproj

@@ -133,6 +133,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="src\testModule\TestCamera.cpp" />
     <ClCompile Include="src\Util\RenderSettings.cpp" />
     <ClCompile Include="src\third\glm\detail\glm.cpp" />
     <ClCompile Include="src\Util\CommonHead.cpp" />
@@ -153,6 +154,7 @@
     <ClCompile Include="src\Util\Texture.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="src\testModule\TestCamera.h" />
     <ClInclude Include="src\Util\RenderSettings.h" />
     <ClInclude Include="src\third\glm\common.hpp" />
     <ClInclude Include="src\third\glm\detail\compute_common.hpp" />

+ 6 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/OpenGLDemo.vcxproj.filters

@@ -69,6 +69,9 @@
     <ClCompile Include="src\Util\RenderSettings.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
+    <ClCompile Include="src\testModule\TestCamera.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\third\imgui\imstb_truetype.h">
@@ -974,6 +977,9 @@
     <ClInclude Include="src\Util\UtilTemplate.h">
       <Filter>头文件</Filter>
     </ClInclude>
+    <ClInclude Include="src\testModule\TestCamera.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shader\TextPosition\Vertex.vert" />

+ 7 - 2
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/imgui.ini

@@ -14,7 +14,12 @@ Size=391,97
 Collapsed=0
 
 [Window][Rotate]
-Pos=239,11
-Size=500,192
+Pos=615,4
+Size=291,161
+Collapsed=0
+
+[Window][Camera]
+Pos=281,42
+Size=339,96
 Collapsed=0
 

+ 1 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/CommonHead.h

@@ -8,6 +8,7 @@
 #include <set>
 #include <unordered_set>
 #include <vector>
+#include <algorithm>
 
 #include "glad/glad.h"
 #include "GLFW/glfw3.h"

+ 3 - 1
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/main.cpp

@@ -13,6 +13,7 @@
 
 #include "testModule/TestClearColor.h"
 #include "testModule/TestPosition.h"
+#include "testModule/TestCamera.h"
 
 
 // 定义回调函数
@@ -107,7 +108,8 @@ int main()
     InitImGUI(window);
 
     //TestClearColor TestApp;
-    TestPosition TestApp;
+    //TestPosition TestApp;
+    TestCamera TestApp;
 
     TestApp.OnEnter(window);
 

+ 194 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestCamera.cpp

@@ -0,0 +1,194 @@
+#include "TestCamera.h"
+#include "../Util/RenderSettings.h"
+
+void TestCamera::OnEnter(GLFWwindow* window)
+{
+	//					 坐标					颜色						UV 坐标			贴图序号
+	m_vertexs.push_back({ 0.5f,  0.5f, -0.5f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 1.0f,		0 });
+	m_vertexs.push_back({ 0.5f, -0.5f, -0.5f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 0.0f,		0 });
+	m_vertexs.push_back({ -0.5f, -0.5f, -0.5f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 0.0f,		1 });
+	m_vertexs.push_back({ -0.5f,  0.5f, -0.5f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 1.0f,		1 });
+	m_vertexs.push_back({ 0.5f,  0.5f,  0.5f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 1.0f,		0 });
+	m_vertexs.push_back({ 0.5f, -0.5f,  0.5f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 0.0f,		0 });
+	m_vertexs.push_back({ -0.5f, -0.5f,  0.5f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 0.0f,		1 });
+	m_vertexs.push_back({ -0.5f,  0.5f,  0.5f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 1.0f,		1 });
+
+	GLuint indices[] = {
+		0, 1, 2, 2, 3, 0,			// 组成下面的两个三角形
+		4, 5, 6, 6, 7, 4,			
+		1, 2, 6, 6, 5, 1,
+		0, 1, 5, 5, 4, 0,
+		2, 3, 7, 7, 6, 2,
+		0, 3, 4, 4, 7, 3,
+	};
+	
+	// 启动深度测试
+	glEnable(GL_DEPTH_TEST);
+
+	// 创建 VAO
+	glGenVertexArrays(1, &m_VAO);
+
+	// 绑定 VAO
+	glBindVertexArray(m_VAO);
+
+	// 创建 VBO IB
+	glGenBuffers(1, &m_VBO);
+	glGenBuffers(1, &m_IB);
+
+	// 绑定 VBO 和 数据
+	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_VBO));
+	GL_CALL(glBufferData(GL_ARRAY_BUFFER, m_vertexs.size() * sizeof(Vertex_v0), m_vertexs.data(), GL_STATIC_DRAW));
+
+	// 绑定 IB 和 数据
+	GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IB));
+	GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW));
+
+	// 设置 VAO 内存结构
+	GL_CALL(glEnableVertexAttribArray(0));
+	GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex_v0), (void *)offsetof(Vertex_v0, position)));
+
+	GL_CALL(glEnableVertexAttribArray(1));
+	GL_CALL(glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex_v0), (void*)offsetof(Vertex_v0, color)));
+
+	GL_CALL(glEnableVertexAttribArray(2));
+	GL_CALL(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex_v0), (void*)offsetof(Vertex_v0, texCoord)));
+
+	GL_CALL(glEnableVertexAttribArray(3));
+	GL_CALL(glVertexAttribPointer(3, 1, GL_INT, GL_FALSE, sizeof(Vertex_v0), (void*)offsetof(Vertex_v0, texIndex)));
+
+	// 初始化 shader
+	//m_Shader.NewInit("res/shader/TextPosition/Vertex.vert", "res/shader/TextPosition/Fragment.frag");
+	m_Shader.Init("res/shader/TextPosition/Vertex.vert", "res/shader/TextPosition/Fragment.frag");
+
+	// 初始化 texture
+	m_Tex1.Init("res/textures/test2.png");
+	m_Tex2.Init("res/textures/test3.png");
+
+	m_Tex1.Bind(0);
+	m_Tex2.Bind(1);
+
+	m_Shader.UnBind();
+
+	// 设置鼠标捕获和隐藏
+	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+	glfwSetWindowUserPointer(window, this);
+	glfwSetCursorPosCallback(window, &TestCamera::StaticMouseCallback);
+}
+
+void TestCamera::OnExit(GLFWwindow* window)
+{
+	glfwSetWindowUserPointer(window, nullptr);
+}
+
+void TestCamera::UpdateLogic(float delayTime)
+{
+	m_model = glm::mat4(1.0f);
+	m_view = glm::lookAt(m_CameraLocation, m_CameraLocation + m_CameraForward, m_CameraUp);
+
+	// 可能会更新窗口视口大小 每帧更新一下
+	m_proj = glm::perspective(glm::radians(45.0f), (float)RSI->ViewportHeight / (float)RSI->ViewportWidth, 0.1f, 100.0f);
+}
+
+void TestCamera::ClearRender(GLFWwindow* window)
+{
+	//TestBase::ClearRender(window);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void TestCamera::Render(GLFWwindow* window)
+{
+	m_Shader.Bind();
+	m_Shader.SetUniform1i("u_Texture0", 0);
+	m_Shader.SetUniform1i("u_Texture1", 1);
+
+	m_Shader.SetUniformMat4f("model", m_model);
+	m_Shader.SetUniformMat4f("view", m_view);
+	m_Shader.SetUniformMat4f("projection", m_proj);
+
+	glBindVertexArray(m_VAO);
+	glDrawElements(GL_TRIANGLES, 6 * 6, GL_UNSIGNED_INT, 0);
+}
+
+void TestCamera::UpdateImGUI(GLFWwindow* window)
+{
+	const auto& io = ImGui::GetIO();
+
+	ImGui::Begin("Camera");
+
+	ImGui::SliderFloat("Camera Move Speed", &m_MoveSpeed, 0.0f, 0.1f);
+	ImGui::SliderFloat("Camera Rotate Speed", &m_RorateSpeed, 0.01f, 0.1f);
+
+	if (ImGui::Button("Close Window"))
+		glfwSetWindowShouldClose(window, true);
+
+	ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
+	ImGui::End();
+}
+
+void TestCamera::InputProcess(GLFWwindow* window)
+{
+	TestBase::InputProcess(window);
+
+	if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
+	{
+		m_CameraLocation -= glm::normalize(glm::cross(m_CameraForward, m_CameraUp)) * m_MoveSpeed;
+	}
+	else if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
+	{
+		m_CameraLocation += glm::normalize(glm::cross(m_CameraForward, m_CameraUp)) * m_MoveSpeed;
+	}
+	else if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
+	{
+		m_CameraLocation += m_CameraForward * m_MoveSpeed;
+	}
+	else if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
+	{
+		m_CameraLocation -= m_CameraForward * m_MoveSpeed;
+	}
+}
+
+void TestCamera::StaticMouseCallback(GLFWwindow* window, double xpos, double ypos)
+{
+	TestCamera* test = static_cast<TestCamera*>(glfwGetWindowUserPointer(window));
+	if (test)
+	{
+		test->MouseCallback(window, xpos, ypos);
+	}
+}
+
+void TestCamera::MouseCallback(GLFWwindow* window, double xpos, double ypos)
+{
+	if (m_isFirstMouse)
+	{
+		m_LastMousePosX = xpos;
+		m_LastMousePosY = ypos;
+		m_isFirstMouse = false;
+	}
+
+	float offsetX = xpos - m_LastMousePosX;
+	// OpenGL 屏幕空间 Y 轴正方向向下,所以向下移动时 ypos 会增加
+	float offsetY = -(ypos - m_LastMousePosY);
+
+	m_LastMousePosY = ypos;
+	m_LastMousePosX = xpos;
+
+	offsetX *= m_RorateSpeed;	// 比例变换
+	offsetY *= m_RorateSpeed;
+
+	m_CameraYaw += offsetX;
+	m_CameraPitch += offsetY;
+
+	// 限制 pitch 仰角的大小,你头向上仰也有一个限制 类似的
+	if (m_CameraPitch > 89.0f || m_CameraPitch < -89.0f)
+	{
+		m_CameraPitch = glm::clamp(m_CameraPitch, -89.0f, 89.0f);
+	}
+
+	glm::vec3 front;
+	front.x = cos(glm::radians(m_CameraYaw)) * cos(glm::radians(m_CameraPitch));
+	front.y = sin(glm::radians(m_CameraPitch));
+	front.z = sin(glm::radians(m_CameraYaw)) * cos(glm::radians(m_CameraPitch));
+	m_CameraForward = glm::normalize(front);
+
+	std::cout << "x " << m_CameraForward.r << " y " << m_CameraForward.g << " z " << m_CameraForward.b << std::endl;
+}

+ 57 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestCamera.h

@@ -0,0 +1,57 @@
+#pragma once
+#include "TestBase.h"
+#include "../Util/CommonData.h"
+
+#include "../Util/Shader.h"
+#include "../Util/Texture.h"
+
+class TestCamera : public TestBase
+{
+public:
+	virtual void OnEnter(GLFWwindow* window) override;
+	virtual void OnExit(GLFWwindow* window) override;
+
+	virtual void UpdateLogic(float delayTime) override;
+	virtual void ClearRender(GLFWwindow* window) override;
+	virtual void Render(GLFWwindow* window) override;
+	virtual void UpdateImGUI(GLFWwindow* window) override;
+
+	virtual void InputProcess(GLFWwindow* window) override;
+
+public:
+	static void StaticMouseCallback(GLFWwindow* window, double xpos, double ypos);
+
+	void MouseCallback(GLFWwindow* window, double xpos, double ypos);
+
+private:
+	GLuint m_VBO{ GL_ZERO };
+	GLuint m_VAO{ GL_ZERO };
+	GLuint m_IB{ GL_ZERO };
+
+	Shader m_Shader;
+	Texture m_Tex1;
+	Texture m_Tex2;
+
+	std::vector<Vertex_v0> m_vertexs;
+
+	glm::mat4 m_model = glm::mat4(1.0f);		// 模型矩阵
+	glm::mat4 m_view = glm::mat4(1.0f);			// 视图矩阵
+	glm::mat4 m_proj = glm::mat4(1.0f);			// 投影矩阵
+
+	glm::vec3 m_CameraLocation = glm::vec3(0.0f, 0.0f, 3.0f);
+
+
+	glm::vec3 m_CameraForward = glm::vec3(0.0f, 0.0f, -1.0f);
+	glm::vec3 m_CameraUp = glm::vec3(0.0f, 1.0f, 0.0f);
+
+	float m_MoveSpeed = 0.1f;
+	float m_RorateSpeed = 0.1f;
+
+	float m_CameraPitch = 0.0f;
+	float m_CameraYaw = -90.0f;
+
+	float m_LastMousePosX;
+	float m_LastMousePosY;
+	bool m_isFirstMouse = true;
+};
+

+ 21 - 9
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestPosition.cpp

@@ -4,15 +4,26 @@
 void TestPosition::OnEnter(GLFWwindow* window)
 {
 	//					 坐标					颜色						UV 坐标			贴图序号
-	m_vertexs.push_back({ 0.5f,  0.5f, 0.0f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 1.0f,		0 });
-	m_vertexs.push_back({ 0.5f, -0.5f, 0.0f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 0.0f,		0 });
-	m_vertexs.push_back({ -0.5f, -0.5f, 0.0f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 0.0f,		1 });
-	m_vertexs.push_back({ -0.5f,  0.5f, 0.0f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 1.0f,		1 });
+	m_vertexs.push_back({ 0.5f,  0.5f, -0.5f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 1.0f,		0 });	// 立方体 下面 右上角
+	m_vertexs.push_back({ 0.5f, -0.5f, -0.5f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 0.0f,		0 });	// 立方体 下面 右下角
+	m_vertexs.push_back({ -0.5f, -0.5f, -0.5f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 0.0f,		1 });	// 立方体 下面 左下角
+	m_vertexs.push_back({ -0.5f,  0.5f, -0.5f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 1.0f,		1 });	// 立方体 下面 左上角
+	m_vertexs.push_back({ 0.5f,  0.5f,  0.5f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 1.0f,		0 });	// 立方体 上面 右上角
+	m_vertexs.push_back({ 0.5f, -0.5f,  0.5f,	1.0f, 1.0f, 0.0f, 1.0f,		1.0f, 0.0f,		0 });	// 立方体 上面 右下角
+	m_vertexs.push_back({ -0.5f, -0.5f,  0.5f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 0.0f,		1 });	// 立方体 上面 左下角
+	m_vertexs.push_back({ -0.5f,  0.5f,  0.5f,	0.0f, 1.0f, 1.0f, 1.0f,		0.0f, 1.0f,		1 });	// 立方体 上面 左上角
 
 	GLuint indices[] = {
-		0, 1, 2,
-		2, 3, 0
+		0, 1, 2, 2, 3, 0,			// 组成下面的两个三角形
+		4, 5, 6, 6, 7, 4,			
+		1, 2, 6, 6, 5, 1,
+		0, 1, 5, 5, 4, 0,
+		2, 3, 7, 7, 6, 2,
+		0, 3, 4, 4, 7, 3,
 	};
+	
+	// 启动深度测试
+	glEnable(GL_DEPTH_TEST);
 
 	// 创建 VAO
 	glGenVertexArrays(1, &m_VAO);
@@ -84,12 +95,13 @@ void TestPosition::UpdateLogic(float delayTime)
 	m_view = glm::translate(glm::mat4(1.0f), m_Transition);
 
 	// 可能会更新窗口视口大小 每帧更新一下
-	m_proj = glm::perspective(glm::radians(45.0f), (float)RSI->ViewportWidth / (float)RSI->ViewportWidth, 0.1f, 100.0f);
+	m_proj = glm::perspective(glm::radians(45.0f), (float)RSI->ViewportHeight / (float)RSI->ViewportWidth, 0.1f, 100.0f);
 }
 
 void TestPosition::ClearRender(GLFWwindow* window)
 {
-	TestBase::ClearRender(window);
+	//TestBase::ClearRender(window);
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 }
 
 void TestPosition::Render(GLFWwindow* window)
@@ -103,7 +115,7 @@ void TestPosition::Render(GLFWwindow* window)
 	m_Shader.SetUniformMat4f("projection", m_proj);
 
 	glBindVertexArray(m_VAO);
-	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
+	glDrawElements(GL_TRIANGLES, 6 * 6, GL_UNSIGNED_INT, 0);
 }
 
 void TestPosition::UpdateImGUI(GLFWwindow* window)