原创

Unity Shader学习2——第一个Shader程序解析

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://linsh-tech.blog.csdn.net/article/details/51366248

前言:

        上篇文章中我们大致解释了什么是Shader,以及使用哪些语言可以进行Shader程序的编写等,那我接下来要做的就是开始在Unity引擎的环境下,编写一些Shader并查看是否达到预想的效果。

        Unity引擎是一个非常强大的支持跨平台开发的游戏引擎,基于Mono这个开源.Net的框架设计而成,在Unity中定义了ShaderLab来组织Shader的内容,针对不同平台进行编译


一、第一个Shader:

Shader "Custom/FirstShader" {
	Properties {
		_Color("Main Color", Color) = (0, 0, 0, 1)
	}
	SubShader {
		Pass{
             Color[_Color]
             }
	}
	FallBack "Diffuse"
}

        1.在当前场景中创建一个Plane面片,用于展示Shader着色后的效果:

        

       2.绑上我们新创建的Shader文件,但先不设置_Color属性的值,使用默认缺省值进行着色,结果如下:

        

        3.通过点击颜色选择框选中某个颜色值,得到新的着色结果为:

        


二、代码解析:

        以上是一个Shader程序,以及其应用于Plane上进行着色的效果,我们可以从中看出Shader编程的一些特征:

1、在Unity中Shader程序文件以.shader为后缀

        


2、Shader程序都是以关键字“Shader”开始的,后面紧接着的是Shader的命名(引用名),可以像目录一样,但是Shader的文件名和引用名不必一样。我们可以尝试在需要绑定Shader的组件上找到刚才创建的Shader,不难发现Shader的索引目录与命名对应:
        


3、Properties:

        Properties中用来声明一些可用于可视化配置的属性,一般声明的格式为:

        name("display name",为属性赋值的数据类型) = 赋值内容(缺省值或初始值)

        就像上例中的“_Color("Main Color", Color) = (0, 0, 0, 1)”,其中name是属性索引(通常带下划线,例如:_Color、__MainTex等),display name是属性在Unity中展示名称,由于各种属性的赋值类型不尽相同,所以对其赋值之前要先规定其属性对应的数据类型,并在最后填写一个默认的属性值(缺省值)。常见的属性有:

Properties{
	_MyTexture("Texture (RGB)",2D) = "white" {}//图片形式的属性
	_MyColor("Color of Object",Color) = (1,1,1,1)//颜色属性
	_MyCube("Environment map",Cube) = "white"{}//3D贴图,需要两张图片
	_MyVector("Vector",vector) = (1,1,1,1)//4个元素的向量
	_MyFloat("Float Value",float) = 1.0//浮点小数
	_MyRange("Another type of float",range(-13,14)) = 1.0//限定范围的浮点数
}


4、SubShader:

        真正用于呈现渲染物体的内容其实就是写在SubShader里面的,使用SubShader的原因是针对不同的显卡编写不同的Shader,所以一个Shader中可以包含多个SubShader(理论上可以有无限个),在实际使用时只会呈现第一个符合当前显卡的SubShader的内容。


5、Pass:

        每个SubShader又可以包含多个Pass,Pass是具体对渲染进行操作的单元,可用于设置:颜色、材质或者贴图等。例如此处使用到的“Pass{Color[_Color]}”就是设置渲染颜色属性的设置操作。

        其实Pass中内置的标签都是针对渲染路径的,用来告诉渲染引擎这个Pass应该在什么渲染路径下被渲染。Unity支持3种渲染路径(RenderingPath),分别是:VertextLitForwardDeferred Lighting,这些对应了Pass中使用的一些LightMode标签:Vertex、ForwardBase、ForwardAdd、PrepassBase、PrepassFinal等。


6、FallBack:

       这是Unity自己预制的Shader实现,一般能够在所有显卡上运行。加入此段代码是为了保证Shader的广泛性,因为用户自己定的SubShader可能在某个平台上出现所有SubShader都失败的情况,此时就需要使用默认的FallBack来进行渲染。


7.Shader编程语言的选择:

        在Unity所提供的框架中,我们既可以用GLSL来编写Shader程序,也可以使用Cg/HLSL来进行编写,但需要遵循一些规则:

        a.使用GLSL,代码必须位于GLSLPROGRAMENDGLSL之间

        b.使用Cg/HLSL,代码必须位于CGPROGRAMENDCG之间

        例如:

Shader "MyShader/FirstShader" {
	Properties{
		_MyTexture("Texture (RGB)",2D) = "white" {}
		_MyColor("Color of Object",Color) = (1,1,1,1)
	}
	SubShader{
		Pass{
			CGPROGRAM
			//Cg代码
			ENDCG
		}
	}
}


三、Shader Language原理:

        现在主要的Shader Language有三种:基于OpenGL的GLSL,基于Direct3D的HLSL,还有基于NVIDIA公司的Cg语言。

        使用Shader language编写的程序称为shader program(着色程序),着色程序又分为两类:vertex shader program(顶点着色程序)和fragment shader program(片段着色程序)。那么我们就需要提及两个对应的GPU上的组件: Programmable Vertex Processor (可编程顶点处理器,又称为顶点着色器)和 Programmable Fragment Processor (可编程片断处理器,又称为片断着色器)。

        顶点着色程序和片段着色程序的分工为:Vertex program负责顶点坐标变换,Fragment program负责像素颜色计算,前者的输出是后者的输入。

        

        上图是可编程图形硬件的输入\输出流程图,其中:输入寄存器存放输入的图元信息;输出寄存器存放处理后的图元信息;纹理buffer存放纹理数据(目前大多数可编程图形硬件只支持片段处理器处理纹理);从外部宿主程序传入的常量放在常量寄存器中;临时寄存器存放着色程序在执行过程中产生的临时数据。


四、总结:

         一个Shader中包含了一个或多个SubShader,每个SubShader中包装了一套渲染方案,每个SubShader由多个Pass,每个Pass包含着渲染一个几何物体的具体代码。


附件:

        用图形绘制管线描述GPU渲染流程,即“给定视点、三维物体、光源、照明模式和纹理等元素,如何绘制一幅二维图像”。图像绘制其实分为三个阶段:应用程序阶段几何阶段光栅阶段

1.应用程序阶段:使用高级语言(C、C++等)进行开发,主要和CPU、内存打交道,诸如:碰撞检测、场景图建立、空间八叉树更新、视锥裁剪等经典算法都在此阶段。在该阶段末端,几何体数据(顶点坐标、法向量、纹理等)通过数据总线传送给图形硬件。

2.几何阶段:主要负责顶点坐标变换、光照、裁剪、投影以及屏幕映射,该阶段基于GPU进行计算。在该阶段末端,得到经过变换和投影之后的顶点坐标、颜色、以及纹理坐标。

3.光栅阶段:基于几何阶段的输出数据,为像素(Pixel)正确配色,以便绘制完整图像,该阶段进行的都是单个像素的操作,每个像素的信息存储在颜色缓冲器(color buffer或者frame buffer)中。

        例如:光照计算属于几何阶段、雾化以及涉及物体透明度的计算属于光栅阶段、深度信息(Z值)的计算属于几何阶段并传递给光栅阶段。

文章最后发布于: 2016-05-11 15:33:46
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览