소스 검색

feat: 实现天空盒

NiceTry12138 9 달 전
부모
커밋
dfb1a11117

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

@@ -804,4 +804,28 @@ cmake ../ -A win32
 
 **天空盒** 顾名思义就是其实是将世界包围在一个巨大的盒子里面,然后通过当前相机朝向作为向量计算与立方体贴图交点,得到背景颜色信息
 
+在绘制天空盒的时候,消除相机位移的影响,保证天空盒的中心永远在相机上,这样子就能保证天空盒不会由于相机移动导致偏移
+
+对比将天空盒放大到特别大来模拟效果,首先过远的平面会被剔除,其次相机一直移动总归是能够移动到边界的
+
+```cpp
+// 通过将 4阶矩阵 转换为 3阶矩阵 去除位移信息,保证天空盒永远以相机为中心
+auto cubeView = glm::mat4(glm::mat3(view));
+```
+
+绘制天空盒需要保证天空盒的深度永远是最底层的,有两种方案
+
+1. 绘制天空盒时关闭深度写入,这样天空盒就会永远绘制带其他物体之后,虽然它离我们很近,但是实际的深度却很高
+2. 根据深度计算的公式,将天空盒顶点的计算值永远设置为 1,那么其深度永远低于其他
+
+前面写过顶点着色器,顶点其实是一个四维向量 (x、y、z、w),顶点的 NDC 坐标其实 (x/w, y/w, z/w) 
+
+所以,如果将天空盒的顶点 z 轴手动设置为 w,那么天空盒深度永远是 1,永远在其他物体的后面
+
+```glsl
+vec4 pos = projection * view * vec4(inPosition, 1.0);
+gl_Position = pos.xyww;
+```
+
+
 

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

@@ -495,6 +495,8 @@
     <None Include="res\shader\Light\Vertex.vert" />
     <None Include="res\shader\model\model.frag" />
     <None Include="res\shader\model\model.vert" />
+    <None Include="res\shader\SkyBox\model.frag" />
+    <None Include="res\shader\SkyBox\model.vert" />
     <None Include="res\shader\SkyBox\skybox.frag" />
     <None Include="res\shader\SkyBox\skybox.vert" />
     <None Include="res\shader\TextPosition\Fragment.frag" />

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

@@ -1476,6 +1476,8 @@
     <None Include="res\shader\TextPosition\Vertex.vert" />
     <None Include="res\shader\SkyBox\skybox.frag" />
     <None Include="res\shader\SkyBox\skybox.vert" />
+    <None Include="res\shader\SkyBox\model.frag" />
+    <None Include="res\shader\SkyBox\model.vert" />
   </ItemGroup>
   <ItemGroup>
     <Image Include="res\textures\test.jpg">

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

@@ -34,7 +34,7 @@ Size=396,162
 Collapsed=1
 
 [Window][SkyBox]
-Pos=353,55
+Pos=368,52
 Size=330,99
-Collapsed=0
+Collapsed=1
 

+ 13 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/SkyBox/model.frag

@@ -0,0 +1,13 @@
+#version 330 core
+
+layout(location = 0) out vec4 o_color;
+
+uniform sampler2D texture_diffuse1;     // 漫反射贴图
+uniform sampler2D texture_normal1;      // 法线贴图
+uniform sampler2D texture_shiness1;     // 镜面反射贴图
+
+in vec2 TexCoords;				// UV 坐标
+
+void main() {
+    o_color = vec4(texture(texture_diffuse1, TexCoords).rgb, 1.0);
+}

+ 16 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/SkyBox/model.vert

@@ -0,0 +1,16 @@
+#version 330 core
+
+layout (location = 0) in vec3 inPosition;
+layout (location = 1) in vec3 aNormal;
+layout (location = 2) in vec2 aTexCoords;
+
+uniform mat4 model;
+uniform mat4 view;
+uniform mat4 projection;
+
+out vec2 TexCoords;
+
+void main() {
+    TexCoords = aTexCoords;    
+  	gl_Position = projection * view * model * vec4(inPosition, 1.0);
+}

+ 4 - 4
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/CommonData.h

@@ -73,12 +73,12 @@ enum class ESkyBoxTextureType : uint8_t
 };
 
 static std::map<ESkyBoxTextureType, unsigned int> G_CubeTextureTypeMap = {
-	{ ESkyBoxTextureType::E_Right	, GL_TEXTURE_CUBE_MAP_POSITIVE_X },
-	{ ESkyBoxTextureType::E_Left	, GL_TEXTURE_CUBE_MAP_NEGATIVE_X },
+	{ ESkyBoxTextureType::E_Right	, GL_TEXTURE_CUBE_MAP_NEGATIVE_X  },
+	{ ESkyBoxTextureType::E_Left	, GL_TEXTURE_CUBE_MAP_POSITIVE_X},
 	{ ESkyBoxTextureType::E_Top		, GL_TEXTURE_CUBE_MAP_POSITIVE_Y },
 	{ ESkyBoxTextureType::E_Bottom	, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y },
-	{ ESkyBoxTextureType::E_Front	, GL_TEXTURE_CUBE_MAP_POSITIVE_Z },
-	{ ESkyBoxTextureType::E_Back	, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z },
+	{ ESkyBoxTextureType::E_Front	, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z},
+	{ ESkyBoxTextureType::E_Back	, GL_TEXTURE_CUBE_MAP_POSITIVE_Z  },
 };
 
 // 顶点信息 v0 版本 后续根据需要可能新增 v1、v2 ...

