Przeglądaj źródła

feat: 封装 Camera 类和绑定鼠标的基类

NiceTry12138 10 miesięcy temu
rodzic
commit
da0185f6a2

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


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


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

@@ -524,4 +524,38 @@ view = glm::lookAt(glm::vec3(0.0f, 0.0f, 3.0f),  glm::vec3(0.0f, 0.0f, 0.0f),  g
 
 注意:此时 `Camera Up Vector` 保持不变,因为 `Up Vector` 是用于控制 `Roll` 的,一般不会变化
 
+## 颜色
+
+人能观察到物体的颜色,其实是物体不能吸收的颜色,也可以理解为反射的颜色
+
+![](Image/032.png)
+
+如果一个物体是白色,那么它对 RGB 三通道的颜色的吸收率是 0%,也就是 RGB 的反射率是 100%,所以它的 RGB 值为 (1.0, 1.0, 1.0)
+
+如果一个物体是黑色,那么它对 RGB 三通道的颜色的吸收率是 100%,也就是 RGB 的反射率是 0%,所以它的 RGB 值为 (0.0, 0.0, 0.0)
+
+如果一个物体是正红色,那么它对 RGB 三通道的颜色的吸收率是 0%,100%,100%,所以它的 RGB 值为 (1.0, 0.0, 0.0)
+
+如果一个红色光打在蓝色的物体上,这个物体显示的颜色应该是黑色,光的颜色是 (1, 0, 0),物体是蓝色,的三通道的反射率是 (0, 0, 1),相乘得到的结果是 (0, 0, 0)
+
+推理得到下面的基本光照计算
+
+```cpp
+glm::vec3 lightColor(l1, l2, l3);	// l1、l2、l3 光照的 RGB 值 
+glm::vec3 toyColor(t1, t2, t3);		// t1、t2、t3 物体的 RGB 值
+glm::vec3 finalColor = lightColor * toyColor;
+```
+
+现实生活中,光照是很复杂的,通过简化的光照模型可以用较少的计算量模拟出现实光照
+
+使用的较多的简单光照模型就是 Phong 模型,它包括:环境光、漫反射光、镜面反射光
+
+- 环境光照( `Ambient` ):即使在黑暗的情况下,通常也有一些光亮(月光、星光等),所以物体通常不是完全黑暗的,为了模拟这个设置了环境光照,他永远会给物体一些颜色
+- 漫反射光照( `Diffuse` ):模拟光源对物体的方向性影响
+- 镜面光照( `Specular` ):模拟光泽物体上出现的亮点
+
+![](Image/033.png)
+
+[101中关于漫反射的计算](../Games101/图形学.md#blinn-phong反射模型)
+
 

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

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

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

@@ -72,6 +72,15 @@
     <ClCompile Include="src\testModule\TestCamera.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
+    <ClCompile Include="src\testModule\TestLight.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Util\Camera.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="src\testModule\TestWithMouseBase.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\third\imgui\imstb_truetype.h">
@@ -980,6 +989,15 @@
     <ClInclude Include="src\testModule\TestCamera.h">
       <Filter>头文件</Filter>
     </ClInclude>
+    <ClInclude Include="src\testModule\TestLight.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Util\Camera.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="src\testModule\TestWithMouseBase.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shader\TextPosition\Vertex.vert" />

+ 76 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Camera.cpp

@@ -0,0 +1,76 @@
+#include "Camera.h"
+
+void Camera::InputProcess(GLFWwindow* 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 Camera::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_Yaw += offsetX;
+	m_Pitch += offsetY;
+
+	// 限制 pitch 仰角的大小,你头向上仰也有一个限制 类似的
+	if (m_Pitch > 89.0f || m_Pitch < -89.0f)
+	{
+		m_Pitch = glm::clamp(m_Pitch, -89.0f, 89.0f);
+	}
+
+	glm::vec3 front;
+	front.x = cos(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch));
+	front.y = sin(glm::radians(m_Pitch));
+	front.z = sin(glm::radians(m_Yaw)) * cos(glm::radians(m_Pitch));
+	m_CameraForward = glm::normalize(front);
+}
+
+glm::mat4 Camera::GetView()
+{
+	return glm::lookAt(m_CameraLocation, m_CameraLocation + m_CameraForward, m_CameraUp);
+}
+
+void Camera::SetFirstMouse(bool bIsFirst)
+{
+	m_isFirstMouse = bIsFirst;
+}
+
+void Camera::SetMoveSpeed(float moveSpeed)
+{
+	m_MoveSpeed = moveSpeed;
+}
+
+void Camera::SetRotateSpeed(float rotateSpeed)
+{
+	m_RorateSpeed = rotateSpeed;
+}

+ 32 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Camera.h

@@ -0,0 +1,32 @@
+#pragma once
+#include "CommonHead.h"
+
+class Camera
+{
+public:
+	void InputProcess(GLFWwindow* window);
+	void MouseCallback(GLFWwindow* window, double xpos, double ypos);
+	glm::mat4 GetView();
+
+public:
+	void SetFirstMouse(bool bIsFirst);
+	void SetMoveSpeed(float moveSpeed);
+	void SetRotateSpeed(float rotateSpeed);
+
+private:
+	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_Pitch = 0;
+	float m_Yaw = -90;
+	float m_Roll = 0;
+
+	float m_MoveSpeed = 0.1f;
+	float m_RorateSpeed = 0.1f;
+
+	float m_LastMousePosX;
+	float m_LastMousePosY;
+	bool m_isFirstMouse = true;			// 防止鼠标进入捕获状态时 突然闪烁
+};
+

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

@@ -14,6 +14,7 @@
 #include "testModule/TestClearColor.h"
 #include "testModule/TestPosition.h"
 #include "testModule/TestCamera.h"
+#include "testModule/TestLight.h"
 
 
 // 定义回调函数
@@ -109,7 +110,8 @@ int main()
 
     //TestClearColor TestApp;
     //TestPosition TestApp;
-    TestCamera TestApp;
+    //TestCamera TestApp;
+    TestLight TestApp;
 
     TestApp.OnEnter(window);
 

+ 159 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestLight.cpp

@@ -0,0 +1,159 @@
+#include "TestLight.h"
+#include "../Util/RenderSettings.h"
+
+void TestLight::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();
+
+	BindMouse(window);
+}
+
+void TestLight::OnExit(GLFWwindow* window)
+{
+	glfwSetWindowUserPointer(window, nullptr);
+}
+
+void TestLight::UpdateLogic(float delayTime)
+{
+	m_model = glm::mat4(1.0f);
+	m_view = m_Camera.GetView();
+	m_Camera.SetMoveSpeed(m_CameraMoveSpeed);
+	m_Camera.SetRotateSpeed(m_CameraRotateSpeed);
+
+	// 可能会更新窗口视口大小 每帧更新一下
+	m_proj = glm::perspective(glm::radians(45.0f), (float)RSI->ViewportHeight / (float)RSI->ViewportWidth, 0.1f, 100.0f);
+}
+
+void TestLight::ClearRender(GLFWwindow* window)
+{
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void TestLight::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 TestLight::UpdateImGUI(GLFWwindow* window)
+{
+	const auto& io = ImGui::GetIO();
+
+	ImGui::Begin("Camera");
+
+	ImGui::SliderFloat("Camera Move Speed", &m_CameraMoveSpeed, 0.0f, 0.1f);
+	ImGui::SliderFloat("Camera Rotate Speed", &m_CameraRotateSpeed, 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 TestLight::InputProcess(GLFWwindow* window)
+{
+	TestWithMouseBase::InputProcess(window);
+	
+	m_Camera.InputProcess(window);
+	
+	if (glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS)
+	{
+		m_bLeftAltPress = true;
+		UnBindMouse(window);
+	}
+	else if(m_bLeftAltPress) {
+		// 因为当前状况 如果不按下 左 alt,每帧都会导致该函数触发,加个判断防止重复触发
+		m_bLeftAltPress = false;
+		BindMouse(window);
+	}
+}
+
+void TestLight::MouseCallback(GLFWwindow* window, double xpos, double ypos)
+{
+	m_Camera.MouseCallback(window, xpos, ypos);
+}
+
+void TestLight::BindMouse(GLFWwindow* window)
+{
+	m_Camera.SetFirstMouse(true);
+	TestWithMouseBase::BindMouse(window);
+}
+
+void TestLight::UnBindMouse(GLFWwindow* window)
+{
+	m_Camera.SetFirstMouse(false);
+	TestWithMouseBase::UnBindMouse(window);
+}

+ 50 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestLight.h

@@ -0,0 +1,50 @@
+#pragma once
+#include "TestWithMouseBase.h"
+#include "../Util/CommonData.h"
+
+#include "../Util/Shader.h"
+#include "../Util/Texture.h"
+#include "../Util/Camera.h"
+
+class TestLight : public TestWithMouseBase
+{
+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;
+
+	virtual void MouseCallback(GLFWwindow* window, double xpos, double ypos) override;
+
+	virtual void BindMouse(GLFWwindow* window) override;
+	virtual void UnBindMouse(GLFWwindow* window) override;
+public:
+
+
+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);			// 投影矩阵
+
+	float m_CameraMoveSpeed = 0.1f;
+	float m_CameraRotateSpeed = 0.1f;
+
+	Camera m_Camera;
+	bool m_bLeftAltPress = false;
+};
+

+ 27 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestWithMouseBase.cpp

@@ -0,0 +1,27 @@
+#include "TestWithMouseBase.h"
+
+void TestWithMouseBase::BindMouse(GLFWwindow* window)
+{
+	// 设置鼠标捕获和隐藏
+	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
+	glfwSetWindowUserPointer(window, this);
+	glfwSetCursorPosCallback(window, &TestWithMouseBase::StaticMouseCallback);
+}
+
+void TestWithMouseBase::UnBindMouse(GLFWwindow* window)
+{
+	glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
+
+	// 因为设置自己的鼠标绑定把 ImGUI 的鼠标绑定覆盖了 所以退出自己的鼠标绑定时 重新让 ImGUI 绑定
+	ImGui_ImplGlfw_RestoreCallbacks(window);
+	ImGui_ImplGlfw_InstallCallbacks(window);
+}
+
+void TestWithMouseBase::StaticMouseCallback(GLFWwindow* window, double xpos, double ypos)
+{
+	TestWithMouseBase* test = static_cast<TestWithMouseBase*>(glfwGetWindowUserPointer(window));
+	if (test)
+	{
+		test->MouseCallback(window, xpos, ypos);
+	}
+}

+ 17 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestWithMouseBase.h

@@ -0,0 +1,17 @@
+#pragma once
+
+#include "../Util/CommonHead.h"
+#include "TestBase.h"
+
+class TestWithMouseBase : public TestBase
+{
+public:
+	virtual void BindMouse(GLFWwindow* window);
+	virtual void UnBindMouse(GLFWwindow* window);
+
+	static void StaticMouseCallback(GLFWwindow* window, double xpos, double ypos);
+
+	// 绑定之后 触发的鼠标事件回调函数
+	virtual void MouseCallback(GLFWwindow* window, double xpos, double ypos) = 0;
+};
+