渲染流水线

 

一、渲染流水线

  渲染流水线的工作任务在于由一个三维场景出发、生存(或者说渲染)一张二维图像。换句话说,计算机需要从一系列的顶点数据、纹理等信息出发,把这些信息最终转换成一张人眼可以看到的图像。而这个工作通常是由CPU和GPU共同完成。
一个渲染流程分三个阶段:应用阶段(Application Stage)、几何阶段(Geometry Stage)、光栅化阶段(Rasterizer Stage)。
  

  1、应用阶段

  从名字我们可以看出,这个阶段是由我们的应用主导的,因此通常由CPU负责实现。换句话说,我们这些开发者具有这个阶段的绝对控制权。这一阶段中,开发者有3个主要任务:
  首先,我们需要准备好场景数据,例如摄像机的位置、视锥体、场景中包含了哪些模型、使用了那些光源等等;
  其次,为了提高渲染性能,我们往往需要做一个粗粒度剔除工作,以把那些看不见的物剔除出去,这样就不需要再移交给几何阶段进行处理;
  最后,我们需要设置好每个模型的渲染状态,这些渲染状态包括但不限于它使用的材质(漫反射颜色、高光反射颜色)、试用的纹理、使用的shader等。
  这一阶段最重要的输出是渲染所需要的几何信息,即渲染图元(Rendering Primitives)。通俗来讲,渲染图元可以是点、线、三角面等。这些渲染图元将会被传递给下一个阶段——几何阶段。

  2、几何阶段

  几何阶段用于处理所有和我们要绘制的几何相关的事情。例如,决定需要绘制的图元是什么,怎么绘制它们,在哪里绘制它们。这一阶段通常在GPU上进行。
  几何阶段负责和每个渲染图元打交道,进行逐顶点、逐多边形的操作。这个阶段可以进一步分成更小的流水线阶段。几何阶段的一个重要任务就是把顶点变换到屏幕空间中,再交给光栅器进行处理。通过对输入的渲染图元进行多步处理后,这一阶段将会输出屏幕空间的二维顶点坐标、每个顶点对应的深度值、着色等相关信息,并传递给下一阶段。

  3、光栅化阶段

  这一阶段将会使用上个阶段传递的数据来产生屏幕上的像素,并渲染出最终的图像。这一阶段也是在GPU上运行。光栅化的任务主要是决定每个渲染图元中的哪些像素应该被绘制在屏幕上。它需要对上一个阶段的逐顶点数据(例如纹理坐标、顶点颜色等)进行插值,然后再进行逐像素处理。
 

二、CPU和GPU之间的通信

  渲染流水线的起点是CPU,即应用阶段。应用阶段大致可分为下面3个阶段:
  (1)把数据加载到显存中
  (2)设置渲染状态
  (3)调用DrawCall
  DrawCall是一个命令,它的发起方是CPU,就收方是GPU。这个命令仅仅会指向一个需要被渲染的图元列表,而不会再包含任何材质信息

三、GPU流水线

  当给定一个DrawCall时,GPU就会根据渲染状态(例如材质、纹理、着色器等)和所有输入的顶点数据进行计算,最终输出成屏幕上显示的那些漂亮的像素。而这个计算过程,就是GPU流水线。
  从图中可以看出,GPU的渲染流水线接收顶点数据作为输入。这些顶点数据是由应用阶段加载到显存中,再由DrawCall指定的。这些数据随后被传递给顶点着色器。
  顶点着色器(Vertex Shader)是完全可编程的,它通常用于实现顶点的空间变换、顶点着色等功能。
  曲面细分着色器(Tessellation Shader)是一个可选的着色器,它用于细分图元。
  几何着色器(Geometry Shader)同样是一个可选的着色器,它可以被用于执行逐图元(Per-Primitive)的着色操作,或者被用于产生更多的图元。
  裁剪(Clipping)这一阶段的目的是将那些不在摄像机视野内的顶点裁减掉,并剔除某些三角图元的面片。
  屏幕映射(Screen Mapping)这一阶段是不可配置和编程的,它负责把每个图元的坐标变换到屏幕坐标系中。
  三角形设置(Triangle Setup)和三角形遍历(Triangle Traversal)阶段也都是固定函数的阶段,片元着色器(Fragment Shader)则是完全可编程的,它用于实现逐片元的着色操作。最后,逐片元操作(Per-Fragment Operation)阶段负责执行很多重要的操作,例如修改颜色、深度缓冲、进行混合等。
 

