Shader编程学习笔记(二)—— Shader和渲染管线

Shader和渲染管线

什么是Shader

  Shader,中文翻译即着色器,是一种较为短小的程序片段,用于告诉图形硬件如何计算和输出图像,过去由汇编语言来编写,现在也可以使用高级语言来编写。一句话概括:Shader是可编程图形管线的算法片段。
  它主要分为两类:Vertex Shader和Fragment Shader。

什么是渲染管线

  渲染管线也称为渲染流水线,是显示芯片内部处理图形信号相互独立的并行处理单元。一个流水线是一序列可以并行和按照固定顺序进行的阶段。就像一个在同一时间内,不同阶段不同的汽车一起制造的装配线,传统的图形硬件流水线以流水的方式处理大量的顶点、几何图元和片段。

  注意理解的是这里有一个前后关系,前一个阶段的输入会到后一个阶段去输出。比如在顶点程序当中,顶点程序计算的数据就会作为片段程序再进一步加工的材料。

  为了更形象地理解渲染管线,来看一下下面的插图。

  最上面的是【3D应用或者游戏】,【3D应用或者游戏】会直接调用【3D应用接口】,也就是OpenGL或者DirectX等。OpenGL和DirectX是方便应用程序去进行硬件访问和调用的中间层。如果没有它们,我们需要为硬件去编写一个非常复杂的专门针对硬件的驱动程序。
  再接下来就是【CPU和GPU的分界线】,在此之上都是CPU的操作,以下进行GPU运算。
  GPU的运算是从左到右依次进行,最开始【GPU前端模块】到【图元装配】这中间如果在过去T&L流水线的过程当中是由硬件设计好的运算过程,也就是集成的,它不能够进行编程控制。当图形硬件具有了可编程能力之后,我们就可以在这个阶段使用【顶点着色器】进行编写运算逻辑,用于取代过去直接集成在硬件当中的运算。在这个阶段完成之后,会到【光栅化以及插值】阶段。
  光栅化就是把计算机显卡当中运算的数据进行一个细分,用于去适配屏幕上具体的每一个像素的显示,但是光栅化并不等同于像素显示,像素显示最终反映的是颜色,而光栅化过后得到的结果是【帧缓存】,在这个过程当中,我们可以插入【片段着色器】,这个部分就可以使用可编程化运算。所以【片段着色器】的目标是为屏幕上最终要显示的每一个像素去计算它最后需要什么样的颜色。

  对于Unity来说,以上过程可以通过下图来解释。

  最上面【Geometry】是几何模型,几何模型进入【Unity】,可以理解为把几何模型Mesh、网格等数据交给Unity,Unity导入后就通过Unity引擎去调用【Grphics APU】图形API,调用图形API的过程就是在驱动GPU进行处理运算。
  进入GPU运算首先进行的是【Vertex Processor】顶点处理器,这个部分就需要我们使用【Vertex Shader】顶点着色器,顶点着色器运算的结果会交给【Pixel Processor】像素处理器,也就是片段处理器,在这个部分我需要为像素处理编写【Pixel Shader】像素着色器程序,这部分计算完后就输出了最终我们可以用于在屏幕上的颜色信息,我们把它叫做【Frame Buffer】帧缓冲。帧缓冲存储的是计算机依次显示所要的数据,但也不仅仅是这些数据,它还有其他的附加信息,比如深度值等。

  下面是Unity官方手册中的一张渲染管线图示。

  渲染管道线中最左边的这个部分中Transform指的是模型的空间变换,主要针对的是顶点的空间几何变换;TexGen即Texture Generator,表示的是纹理坐标的生成,主要用于在顶点当中去取得纹理坐标,再转换为UV取值的范围;Lighting指的是光照。因此这个部分就是过去就是T&L几何变换光照流水线,当图形硬件具有了可编程能力后,这个固定的模块就被【Vertex Shader】顶点着色器代替了。

  在顶点着色器处理过后,Unity就进入【Culling & Depth Test】裁剪和深度测试过程。裁剪和深度测试描述的是如果一个物体在摄像机前展示,它向着摄像机的面会被观察到,它背对着摄像机的面不会被观察到,在这样的情况下,为了减少GPU处理数据量就进行了一个裁剪(Culling),把看不见的面直接剔除,不需要去处理的这些面所涉及的顶点数据,从而加速图形处理。第二个方面深度测试(Depth Test),指的是摄像机有一个特性,在计算机当中没有无限这个概念,计算机处理的数据都是离散化的,它有一个范围,当超过最近和最远这个范围的这部分会被剔除。

  接下来就进入到纹理采样(Texturing)和雾化处理(Fog)阶段。在这阶段实际上就是在进行光栅化处理,描述的就是如何在屏幕上显示每一个像素的颜色。这里需要去纹理采样,一张贴图有很多数据,我们去采集纹理上某一点的颜色值,这个就叫做纹理采样。雾化就是根据最后计算的数据后需不需要进行一个雾化处理,近处的很清晰,远处的有种朦胧感,这个部分就是片段着色器可编程的能力范围。

  之后还需要【Alpha Test】,指的是去绘制那些半透明的或全透明的物体。经过【Alpha Test】之后还需要进行【Blending】处理,这阶段会混合最终的图像。

  以上介绍的是渲染管线的流程,要把握的主要的过程就是我们可编程能力是两个部分,一个就是几何变换和光照使用的顶点着色器部分,另一个就是关于如何去采样,去计算颜色以及雾化处理等使用的片段着色器部分。

  这里需要注意的是Unity优化当中有一个主要部分就是减少Draw Call的调用,Draw Call就指的是应用程序去调用图形硬件GPU去进行渲染的调度过程。应用程序需要准备很多的数据,包括顶点数据、矩阵、向量等数据,都需要通过应用程序传递给GPU,这样个调度过程CPU必须要去收集数据以后才产生一个API的调用,这个过程的消耗是高昂的,如果反复地启动这个调用,那么就仅仅收集和传递参数这样的过程相当耗时耗力,就会造成了应用程序或游戏运行的瓶颈。因此要尽量减少Draw Call,尽量减少CPU对GPU这样的调用。

