计算机图形学笔记七:Shading 2(着色频率,图形(实时渲染)管线)

1.着色频率(方法)(Shading Frequencies)

下图是三种不同的着色频率的应用:
在这里插入图片描述

1.1平面着色(Flat shading)

对每个三角面着色
在这里插入图片描述
如上图所示,这种着色方法,是在一个三角形上取一个点然后根据平面的法向量对点进行着色,最后将这个点作为该面的着色(一个面上着色一次),在三角形的内部并不会发生颜色的变化,所以可以明显的看到球上的每个三角形。

1.2高洛德着色(Gouraud shading)

对每个顶点着色
在这里插入图片描述
如上图所示,这种着色方法,是在三角形每个顶点算出其对应的法线,然后对每个顶点进行一次着色,至于三角形内部某一点的颜色我们用三个顶点的插值来进行计算,这样三角形内部的颜色就会有一个渐变的效果,也能够更加平滑。

1.3冯着色(Phone shading)

对每个像素着色
在这里插入图片描述
如上图所示,对三角形的三个顶点分别求出法线,然后把法线的方向在三角形内部进行插值,从而我们在每一个像素上都可以求得一个独有的法向量,然后就可以在每一个像素上都进行一次着色,这样就可以得到一个相对比较好的结果。

三种着色频率的比较:
在这里插入图片描述
如上图所示,如果模型的面数量足够多时,那么用Flat shading就可以达到一个平滑的效果,如果仍然去用Phone shading就会增加额外的计算量,反而会导致效率降低。所以,具体选择哪一种方式,还要根据具体的模型具体选择。

1.4定义逐顶点法线

在这里插入图片描述
对于要表示球:要找一个球面上顶点的法线,根据几何知识可得,球心和球面上点的连线就是该点的法线。
在这里插入图片描述
对于要表示任意物体:由一个物体都是由许多三角形相连无缝贴合组成的可知,一个顶点就是多个三角形的顶点,所以这个顶点的法线就是周围相邻的几个面的法线的平均。
但是这样简单的平均没有意义,比如说一个三角形的面积很小,而另一个三角形的面积很大,那么这个大的三角形的法向量平均的份就应该多一些,相反,小三角形的法向量占平均的份就应该少一些。所以在平均时,将每个三角形的面积作为权值,对每个法向量进行加权平均,并且在求平均时要对向量进行标准化。
因此可得:
在这里插入图片描述

1.5定义逐像素的法线

在这里插入图片描述
两个顶点间的法线已经可以将求出来了,对于中间平滑过渡的法线,需要运用重心坐标的知识解决。

2.图形(实时渲染)管线(Graphics(Real-time Rendering) Pipeline)

概念表示: 从场景到最后屏幕上显示的图,在这中间经历了什么样的过程,这个过程就是管线。如下所示:
在这里插入图片描述

2.1具体每一步的操作

首先,对模型的每一个顶点的位置进行变换
在这里插入图片描述
然后我们进行光栅化采样
在这里插入图片描述
光栅化后产生了一个个片元(fragment)之后我们接着通过Z-BUffer判定是不是可见:
在这里插入图片描述
接着是着色shading:
在这里插入图片描述
此时可以看出着色会发生在顶点操作和像素操作两处中,这是因为我们要考虑着色频率,如果我们是Gouraud shading,那么肯定是在顶点操作中进行的着色,如果是phong shading,那么就是在fragment processing中进行的着色。

最后是进行纹理映射(Texture mapping):
在这里插入图片描述

2.2着色器(Shader)

Shader本质上是一些能在硬件上执行的语言。
GPU特点,并行计算;渲染中像素很多做同样的运算,所以很适合在GPU上运行。

