Kaynağa Gözat

feat: 添加 贴图、Shader 的封装,添加 Position 测试模块用于下一阶段 3D 坐标测试

NiceTry12138 10 ay önce
ebeveyn
işleme
84fdff51ac
21 değiştirilmiş dosya ile 823 ekleme ve 14 silme
  1. 97 0
      图形学/OpenGL学习/OpenGLDemo.md
  2. 18 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/OpenGLDemo.vcxproj
  3. 42 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/OpenGLDemo.vcxproj.filters
  4. 2 2
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/imgui.ini
  5. 18 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/TextPosition/Fragment.frag
  6. 17 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/TextPosition/Vertex.vert
  7. BIN
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/textures/test2.png
  8. BIN
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/textures/test3.png
  9. 11 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/CommonData.h
  10. 40 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/CommonHead.cpp
  11. 34 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/CommonHead.h
  12. 251 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Shader.cpp
  13. 35 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Shader.h
  14. 67 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Texture.cpp
  15. 26 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Texture.h
  16. 16 2
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/main.cpp
  17. 1 8
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestBase.h
  18. 22 2
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestClearColor.cpp
  19. 3 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestClearColor.h
  20. 93 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestPosition.cpp
  21. 30 0
      图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestPosition.h

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

@@ -356,6 +356,103 @@ glBindTexture(GL_TEXTURE_2D, texture);
 
 > `GL_TEXTURE8` 等价于 `GL_TEXTURE0 + 8`
 