四、什么是DrawCall

  DrawCall本身的含义很简单,就是CPU调用图像编程接口,如OpenGL中的glDrawElements命令或者DirectX中的DrawIndexedPrimitive命令,以命令GPU进行渲染的操作。
  一个常见的误区是,DrawCall中造成性能问题的元凶是GPU,认为GPU上的状态切换是耗时的,其实不是的,真正“拖后腿”其实是CPU。
  问题一:CPU和GPU是如何实现并行工作的
  想让CPU和GPU可以并行工作,解决方法是使用一个命令缓冲区(Command Buffer)。
命令缓冲区包含了一个命令队列,由CU向其中添加命令,而由GPU从中读取命令,添加和读取的过程是相互独立的。命令缓冲区使得CPU和GPU可以相互独立工作,当CPU需要渲染一些对象时,它可以向命令缓冲区添加命令,而当GPU完成了上一次的渲染任务后,它就可以从命令队列中再取出一个命令并执行它。
  命令缓冲区的命令有很多种类,而DrawCall是其中一种,其他命令还有改变渲染状态等(例如改变使用的着色器,使用不同的纹理等)。
  问题二:为什么DrawCall多了会影响帧率
  在每次调用DrawCall之前,CPU需要向GPU发送很多内容,包括数据、状态和命令等。这一阶段,CPU需要完成很多工作,例如检查渲染状态等。而一旦CPU完成了这些准备工作,CPU就可以开始本次的渲染。GPU的渲染能力是很强的,渲染200个还是2000个三角网格通常没什么区别,因此渲染速度往往快于CPU提交命令的速度。如果DrawCall数量太多,CPU就会把大量时间花费在提交DrawCall上,造成CPU的过载。
  问题三:如何减少DrawCall
  减少DrawCall一个很显然的优化想法就是把很多小的DrawCall合并成一个大的DrawCall,这就是批处理的思想
  在游戏开发过程中,为了减少DrawCall的开销,有两点需要注意:
  (1)避免使用大量很小的网格。当不可避免地需要使用很小的网格结构时,考虑是否可以合并。
  (2)避免使用过多的材质。尽量在不同的网格之间共用一个材质。
 

五、什么是shader

  我们之所以要花很大篇幅来讲述GPU的渲染流水线,是因为shader所在的阶段就是渲染流水线的一部分,更具体来说,shader就是:
  (1)GPU流水线上一些可以高度编程的阶段,而由着色器编译出来的最终代码是会在GPU上运行的(队于固定管线的渲染来说,着色器有时等同于一些特定的渲染设置);
  (2)有一些特定类型的着色器,如顶点着色器、片元着色器等;
  (3)依靠着色器我们可以控制流水线中的渲染细节,例如用顶点着色器来进行顶点变换以及传递数据,用片元着色器来进行逐像素的渲染。
 