注:shader在每一个顶点或者片元(fragment)会执行一次,所以我们写出的shader是通用的,适合于每一个顶点或者片元(fragment)的。因此我们不需要写for循,只需要写出适用于一个的代码就可以在任意一个上使用。
如果是对于顶点的操作,那么叫做vertex shader,如果是在片元(fragment)操作,叫做pixel shader。
在这里插入图片描述
如上图所示,是一个fragment shader,它的作用是告诉最终像素的颜色是什么,也就是对于一个fragment来说,我们要写清楚怎么样算它的颜色并且将它输出出去。
上述代码中uniform代表全局变量,myTexture(纹理)和 lightDir(光照方向),我们认为每一个fragment有一个固定的光照方向.norm是顶点法线,这个顶点法线是插值出来的。
其中:kd*=…那一行是之前提到的Bling-phong模型的漫反射计算公式。
在这里插入图片描述
最后再返回一个固定的值—gl_FragColor,也就是表达这个fragment的颜色是什么。
注:clamp函数:返回的value介于A、B之间,若value小于min,返回min,若大于max,返回max。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本文将介绍计算机图形学中的着色Shading)技术,包括着色频率图形管线、纹理映射等知识点,并提供部分代码示例。 ## 着色频率 计算机图形学中的着色可以分为两种频率,分别是顶点着色和像素着色。 顶点着色(Vertex Shading)是在顶点级别对图形进行着色的过程,即在图形的每个顶点上计算颜色值,然后通过插值计算出整个图形的颜色。顶点着色通常用于处理顶点属性,如位置、法向量和颜色等。 像素着色(Pixel Shading)是在像素级别对图形进行着色的过程,即对图形的每个像素计算颜色值。像素着色通常用于处理纹理映射、阴影效果、反射和折射等。 ## 图形管线 图形管线(Graphics Pipeline)是计算机图形学中的一个重要概念,它是将输入的几何形状转化为最终图像的过程,通常包括以下几个阶段: 1. 顶点输入:将输入的顶点数据传入图形管线。 2. 顶点着色:在顶点级别对图形进行着色。 3. 图元装配:将顶点组装成图元,如点、线、三角形等。 4. 光栅化:将图元转化为像素,并计算像素在屏幕上的位置。 5. 像素着色:对图形的每个像素进行着色。 6. 输出合成:将所有像素合成成最终的图像。 以下是一个简单的图形管线示例: ```c++ // 顶点着色器 void vertexShader(in vec3 position, out vec4 color) { // 计算顶点颜色 color = vec4(1.0, 0.0, 0.0, 1.0); // 将顶点位置传递给下一个阶段 gl_Position = vec4(position, 1.0); } // 像素着色器 void pixelShader(in vec4 color, out vec4 fragmentColor) { // 直接输出顶点颜色 fragmentColor = color; } // 主程序 int main() { // 顶点数据 vec3 vertices[] = { vec3(-1.0, -1.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, -1.0, 0.0) }; // 图元数据 GLuint indices[] = {0, 1, 2}; // 创建着色器程序 GLuint program = createProgram(vertexShader, pixelShader); // 获取顶点着色器输入位置的位置 GLuint positionLocation = glGetAttribLocation(program, "position"); // 创建顶点数组对象 GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); // 创建顶点缓冲区对象 GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据传递给顶点着色器 glEnableVertexAttribArray(positionLocation); glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0); // 创建索引缓冲区对象 GLuint ibo; glGenBuffers(1, &ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 渲染图元 glUseProgram(program); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0); // 销毁着色器程序、缓冲区对象和顶点数组对象 glDeleteProgram(program); glDeleteBuffers(1, &vbo); glDeleteBuffers(1, &ibo); glDeleteVertexArrays(1, &vao); return 0; } ``` ## 纹理映射 纹理映射(Texture Mapping)是一种基于图像的着色技术,它可以在三维模型表面上贴上图片,从而增强模型的真实感和细节。 纹理映射通常包括以下几个步骤: 1. 加载纹理图像:从文件中加载纹理图像,并将其存储在计算机内存中。 2. 创建纹理对象:将纹理图像传递给图形硬件,并创建一个纹理对象。 3. 纹理坐标计算:计算每个顶点在纹理图像中对应的位置,通常使用二维纹理坐标表示。 4. 纹理采样:在纹理图像中根据纹理坐标采样像素颜色,并将其作为顶点颜色。 5. 顶点着色:使用顶点颜色进行顶点着色。 以下是一个简单的纹理映射示例: ```c++ // 顶点着色器 void vertexShader(in vec3 position, in vec2 texCoord, out vec2 vTexCoord) { // 将纹理坐标传递给下一个阶段 vTexCoord = texCoord; // 将顶点位置传递给下一个阶段 gl_Position = vec4(position, 1.0); } // 像素着色器 uniform sampler2D texture; void pixelShader(in vec2 vTexCoord, out vec4 fragmentColor) { // 在纹理图像中采样像素颜色 vec4 texel = texture2D(texture, vTexCoord); // 输出纹理像素颜色 fragmentColor = texel; } // 主程序 int main() { // 顶点数据 vec3 vertices[] = { vec3(-1.0, -1.0, 0.0), vec3(0.0, 1.0, 0.0), vec3(1.0, -1.0, 0.0) }; // 纹理坐标数据 vec2 texCoords[] = { vec2(0.0, 0.0), vec2(0.5, 1.0), vec2(1.0, 0.0) }; // 图元数据 GLuint indices[] = {0, 1, 2}; // 加载纹理图像 GLuint texture = loadTexture("texture.png"); // 创建着色器程序 GLuint program = createProgram(vertexShader, pixelShader); // 获取顶点着色器输入位置和纹理坐标的位置 GLuint positionLocation = glGetAttribLocation(program, "position"); GLuint texCoordLocation = glGetAttribLocation(program, "texCoord"); // 创建顶点数组对象 GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); // 创建顶点缓冲区对象 GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // 将顶点数据传递给顶点着色器 glEnableVertexAttribArray(positionLocation); glVertexAttribPointer(positionLocation, 3, GL_FLOAT, GL_FALSE, 0, 0); // 创建纹理坐标缓冲区对象 GLuint tbo; glGenBuffers(1, &tbo); glBindBuffer(GL_ARRAY_BUFFER, tbo); glBufferData(GL_ARRAY_BUFFER, sizeof(texCoords), texCoords, GL_STATIC_DRAW); // 将纹理坐标数据传递给顶点着色器 glEnableVertexAttribArray(texCoordLocation); glVertexAttribPointer(texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, 0); // 创建索引缓冲区对象 GLuint ibo; glGenBuffers(1, &ibo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); // 渲染图元 glUseProgram(program); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(glGetUniformLocation(program, "texture"), 0); glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_INT, 0); // 销毁着色器程序、缓冲区对象、纹理对象和顶点数组对象 glDeleteProgram(program); glDeleteBuffers(1, &vbo); glDeleteBuffers(1, &tbo); glDeleteBuffers(1, &ibo); glDeleteTextures(1, &texture); glDeleteVertexArrays(1, &vao); return 0; } ``` 以上是计算机图形学着色技术的简单介绍,希望对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值