Ver código fonte

feat: 添加 gl instanced 的使用案例

NiceTry12138 9 meses atrás
pai
commit
c1600975e6

+ 4 - 1
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/OpenGLDemo.vcxproj

@@ -85,7 +85,8 @@
       <AdditionalLibraryDirectories>$(SolutionDir)Dependencies\assimp\lib;$(SolutionDir)Dependencies\GLFW\lib-vc2022;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
     </Link>
     <PostBuildEvent>
-      <Command>copy /Y "$(SolutionDir)Dependencies\assimp\lib\assimp-vc143-mtd.dll" "$(OutDir)"</Command>
+      <Command>copy /Y "$(SolutionDir)Dependencies\assimp\lib\assimp-vc143-mtd.dll" "$(OutDir)"
+xcopy /Y /E /I "$(SolutionDir)OpenGLDemo\res" "$(OutDir)res\"</Command>
     </PostBuildEvent>
   </ItemDefinitionGroup>
   <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -498,6 +499,8 @@
     <None Include="res\shader\GeoShader\model.vert" />
     <None Include="res\shader\GeoShader\skybox.frag" />
     <None Include="res\shader\GeoShader\skybox.vert" />
+    <None Include="res\shader\Instanced\instanced.frag" />
+    <None Include="res\shader\Instanced\instanced.vert" />
     <None Include="res\shader\Light\Cube.frag" />
     <None Include="res\shader\Light\Cube.vert" />
     <None Include="res\shader\Light\Fragment.frag" />

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

@@ -1497,6 +1497,8 @@
     <None Include="res\shader\GeoShader\line.fs" />
     <None Include="res\shader\GeoShader\line.gs" />
     <None Include="res\shader\GeoShader\line.vs" />
+    <None Include="res\shader\Instanced\instanced.frag" />
+    <None Include="res\shader\Instanced\instanced.vert" />
   </ItemGroup>
   <ItemGroup>
     <Image Include="res\textures\test.jpg">

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

@@ -36,5 +36,10 @@ Collapsed=1
 [Window][SkyBox]
 Pos=368,52
 Size=330,99
+Collapsed=1
+
+[Window][Instance]
+Pos=399,33
+Size=327,98
 Collapsed=0
 

+ 13 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/Instanced/instanced.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);
+}

+ 28 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/res/shader/Instanced/instanced.vert

@@ -0,0 +1,28 @@
+#version 330 core
+
+layout (location = 0) in vec3 inPosition;
+layout (location = 1) in vec3 aNormal;
+layout (location = 2) in vec2 aTexCoords;
+layout (location = 7) in mat4 instanceMatrix;
+
+uniform mat4 model;
+
+layout (std140) uniform Matrices
+{
+    mat4 view;
+    mat4 projection;
+};
+
+out vec2 TexCoords;
+
+uniform int UseInstanceMatrix;
+
+void main() {
+    TexCoords = aTexCoords;    
+
+    if(UseInstanceMatrix < 1){
+      	gl_Position = projection * view * model * vec4(inPosition, 1.0);
+    } else {
+      	gl_Position = projection * view * instanceMatrix * vec4(inPosition, 1.0);
+    }
+}

+ 42 - 2
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Mesh.cpp

@@ -29,7 +29,7 @@ void Mesh::init(const std::vector<Vertex_Mesh>& inVertices, const std::vector<GL
 	setUpMesh();
 }
 
-void Mesh::Draw(Shader& shader)
+void Mesh::Draw(Shader& shader, int count)
 {
 	shader.Bind();
 
@@ -76,13 +76,53 @@ void Mesh::Draw(Shader& shader)
 
 	// draw mesh
 	glBindVertexArray(VAO);
-	glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0);
+
+	if (count != 0)
+	{
+		glDrawElementsInstanced(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0, count);
+	}
+	else {
+		glDrawElements(GL_TRIANGLES, static_cast<unsigned int>(indices.size()), GL_UNSIGNED_INT, 0);
+	}
 
 	// 清空 贴图 和 VAO 的绑定
 	glBindVertexArray(GL_ZERO);
 	glActiveTexture(GL_TEXTURE0);
 }
 