Unity Shader入门基础(一)的更多相关文章

  1. Unity Shader入门精要学习笔记 - 第7章 基础纹理

    转自 冯乐乐的 <Unity Shader 入门精要> 纹理最初的目的就是使用一张图片来控制模型的外观.使用纹理映射技术,我们可以把一张图“黏”在模型表面,逐纹素地控制模型的颜色. 在美术 ...

  2. Unity Shader入门精要学习笔记 - 第6章 开始 Unity 中的基础光照

    转自冯乐乐的<Unity Shader入门精要> 通常来讲,我们要模拟真实的光照环境来生成一张图像,需要考虑3种物理现象. 首先,光线从光源中被发射出来. 然后,光线和场景中的一些物体相交 ...

  3. Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础

    来源作者:candycat   http://blog.csdn.net/candycat1992/article/ 概述 总体来说,在Unity中我们需要配合使用材质和Unity Shader才能达 ...

  4. Unity Shader入门精要读书笔记(一)序章

    本系列的博文是笔者读<Unity Shader入门精要>的读书笔记,这本书的章节框架是: 第一章:着手准备. 第二章:GPU流水线. 第三章:Shader基本语法. 第四章:Shader数 ...

  5. Unity Shader入门精要学习笔记 - 第11章 让画面动起来

    转自 冯乐乐的 <Unity Shader入门精要> Unity Shader 中的内置变量 动画效果往往都是把时间添加到一些变量的计算中,以便在时间变化时画面也可以随之变化.Unity ...

  6. Unity Shader入门精要学习笔记 - 第9章 更复杂的光照

    转载自 冯乐乐的<Unity Shader入门精要> Unity 的渲染路径 在Unity里,渲染路径决定了光照是如何应该到Unity Shader 中的.因此,如果要和光源打交道,我们需 ...

  7. Unity Shader入门精要学习笔记 - 第8章 透明效果

    转载自 冯乐乐的 <Unity Shader入门精要> 透明是游戏中经常要使用的一种效果.在实时渲染中要实现透明效果,通常会在渲染模型时控制它的透明通道.当开启透明混合后,当一个物体被渲染 ...

  8. Unity Shader入门精要学习笔记 - 第4章 学习 Shader 所需的数学基础

    摘录自 冯乐乐的<Unity Shader入门精要> 笛卡尔坐标系 1)二维笛卡尔坐标系 在游戏制作中,我们使用的数学绝大部分都是计算位置.距离.角度等变量.而这些计算大部分都是在笛卡尔坐 ...

  9. Unity Shader入门

    Unity Shader入门 http://www.cnblogs.com/lixiang-share/p/5025662.html http://www.manew.com/blog-30559-1 ...

随机推荐

  1. [LeetCode] Serialize and Deserialize Binary Tree

    Serialize and Deserialize Binary Tree Serialization is the process of converting a data structure or ...

  2. VS2010在运行状态下编辑代码

    在VS2010环境下,当程序处于调试运行状态时,编辑代码会出现下图提示框: 这就给边编辑代码边查看程序运行效果带来不便. 解决方法:在程序没有运行的时候,打开菜单“工具”——>“选项”——> ...

  3. Java Split以竖线作为分隔符

    今天用到了Java中的Split函数,要以“|”作为分割符,当输入竖线时,发现出错,这个问题应该很久前就遇到过,不过太长时间就给忘了! 网上一搜,就找到了答案,这是因为split里面有两个参数,其中一 ...

  4. 解决tkinter在windows上没有正确安装的问题

    问题 Can't find a usable tk.tcl in the following directories: 解决方法 加两个环境变量,在我的机器上是这样的 TCL_LIBRARY=D:\d ...

  5. C# 匿名委托、匿名方法、匿名对象、Lambda表达式

    一.匿名类型可通过使用 new 运算符和对象初始值创建匿名类型.示例:var v = new { Name = "Micro", Message = "Hello&quo ...

  6. Python: 收集所有命名参数

    有时候把Python函数调用的命名参数都收集到一个dict中可以更方便地做参数检查,或者直接由参数创建attribute等.更简单的理解就是def foo(*args, **kwargs): pass ...

  7. 首次构建android studio gradle 下载缓慢的问题

    1.先使用其他工具下载gradle, https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 2.然后放在C:\Users\A ...

  8. openwrt 编译newifi 应用程序

    首先找交叉编译工具( toolchain ) Development Snapshots http://downloads.openwrt.org/snapshots/trunk/ 我需要的版本是 m ...

  9. Android Studio开发第四篇版本管理Git(下)

    前面一片介绍了在as下如何关联远程仓库,这篇就介绍在开发过程中怎么应用. 提交+Push 如果本地开发代码有改动了或者你觉得某功能做完了,你打算把改动代码提交到远程仓库,这个时候很简单, 还是在工具栏 ...

  10. messages.exe病毒的清理

    一.问题提出 20161021,10点05分,发现messages.exe突然出现在进程中,计算机突然重启,msconfig启动目录里多了一项c:\windows\system32\Drivers\m ...