+ 9 - 2
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/SkyBox.cpp

@@ -26,16 +26,23 @@ void SkyBox::Init(const std::map<ESkyBoxTextureType, std::string> InTexturePath)
 
 void SkyBox::Draw(const glm::mat4& view, const glm::mat4& projection)
 {
+    // 通过将 4阶矩阵 转换为 3阶矩阵 去除位移信息,保证天空盒永远以相机为中心
+    auto cubeView = glm::mat4(glm::mat3(view));
+
+    glDepthFunc(GL_LEQUAL);
+
     const int TextureSlot = 1;
     m_cubeImage.BindCubeTexture(TextureSlot);
     m_skyShader.Bind();
     m_skyShader.SetUniform1i("cubeTexture", TextureSlot);
     m_skyShader.SetUniformMat4f("projection", projection);
-    m_skyShader.SetUniformMat4f("view", view);
+    m_skyShader.SetUniformMat4f("view", cubeView);
 
     glBindVertexArray(m_VAO);
     glDrawArrays(GL_TRIANGLES, 0, 6 * 6);
     glBindVertexArray(GL_ZERO);
+
+    glDepthFunc(GL_LESS);
 }
 
 void SkyBox::InitVAO()
@@ -99,7 +106,7 @@ void SkyBox::InitVAO()
     glBindVertexArray(GL_ZERO);
 }
 
-void SkyBox::InitImage()
+void SkyBox::InitImage()    
 {
     m_cubeImage.InitWithSkyBox(m_TexturePath);
 }

+ 1 - 1
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Texture.cpp

@@ -140,7 +140,7 @@ void Texture::InitWithSkyBox(const std::map<ESkyBoxTextureType, std::string>& In
 	glGenTextures(1, &m_TextureId);
 	glBindTexture(GL_TEXTURE_CUBE_MAP, m_TextureId);
 
-	stbi_set_flip_vertically_on_load(1);
+	stbi_set_flip_vertically_on_load(0);
 
 	for (const auto& TextureItem : InTexturesPath)
 	{

+ 7 - 8
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestSkyBox.cpp

@@ -9,7 +9,7 @@ void TestSkyBox::OnEnter(GLFWwindow* window)
 	glEnable(GL_DEPTH_TEST);
 
 	// 初始化 shader
-	m_ModelShader.Init("res/shader/model/model.vert", "res/shader/model/model.frag");
+	m_ModelShader.Init("res/shader/SkyBox/model.vert", "res/shader/SkyBox/model.frag");
 	m_packageModel.Init("res/model/Miku/miku_prefab.fbx");
 
 	m_Camera.SetLocation(glm::vec3(0.0f, 0.0f, 3.0f));
@@ -27,8 +27,8 @@ void TestSkyBox::OnExit(GLFWwindow* window)
 void TestSkyBox::UpdateLogic(float delayTime)
 {
 	m_view = m_Camera.GetView();
-	m_Camera.SetMoveSpeed(1);
-	m_Camera.SetRotateSpeed(1);
+	m_Camera.SetMoveSpeed(0.2f);
+	m_Camera.SetRotateSpeed(0.2f);
 
 	// 可能会更新窗口视口大小 每帧更新一下
 	m_proj = glm::perspective(glm::radians(45.0f), (float)RSI->ViewportHeight / (float)RSI->ViewportWidth, 0.1f, 100.0f);
@@ -43,15 +43,14 @@ void TestSkyBox::Render(GLFWwindow* window)
 {
 	m_ModelShader.Bind();
 
-
 	auto CameraLocation = m_Camera.GetCameraLocation();
 
-	m_ModelShader.SetUniformMat4f("model", glm::mat4(1.0f));
+	auto model = glm::mat4(1.0f);
+	model = glm::rotate(model, glm::radians(-90.0f), glm::vec3(1, 0, 0));
+
+	m_ModelShader.SetUniformMat4f("model", model);
 	m_ModelShader.SetUniformMat4f("view", m_view);
 	m_ModelShader.SetUniformMat4f("projection", m_proj);
-	m_ModelShader.SetUniform3f("lightPos", 0.0f, 0.0f, 0.0f);
-	m_ModelShader.SetUniform3f("viewPos", CameraLocation.x, CameraLocation.y, CameraLocation.z);
-	m_ModelShader.SetUniform1i("shineness", 4);
 
 	m_packageModel.Draw(m_ModelShader);