Unity Shader开发

一.什么是Shader

Shader(着色器),是在GPU运行的程序,通过数学计算将各种属性(颜色,光照,阴影,纹理等)渲染成物体表面可见的状态。在shader里我们可以自定义显卡渲染画面的算法,使画面达到我们想要的效果(放两张图)。

二.Shader语言

Shader是GPU运行的程序,目前实现Shader 的语言主要有三种:

基于OpenGL的OpenGL Shader Language,简称GLSL。

基于DirectX的High Level Shader Language,简称HLSL。

还有NVIDIA公司的高级图形编程语言C for Graphic,简称CG。

三.Shader分类

顶点 shader:3D图形由一个个三角面组成,顶点shader就是处理这些三角面上的顶点,做顶点变换,传递数据到fragment shader。

片元 shader:渲染实现的核心,以片元为单位,计算光照,阴影,着色等一序列渲染算法。

在DX中顶点shader叫做Vertex Shader,片元shader叫做Pixel Shader;在Opengl中顶点shader也叫Vertex Shader,但片元shader叫做Fragment Shader。

四.Unity Shader

图形API有Opengl,Vulkan,Metal,DX等,显卡有Intel,NVIDIA,ATI,Amd等 ,Shader编程语言有GLSL,HLSL,Cg等。

Unity为了跨平台,封装了一下图形,显卡,Shader的差异性,开发了一种便于书写的Shader,又称为ShaderLab。

Unity Shader有三种不同写法:

Surface Shader表面着色器;Vertext/Fragment Shader  顶点/片段着色器;

Fixed Function Shader固定管线着色器(已废弃)。

Surface Shader是Unity对Vertex/Fragment Shader的又一层封装,简化开发逻辑,用少量的代码来完成不同的光照计算以及跨平台逻辑。但Surface Shader的局限性也很明显,Vertex/Fragment Shader能实现的功能,Surface Shader不一定能实现,Vertex/Fragment Shader针对细节上更细腻的处理,比较底层,也符合标准shader的写法。并且Unity2018推出的Shader Graph,生成的代码也是Vertex/Fragment Shader形式,所以我觉得Vertex/Fragment Shader是Unity Shader最主流的写法,本节重点介绍Vertex/Fragment Shader的开发过程。

五.Unity Shader结构

Unity Vertex/Fragment Shader的标准结构如下图所示

结构可拆分为以下几个部分:Shader  “name”;Properties;SubShader;FallBack

Shader "name"

Shader是一个关键字,后面"name"的内容表示具体路径和名称

Properties 属性

材质球Inspector面板上需要显示的参数,纹理等都是在Properties中进行定义设置。如果不需要显示参数可以将Properties{}全部去掉,Properties是个可选项,尽管Properties{}删除了但是不影响C#对shader的参数传递。

SubShaders 

Unity Shader是由一个或者多个SubShader组成的,当渲染模型时,会在Unity Shader中寻找在当前显卡上运行效果最好的SubShader来使用,例如做了一个效果很好的Shader,但是只能在高配显卡上才能有较好的渲染表现,中低端机上渲染比较吃力,这时我们可以在Shader内做三个SubShader,分别对应于高,中,低不同的显卡配置。

SubShaders架构细分包括Tags,渲染设置项,一个或多个Pass。

Tags用来控制引擎如何以及何时被渲染,Unity预定义Tag有以下几种:

RenderType Tag;Quene Tag;DisableBatching Tag;ForceNoShadowCasting Tag;IgnoreProjector Tag; CanUseSpriteAtlas Tag;PreviewType Tag

RenderType Tag

RenderType标签将shader分类为若干个预定以组,Unity可以在运行时替换符合特定RenerType的所有shader。这个功能主要通过Camera.RenderWithShader或Camera.SetReplacementShader函数实现,这两个函数都以1个shader和1个replacementTag作为参数,shader是给定的替换着色器,replacementTag是被替换着色器的标签值。

Quene Tag

Quene 标签用来确定对象的绘制顺序。在shader中决定其渲染对象属于哪个渲染队列,提高渲染效率,保证渲染正确性。

在Unity中有5个预定以的渲染队列,分别如下表示:

Unity在内部使用一些整数索引来表示每个渲染队列,索引号越小越早被渲染,遵循3D渲染的基本规则:

1.先渲染不透明物体,把不透明物体按与摄像机距离的远近进行排序,从前往后渲染,并开启深度测试和深度写入。

2.半透明物体按与摄像机距离的远近进行排序,然后从后往前渲染,并开启深度测试,关闭深度写入。

DisableBatching Tag