Shader和材质、贴图的关系

  Shader(着色器)实际上就是一小段程序,它负责将输入的顶点数据以指定的方式和输入的贴图或者颜色等组合起来,然后输出。绘图单元可以依据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上对应的Shader,以及对Shader的特定的参数设置,将这些内容(Shader及输入参数)打包存储在一起,得到的就是一个Material(材质),之后,我们便可以将材质赋予三维物体来进行渲染(输出)了。

  材质好比引擎最终使用的商品,Shader好比是生产这种商品的加工方法,而贴图就是原材料。

总结

  Shader是图形可编程方案的程序片段。主要分为顶点着色器和片段着色器。

  渲染管线是一种计算机从数据到最终图形成像的形象描述。

  材质可以理解为商品,Shader是加工这种商品的方法,而贴图是加工过程中需要的材料。

时间: 2024-11-09 19:06:30

Shader编程学习笔记(二)—— Shader和渲染管线的相关文章

Shader编程学习笔记(四)——Unity Shader的组织形式(ShaderLab)

Unity Shader的组织形式 Unity Shader的形态 Unity官方手册上讲Unity Shader有三种不同的编写方案,这三种编写方案分别是surface shaders.vertex and fragment shaders和fixed function shaders. 从前面几篇笔记中可以了解到,可编程图形管线中能够编写shader的主要是两个部分:vertex shader和fragment shader,但Unity还有surface shaders和fixed fun

Shader编程学习笔记(七)—— Surface shader 1

