Selaa lähdekoodia

feat: 添加镜面反射贴图和高光反射贴图的实现

NiceTry12138 10 kuukautta sitten
vanhempi
commit
faf172919c

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


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


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


+ 23 - 1
图形学/OpenGL学习/OpenGLDemo.md

@@ -524,7 +524,7 @@ 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` 的,一般不会变化
 
-## 颜色
+## 颜色和光照
 
 人能观察到物体的颜色,其实是物体不能吸收的颜色,也可以理解为反射的颜色
 
@@ -649,4 +649,26 @@ struct Vertex_v1
 
 ![](Image/034.png)
 
+物体具体是什么颜色,可以通过贴图来表现,物体的高光颜色强度也可以通过贴图来表示
+
+| 物体漫反射颜色 | 物体镜面反射颜色 |
+| --- | --- | 
+| ![](Image/035.png) | ![](Image/036.png) |
+
+在片段着色器中,可以使用 UV 坐标获取贴图颜色,将漫反射颜色 + 镜面反射颜色 得到的就是最后物体表现的颜色
+
+```cpp
+// 通过贴图 漫反射颜色
+vec3 diffuse = light.diffuse * diff * texture(cubeMaterial.diffuse, TexCoords).rgb;
+// 通过贴图 镜面反射颜色  
+vec3 specular = light.specular * spec * texture(cubeMaterial.specular, TexCoords).rgb;  
+```
+
+![](Image/037.png)
+
+观察箱子的表面
+
+- 在镜面反射贴图中间是一片黑色,所以物体中间几乎没有镜面反射的高光
+- 在镜面反射贴图四周是带有花纹的白色,所以物体四周会有不规则的高光,模拟出磨损的效果
+
 

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

@@ -133,6 +133,7 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="src\testModule\TestLightCube.cpp" />
     <ClCompile Include="src\testModule\TestModuleManager.cpp" />
     <ClCompile Include="src\testModule\TestWithMouseBase.cpp" />
     <ClCompile Include="src\Util\Camera.cpp" />
@@ -158,6 +159,7 @@
     <ClCompile Include="src\Util\Texture.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="src\testModule\TestLightCube.h" />
     <ClInclude Include="src\testModule\TestModuleManager.h" />
     <ClInclude Include="src\testModule\TestWithMouseBase.h" />
     <ClInclude Include="src\Util\Camera.h" />
@@ -466,6 +468,8 @@
     <ClInclude Include="src\Util\UtilTemplate.h" />
   </ItemGroup>
   <ItemGroup>
+    <None Include="res\shader\Light\Cube.frag" />
+    <None Include="res\shader\Light\Cube.vert" />
     <None Include="res\shader\Light\Fragment.frag" />
     <None Include="res\shader\Light\LightFragment.frag" />
     <None Include="res\shader\Light\LightVertex.vert" />
@@ -610,6 +614,8 @@
     <None Include="src\third\glm\gtx\wrap.inl" />
   </ItemGroup>
   <ItemGroup>
+    <Image Include="res\textures\light\container2.png" />
+    <Image Include="res\textures\light\container2_specular.png" />
     <Image Include="res\textures\test.jpg" />
     <Image Include="res\textures\test2.png" />
     <Image Include="res\textures\test3.png" />

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

@@ -84,6 +84,9 @@
     <ClCompile Include="src\testModule\TestModuleManager.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
+    <ClCompile Include="src\testModule\TestLightCube.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\third\imgui\imstb_truetype.h">
@@ -1004,6 +1007,9 @@
     <ClInclude Include="src\testModule\TestModuleManager.h">
       <Filter>头文件</Filter>
     </ClInclude>
+    <ClInclude Include="src\testModule\TestLightCube.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
   </ItemGroup>
   <ItemGroup>
     <None Include="res\shader\TextPosition\Vertex.vert" />
@@ -1420,6 +1426,8 @@
     <None Include="res\shader\Light\Vertex.vert" />
     <None Include="res\shader\Light\LightFragment.frag" />
     <None Include="res\shader\Light\LightVertex.vert" />
+    <None Include="res\shader\Light\Cube.frag" />
+    <None Include="res\shader\Light\Cube.vert" />
   </ItemGroup>
   <ItemGroup>
     <Image Include="res\textures\test.jpg">
@@ -1431,6 +1439,12 @@
     <Image Include="res\textures\test3.png">
       <Filter>资源文件</Filter>
     </Image>
+    <Image Include="res\textures\light\container2.png">
+      <Filter>资源文件</Filter>
+    </Image>
+    <Image Include="res\textures\light\container2_specular.png">
+      <Filter>资源文件</Filter>
+    </Image>
   </ItemGroup>
   <ItemGroup>
     <Text Include="src\third\glm\CMakeLists.txt" />

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

@@ -9,7 +9,7 @@ Size=339,117
 Collapsed=0
 
 [Window][Common Test Title]
-Pos=6,5
+Pos=6,7
 Size=174,184
 Collapsed=0
 

+ 46 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/Light/Cube.frag

@@ -0,0 +1,46 @@
+#version 330 core
+
+layout(location = 0) out vec4 o_color;
+
+struct Material {
+    sampler2D diffuse;
+    sampler2D specular;
+    int shininess;
+}; 
+
+struct Light {
+    vec3 ambient;
+    vec3 diffuse;
+    vec3 specular;
+
+	vec3 lightPos;
+}; 
+
+uniform Material cubeMaterial;
+uniform Light light;
+
+in vec3 FragPos;                // 顶点坐标
+in vec3 Normal;					// 法线向量
+in vec2 TexCoords;				// UV 坐标
+
+uniform vec3 viewPos;           // 相机坐标
+
+void main() {
+    // 环境光
+    vec3 ambient = light.ambient * texture(cubeMaterial.diffuse, TexCoords).rgb;
+    
+    // 漫反射 
+    vec3 norm = normalize(Normal);
+    vec3 lightDir = normalize(light.lightPos - FragPos);
+    float diff = max(dot(norm, lightDir), 0.0);
+    vec3 diffuse = light.diffuse * diff * texture(cubeMaterial.diffuse, TexCoords).rgb;  
+    
+    // 镜面反射
+    vec3 viewDir = normalize(viewPos - FragPos);
+    vec3 reflectDir = reflect(-lightDir, norm);  
+    float spec = pow(max(dot(viewDir, reflectDir), 0.0), cubeMaterial.shininess);
+    vec3 specular = light.specular * spec * texture(cubeMaterial.specular, TexCoords).rgb;  
+    
+    vec3 result = ambient + diffuse + specular;
+    o_color = vec4(result, 1.0);
+}

+ 21 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/Light/Cube.vert

@@ -0,0 +1,21 @@
+#version 330 core
+
+layout(location = 0) in vec3 inPosition;
+layout(location = 1) in vec3 inNormal;
+layout(location = 2) in vec2 inTexCoords;
+
+uniform mat4 model;
+uniform mat4 view;
+uniform mat4 projection;
+
+out vec3 Normal;
+out vec3 FragPos;
+out vec2 TexCoords;
+
+void main() {
+	FragPos = vec3(model * vec4(inPosition, 1.0));
+	Normal = mat3(transpose(inverse(model))) * inNormal;
+	TexCoords = inTexCoords;
+
+	gl_Position = projection * view * model * vec4(inPosition, 1.0);
+}

BIN
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/textures/light/container2.png


BIN
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/textures/light/container2_specular.png


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

@@ -18,6 +18,14 @@ struct Vertex_v1
 	float normal[3];			  // 法线贴图
 };
 
+// 顶点信息 v2 版本 
+struct Vertex_v2
+{
+	float position[3];			  // 顶点坐标
+	float normal[3];			  // 法线贴图
+	float texCoords[2];			  // UV 坐标
+};
+
 
 // 材质
 struct Material_v0
@@ -37,3 +45,12 @@ struct LightConfig_v0
 
 	glm::vec3 lightPos;		// 灯光的坐标
 };
+
+
+struct Material_v1
+{
+	GLuint diffuse;			// 漫反射光贴图
+	GLuint specular;		// 高光颜色贴图
+
+	int shininesss;			// 反光度
+};

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

@@ -38,6 +38,7 @@ void Texture::Init(const std::string& filePath)
 
 void Texture::Bind(GLuint slot)
 {
+	m_LastBindSlot = slot;
 	GL_CALL(glActiveTexture(GL_TEXTURE0 + slot));
 	GL_CALL(glBindTexture(GL_TEXTURE_2D, m_TextureId));
 }
@@ -57,6 +58,11 @@ int Texture::GetWidth()
 	return m_Width;
 }
 
+GLuint Texture::GetBindSlot()
+{
+	return m_LastBindSlot;
+}
+
 void Texture::DeleteTexture()
 {
 	stbi_image_free(m_LocalBuffer);

+ 3 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Texture.h

@@ -14,6 +14,8 @@ public:
 	int GetHeight();
 	int GetWidth();
 
+	GLuint GetBindSlot();
+
 	void DeleteTexture();
 private:
 	GLubyte* m_LocalBuffer{ nullptr };
@@ -22,5 +24,6 @@ private:
 	std::string m_FilePath;
 
 	GLuint m_TextureId{ GL_ZERO };
+	GLuint m_LastBindSlot;
 };
 

+ 241 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestLightCube.cpp

@@ -0,0 +1,241 @@
+#include "TestLightCube.h"
+#include "../Util/RenderSettings.h"
+
+TestLightCube TestLightCube::_self;
+
+void TestLightCube::OnEnter(GLFWwindow* window)
+{
+	//					 坐标					顶点法线	
+	m_vertexs.push_back({ -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f, });
+	m_vertexs.push_back({  0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  0.0f, });
+	m_vertexs.push_back({  0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f, });
+	m_vertexs.push_back({  0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  1.0f,  1.0f, });
+	m_vertexs.push_back({ -0.5f,  0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  1.0f, });
+	m_vertexs.push_back({ -0.5f, -0.5f, -0.5f,  0.0f,  0.0f, -1.0f,  0.0f,  0.0f, });
+
+	m_vertexs.push_back({ -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f, });
+	m_vertexs.push_back({  0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  0.0f, });
+	m_vertexs.push_back({  0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f, });
+	m_vertexs.push_back({  0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  1.0f,  1.0f, });
+	m_vertexs.push_back({ -0.5f,  0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  1.0f, });
+	m_vertexs.push_back({ -0.5f, -0.5f,  0.5f,  0.0f,  0.0f,  1.0f,  0.0f,  0.0f, });
+
+	m_vertexs.push_back({ -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f, });
+	m_vertexs.push_back({ -0.5f,  0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  1.0f, });
+	m_vertexs.push_back({ -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f, });
+	m_vertexs.push_back({ -0.5f, -0.5f, -0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  1.0f, });
+	m_vertexs.push_back({ -0.5f, -0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  0.0f,  0.0f, });
+	m_vertexs.push_back({ -0.5f,  0.5f,  0.5f, -1.0f,  0.0f,  0.0f,  1.0f,  0.0f, });
+
+	m_vertexs.push_back({ 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f, });
+	m_vertexs.push_back({ 0.5f,  0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  1.0f, });
+	m_vertexs.push_back({ 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f, });
+	m_vertexs.push_back({ 0.5f, -0.5f, -0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  1.0f, });
+	m_vertexs.push_back({ 0.5f, -0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  0.0f,  0.0f, });
+	m_vertexs.push_back({ 0.5f,  0.5f,  0.5f,  1.0f,  0.0f,  0.0f,  1.0f,  0.0f, });
+
+	m_vertexs.push_back({ -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f, });
+	m_vertexs.push_back({  0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  1.0f, });
+	m_vertexs.push_back({  0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f, });
+	m_vertexs.push_back({  0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  1.0f,  0.0f, });
+	m_vertexs.push_back({ -0.5f, -0.5f,  0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  0.0f, });
+	m_vertexs.push_back({ -0.5f, -0.5f, -0.5f,  0.0f, -1.0f,  0.0f,  0.0f,  1.0f, });
+
+	m_vertexs.push_back({ -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f, });
+	m_vertexs.push_back({  0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  1.0f, });
+	m_vertexs.push_back({  0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f, });
+	m_vertexs.push_back({  0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  1.0f,  0.0f, });
+	m_vertexs.push_back({ -0.5f,  0.5f,  0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  0.0f, });
+	m_vertexs.push_back({ -0.5f,  0.5f, -0.5f,  0.0f,  1.0f,  0.0f,  0.0f,  1.0f, });
+
+	// 启动深度测试
+	glEnable(GL_DEPTH_TEST);
+
+	// 创建 VAO
+	glGenVertexArrays(1, &m_VAO);
+
+	// 绑定 VAO
+	glBindVertexArray(m_VAO);
+
+	// 创建 VBO IB
+	glGenBuffers(1, &m_VBO);
+
+	// 绑定 VBO 和 数据
+	GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, m_VBO));
+	GL_CALL(glBufferData(GL_ARRAY_BUFFER, m_vertexs.size() * sizeof(Vertex_v2), m_vertexs.data(), GL_STATIC_DRAW));
+
+	// 偷懒 就不用 index buffer 了
+	//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_v2), (void *)offsetof(Vertex_v2, position)));
+
+	GL_CALL(glEnableVertexAttribArray(1));
+	GL_CALL(glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex_v2), (void*)offsetof(Vertex_v2, normal)));
+
+	GL_CALL(glEnableVertexAttribArray(2));
+	GL_CALL(glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex_v2), (void*)offsetof(Vertex_v2, texCoords)));
+
+	// 初始化 shader
+	//m_Shader.NewInit("res/shader/TextPosition/Vertex.vert", "res/shader/TextPosition/Fragment.frag");
+	m_Shader.Init("res/shader/Light/Cube.vert", "res/shader/Light/Cube.frag");
+
+	m_Shader.UnBind();
+
+	m_LightShader.Init("res/shader/Light/LightVertex.vert", "res/shader/Light/LightFragment.frag");
+	m_LightShader.UnBind();
+
+	m_TDiffuse.Init("res/textures/light/container2.png");
+	m_TSpecular.Init("res/textures/light/container2_specular.png");
+
+	m_TDiffuse.Bind(0);
+	m_TSpecular.Bind(1);
+
+	m_Camera.SetLocation(glm::vec3(0.0f, 0.0f, 3.0f));
+
+	InitLight();
+
+	BindMouse(window);
+}
+
+void TestLightCube::OnExit(GLFWwindow* window)
+{
+	glfwSetWindowUserPointer(window, nullptr);
+	UnBindMouse(window);
+}
+
+void TestLightCube::UpdateLogic(float delayTime)
+{
+	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 TestLightCube::ClearRender(GLFWwindow* window)
+{
+	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void TestLightCube::Render(GLFWwindow* window)
+{
+	m_Shader.Bind();
+	
+	m_Shader.SetUniformMat4f("model", m_model);
+	m_Shader.SetUniformMat4f("view", m_view);
+	m_Shader.SetUniformMat4f("projection", m_proj);
+
+	m_Shader.SetUniform3f("light.ambient", m_light.ambient.x, m_light.ambient.y, m_light.ambient.z);		// 设置强度
+	m_Shader.SetUniform3f("light.diffuse", m_light.diffuse.x, m_light.diffuse.y, m_light.diffuse.z);
+	m_Shader.SetUniform3f("light.specular", m_light.specular.x, m_light.specular.y, m_light.specular.z);
+	m_Shader.SetUniform3f("light.lightPos", m_light.lightPos.x, m_light.lightPos.y, m_light.lightPos.z);
+
+	m_Shader.SetUniform1i("cubeMaterial.diffuse", m_cubeMaterial.diffuse);
+	m_Shader.SetUniform1i("cubeMaterial.specular", m_cubeMaterial.specular);
+	m_Shader.SetUniform1i("cubeMaterial.shininess", m_cubeMaterial.shininesss);
+
+	m_Shader.SetUniform3f("viewPos", m_Camera.GetCameraLocation().x, m_Camera.GetCameraLocation().y, m_Camera.GetCameraLocation().z);
+
+	glBindVertexArray(m_VAO);
+	glDrawArrays(GL_TRIANGLES, 0, 6 * 6);
+
+	auto lightModule = glm::mat4(1.0f);
+	lightModule = glm::translate(lightModule, m_light.lightPos);
+	lightModule = glm::scale(lightModule, glm::vec3(0.2f)); // a smaller cube
+
+	m_LightShader.Bind();
+	m_LightShader.SetUniformMat4f("model", lightModule);
+	m_LightShader.SetUniformMat4f("view", m_view);
+	m_LightShader.SetUniformMat4f("projection", m_proj);
+
+	glBindVertexArray(m_LightVAO);
+	glDrawArrays(GL_TRIANGLES, 0, 6 * 6);
+}
+
+void TestLightCube::UpdateImGUI(GLFWwindow* window)
+{
+	const auto& io = ImGui::GetIO();
+
+	ImGui::Begin("Light");
+
+	ImGui::SliderFloat3("Light ambient", &m_light.ambient.x, 0.0f, 1.0f);
+	ImGui::SliderFloat3("Light diffuse", &m_light.diffuse.x, 0.0f, 5.0f);
+	ImGui::SliderFloat3("Light specular", &m_light.specular.x, 0.0f, 5.0f);
+	ImGui::SliderFloat3("Light position", &m_light.lightPos.x, -5.0f, 5.0f);
+
+	ImGui::SliderInt("Cube Material position", &m_cubeMaterial.shininesss, 1, 100);
+
+
+	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 TestLightCube::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 TestLightCube::MouseCallback(GLFWwindow* window, double xpos, double ypos)
+{
+	m_Camera.MouseCallback(window, xpos, ypos);
+}
+
+void TestLightCube::BindMouse(GLFWwindow* window)
+{
+	m_Camera.SetFirstMouse(true);
+	TestWithMouseBase::BindMouse(window);
+}
+
+void TestLightCube::UnBindMouse(GLFWwindow* window)
+{
+	m_Camera.SetFirstMouse(false);
+	TestWithMouseBase::UnBindMouse(window);
+}
+
+void TestLightCube::CreateLight()
+{
+	glGenVertexArrays(1, &m_LightVAO);
+	glBindVertexArray(m_LightVAO);
+
+	// 直接沿用立方体数据
+	glBindBuffer(GL_ARRAY_BUFFER, m_VBO);	
+	
+	// 设置 VAO 内存结构 
+	// 灯光只需要位置数据
+	GL_CALL(glEnableVertexAttribArray(0));
+	GL_CALL(glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex_v2), (void*)offsetof(Vertex_v2, position)));
+}
+
+void TestLightCube::InitLight()
+{
+	CreateLight();
+
+	m_light.lightPos = glm::vec3(1.2f, 1.0f, 2.0f);
+	m_light.ambient = glm::vec3(1.0f) * 0.1f;
+	m_light.diffuse = glm::vec3(1.0f) * 1.0f;
+	m_light.specular = glm::vec3(1.0f) * 0.5f;
+
+	m_cubeMaterial.diffuse = m_TDiffuse.GetBindSlot();
+	m_cubeMaterial.specular = m_TSpecular.GetBindSlot();
+	m_cubeMaterial.shininesss = 32;
+}

+ 63 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestLightCube.h

@@ -0,0 +1,63 @@
+#pragma once
+#include "TestWithMouseBase.h"
+#include "../Util/CommonData.h"
+
+#include "../Util/Shader.h"
+#include "../Util/Texture.h"
+#include "../Util/Camera.h"
+
+class TestLightCube : public TestWithMouseBase
+{
+public:
+	TestLightCube() : TestWithMouseBase("TestLightCube") {}
+
+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;
+
+protected:
+	void CreateLight();
+
+	void InitLight();
+
+private:
+	GLuint m_VBO{ GL_ZERO };
+	GLuint m_VAO{ GL_ZERO };
+
+	GLuint m_LightVAO{ GL_ZERO };
+
+	Shader m_Shader;
+	Shader m_LightShader;
+	std::vector<Vertex_v2> 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;
+
+	Material_v1 m_cubeMaterial;
+	LightConfig_v0 m_light;
+
+	static TestLightCube _self;
+
+	Texture m_TDiffuse;							// Cube 表面的漫反射贴图
+	Texture m_TSpecular;						// Cube 表面的镜面反射贴图
+};
+