【unity shaders】:Unity中的Shader及其基本框架
shader和Material的基本关系
Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用,然后输出。绘图单元可以依据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上对应的Shader,以及对Shader的特定的参数设置,将这些内容(Shader及输入参数)打包存储在一起,得到的就是一个Material(材质)。之后,我们便可以将材质赋予合适的renderer(渲染器)来进行渲染(输出)了。
所以说Shader并没有什么特别神奇的,它只是一段规定好输入(颜色,贴图等)和输出(渲染器能够读懂的点和颜色的对应关系)的程序。而Shader开发者要做的就是根据输入,进行计算变换,产生输出而已。
Unity中Shader的三种基本类型
按照渲染管线的分类,可以把Sharder分成3个类别:
固定功能着色器(Fixed Function Shader)
固定功能着色器为固定功能渲染管线的具体表现。
表面着色器
存在于Unity3D中由U3D发扬光大的一门技术。Untiy3D为我们把Shader的复杂性包装起来,降低shader的书写门槛。
顶点着色器和片段着色器
GPU上含有两个组件:可编程顶点处理器和可编程片段处理器,顶点和片段处理器被分离成可编程单元,可编程顶点处理器是一个硬件单元,可以运行顶点程序,而可编程片段处理器则是一个可以运行片段程序的单元。
顶点着色器
顶点着色程序从GPU前端(寄存器)中提取图元信息(顶点位置、法向量、纹理坐标),并完成顶点坐标空间变换、法向量空间转换、光照计算等操作,最后将计算数据传送到指定寄存器中。
片段着色器
片段程序从上述寄存器中获取需要的数据:纹理坐标与光照信息等,并根据这些信息以及从应用程序传递的纹理信息进行每个片段的颜色计算(纹理查询),最后将处理后的数据传送光栅操作模块。
三种着色器的共同点:
- 都必须从唯一一个根Shader开始
- Prooerties参数部分,作用以及语法完全相同。
- 具体功能都在SubShader里。
- 都可以打标签
- 都可以Fallback
- 都可以处理基本的功能,例如光照漫反射以及镜面反射。但如uv计算效果等高级功能,固定功能着色器无法完成。
三种着色器的不同点
- 表面着色器没有通道pass{},加了会报错,该着色器已经把具体内容打包在光照模型中了。
- 固定渲染管线每句代码之后都没有“;”
- 核心结构不同:
固定渲染管线的核心是:
Material{}以及SetTexture[_MainTex]{}
顶点与片段着色器的核心是:
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
ENDCG
表面着色器的核心是:
1.表面着色器使用Unity3D自带光照模型Lambert,也不做顶点处理,只需要一个表面处理函数surf即可。
CGPROGRAM#Pragma surface surf Lambert
ENDCF
2.这套表示使用的是自己写的光照模型lsyLightModel,并且使用了顶点处理函数vert
CGPROGRAM
#pragma surface surf lsyLightModel vertex:vert
ENDCG
在Unity中如何区分以上三种着色器
- 没有嵌套CG语言,即代码中没有CGPROGARAM和ENDCG关键字的,就是固定功能着色器。
- 嵌套CG语言,代码中有surf函数的为表面着色器
- 嵌套了CG语言,代码中有#pragma vertex name和 #pragma fragment frag声明的,就是顶点着色器&片段着色器。
Unity中Shader的基本框架
Unity中Shader整体的框架写法可以用如下的形式来概括:
Shader "name" { [Properties] SubShaders[Fallback] }
Unity中所有着色器都由关键字shader开始,随后的字符表示着色器的名字,这个名字会显示在Inspector检视面板中,所有的代码都应该放在{}里面。
name
该名字不需要和shader文件名同名,它应该是简单的描述性词语,在name后面加上/能够中Inspector面板中创造出二级菜单(多个/创建多级菜单)。
shader整体框架
如上面的整体框架,我们可以画出下面这图:

从这幅图可以看到,Unity中的shader可以分为以下三个模块:
属性Properties
Properties一般定义中着色器的起始部分。属性模块可以定义一些属性,用来指定那个这段代码有哪些输入。在使用shader的时候可以直接中材质面板里编辑这些属性。Properties块内的语法都是单行的。属性的定义格式如下所示:

