Jelajahi Sumber

feat: 添加着色器解释

nicetry12138 1 tahun lalu
induk
melakukan
39d760d8e1

TEMPAT SAMPAH
图形学/OpenGL学习/Image/008.png


+ 76 - 1
图形学/OpenGL学习/README.md

@@ -281,6 +281,8 @@ while (!glfwWindowShouldClose(window))
 
 ## 顶点缓冲
 
+### 顶点
+
 顶点缓冲区本质上还是一个**缓冲区**,是一个内存缓冲区,也就是一个数组。也就是定义一组数据来表示三角形,并且将其放到 `GPU` 的 `VRAM` 中,在绘制时 告诉 `GPU` 如何从 `VRAM` 读取并且解释数据信息,以及如何绘制到屏幕上
 
 **顶点** 并不代表坐标,坐标信息只是顶点的一部分,除此之外顶点还可以有其他信息,比如:颜色、法线、纹理等。所以顶点指的是一整个构成顶点的数据集合
@@ -360,7 +362,80 @@ void glVertexAttribPointer(	GLuint index,
 
 ![](Image/007.png)
 
-如上图类似,通过 `index` 知道启示遍历序号,通过 `size` 知道顶点属性的数量,通过 `type` 知道顶点属性的数据类型,通过 `stride` 知道地址需要偏移多少
+如上图类似,提供一块内存,通过 `index` 知道起始遍历序号,通过 `size` 知道顶点属性的数量,通过 `type` 知道顶点属性的数据类型,通过 `stride` 知道地址需要偏移多少
 
 通过上面传入的数据,就可以完全遍历一块内存了。我们知道区域的数据类型,但是 `OpenGL` 不知道,所以这个函数就是告诉 `OpenGL` 如何解析一块内存区域
 
+### 着色器
+
+前面的代码只是提供了顶点坐标,并没有提供颜色,为什么会绘制出白色的三角形呢?
+
+这个是因为 如果程序没有提供着色器的话, GPU 会驱动提供默认的**着色器**
+
+那么什么是**着色器**?
+
+**渲染管线**(`Render Pipeline`)和**着色器**(`Shaders`)的关系是非常紧密的。在现代图形处理中,渲染管线是由一系列顺序执行的阶段组成的,这些阶段共同完成将3D场景转换为2D图像的任务。着色器则是在这个管线中的关键组件,负责处理图形和图像的具体细节
+
+**渲染管线**是将3D场景转换为2D图像的过程。想象一下它就像一个工厂的流水线,不同的加工环节(渲染阶段)根据用户需求对每个环节进行灵活改造或拆卸,将原始材料(CPU端向GPU端提交的纹理等资源以及指令等)加工为最终的成品,即呈现在用户屏幕上的图像
+
+功能性阶段划分
+
+1. 应用阶段 (Application)
+   - 在CPU上执行,完全可控制
+   - 主要任务是输入装配,将顶点和索引装配为几何图元
+   - 例如,从显存中读取几何数据,装配顶点,构成图元传递给几何阶段
+2. 几何阶段 (Geometry Processing)
+   - 在GPU上运行,处理应用阶段发送的渲染图元
+   - 主要任务是将顶点坐标变换到屏幕空间中,再交给光栅器进行处理
+   - 包括顶点着色阶段、投影阶段、裁剪阶段和屏幕映射阶段
+3. 光栅化阶段 (Rasterization)
+   - 也在GPU上执行
+   - 目标是找到处于图元内部的所有像素,将2D坐标顶点转为屏幕上的像素
+   - 插值逐像素数据,传递给像素阶段
+4. 像素阶段 (Pixel Processing)
+   - 处理光栅化阶段传来的像素数据
+   - 包括像素着色器,计算像素的颜色和其他属性
+   - 最终生成图像
+
+渲染管线的不同阶段会应用不同的着色器
+
+现在GPU允许通过编程的方式,处理顶点、像素的着色操作,通过**着色器**(`Shaders`)的方式
+
+- OpenGL: GLSL语言
+- DirectX: HLSL语言
+
+1. 顶点着色器(Vertex Shader)
+   - 描述顶点的属性,如位置、纹理坐标、颜色等
+   - 将3D空间中的顶点坐标变换为屏幕上的2D坐标
+   - 无法生成新的顶点,但输出传递到流水线的下一步
+2. 像素着色器(Pixel Shader)
+   - 也称为片段着色器,用于计算像素的颜色和其他属性
+   - 处理单独的像素,通常指单独的屏幕像素
+   - 可以实现光照、凹凸贴图、阴影、半透明等效果
+3. 几何着色器(Geometry Shader)
+   - 可以生成新的图形基元,如点、线和三角形
+   - 可以在图形处理器内修改场景中的几何结构
+   - 用于增加模型细节和执行对CPU来说过于繁重的几何操作
+4. 曲面细分着色器(Tessellation Shader)
+   - 引入于OpenGL 4.0和Direct3D 11
+   - 可以将简单网格细分为更复杂的网格,根据特定函数计算
+   - 可以根据视点距离等变量动态调整细节层次
+
+![](Image/008.png)
+
+以前面的代码为例子
+
+```cpp
+float positions[6] = {
+    -0.5f, -0.5f,
+    0.0f,  0.5f,
+    0.5f, -0.5f
+};
+```
+
+这里 `positions` 传递了三个顶点,意味着顶点着色器需要运行三次,每个顶点一次
+
+一个顶点着色器的基本目的就是告诉那个顶点需要绘制到屏幕的哪里
+
+然后将数据传递给片段着色器,为每个像素运行一次片段着色器程序,片段着色器的基本目的就是决定像素的颜色
+

+ 4 - 0
图形学/OpenGL学习/src/OpenGLStudy/OpenGLStudy/OpenGLStudy.vcxproj

@@ -138,6 +138,10 @@
   <ItemGroup>
     <ClCompile Include="src\Application.cpp" />
   </ItemGroup>
+  <ItemGroup>
+    <None Include="src\Fragment.frag" />
+    <None Include="src\Vertex.vert" />
+  </ItemGroup>
   <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
   <ImportGroup Label="ExtensionTargets">
   </ImportGroup>

+ 8 - 0
图形学/OpenGL学习/src/OpenGLStudy/OpenGLStudy/OpenGLStudy.vcxproj.filters

@@ -22,4 +22,12 @@
       <Filter>源文件</Filter>
     </ClCompile>
   </ItemGroup>
+  <ItemGroup>
+    <None Include="src\Vertex.vert">
+      <Filter>src</Filter>
+    </None>
+    <None Include="src\Fragment.frag">
+      <Filter>src</Filter>
+    </None>
+  </ItemGroup>
 </Project>

+ 41 - 0
图形学/OpenGL学习/src/OpenGLStudy/OpenGLStudy/src/Application.cpp

@@ -13,6 +13,47 @@ void render() {
 	glEnd();
 }
 
+static GLuint CompiledShader(const std::string& source, GLenum inType) {
+	GLuint id = glCreateShader(inType);
+	const char* src = source.c_str();
+	glShaderSource(id, 1, &src, nullptr);
+	glCompileShader(id);
+
+	// Shader 错误处理
+	GLint result;
+	glGetShaderiv(id, GL_COMPILE_STATUS, &result);
+	if (result == GL_FALSE) {
+		int length;
+		glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length);
+		// alloca 在栈上申请内存,不需要 free ,在作用域结束后自动释放
+		char* msg = (char*)alloca(length * sizeof(char));
+		glGetShaderInfoLog(id, length, &length, msg);
+		std::cout << "Sharder Compile " << (inType == GL_VERTEX_SHADER ? "vertex sharder" : "fragment sharder") << " Faild" << std::endl;
+		std::cout << msg << std::endl;
+		
+		glDeleteShader(id);
+		return GL_ZERO;
+	}
+
+	return id;
+}
+
+static unsigned int CreateShader(const std::string& vertexShader, const std::string& fragmentShader) {
+	GLuint program = glCreateProgram();
+	GLuint vs = CompiledShader(vertexShader, GL_VERTEX_SHADER);
+	GLuint fs = CompiledShader(fragmentShader, GL_FRAGMENT_SHADER);
+
+	glAttachShader(program, vs);
+	glAttachShader(program, fs);
+	glLinkProgram(program);
+	glValidateProgram(program);
+
+	glDeleteShader(fs);
+	glDeleteShader(vs);
+
+	return program;
+}
+
 int main(void)
 {
 	GLFWwindow* window;

+ 7 - 0
图形学/OpenGL学习/src/OpenGLStudy/OpenGLStudy/src/Fragment.frag

@@ -0,0 +1,7 @@
+#version 330 core
+
+layout(location = 0) out vec4 color;
+
+void main() {
+	color = vec4(1.0, 0.0, 0.0, 1.0):
+}

+ 7 - 0
图形学/OpenGL学习/src/OpenGLStudy/OpenGLStudy/src/Vertex.vert

@@ -0,0 +1,7 @@
+#version 330 core
+
+layout(location = 0) in vec4 position;
+
+void main() {
+	gl_Position = position;
+}