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读取纹理贴图颜色,并输出片元数据到测试阶段。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,888评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,677评论 3 399
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 168,386评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,726评论 1 297
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,729评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,337评论 1 310
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,902评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,807评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,349评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,439评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,567评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,242评论 5 350
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,933评论 3 334
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,420评论 0 24
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,531评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,995评论 3 377
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,585评论 2 359

推荐阅读更多精彩内容