Unity Shader学习笔记

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

前言

一、ShaderLab

二、Unity Shader结构

三、GPU流水线

四、着色器

五、坐标空间

六、编写及实现

总结



前言

Unity shader是计算机图形渲染管线的一部分,是一小段应用程序,是GPU渲染流水线的

一些可高度编程的阶段,而编译出来的最终代码是会在GPU上运行的。Unity Shader告诉计算机在场景中怎样对物体渲染和着色,这个过程包括计算颜色和光照,并将其赋予对象,使其按照我们的想法显示在屏幕上。

在unity中需要配合材质才能达到需要的效果。常见流程是1.创建一个材质,2.创建一个Unity Shader,并把它赋给上步创建的材质,3.把材质赋给要渲染的对象,4.在材质面板中调整Unity Shader的属性得到满意的结果。


一、ShaderLab

ShaderLab作为一种专门为Unity Shader服务的语言。即我们可以编写ShaderLab来生成Unity Shader。Cg(C for Graphic)/ HLSL(High Level Shading Language)/ GLSL(OnpenGL Shading Language)都是着色语言,作为中间语言,即交给GPU可以理解的语言。

因为Microsoft和NVIDIA合作,所以Cg/HLSL实际上是同一种语言。而ShaderLab内部可以嵌套Cg/HLSL语言编写着色代码,需要嵌套在命令CGPROGRAM和ENDCG之间。这里的Cg/HLSL是Unity经封装后提供的,有些原生的函数和用法Unity并没有提供支持。

也可以用GLSL来编写,但是目标平台只有Masc OS X、OpenGL ES 2.0、Linux。代码嵌套在GLSLPROGRAM和ENDGLSL之间。

二、Unity Shader结构

名字:Shader “MyShader”{}

属性:Properties{

Name {“display name”, PropertyType} = DefaultValue

}//材质和Unity Shader交互

重要成员:SubShader{//不少于一个

[Tags]//标签设置,告诉渲染引擎希望怎样以及何时渲染这个对象,可选

[RenderSetup]//状态设置,设置显卡的各种状态,如是否开启深度测试等,可选

Pass{

[Name]//通过这个名称,可以使用UsePass命令直接使用其他Unity Shader的Pass

[Tags]

[RenderSetup]

//other code

//一次完整的渲染流程,如果Pass数目过多,往往会导致渲染性能下降。

//状态和标签同样可以在Pass中声明,不同的是,SubShader中的一些标签设置是 //特定的,如果在SubShader进行了这些设置,将会用于所有的Pass。

}

//Other Passes

}

后路:Fallback ”name”//如果上面所有的SubShader在这块显卡中都不能运行,就用这个最低级的Shader

三、GPU流水线

顶点数据->顶点着色器->装配图元->光栅化->片段着色器->测试和混合->帧缓存

GPU获取到CPU传递的顶点数据之后,流水线开始运作,在顶点着色器中,顶点坐标从模型空间变换到裁切空间,并可以通过shader程序对顶点进行处理,以实现一些特殊的效果。

装配图元阶段将顶点着色器输出的顶点数据装配成指定的几何图元,基本图元包括点线面。光栅化阶段将几何图元转变为片段,确定屏幕坐标中的哪些整形栅格区域被基本图元占用,再分配颜色值和深度值到各个区域。片段在经过视锥体裁切之后被传递到片元着色器,在这个阶段,片元着色器会计算光照、阴影、纹理等所有颜色数据,最终计算出像素的颜色。确定了像素的颜色之后会进入测试和混合阶段,在这个阶段会检测所有像素的深度值,将当前片段的深度值与深度缓存中的数值进行比较,从而判断这个像素前面是否有物体对它进行遮挡,进而决定这个像素是否应该被丢弃,通过测试的像素会与已经绘制好的图像进行混合,从而得到最终的颜色。帧缓存是流水线的最后一站,用于存储将要渲染到屏幕上的像素,等待下一步输出到屏幕上。