属性可以划分为以下几类:
数字与滑动条
name ("display name", Range (min, max)) = number //滑动条调节
name ("display name", Float) = number//数字调节
name ("display name", Int) = number//数字调节
颜色与向量(注意是四元数)
name ("display name", Color) = (number,number,number,number)
name ("display name", Vector) = (number,number,number,number)
贴图
name ("display name", 2D) = "defaulttexture" {}
name ("display name", Cube) = "defaulttexture" {}//立方体贴图
name ("display name", 3D) = "defaulttexture" {}
细节
- Range与float的属性只能是单精度值。
- 在后面的着色器程序中,属性值通过[name]来访问。而display name将显示在材质检视器中。
- 可以使用在属性定义加上等号为每个属性提供缺省值。
- 对于纹理(2D, Rect, Cube) 缺省值既可以是一个空字符串也可以是某个内置的缺省纹理:"white", "black", "gray" or"bump"
使用示例
// properties for a water shader
Properties
{
_WaveScale ("Wave scale", Range (0.02,0.15)) = 0.07 // sliders
_ReflDistort ("Reflection distort", Range (0,1.5)) = 0.5
_RefrDistort ("Refraction distort", Range (0,1.5)) = 0.4
_RefrColor ("Refraction color", Color) = (.34, .85, .92, 1) // color
_ReflectionTex ("Environment Reflection", 2D) = "" {} // textures
_RefractionTex ("Environment Refraction", 2D) = "" {}
_Fresnel ("Fresnel (A) ", 2D) = "" {}
_BumpMap ("Bumpmap (RGB) ", 2D) = "" {}
}
子着色器SubShader
可以有一个或者有多个子着色器SubShader(至少有一个),子着色器SubShader中含有一个或者多个通道Pass(也是至少要有一个)。
在Pass中一般可以写以下的代码
Color Color 设定对象的纯颜色,可以是括号中的四个值,也可以是被方框包围的颜色属性名称
Material{Material Block} 材质被用于定义对象的材质属性,关于材质块的内容可以看下面的介绍
Lighting On/Off 定义上述材质块的定义是否有效,On时材质块效果有效,Off时颜色通过Color命令直接给出
SeparateSpecular On/Off 开启独立镜面反射,这个命令会添加高光光照到着色器通道的末尾,因此贴图对高光没有影响。只在光照开启时有效。
ColorMaterial AmbientAndDiffuse | Emission
使用每顶点的颜色替代材质中的颜色集。AmbientAndDiffuse 替代材质的阴影光和漫反射值;Emission 替代 材质中的光发射值。
Pash中材质块Material{}代码写法
上面已经说了,在Pass中可以书写材质块代码用于定义对象的材质属性,如下的代码可以写在材质块中:
Diffuse Color(R,G,B,A);对象基本颜色,漫反射
Ambient Color(R,G,B,A);环境光,当对象被RenderSettings.中设定的环境色所照射时对象所表现的颜色。
Specular Color(R,G,B,A);对象反射高光的颜色
Emission Color 对象自发光
Shininess Number 取值在0-1之间表示加亮时的光泽度
对象完整光照的最终颜色是:
FinalColor=Ambient * RenderSettings ambientsetting + (Light Color * Diffuse + Light Color *Specular) + Emission
即:
最终颜色=环境光反射颜色* 渲染设置环境设置 (灯光颜色漫反射颜色+灯光颜色*镜面反射颜色)+自发光
示例代码:
Shader "我的Shader"
{
Properties
{
_MainColor ("主颜色",Color)=(0,0,0,0)
_AmbientColor("环境光颜色",Color)=(0.8,0.2,0.2,0)
_SpecularColor("放射高光颜色",Color)=(0.8,0.2,0.2,0)
_ShininessNum("光泽度",Range(0,1))= 0.5 //滑动条
}
//---------------------------------【子着色器1】----------------------------------
SubShader
{
//----------------通道---------------
Pass
{
Color(1,0,0,0) //当光照开启时无效。
//----------材质块------------
Material
{
//将漫反射和环境光反射颜色设为相同
Diffuse[_MainColor]
Ambient[_AmbientColor]
Specular[_specularColor]
Shininess[_ShinnessNum]
}
//开启光照 //光照影响了颜色
Lighting On
SeparateSpecular On
}
}
}
效果:

回滚FallBack
Shader基本框架的最后是指定一个回滚函数Fallback,用来处理所有的子着色器都不能运行时的情况(当目标设备太老时,所有的设备都有其不支持的特性时使用了Fallback),可以认为是一种defult。
Fallback" Diffuse "
关于纹理的载入在下一节讲解。
【unity shaders】:Unity中的Shader及其基本框架的更多相关文章
- 【Unity Shaders】Vertex & Fragment Shader入门
写在前面 三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Shader中实现描边效果的弊端,也就是只对表面平缓的模型有效.这是因为我们是依赖法线和视角的点乘结果来进行描边判 ...
- 【Unity Shaders】初探Surface Shader背后的机制
转载请注明出处:http://blog.csdn.net/candycat1992/article/details/39994049 写在前面 一直以来,Unity Surface Shader背后的 ...
- 【Unity Shaders】学习笔记——渲染管线
[Unity Shaders]学习笔记——Shader和渲染管线 转载请注明出处:http://www.cnblogs.com/-867259206/p/5595924.html 写作本系列文章时使用 ...
- 【Unity Shaders】Diffuse Shading——在Surface Shader中使用properties
本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...
- Unity Shaders Vertex & Fragment Shader入门
http://blog.csdn.net/candycat1992/article/details/40212735 三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Sha ...
- 【Unity Shaders】使用CgInclude让你的Shader模块化——创建CgInclude文件存储光照模型
本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...
- 【Unity Shaders】使用CgInclude让你的Shader模块化——Unity内置的CgInclude文件
本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...
- 【Unity Shaders】使用Unity Render Textures实现画面特效——画面特效中的亮度、饱和度和对照度
本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...
- 【Unity Shaders】Mobile Shader Adjustment —— 为手机定制Shader
本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图.这里是本书所需的代码和 ...
随机推荐
- Android中分页滑动实现总结
手机的屏幕相对较小,因此会出现当有多项内容需要展示而不得不进行分页的情况.例如手机桌面的应用图标的展示.一般一屏可以显示4*4=16个小方块形的应用程序,可以通过左右滑动进行屏幕的选择.而Androi ...
- Javascript 代码格式化(JsFormat)
JsFormat 在GitHub 上的地址: https://github.com/jdc0589/JsFormat 这是一个sublime text 2 的插件. 安装: 先安装 sublime p ...
- IT教程网
这个IT教程网(印度),我认为是最好的.里面的知识基础实用,覆盖面很广,作为IT入门和了解都是极好的. http://www.tutorialspoint.com/
- BZOJ 1014 【JSOI2008】 火星人prefix
Description 火星人最近研究了一种操作:求一个字串两个后缀的公共前缀.比方说,有这样一个字符串:madamimadam,我们将这个字符串的各个字符予以标号:序号: 1 2 3 4 5 6 7 ...
- 批量修改string中的字符
#1,修改"/"为"\\",多用于在txt读取内容后进行修改 size_t pos0 = mkfolder.find("/");//首次查找 ...
- [MetaHook] Surface hook
Hook ISurface function. #include <metahook.h> #include <vgui/ISurface.h> using namespace ...
- .NET技术在中国为什么老被人嫌弃
这个话题有点自黑的意思,我从.NET 1.1开始玩.NET,到现在已经11年了,我是看着.NET成长起来,在中国壮大的,也见证了近几年.NET被各种嫌弃,其实说到底还是中国的架构师太少,我是说真正懂行 ...
- 对《重建中国.NET生态系统》评论贴的总结
Neuzilla官方微信公众号:搜 架构师联盟 或 neuzilla,也可以扫下面二维码 在看了<重建中国.NET生态系统>的各种哭爹喊娘骂街的评论之后,我觉得哦,淫才确实很多,但是么真正 ...
- [转]Linux系统中‘dmesg’命令处理故障和收集系统信息的7种用法
'dmesg'命令显示linux内核的环形缓冲区信息,我们可以从中获得诸如系统架构.cpu.挂载的硬件,RAM等多个运行级别的大量的系统信息.当计算机启动时,系统内核(操作系统的核心部分)将会被加载到 ...
- unity3d Vector3.Lerp解析
Vector3.Lerp:http://www.ceeger.com/Script/Vector3/Vector3.Lerp.html 手册中描述的不是很详细,什么叫“按照数字t在from到to之间插 ...