Surface shader 本小结对Unity的Surface Shader做一个大概的了解.主要了解在Surface Shader当中比较重要的几个部分,分别是: SurfaceOutput Input lighing shadow 首先查看一下Unity的官方手册中的Writing Surface Shaders,其中描述道:如果要编写一个shader去和光进行交互是比较复杂的,因为光照会有不同的光照类型,不同的阴影选项和不同的渲染路径(包括foward和deferred renderin

Shader编程学习笔记(三)——三大主流编程语言 HLSL/GLSL/Cg

三大主流编程语言 HLSL/GLSL/Cg Shader Language Shader Language的发展方向是设计出在便携性方面可以和C++.Java等相比的高级语言,“赋予程序员灵活而方便的编程方式”,并“尽可能的控制渲染过程”同时“利用图形硬件的并行性,提高算法效率”. Shader Language目前主要有3种语言:基于OpenGL的OpenGL Shading Language,简称GLSL;基于DirectX的High Level Shading Language,简称HLS

Shader编程学习笔记(一)—— 图形硬件简史与可编程管线

图形处理器(GPU)简史 GPU发展简史 GPU英文全称Graphic Processing Unit,中文翻译为“图形处理器”,在现代计算机系统中的作用变得越来越重要. 20世纪六.七十年代,受硬件条件的限制,图形显示器只是计算机输出的一种工具.限于硬件发展水平,人们只是纯粹从软件实现的角度来考虑图形用户界面的规范问题.此时还没有GPU的概念. GPU概念在20世纪70年代末和80年代初被提出,使用单片集成电路(monolithic)作为图形芯片,此时的GPU被用于视频游戏和动画方面,它能够很

Shader编程学习笔记(八)—— Surface Shader 2

Surface Shader 上一小结主要了解了Surface Shader使用了“#pragma surface surf Standard fullforwardshadows”指令的意义,这一小节主要了解“surf”surface函数. void surf (Input IN, inout SurfaceOutputStandard o) { // Albedo comes from a texture tinted by color fixed4 c = tex2D (_MainTex,

FFmpeg编程学习笔记二:音频重采样

ffmpeg实现音频重采样的核心函数swr_convert功能非常强大,可是ffmpeg文档对它的注释太过简单,在应用中往往会出这样那样的问题,其实在读取数据->重采样->编码数据的循环中在第一次执行swr_convert后还应用swr_convert再作个缓存检测看看是否还有数据,如果有就要把它写到FIFO中去,留在下次再使用,这点在转码和由低向高转换采样率时特别重要. 下面一段简单的代码,摘自我自已写的测试程序. const int frame_size = FFMIN(fifo_size

linux sheel编程学习笔记(二) --- grep命令

Linux系统中grep命令是一种强大的文本搜索工具,它能使用正则表达式搜索文本,并把匹 配的行打印出来.grep全称是Global Regular Expression Print,表示全局正则表达式版本,它的使用权限是所有用户. grep的工作方式是这样的,它在一个或多个文件中搜索字符串模板.如果模板包括空格,则必须被引用,模板后的所有字符串被看作文件名.搜索的结果被送到标准输出,不影响原文件内容. grep可用于shell脚本,因为grep通过返回一个状态值来说明搜索的状态,如果模板搜索成

linux网络编程学习笔记之二 -----错误异常处理和各种碎碎(更新中)

errno 在unix系统中对大部分系统调用非正常返回时,通常返回值为-1,并设置全局变量errno(errno.h),如socket(), bind(), accept(), listen().erron存放一个正整数来保存上次出错的错误值. 对线程而言,每个线程都有专用的errno变量,不必考虑同步问题. strerror converts to English (Note: use strerror_r for thread safety) perror is simplified str

Win8 HTML5与JS编程学习笔记(二)

近期一直受到win8应用的Grid布局困扰,经过了半下午加半个晚上的奋斗,终于是弄明白了Grid布局方法的规则.之前我是阅读的微软官方的开发教程,书中没有详细说明CSS3的布局规则,自己鼓捣了半天也是一头雾水,于是又找到了官方的启蒙教程的布局一张,仔细阅读了一遍,又思考了代码,并在代码的基础上实验,终于是明白了布局方法.官方教程地址是:http://msdn.microsoft.com/zh-cn/library/windows/apps/jj841108.aspx 微软基于CSS3开发了Gri