+void Mesh::AddInstanceData()
+{
+	glBindVertexArray(VAO);
+
+	// 这里可以整合成一个 for 循环 
+	int Index = 7;
+	glEnableVertexAttribArray(Index);
+	glVertexAttribPointer(Index, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)0);
+	glVertexAttribDivisor(Index, 1);
+
+	++Index;
+	glEnableVertexAttribArray(Index);
+	glVertexAttribPointer(Index, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4)));
+	glVertexAttribDivisor(Index, 1);
+	
+	++Index;
+	glEnableVertexAttribArray(Index);
+	glVertexAttribPointer(Index, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4) * 2));
+	glVertexAttribDivisor(Index, 1);
+
+	++Index;
+	glEnableVertexAttribArray(Index);
+	glVertexAttribPointer(Index, 4, GL_FLOAT, GL_FALSE, sizeof(glm::mat4), (void*)(sizeof(glm::vec4) * 3));
+	glVertexAttribDivisor(Index, 1);
+
+	glBindVertexArray(GL_ZERO);
+}
+
+GLuint Mesh::GetVAO() const
+{
+	return VAO;
+}
+
 void Mesh::setUpMesh()
 {
 	glGenVertexArrays(1, &VAO);

+ 5 - 1
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Mesh.h

@@ -19,7 +19,11 @@ public:
 
 	void init(const std::vector<Vertex_Mesh>& inVertices, const std::vector<GLuint>& inIndices, const std::vector<Texture_Mesh>& inTextures);
 
-	void Draw(Shader& shader);
+	void Draw(Shader& shader, int count = 0);
+
+	void AddInstanceData();
+
+	GLuint GetVAO() const;
 protected:
 	// 绑定数据信息
 	void setUpMesh();

+ 20 - 2
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/Util/Model.cpp

@@ -14,11 +14,29 @@ void Model::Init(const std::string& Path)
     loadModel(Path);
 }
 
-void Model::Draw(Shader& shader)
+void Model::Draw(Shader& shader, int count)
 {
     for (auto& meshItem : meshes)
     {
-        meshItem.Draw(shader);
+        meshItem.Draw(shader, count);
+    }
+}
+
+std::vector<GLuint> Model::GetMeshVAOs()
+{
+    std::vector<GLuint> Result;
+    for (const auto& item : meshes)
+    {
+        Result.push_back(item.GetVAO());
+    }
+    return Result;
+}
+
+void Model::AddInstanceData()
+{
+    for (auto& Item : meshes)
+    {
+        Item.AddInstanceData();
     }
 }
 

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

@@ -17,7 +17,10 @@ public:
 	Model() = default;
 
 	void Init(const std::string& Path);
-	void Draw(Shader& shader);
+	void Draw(Shader& shader, int count = 0);
+
+	std::vector<GLuint> GetMeshVAOs();
+	void AddInstanceData();
 protected:
 	void loadModel(const std::string& Path);
 	void processNode(aiNode* node, const aiScene* scene);

+ 81 - 9
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestGLInstance.cpp

@@ -1,6 +1,7 @@
 #include "TestGLInstance.h"
 #include "../Util/RenderSettings.h"
 #include "TestModuleManager.h"
+#include <random>
 
 TestGLInstance TestGLInstance::_self;
 
@@ -11,7 +12,7 @@ void TestGLInstance::OnEnter(GLFWwindow* window)
 	glEnable(GL_DEPTH_TEST);
 
 	// 初始化 shader
-	m_ModelShader.Init("res/shader/SkyBox/model.vert", "res/shader/SkyBox/model.frag");
+	m_ModelShader.Init("res/shader/Instanced/instanced.vert", "res/shader/Instanced/instanced.frag");
 	m_packageModel.Init("res/model/Miku/miku_prefab.fbx");
 
 	m_Camera.SetLocation(glm::vec3(0.0f, 0.0f, 3.0f));
@@ -19,6 +20,10 @@ void TestGLInstance::OnEnter(GLFWwindow* window)
 
 	InitSkyBox();
 	InitUBO();
+	InitGVBO();
+
+	glBindBuffer(GL_ARRAY_BUFFER, m_GVBO);
+	m_packageModel.AddInstanceData();
 }
 
 void TestGLInstance::OnExit(GLFWwindow* window)
@@ -37,6 +42,7 @@ void TestGLInstance::UpdateLogic(float delayTime)
 	m_proj = glm::perspective(glm::radians(45.0f), (float)RSI->ViewportHeight / (float)RSI->ViewportWidth, 0.1f, 100.0f);
 
 	UpdateUBO();
+	UpdateGVBOData(delayTime);
 }
 
 void TestGLInstance::ClearRender(GLFWwindow* window)
@@ -51,15 +57,21 @@ void TestGLInstance::Render(GLFWwindow* window)
 	m_ModelShader.Bind();
 
 	auto CameraLocation = m_Camera.GetCameraLocation();
-
-	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.BindUBO("Matrices", UBOSLOT);
-	
-	m_packageModel.Draw(m_ModelShader);
 
