unity shader之预备知识

1.渲染流水线

任务:从一个三维场景出发,生成(或者渲染)一张二维图像。即:计算机需要从一系列的定点出数据,纹理等信息出发,把这些信息最终转换程一张人眼可以看到的图像。而这个工作通常是由CPU和GPU共同完成的。

三个阶段:

(1)应用阶段(CPU):1.准备场景数据。2.粗粒度剔除工作。3设置模型的渲染状态,输出渲染所需要的几何信息.

应用阶段大致可以分为三个阶段:

1.把数据加载到显存中。

2.设置渲染状态。渲染状态:定义场景中的网格是怎样被渲染的。如:使用那个顶点着色器/片元着色器。

3.调用DrawCall。DrawCall是一个命令,发起方为CPU,接收方为GPU。

(2)几何阶段:把定点坐标变换到屏幕空间中,再交给光栅器进行处理。对输入的渲染图源进行多部处理后,将会输出屏幕空间的二维顶点坐标,每个定点对应的深度值,着色等相关信息。

(3)光栅化阶段:产生屏幕上的像素,并渲染最终的图像。光栅化的任主要是决定每个渲染图源中的那些像素应该被绘制再屏幕上。对上一阶段得到的逐定点数据进行插值,然后再进行逐像素处理。

为了避免我们看到的那些正在进行光栅化的图元,GPU会使用双重缓冲策略(前置缓冲,后置缓冲)。当场景被渲染到后置缓冲中,GPU会交换前后置缓冲中的内容,前置缓冲事之前显示在屏幕上的图像。

(1)顶点着色器:处理单位是顶点,输入进来的每个定点都会调用一次定点着色器。顶点着色器本身不可以创建或者销毁任何顶点,而且无法得到顶点与顶点之间的关系。完成的工作主要由:坐标变换(把顶点坐标从模型空间转换到裁剪空间如:mul(UNITY_MVP,v.postion))和逐顶点光照。

(2)裁剪:一个图元和摄像机事业的关系有三种:完全在视野内,部分在视野内,完全在视野外。

(3)屏幕映射:把每个图元的x,y坐标转换到屏幕坐标系下。

(4)三角形设置:计算光栅化一个三角网格所需要的信息。即:得到三角形的每个顶点,需要得到整个三角网格对像素的覆盖情况。

(5)三角遍历:检查每个像素是否被一个三角网络所覆盖。根据上一个阶段的计算结果来判断一个三角网格覆盖了那些像素,并使用三角网格3个顶点的顶点信息对整个覆盖区域的像素进行插值。

(6)片元着色器:采用的主要技术为纹理采样。在顶点着色器阶段输出每个顶点对应的纹理坐标,然后经过光栅化阶段对三角网格的3个顶点对应的纹理坐标进行插值,就可以得到其覆盖的片元的纹理坐标。

(7)逐片元操作:几个主要任务:

1.决定每个片元的可见性。涉及很多测试工作,如:深度测试,模板测试。

2.当某个片元通过了所有测试,就需要把这个片元的颜色值和已经存储在颜色缓冲区中的颜色进行合并(混合)。

开启混合功能:GPU会取出资源颜色和目标颜色,将两种颜色进行混合。

关闭混合功能:会直接使用片元的颜色覆盖掉颜色缓冲区中的颜色。

对于不透明的物体,即使关闭混合操作,片元着色器计算得到的颜色值可以直接覆盖掉颜色缓冲区中的像素值。但是对于半透明物体,就需要使用混合操作来使物体看上去湿透明的。

 2.Draw Call

(1)CPU和GPU是如何实现并行工作的?

  使用命令缓冲区。命令缓冲区包含了一个命令队列,由CPU向其中添加命令,而GPU从中读取命令,读取和添加命令是相互独立的。

(2)为什么Draw Call多了会影响帧率?

  每次调用Draw Call之前,CPU需要向GPU发送很多内容,包括数据,状态和命令等。

(3)如何减少Draw Call?

  批处理方法。把很多小的Draw Call合并成一个大的Draw Call 。

 在游戏开发过程中,为了减少Draw Call的开销,需要注意:

(1)避免使用大量很小的网格,当不可避免地需要使用很小的网格时,可以考虑是否可以合并。

(2)避免使用过多的材质。尽量在不同得网络之间共用同一个材质。、

3.Shader结构

1.使用流程:

(1)创建材质。

(2)创建一个Shader,并赋给(1)创建的材质。

(3)把材质赋给要渲染的对象

(4)在材质面板中调节shader的属性。

2.基础结构

Shader "Custom/MyShader" {
    Properties {
        _Int ("Int", Int) = 2
        _Float("Float",Float) = 1.5
        _Range("Range",Range(0.0,5.0)) = 3.0
        _Color("Color",Color)=(1,1,1,1)
        _Vector("Vector",Vector)=(2,3,5,6)
        _2D("2D",2D) = "" {}
        _Cube("Cube",Cube) = "white" {}
        _3D("3D",3D) = "black" {}
    }
    SubShader {
        //真正意义上的Shader代码会出现在这里
        //表面着色器/顶点/片元/固定函数着色器
        ///可选
        //标签
        Tags { "RenderType"="Opaque" }
        //状态
        [RenderSetup]
        Pass{
            [Name]
            [Tags]
            [RenderSetup]
        }
        //other pass
    } 
    Fallback "name"
}

Tag标签属性

4.数学基础

(1)向量的点积(内积)和叉积(外积)

点积:a.b=|a|.|b|cosα。|b|cosα的几何意义:a在b方向上的投影,即a在B放向上的影子。结果是个标量

叉积:|a*b|=|a|*|b|sinα,结果是个矢量。

(2)矩阵

1.性质:

2。转置矩阵的性质

(1)                                     (2)

               

3.方正的逆矩阵

一个矩阵的行列式不为0,那么他就是可逆的。

性质:

      

 4。正交矩阵

      

5。列矩阵,行矩阵

(3)变换

1.线性变换:旋转,缩放,错切(shear),镜像(mirroring,reflection),正交投影(orthographic)等

 2.仿射变换:合并线性变换和平移变换的变换类型

 (4)分解基础变换矩阵

把一个基础变换矩阵分解为4个组成部分:

左上角矩阵用于表示旋转和缩放,右上角用于表示平移,左下角的零矩阵,右下角是标量1。

(5)平移矩阵:不是正交矩阵

(6)缩放矩阵:不一定是正交矩阵

把点(X,Y,Z)按缩放系数(K,K,K)进行缩放

(7)旋转矩阵:是正交矩阵

unity中旋转的顺序是ZXY。

(8)复合矩阵

计算的顺序是从右到左,即先进行缩放变换,再进行旋转变换,最后进行平移变换。

一半情况下约定:变换的顺序是先缩放,再旋转,最后平移。

 (3)变换空间

1.模型空间(左手坐标系):对象空间或局部空间

2.世界空间(左手坐标系):顶点变换的第一步就是将顶带你坐标从模型空间变换到世界空间---称为模型变换

3.观察空间(右手坐标系):也称为摄像机空间。顶点变换的第二步是将顶点从世界空间变换到观察空间中。

4.裁剪空间:完全位于“这块空间”内部的图源会被保留,完全位于“这块空间”的图元会被剔除,与“这块空间”香蕉的图源会被裁剪。“这块空间”由视锥体决定。

视锥体的两种类型:

(1)正交投影(orthographic projection):2D游戏或渲染小地图

   (2)透视投影(perspective projection):模拟人眼看世界,从近到远,越来越小,适用于追求真实感的3D游戏

    

 

 5.屏幕空间:是一个二维空间。需要把顶点从裁剪空间投影到屏幕空间,生成对应的2D坐标。两个步骤:

(1)标准齐次除法(透视除法):用齐次坐标系的w分量除以X,Y,Z分量,使得X,Y,Z分量的范围为[-1,1]。

(2)根据变换后的X,Y坐标来映射输出窗口的对应像素坐标。

在unity中,从裁剪空间到屏幕空间,只需用顶点着色器把顶点转换到裁剪空间。

 总结:

在unity shader中的矩阵类型使用的是行优先的方式填充。

原文地址:https://www.cnblogs.com/shirln/p/9294477.html