四、着色器

Shader一般有顶点/片元着色器、表面着色器、固定管线着色器(正在被淘汰)

顶点/片元着色器:用顶点着色器进行坐标变换、逐顶点光照以及传递数据(模型空间->齐次裁剪空间->计算顶点颜色),用片元着色器进行逐像素的渲染(输入上一阶段对顶点信息的插值,输出颜色值),一般都是同时出现。Cg代码写在Pass语义块中,定义在CGPROGRAM和ENDCG之间。复杂但灵活性更高。通过#pragma vertex vert #pragma fragment frag编译Cg代码片段。

表面着色器:对顶点/片元着色器的更进一层封装,Unity自己创造的一种着色器代码类型,在背后做了很多工作,为我们处理了很多光照细节,使代码量有明显的降低。Cg代码写在SubShader语义块中,定义在CGPROGRAM和ENDCG之间。对细节的把控不如顶点/片元着色器。背后仍旧将其转换成对应的顶点/片元着色器,渲染代价比较大。通过#pragma surface编译Cg代码片段。

五、坐标空间

shader具有很强的封装性,在实际编写shader的过程中,除了调用必须的函数外,还需要进行坐标的转换(如:o.vertex = UnityObjectToClipPos(v.vertex)),在不同的空间中有不同的坐标系:

模型空间(Object Space):float4

定义:以模型(通常为模型的重心)为原点的空间,一般默认物体前方为z轴,右边为x轴,上方为y轴。

世界空间 WS(World Space):float4

定义:一般来说世界空间就是游戏空间,其原点放置在游戏空间的中心。

观察空间 VS(View Space):float4

定义:以相机为原点的坐标空间。(观察空间与屏幕空间不一样,观察空间是一个三维空间,屏幕空间是二维空间)。

裁剪空间 CS(Clip Space):float4

定义:与投影矩阵计算后也被称为齐次裁剪空间(HCS Homogeneous Clip Space),这个用于变换的矩阵叫做裁剪矩阵(Clip Matrix),也被称为投影矩阵(Projection Matrix)。

屏幕空间 SS(Screen Space):float2

定义:当裁剪工作完毕后,就需要进行真正的投影,也就是说需要把视锥体投影到屏幕空间(Screen Space)。经过这一步变换就会得到真正的像素位置,而不是虚拟的三维坐标。

视口空间 VP(ViewPort Space):float2

定义:屏幕空间除以屏幕分辨率得到的就是视口空间(viewport space)中的坐标。

模型空间(本地空间)经模型变换矩阵变换为世界空间

世界空间经视变换矩阵变换为摄像机空间(观察空间)

摄像机空间(观察空间)经裁切矩阵变换为裁切空间(裁切几何体)

裁切空间(裁切几何体)经投影矩阵变换为屏幕空间(得到屏幕像素坐标)

六、编写及实现

通过编写Unity shader最终实现包括但不限于:光照,阴影,纹理,透明,流光,描边,消融,液体,序列帧动画,后期处理等效果。

而在用visua studio编写Unity shader的过程中会发现,没有代码补全,没有报错提示,编写完成运行的时候,在console中报的错误也很模糊,不易找出哪里出现了bug。

ASE是一款Unity提供的付费插件,下载并导入之后,可以在此进行shader的编写,只需进行节点的创建以及设置并进行连线即可,连线完成就意味着代码生成完毕,可当做手写的shader直接赋予材质。不仅如此,ASE还可以在编写过程中,查看中间节点的运行效果。

此外,还可以在C#脚本中创建材质,并找到指定的Unity shader赋予给该材质(避免创建材质并拖动),同时,可在脚本中对材质的各个属性进行设置。


总结

以上就是要讲的内容,本文仅仅简单介绍了unity shader的简单概念,而在实际的编写及应用中还需要更深一步的学习。

你可能感兴趣的:(unity,visual,studio,c#,游戏引擎,学习)