+	m_ModelShader.SetUniform1i("UseInstanceMatrix", m_useInstance ? 10 : 0);
+	if (!m_useInstance)
+	{
+		for (const auto& model : m_InstanceData)
+		{
+			m_ModelShader.SetUniformMat4f("model", model);
+			m_packageModel.Draw(m_ModelShader);
+		}
+	}
+	else {
+		m_packageModel.Draw(m_ModelShader, m_InstanceData.size());
+	}
+	
 	m_sky.Draw(m_view, m_proj);
 }
 
@@ -67,7 +79,10 @@ void TestGLInstance::UpdateImGUI(GLFWwindow* window)
 {
 	const auto& io = ImGui::GetIO();
 
-	ImGui::Begin("SkyBox");
+	ImGui::Begin("Instance");
+
+	ImGui::Checkbox("Use Instance", &m_useInstance);
+	ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
 
 	ImGui::End();
 }
@@ -129,3 +144,60 @@ void TestGLInstance::UpdateUBO()
 
 	glUnmapBuffer(GL_UNIFORM_BUFFER);
 }
+
+void TestGLInstance::InitGVBO()
+{
+	const float Radius = 50.0f;			// 旋转半径
+
+	srand(glfwGetTime()); // 初始化随机种子    
+
+	// 使用更精确的随机数生成
+	std::mt19937 rng(std::random_device{}());
+	std::uniform_real_distribution<float> dist_z(-5.0f, 5.0f);      // Z轴范围扩大
+	std::uniform_real_distribution<float> dist_scale(0.5f, 1.5f);      // 缩放范围
+	std::uniform_real_distribution<float> dist_angle(0.0f, 2.0f * glm::pi<float>()); // 弧度制随机角度
+	std::uniform_real_distribution<float> dist_axis(-1.0f, 1.0f);      // 随机旋转轴
+
+	for (int index = 0; index < m_InstanceNum; ++index)
+	{
+		glm::mat4 model = glm::mat4(1.0f); // 显式初始化单位矩阵
+
+		// 随机圆周分布(带随机半径偏移)
+		float angle = dist_angle(rng);
+		float radius_variation = 0.8f + 0.2f * (rng() / (float)rng.max()); // 半径80%~100%
+		float x = cos(angle) * Radius * radius_variation;
+		float z = sin(angle) * Radius * radius_variation;
+		float y = dist_z(rng); // 使用连续随机分布
+
+		model = glm::translate(model, glm::vec3(x, y, z));
+
+		// 随机缩放
+		float scale = dist_scale(rng);
+		model = glm::scale(model, glm::vec3(scale));
+
+		// 随机旋转轴和角度
+		glm::vec3 rot_axis = glm::normalize(glm::vec3(
+			dist_axis(rng),
+			dist_axis(rng),
+			dist_axis(rng)
+		));
+
+		float rot_angle = dist_angle(rng); // 直接使用弧度制
+		model = glm::rotate(model, rot_angle, rot_axis);
+
+		m_InstanceData.push_back(model);
+	}
+
+	glBindVertexArray(GL_ZERO);
+
+	glGenBuffers(1, &m_GVBO);
+	glBindBuffer(GL_ARRAY_BUFFER, m_GVBO);
+	glBufferData(GL_ARRAY_BUFFER, sizeof(glm::mat4) * m_InstanceData.size(), m_InstanceData.data(), GL_DYNAMIC_DRAW);
+}
+
+void TestGLInstance::UpdateGVBOData(float delayTime)
+{
+	for (int index = 0; index < m_InstanceNum; ++index)
+	{
+	}
+}

+ 10 - 0
图形学/OpenGL学习/src/OpenGLDemo/OpenGLDemo/src/testModule/TestGLInstance.h

@@ -38,6 +38,9 @@ protected:
 	void InitUBO();
 	void UpdateUBO();
 
+	void InitGVBO();
+	void UpdateGVBOData(float delayTime);
+
 private:
 	glm::mat4 m_model = glm::mat4(1.0f);		// 模型矩阵
 	glm::mat4 m_view = glm::mat4(1.0f);			// 视图矩阵
@@ -53,6 +56,13 @@ private:
 	Shader m_ModelShader;
 	Model m_packageModel;
 
+	GLuint m_GVBO;								// 一个全局的 VBO 用于存储 实例化数组
+
+	std::vector<glm::mat4> m_InstanceData;		
+
+	int m_InstanceNum = 1000;
+
+	bool m_useInstance = true;
 	static TestGLInstance _self;
 };