+#### 封装类
+
+为了方便贴图的使用,封装了下面这样一个简单的 texture 类
+
+```cpp
+#include "Texture.h"
+#include "stb_image.h"
+
+Texture::~Texture()
+{
+	DeleteTexture();
+}
+
+void Texture::Init(const std::string& filePath)
+{
+	if (m_FilePath == filePath) {
+		return;
+	}
+
+	DeleteTexture();
+	m_FilePath = filePath;
+
+	stbi_set_flip_vertically_on_load(1);
+	m_LocalBuffer = stbi_load(filePath.c_str(), &m_Width, &m_Height, &m_BPP, 4);
+
+	GL_CALL(glGenTextures(1, & m_TextureId));
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, m_TextureId));
+
+	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));		// 指定缩小器
+	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));		// 指定放大器
+	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));	// 设置贴图超过 0~1 之后的读取方式
+	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));	// 
+
+	GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_LocalBuffer));
+
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));		// 解绑
+
+	if (m_LocalBuffer) {
+		stbi_image_free(m_LocalBuffer);
+		m_LocalBuffer = nullptr;
+	}
+}
+
+void Texture::Bind(GLuint slot)
+{
+	GL_CALL(glActiveTexture(GL_TEXTURE0 + slot));
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, m_TextureId));
+}
+
+void Texture::UnBind()
+{
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
+}
+
+int Texture::GetHeight()
+{
+	return m_Height;
+}
+
+int Texture::GetWidth()
+{
+	return m_Width;
+}
+
+void Texture::DeleteTexture()
+{
+	stbi_image_free(m_LocalBuffer);
+	m_LocalBuffer = nullptr;
+
+	GL_CALL(glDeleteTextures(1, &m_TextureId));
+	m_TextureId = GL_ZERO;
+}
+
+这个类存在一个问题,下面这段代码在运行时会出现问题
+
+```cpp
+m_Tex1.Init("res/textures/test2.png");
+m_Tex1.Bind(0);
+m_Tex2.Init("res/textures/test3.png");
+m_Tex2.Bind(1);
+```
+
+1. `m_Tex1.Bind(0)` 激活了 `GL_TEXTURE0` 槽位并绑定了贴图
+2. 因为当前激活了 `GL_TEXTURE0`,所以`m_Tex2.Init` 仍然在 `GL_TEXTURE0` 槽位上进行
+3. `m_Tex2.Init` 最后 `glBindTexture(GL_TEXTURE_2D, 0)` 解绑了 `GL_TEXTURE0` 上的贴图
+
+那么,最后 `m_Tex1` 这个贴图就是绑定失败的,它被 `m_Tex2` 给无意间释放掉了
+
+所以,`Texture` 建议下面这样操作,一起初始化,一起绑定
+
+```cpp
+m_Tex1.Init("res/textures/test2.png");
+m_Tex2.Init("res/textures/test3.png");
+m_Tex1.Bind(0);
+m_Tex2.Bind(1);
+```
+
 ## 坐标系统
 
 

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

@@ -133,6 +133,8 @@
     </Link>
   </ItemDefinitionGroup>
   <ItemGroup>
+    <ClCompile Include="src\Util\CommonHead.cpp" />
+    <ClCompile Include="src\Util\Shader.cpp" />
     <ClCompile Include="src\glad.c" />
     <ClCompile Include="src\main.cpp" />
     <ClCompile Include="src\third\imgui\imgui.cpp" />
@@ -145,8 +147,12 @@
     <ClCompile Include="src\third\stb_image\stb_image.cpp" />
     <ClCompile Include="src\testModule\TestBase.cpp" />
     <ClCompile Include="src\testModule\TestClearColor.cpp" />
+    <ClCompile Include="src\testModule\TestPosition.cpp" />
+    <ClCompile Include="src\Util\Texture.cpp" />
   </ItemGroup>
   <ItemGroup>
+    <ClInclude Include="src\Util\CommonData.h" />
+    <ClInclude Include="src\Util\Shader.h" />
     <ClInclude Include="src\third\imgui\imconfig.h" />
     <ClInclude Include="src\third\imgui\imgui.h" />
     <ClInclude Include="src\third\imgui\imgui_impl_glfw.h" />
@@ -159,6 +165,18 @@
     <ClInclude Include="src\third\stb_image\stb_image.h" />
     <ClInclude Include="src\testModule\TestBase.h" />
     <ClInclude Include="src\testModule\TestClearColor.h" />
+    <ClInclude Include="src\testModule\TestPosition.h" />
+    <ClInclude Include="src\Util\Texture.h" />
+    <ClInclude Include="src\Util\CommonHead.h" />
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="res\shader\TextPosition\Fragment.frag" />
+    <None Include="res\shader\TextPosition\Vertex.vert" />
+  </ItemGroup>
+  <ItemGroup>
+    <Image Include="res\textures\test.jpg" />
+    <Image Include="res\textures\test2.png" />
+    <Image Include="res\textures\test3.png" />
   </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">

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

@@ -51,6 +51,18 @@
     <ClCompile Include="src\testModule\TestClearColor.cpp">
       <Filter>源文件</Filter>
     </ClCompile>
+    <ClCompile Include="src\testModule\TestPosition.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Util\Shader.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Util\Texture.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
+    <ClCompile Include="src\Util\CommonHead.cpp">
+      <Filter>源文件</Filter>
+    </ClCompile>
   </ItemGroup>
   <ItemGroup>
     <ClInclude Include="src\third\imgui\imstb_truetype.h">
@@ -89,5 +101,35 @@
     <ClInclude Include="src\testModule\TestClearColor.h">
       <Filter>头文件</Filter>
     </ClInclude>
+    <ClInclude Include="src\testModule\TestPosition.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Util\Shader.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Util\Texture.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Util\CommonHead.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+    <ClInclude Include="src\Util\CommonData.h">
+      <Filter>头文件</Filter>
+    </ClInclude>
+  </ItemGroup>
+  <ItemGroup>
+    <None Include="res\shader\TextPosition\Vertex.vert" />
+    <None Include="res\shader\TextPosition\Fragment.frag" />
+  </ItemGroup>
+  <ItemGroup>
+    <Image Include="res\textures\test.jpg">
+      <Filter>资源文件</Filter>
+    </Image>
+    <Image Include="res\textures\test2.png">
+      <Filter>资源文件</Filter>
+    </Image>
+    <Image Include="res\textures\test3.png">
+      <Filter>资源文件</Filter>
+    </Image>
   </ItemGroup>
 </Project>

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

@@ -9,7 +9,7 @@ Size=124,77
 Collapsed=0
 
 [Window][ClearColor]
-Pos=349,68
-Size=394,84
+Pos=755,32
+Size=391,97
 Collapsed=0
 

+ 18 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/TextPosition/Fragment.frag

@@ -0,0 +1,18 @@
+#version 330 core
+
+layout(location = 0) out vec4 o_color;
+
+in vec4 v_Color;
+in vec2 v_TexCoord;
+flat in int v_TexIndex;
+
+uniform sampler2D u_Texture0;
+uniform sampler2D u_Texture1;
+
+void main() {
+    vec4 texColor = v_TexIndex == 0 ? 
+        texture(u_Texture0, v_TexCoord) : 
+        texture(u_Texture1, v_TexCoord);
+    
+    o_color = mix(texColor, v_Color, 0.3); // »ìºÏÎÆÀíºÍÑÕÉ«
+}

+ 17 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/TextPosition/Vertex.vert

@@ -0,0 +1,17 @@
+#version 330 core
+
+layout(location = 0) in vec3 inPosition;
+layout(location = 1) in vec4 inColor;
+layout(location = 2) in vec2 inTexCoord;
+layout(location = 3) in int inTexIndex;
+
+out vec4 v_Color;
+out vec2 v_TexCoord;
+flat out int v_TexIndex;
+
+void main() {
+	gl_Position = vec4(inPosition, 1.0f);
+	v_TexCoord = inTexCoord;
+	v_TexIndex = inTexIndex;
+	v_Color = inColor;
+}

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


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


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

@@ -0,0 +1,11 @@
+#pragma once
+
+// 顶点信息 v0 版本 后续根据需要可能新增 v1、v2 ...
+struct Vertex_v0
+{
+	float position[3];			  // 顶点坐标
+	float color[4];				  // 顶点颜色
+	float texCoord[2];			  // 顶点的 UV 坐标	
+	int texIndex;				  // 顶点使用贴图的序号
+};
+

+ 40 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/CommonHead.cpp

@@ -0,0 +1,40 @@
+#include "CommonHead.h"
+
+void GLClearError() {
+	while (glGetError() != GL_NO_ERROR);
+}
+
+void LogError(const char* file, unsigned int Line, const char* functionName) {
+	GLuint errorType = glGetError();
+	while (errorType != GL_NO_ERROR) {
+		std::cout << file << " Line: " << Line << " Function Name: " << functionName << " ";
+		switch (errorType)
+		{
+		case GL_INVALID_ENUM:
+			std::cout << "LogError: " << "GL_INVALID_ENUM" << std::endl;
+			break;
+		case GL_INVALID_VALUE:
+			std::cout << "LogError: " << "GL_INVALID_VALUE" << std::endl;
+			break;
+		case GL_INVALID_OPERATION:
+			std::cout << "LogError: " << "GL_INVALID_OPERATION" << std::endl;
+			break;
+		case GL_INVALID_FRAMEBUFFER_OPERATION:
+			std::cout << "LogError: " << "GL_INVALID_FRAMEBUFFER_OPERATION" << std::endl;
+			break;
+		case GL_OUT_OF_MEMORY:
+			std::cout << "LogError: " << "GL_OUT_OF_MEMORY" << std::endl;
+			break;
+		//case GL_STACK_UNDERFLOW:
+		//	std::cout << "LogError: " << "GL_STACK_UNDERFLOW" << std::endl;
+		//	break;
+		//case GL_STACK_OVERFLOW:
+		//	std::cout << "LogError: " << "GL_STACK_OVERFLOW" << std::endl;
+			break;
+		}
+
+		// __debugbreak();	// 中断函数 编译器强相关函数,gcc 没有
+
+		errorType = glGetError();
+	}
+}

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

@@ -0,0 +1,34 @@
+#pragma once
+
+#include <iostream>
+#include <string>
+#include <chrono>
+#include <map>
+#include <unordered_map>
+#include <set>
+#include <unordered_set>
+#include <vector>
+
+#include "glad/glad.h"
+#include "GLFW/glfw3.h"
+
+#include "imgui.h"
+#include "imgui_impl_glfw.h"
+#include "imgui_impl_opengl3.h"
+
+#include "glm.hpp"
+#include "gtc/matrix_transform.hpp"
+
+#define GL_CHECK_ERROR do { LogError(__LINE__); }while(0);
+#define GL_CLEAR_ERROR do { GLClearError(); } while(0);
+
+#define GL_CALL(x) do {						\
+	GLClearError();							\
+	x;										\
+	LogError(__FILE__, __LINE__, #x);		\
+} while (0);								\
+
+// 清除所有错误
+void GLClearError();
+// 输出当前错误
+void LogError(const char* file, unsigned int Line, const char* functionName = nullptr);

+ 251 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Shader.cpp

@@ -0,0 +1,251 @@
+#include "Shader.h"
+#include <fstream>
+#include <sstream>
+#include <iostream>
+
+GLuint Shader::s_CurrentBindShader = GL_ZERO;
+
+void checkCompileErrors(GLuint shader, std::string type)
+{
+	GLint success;
+	GLchar infoLog[1024];
+	if (type != "PROGRAM")
+	{
+		glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
+		if (!success)
+		{
+			glGetShaderInfoLog(shader, 1024, NULL, infoLog);
+			std::cout << "ERROR::SHADER_COMPILATION_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
+		}
+	}
+	else
+	{
+		glGetProgramiv(shader, GL_LINK_STATUS, &success);
+		if (!success)
+		{
+			glGetProgramInfoLog(shader, 1024, NULL, infoLog);
+			std::cout << "ERROR::PROGRAM_LINKING_ERROR of type: " << type << "\n" << infoLog << "\n -- --------------------------------------------------- -- " << std::endl;
+		}
+	}
+}
+
+void Shader::NewInit(const std::string& inVertexFile, const std::string& inFragmentFile)
+{
+	// 1. retrieve the vertex/fragment source code from filePath
+	std::string vertexCode;
+	std::string fragmentCode;
+	std::ifstream vShaderFile;
+	std::ifstream fShaderFile;
+	// ensure ifstream objects can throw exceptions:
+	vShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+	fShaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+	try
+	{
+		// open files
+		vShaderFile.open(inVertexFile);
+		fShaderFile.open(inFragmentFile);
+		std::stringstream vShaderStream, fShaderStream;
+		// read file's buffer contents into streams
+		vShaderStream << vShaderFile.rdbuf();
+		fShaderStream << fShaderFile.rdbuf();
+		// close file handlers
+		vShaderFile.close();
+		fShaderFile.close();
+		// convert stream into string
+		vertexCode = vShaderStream.str();
+		fragmentCode = fShaderStream.str();
+	}
+	catch (std::ifstream::failure& e)
+	{
+		std::cout << "ERROR::SHADER::FILE_NOT_SUCCESSFULLY_READ: " << e.what() << std::endl;
+	}
+	const char* vShaderCode = vertexCode.c_str();
+	const char* fShaderCode = fragmentCode.c_str();
+	// 2. compile shaders
+	unsigned int vertex, fragment;
+	// vertex shader
+	vertex = glCreateShader(GL_VERTEX_SHADER);
+	glShaderSource(vertex, 1, &vShaderCode, NULL);
+	glCompileShader(vertex);
+	checkCompileErrors(vertex, "VERTEX");
+	// fragment Shader
+	fragment = glCreateShader(GL_FRAGMENT_SHADER);
+	glShaderSource(fragment, 1, &fShaderCode, NULL);
+	glCompileShader(fragment);
+	checkCompileErrors(fragment, "FRAGMENT");
+	// shader Program
+	m_ShaderID = glCreateProgram();
+	glAttachShader(m_ShaderID, vertex);
+	glAttachShader(m_ShaderID, fragment);
+	glLinkProgram(m_ShaderID);
+	checkCompileErrors(m_ShaderID, "PROGRAM");
+	// delete the shaders as they're linked into our program now and no longer necessary
+	glDeleteShader(vertex);
+	glDeleteShader(fragment);
+}
+
+void Shader::Init(const std::string& inVertexFile, const std::string& inFragmentFile)
+{
+	if (m_ShaderID != GL_ZERO) 
+	{
+		DeleteShader();
+	}
+
+	std::ifstream ifs;
+	ifs.open(inVertexFile, std::ios::in);
+	if (!ifs.is_open()) {
+		std::cout << "Compile Shader Fail: Can't Open File" << std::endl;
+		return;
+	}
+
+	std::string vertextShaderSrouce((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
+	ifs.close();
+
+	ifs.open(inFragmentFile, std::ios::in);
+	if (!ifs.is_open()) {
+		std::cout << "Compile Shader Fail: Can't Open File" << std::endl;
+		return;
+	}
+
+	std::string fragmentShaderSource((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
+	ifs.close();
+
+	m_ShaderID = CreateShader(vertextShaderSrouce, fragmentShaderSource);
+}
+
+Shader::~Shader()
+{
+	GL_CALL(glDeleteProgram(m_ShaderID));
+}
+
+void Shader::SetUniform1i(const std::string& inName, const int& value)
+{
+	// 防止使用时忘记先绑定 又为了避免每次设置都绑定 使用 s_CurrentBindShader 记录绑定状态
+	Bind();
+	auto location = GetShaderLocation(inName);
+	if (location == -1)
+	{
+		return;
+	}
+	GL_CALL(glUniform1i(location, value));
+}
+
+void Shader::SetUniform4f(const std::string& inName, float v0, float v1, float v2, float v3)
+{
+	Bind();
+	GLint location = GetShaderLocation(inName);
+	if (location == -1)
+	{
+		return;
+	}
+	GL_CALL(glUniform4f(location, v0, v1, v2, v3));
+}
+
+void Shader::SetUniformMat4f(const std::string& inName, const glm::mat4& inMat4)
+{
+	Bind();
+	GLint location = GetShaderLocation(inName);
+	if (location == -1)
+	{
+		return;
+	}
+	GL_CALL(glUniformMatrix4fv(location, 1, GL_FALSE, &inMat4[0][0]));
+}
+
+void Shader::Bind()
+{
+	if (s_CurrentBindShader == m_ShaderID)
+	{
+		return;
+	}
+	GL_CALL(glUseProgram(m_ShaderID));
+	s_CurrentBindShader = m_ShaderID;
+}
+
+void Shader::UnBind()
+{
+	if (s_CurrentBindShader != GL_ZERO)
+	{
+		GL_CALL(glUseProgram(0));
+		s_CurrentBindShader = GL_ZERO;
+	}
+}
+
+bool Shader::IsValid()
+{
+	return m_ShaderID == GL_ZERO;
+}
+
+void Shader::DeleteShader()
+{
+	GL_CALL(glDeleteShader(m_ShaderID));
+}
+
+GLint Shader::GetShaderLocation(const std::string& inName)
+{
+	if (m_locationMap.find(inName) != m_locationMap.end())
+	{
+		return m_locationMap[inName];
+	}
+
+	GLint result = -1;
+	result = glGetUniformLocation(m_ShaderID, inName.c_str());
+
+	if (result == -1) {
+		std::cout << "can't find Shader Location with Name " << inName << std::endl;
+	}
+	
+	// shader 内容不会变,同一个 shader 没有这个 name 的槽就一定没有
+	m_locationMap[inName] = result;
+
+	return result;
+}
+
+GLuint Shader::CreateShader(const std::string& vertexSource, const std::string& fragmentSource)
+{
+	GLuint program = glCreateProgram();
+	
+	GLuint vs = CompileShader(vertexSource, GL_VERTEX_SHADER);
+	GLuint fs = CompileShader(fragmentSource, GL_FRAGMENT_SHADER);
+
+	GL_CALL(glAttachShader(program, vs));			// 将 vs 绑定到 program 上
+	GL_CALL(glAttachShader(program, fs));			// 将 fs 绑定到 program 上
+
+	GL_CALL(glLinkProgram(program));					// 链接程序,将所有着色器合并为一个可执行的程序
+	GL_CALL(glValidateProgram(program));				// 验证程序是否可以执行
+
+	GL_CALL(glDeleteShader(vs));						// 删除着色器对象,一旦链接成功那么代码已经连接到程序中了,可以删除着色器对象
+	GL_CALL(glDeleteShader(fs));
+	
+	return program;
+}
+
+GLuint Shader::CompileShader(const std::string& inSource, GLenum inType)
+{
+	GLuint shaderId = glCreateShader(inType);
+
+	const char* source = inSource.c_str();
+	GL_CALL(glShaderSource(shaderId, 1, &source, nullptr));			// 传入 nullptr 表示读取整个字符串数组
+	GL_CALL(glCompileShader(shaderId));
+
+	GLint errorId;
+	GL_CALL(glGetShaderiv(shaderId, GL_COMPILE_STATUS, &errorId));
+	if (errorId == GL_FALSE)
+	{
+		// 编译错误
+		GLint length = 0;
+		GL_CALL(glGetShaderiv(shaderId, GL_INFO_LOG_LENGTH, &length));
+		
+		char* msg = (char*)alloca(length);
+		GL_CALL(glGetShaderInfoLog(shaderId, length, &length, msg));
+
+		std::cout << "Shader Compile " << (inType == GL_VERTEX_SHADER ? "Vertex Shader" : "Fragment Shader") << " Failed" << std::endl;
+		std::cout << msg << std::endl;
+
+		GL_CALL(glDeleteShader(shaderId));
+		return GL_ZERO;
+	}
+
+	return shaderId;
+}
+

+ 35 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Shader.h

@@ -0,0 +1,35 @@
+#pragma once
+#include "CommonHead.h"
+
+class Shader
+{
+public:
+	void NewInit(const std::string& inVertexFile, const std::string& inFragmentFile);
+	void Init(const std::string& inVertexFile, const std::string& inFragmentFile);
+	~Shader();
+
+	void SetUniform1i(const std::string& inName, const int& value);
+	void SetUniform4f(const std::string& inName, float v0, float v1, float v2, float v3);
+	void SetUniformMat4f(const std::string& inName, const glm::mat4& inMat4);
+
+	void Bind();
+	void UnBind();
+
+	bool IsValid();
+	void DeleteShader();
+
+protected:
+	GLint GetShaderLocation(const std::string& inName);
+
+	GLuint CreateShader(const std::string& vertexSource, const std::string& fragmentSource);
+	GLuint CompileShader(const std::string& inSource, GLenum inType);
+
+private:
+	static GLuint s_CurrentBindShader;
+
+	//GLuint CreateShaderWithFile(const std::string& vertexFile, const std::string& fragmentFile);
+private:
+	std::unordered_map<std::string, GLint> m_locationMap;	// ²ÛλӳÉä
+	GLuint m_ShaderID{ GL_ZERO };
+};
+

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

@@ -0,0 +1,67 @@
+#include "Texture.h"
+#include "stb_image.h"
+
+Texture::~Texture()
+{
+	DeleteTexture();
+}
+
+void Texture::Init(const std::string& filePath)
+{
+	if (m_FilePath == filePath) {
+		return;
+	}
+
+	DeleteTexture();
+	m_FilePath = filePath;
+
+	stbi_set_flip_vertically_on_load(1);
+	m_LocalBuffer = stbi_load(filePath.c_str(), &m_Width, &m_Height, &m_BPP, 4);
+
+	GL_CALL(glGenTextures(1, & m_TextureId));
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, m_TextureId));
+
+	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));		// 指定缩小器
+	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));		// 指定放大器
+	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));	// 设置贴图超过 0~1 之后的读取方式
+	GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));	// 
+
+	GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, m_Width, m_Height, 0, GL_RGBA, GL_UNSIGNED_BYTE, m_LocalBuffer));
+
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));		// 解绑
+
+	if (m_LocalBuffer) {
+		stbi_image_free(m_LocalBuffer);
+		m_LocalBuffer = nullptr;
+	}
+}
+
+void Texture::Bind(GLuint slot)
+{
+	GL_CALL(glActiveTexture(GL_TEXTURE0 + slot));
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, m_TextureId));
+}
+
+void Texture::UnBind()
+{
+	GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
+}
+
+int Texture::GetHeight()
+{
+	return m_Height;
+}
+
+int Texture::GetWidth()
+{
+	return m_Width;
+}
+
+void Texture::DeleteTexture()
+{
+	stbi_image_free(m_LocalBuffer);
+	m_LocalBuffer = nullptr;
+
+	GL_CALL(glDeleteTextures(1, &m_TextureId));
+	m_TextureId = GL_ZERO;
+}

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

@@ -0,0 +1,26 @@
+#pragma once
+#include "CommonHead.h"
+
+class Texture
+{
+public:
+	virtual ~Texture();
+
+	void Init(const std::string& filePath);
+
+	void Bind(GLuint slot = 0);
+	void UnBind();
+
+	int GetHeight();
+	int GetWidth();
+
+	void DeleteTexture();
+private:
+	GLubyte* m_LocalBuffer{ nullptr };
+	// BPP Bit Per Pixel 表示每个像素的位数, 24bit-color 通常由三通道颜色组成;32bit-color 通常由四通道颜色组成
+	int m_Width = 0, m_Height = 0, m_BPP = 0;
+	std::string m_FilePath;
+
+	GLuint m_TextureId{ GL_ZERO };
+};
+

+ 16 - 2
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/main.cpp

@@ -1,4 +1,7 @@
 #include <iostream>
+#include <chrono>
+
+// 先 include glad 再 include glfw
 #include <glad/glad.h>
 #include <GLFW/glfw3.h>
 
@@ -7,6 +10,7 @@
 #include "imgui_impl_opengl3.h"
 
 #include "testModule/TestClearColor.h"
+#include "testModule/TestPosition.h"
 
 // 定义回调函数
 void framebuffer_size_callback(GLFWwindow* window, int width, int height)
@@ -97,16 +101,26 @@ int main()
 
     InitImGUI(window);
 
-    TestClearColor TestApp;
+    //TestClearColor TestApp;
+    TestPosition TestApp;
 
     TestApp.OnEnter(window);
 
+    auto prevTime = std::chrono::high_resolution_clock::now();
+
+    glEnable(GL_BLEND);
+    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
     // 如果不需要关闭窗口,则持续进入循环
     while (!glfwWindowShouldClose(window))
     {
+        auto currentTime = std::chrono::high_resolution_clock::now();
+        float deltaTime = std::chrono::duration_cast<std::chrono::milliseconds>(currentTime - prevTime).count() / 1000.0f;
+        prevTime = std::move(currentTime);
+
         TestApp.ClearRender(window);
         TestApp.InputProcess(window);
-        TestApp.Update(window, 0.017f);
+        TestApp.Update(window, deltaTime);
         TestApp.Render(window);
 
         glfwSwapBuffers(window);    // 交换缓冲区

+ 1 - 8
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestBase.h

@@ -1,13 +1,6 @@
 #pragma once
 
-#include "GLFW/glfw3.h"
-
-#include "imgui.h"
-#include "imgui_impl_glfw.h"
-#include "imgui_impl_opengl3.h"
-
-#include "glm.hpp"
-#include "gtc/matrix_transform.hpp"
+#include "../Util/CommonHead.h"
 
 class TestBase
 {

+ 22 - 2
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestClearColor.cpp

@@ -12,7 +12,20 @@ void TestClearColor::OnExit(GLFWwindow* window)
 
 void TestClearColor::UpdateLogic(float delayTime)
 {
-
+	if (!m_UseImGUI)
+	{
+		float rate = m_IsAdd ? 1 : -1;
+		m_ClearColor[0] += rate * delayTime;
+		m_ClearColor[1] += rate * delayTime * 2;
+		m_ClearColor[2] += rate * delayTime * 3;
+
+		if (m_ClearColor[0] > 1.0f || m_ClearColor[0] < 0.0f) {
+			m_ClearColor[0] = m_IsAdd ? 1.0f : 0.0f;
+			m_ClearColor[1] = m_IsAdd ? 1.0f : 0.0f;
+			m_ClearColor[2] = m_IsAdd ? 1.0f : 0.0f;
+			m_IsAdd = !m_IsAdd;
+		}
+	}
 }
 
 void TestClearColor::ClearRender(GLFWwindow* window)
@@ -27,8 +40,15 @@ void TestClearColor::Render(GLFWwindow* window)
 
 void TestClearColor::UpdateImGUI(GLFWwindow* window)
 {
+	const auto& io = ImGui::GetIO();
+
 	ImGui::Begin("ClearColor");
-	ImGui::SliderFloat3("ClearColor", m_ClearColor, 0.0f, 1.0f);
+	ImGui::Checkbox("ClearColorWithTime", &m_UseImGUI);    
+	if (m_UseImGUI)
+	{
+		ImGui::SliderFloat3("ClearColor", m_ClearColor, 0.0f, 1.0f);
+	}
+	ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
 	if (ImGui::Button("Close Window"))
 		glfwSetWindowShouldClose(window, true);
 	ImGui::End();

+ 3 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestClearColor.h

@@ -14,5 +14,8 @@ public:
 
 private:
 	float m_ClearColor[3] = { 0.0f, 0.0f ,0.0f };
+	bool m_UseImGUI = true;
+
+	bool m_IsAdd = true;
 };
 

+ 93 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestPosition.cpp

@@ -0,0 +1,93 @@
+#include "TestPosition.h"
+
+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 });
+
+	GLuint indices[] = {
+		0, 1, 2,
+		2, 3, 0
+	};
+
+	// 创建 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();
+}
+
+void TestPosition::OnExit(GLFWwindow* window)
+{
+	
+}
+
+void TestPosition::UpdateLogic(float delayTime)
+{
+}
+
+void TestPosition::ClearRender(GLFWwindow* window)
+{
+	TestBase::ClearRender(window);
+}
+
+void TestPosition::Render(GLFWwindow* window)
+{
+	m_Shader.Bind();
+	m_Shader.SetUniform1i("u_Texture0", 0);
+	m_Shader.SetUniform1i("u_Texture1", 1);
+
+	glBindVertexArray(m_VAO);
+	glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
+}
+
+void TestPosition::UpdateImGUI(GLFWwindow* window)
+{
+	const auto& io = ImGui::GetIO();
+
+	ImGui::Begin("ClearColor");
+	ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
+	if (ImGui::Button("Close Window"))
+		glfwSetWindowShouldClose(window, true);
+	ImGui::End();
+}

+ 30 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestPosition.h

@@ -0,0 +1,30 @@
+#pragma once
+#include "TestBase.h"
+#include "../Util/CommonData.h"
+
+#include "../Util/Shader.h"
+#include "../Util/Texture.h"
+
+class TestPosition : 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;
+
+private:
+	GLuint m_VBO;
+	GLuint m_VAO;
+	GLuint m_IB;
+
+	Shader m_Shader;
+	Texture m_Tex1;
+	Texture m_Tex2;
+
+	std::vector<Vertex_v0> m_vertexs;
+};
+