禁用批处理,有三个标签设置值: True,False(默认值),LODFading(当LOD衰减活动时禁用批处理)

ForceNoShadowCasting Tag

强制没有阴影投射,有两个标签设置值:True,False(默认值) 

IgnoreProjector Tag

忽略投影机,有两个标签设置值:True,False(默认值) 

CanUseSpriteAtlas Tag

是否可以使用Sprite图集,有两个标签设置值:True,False(默认值) 

PreviewType Tag

在inspector面板视图下材质球的预览样式,有三个标签值:

Spheres(默认值,材质显示为球体),Plane(材质显示为平面),Skybox(材质显示为天空球)

渲染状态(可写Pass外,也可写Pass内)

culling阶段

Cull控制渲染的哪一面被剔除,有三个不同设置:Back(默认,剔除渲染模型的背面),Front(剔除渲染模型的正面),Off(背面和正面都渲染)

深度测试阶段

ZWrite

控制是否写入深度缓冲,有两个不同设置:On(默认,写入深度缓冲),Off(不写入深度缓冲)

ZTest 控制深度测试逻辑,有以下几个不同设置:

Greater , GEqual , Less , LEqual(默认值) , Equal , NotEqual , Always , Off。ZTest Off 等同于 ZTest Always

Blending阶段

渲染图形时,在片元通过深度测试和模版测试后,像素将写入到屏幕。这些像素与已有像素的混合合方式由 Blend 命令控制,Blending主要用于生成透明对象。Blend有几个以下不同设置:

Blend Off:默认值,关闭混合:

Blend SrcFactor DstFactor: 生成颜色乘以SrcFactor,缓冲区中的颜色乘以DstFactor,然后将这个值相加

Blend SrcFactor DstFactor, SrcFactorA DstFactorA:功能同上,SrcFactor DstFactor控制RGB混合系数,SrcFactorA DstFactorA控制Alpha(A)通道的混合系数。

BlendOp Op:执行不同的混合操作,Op为不同的混合运算,

Op运算语法有以下5个:

Add(默认值,将源颜色和目标颜色相加),Sub(将源颜色减去目标颜色色),RevSub(将目标颜色减去源颜色),Min(源颜色和目标颜色取小值),Max(源颜色和目标颜色取大值)

BlendOp OpColor, OpAlpha:功能同上。

Unity内部自定义了一些常见的混合类型:

Blend SrcAlpha OneMinusSrcAlpha (传统透明度);

Blend One OneMinusSrcAlpha (预乘透明度);

Blend One One ( 加法);

Blend OneMinusDstColor One ( 软加法);

Blend DstColor Zero (乘法);

Blend DstColor SrcColor ( 2x 乘法)

对应的系数说明如下:

Stencil测试阶段:

如果开启模版测试,GPU会首先读取模版缓冲区里该片元位置的模版值,然后将该值和读取到的参考值进行比较,若没有通过测试,该片元就会被舍弃掉,但不管片元有没有通过测试,我们都可以根据模版测试的结果来修改模版缓冲区,常用的模版缓冲配置如下:

其Comparison Function如下:

Stencil Operation如下

Pass

pass是Unity Shader中最重要的组成部分,包含渲染的核心——着色器。

pass的结构包含以下:

   Name "name": 定义Pass名称(可选项),便于以后在其他SubShader当中复用该Pass。

   Tags:同SubShader Tag;但有些Unity内置的Tag不能放在SubShader里,只能放在Pass内才能生效,比如:

    LightMode,PassFlags,RequireOptions。

    LightMode:支持以下几种Tag设置

     Always(总是渲染,不处理光照);

     ForwardBase(在前向渲染管线中使用,处理环境光,直射光,顶点光照)

     ForwardAdd(在前向渲染管线中使用,处理像素光源)

     Deferred(在延迟渲染管线中使用,G—Buffer渲染)

 渲染状态:同SubShader 渲染状态。

顶点/片元着色器

用“CGPROGRAM和ENDCG或者HLSLPROGRAM和ENDHLSL”指令包围的代码即顶点着色器和片元着色器,代码结构如下

#pragma vertex声明顶点着色器函数

#pragma fragment声明片元着色器函数

a2v结构体表示应用程序传递到顶点着色器的模型数据,数据类型如下:

v2f结构体表示把顶点着色器的数据传递到片元着色器

vert函数主要作用是顶点变换,把模型坐标从本地空间转到裁剪空间,并将顶点数据传递到片元着色器。

frag函数主要作用是做片元映射和着色,自定义光照模型,根据uv读取纹理贴图颜色,并输出片元数据到测试阶段。

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值