zoukankan      html  css  js  c++  java
  • Unity Shader学习笔记-1

    本篇文章是对Unity Shader入门精要的学习笔记,插图大部分来自冯乐乐女神的github

    如果有什么说的不正确的请批评指正

    渲染流水线

    流水线机制,拆分小段,前面的工序不用等后面的工序,流水线机制在计算机世界中经常使用,比如:TCP

    image-20200506201708690

    流程图

    渲染管线

    应用阶段(开发者控制)、几何阶段(决定图元)、光栅化阶段(决定像素)

    Shader作用

    顶点着色器:实现顶点的空间变换,坐标变换(模型空间转换到齐次裁减空间)、逐顶点光照、计算顶点颜色

    曲面细分着色器:细分图元,图元就是:点、线、面等渲染所需的几何信息

    几何着色器:执行逐个图元的着色操作,或者用于产生更多的图元

    片元着色器:逐片元的着色操作,修改颜色、深度缓冲、进行混合

    屏幕映射

    image-20200419105949276

    三角形遍历

    ​ 三角形设置:由定点信息计算出边的信息

    ​ 三角形遍历:计算是否在三角形内,使用与三条边叉乘的方法判断在边的左边或者右边,遍历3条边的方式按照顺时针或者逆时针,对应点在

    ​ 计算三角形内的数据:

    ​ 计算颜色:插值计算

    两大渲染测试

    决定是否丢弃片元

    • 模板测试
      • 通常用于限制渲染的区域
      • 使用一个比较函数比较参考值和实际值
      • 高级用法:渲染阴影、轮廓渲染
    • 深度测试
      • 与深度缓冲区的深度值进行比较大于时舍弃该片元
      • 如果一个片元没有通过深度测试那么它就没权力修改深度缓冲区
    • 两者的区别:除功能外,模板状态设置更新即使舍弃了该片元也会更新模板缓冲区的值
      • image-20200419112316936
    • early-z的方法:提前进行深度测试,可以帮助决定是否绘制片元,减少GPU开销
      • image-20200419112924601

    混合

    合并颜色,颜色缓冲区,这次得到的结果和存储的结果进行合并

    image-20200419112630907

    CPU、GPU、图形接口和驱动的关系

    CPU和GPU之间的通信

    • 数据加载到显存(显卡的内存,图像缓冲、深度缓冲)

    • 设置渲染状态

    • 调用DrawCall

      image-20200419113502454

    CPU和GPU并行工作的秘密:命令缓冲区

    • 一个命令队列,cpu给命令、gpu拿命令

    • drawcall就是一种命令,GPU的渲染速度很快,性能瓶颈主要是在CPU传递命令这方面

      • 减少drawcall的方法有很多,其中Batching批处理是很常用的方法,思路就是把小的drawcall合并成大的drawcall,适用于静态的物体

        image-20200419114525719

    显示流畅的方法

    • Double Buffering:避免我们看到正在渲染的片元
      • Front Buffer
        • 实际显示的图像
      • Back Buffer
        • 在后面渲染的图像
      • 后置缓冲区渲染完成后交换两缓冲区的值

    着色器语言

    用于编写着色器的语言,主要是顶点着色器和片元着色器需要编写

    • HLSL DirectX
      • 微软控制的着色器编译,各硬件编译的结果相同
    • CG NVIDIA
      • 和HLSL很像,根据平台的不同编译成相应的中间语言
    • GLSL OpenGL
      • 依赖硬件来编译,用显卡驱动来编译,各驱动的编译结果根据硬件变化
    • 它们编译成中间语言IL给显卡驱动识别(这也是某种跨平台的意思吧-。-)
    • ShaderLab unity的简化语言,少了很多的配置流程,大部分流程是unity自己做

    ShaderLab

    Shader选用

    摘取乐乐女神的指导

    image-20200419121533003

    一般用CG/HLSL代码写: CG代码和DX9的HLSL代码几乎一样,要在CGPROGRAM中写,CGPROGRAM要使用上面的Property的数据就要声明和上面Property一样名字一样类型的变量,如果不想在多个Pass里声明,则可以在Pass前的CGINCLUDE ... ENDCG之间声明变量,这样的Property是多Pass共用的

    Properties{
    		_Color("Color Tint", Color) = (1, 1, 1, 1)
    }
    	
    SubShader{
    	Pass{
    			...
    			fixed4 _Color;
    			...
    	}
    }
    

    顶点片元着色器 Unlit Shader

    结构

    命个名和shader在面板中的目录

    Shader "Custom/MyShader"    //名字
    

    Properties

    属性,会出现在材质面板中

    Properties{
    	Name("display name",PropertyType) = DefaultValue
    	//.......
    }
    

    Name:属性的名字

    display name:显示的名字

    PropertyType:类型

    ps:shader里改过了Property在C#脚本里并不能获得更改后的信息,只能获得预设的信息,GPU像CPU传数据使用Compute Shader

    数据类型

    image-20200419120351348

    2D、Cube、3D是三种纹理类型,默认值是一个字符串+{},字符串是内置的纹理名称

    SubShader

    unity扫描所有的SubShader块找到能够在目标平台上运行的SubShader,如果找不到就使用Fallback提供的Unity Shader

    SubShader
    {
    	[Tags]//标签
    	[RenderSetup]//状态
    	
    	Pass{
    	}//完整的渲染流程
    	//Other Pass
    }
    

    显卡状态,在Pass里写的,剔除、深度、混合

    image-20200419121013508

    怎么样以及何时渲染该对象,渲染队列最重要

    image-20200419121145597

    Pass

    表示渲染流程,一个Pass表示通过管线一次,可以写顶点着色器和片元着色器

    image-20200419121242075

    UsePass可以使用其他Unity Shader的Pass,以提升复用性(用法:指明路径,并且Pass要有Name)

    image-20200419121423098

    LightMode在有光照信息时读取光源的信息使用,主要是确定光源位置等

    一个简单的Shader
    Shader "Unlit/Chapter5SimpleShader"
    {
    	SubShader
    	{
    		//选择不声明任何材质属性
    
    		Pass
    		{
    			CGPROGRAM
    			#pragma vertex vert
    			#pragma fragment frag//编译指令
    			//哪个函数包括了顶点着色器的代码
    			//哪个函数包括了片元着色器的代码
    			#include "UnityCG.cginc"//调库,你的unity目录EditorDataCGIncludes
    			struct a2v {
    				float4 vertex :POSITION;
    				float3 normal:NORMAL;
    				float4 texcoord:TEXCOORD0;
    			};
    
    			float4 vert(a2v v) :SV_POSITION{
    				return UnityObjectToClipPos(v.vertex);
    			}//接受顶点坐标(POSITION)返回了顶点在裁剪坐标的位置(SV_POSITION)
    			float4 frag() : SV_Target{
    				return fixed4(1.0,1.0,0.0,1.0);
    			}//SV_Target告诉渲染器把用户的输出颜色存储到一个渲染目标中,这里是帧缓存
    			ENDCG
    		}
    	}
    }
    
    

    POSITION、NORMAL、TEXTCOORD0等都称为语义semantic,在结构体里的表示把提取到的信息当成一个什么对待,输出语义表示输出的结果是作为什么对待

    POSITION顶点位置,在模型空间,NORMAL顶点法向量,也是模型空间,TEXTCOORD0表示纹理坐标,按理说纹理坐标只要uv,2维就可以了,但是有时比如天空盒的纹理需要用到3维的信息,一张纹理图有时前两维给一些信息,后两维又给一张图的uv信息

    image-20200419193635194

    vert里的输出语义没有也可以,可以选择输出结构体

    			struct a2v {
    				float4 vertex : POSITION;
    				float2  texcoord0 : TEXCOORD0;
    
    			};
              ...
    			v2f vert(a2v i)
    			{
    				v2f o;
    				o.pos = UnityObjectToClipPos(i.vertex);
    				o.uv =  i.texcoord0;
    
    				return o;
    			}
    			...
    

    在frag里的SV_Target表示屏幕上的像素(帧缓冲),还可以输出SV_Depth来覆盖深度缓冲区,不过官方说吃性能

    库文件

    image-20200419182140630

    image-20200419182149720

    image-20200419182201995

    调试

    1、假彩色图像,把数据作为颜色输出到屏幕上然后用取色器查看的数值调试法。

    没办法,渲染管线里的数据不是想拿就拿的,让你随便拿了管线不相当于开了个洞,像素都漏了

    2、帧缓冲区调试,Frame Debugger

    3、VS插件ShaderLab补全,体验一般,甚至不想开

    注意点

    GPU结构决定它不擅长处理选择、循环等结构的程序,分支下的代码、分支的层数要尽可能少因为他会降低GPU的并行处理操作,条件变量最好是常数

    3D数学

    太多了,不好写,基础知识看看乐乐老师的书吧0.0

    空间

    各种空间关系一开始搞不太懂也没事,后面可以在实践中慢慢理解

    这块乐乐老师的书上讲的牛的点变换推导很详细

    模型空间:也叫对象空间、局部空间

    世界空间:绝对位置,一个Transform没有父节点他的位置就是绝对位置

    观察空间:摄像机空间,模型空间的特例

    • 摄像机右手系
      • image-20200419162537284
      • 观察变换:投影变换

    裁剪空间:clip space 裁剪矩阵,有一个视锥体决定摄像机可以看到的空间

    • 投影矩阵的本质就是对xyz分量进行不同程度的缩放

    屏幕空间

    • 降维2d坐标
    • 进行齐次除法
    • 透视出发转化到NDC归一化的设备坐标

    image-20200419164146168

    unity坐标旋向性

    image-20200419164204739

  • 相关阅读:
    牛客网分糖果
    【bzoj3717】[PA2014]Pakowanie 状压dp
    【bzoj1042】[HAOI2008]硬币购物 背包dp+容斥原理
    [POI2007]堆积木Klo
    【bzoj5018】[Snoi2017]英雄联盟 背包dp
    BZOJ 1492 [NOI2007]
    bzoj 2741 [FOTILE模拟赛] L
    bzoj 1486 最小圈
    计数
    cf 700
  • 原文地址:https://www.cnblogs.com/FlyingZiming/p/12838968.html
Copyright © 2011-2022 走看看