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" {}

细节

  1. Range与float的属性只能是单精度值。
  2. 在后面的着色器程序中,属性值通过[name]来访问。而display name将显示在材质检视器中。
  3. 可以使用在属性定义加上等号为每个属性提供缺省值。
  4. 对于纹理(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及其基本框架的更多相关文章

  1. 【Unity Shaders】Vertex & Fragment Shader入门

    写在前面 三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Shader中实现描边效果的弊端,也就是只对表面平缓的模型有效.这是因为我们是依赖法线和视角的点乘结果来进行描边判 ...

  2. 【Unity Shaders】初探Surface Shader背后的机制

    转载请注明出处:http://blog.csdn.net/candycat1992/article/details/39994049 写在前面 一直以来,Unity Surface Shader背后的 ...

  3. 【Unity Shaders】学习笔记——渲染管线

    [Unity Shaders]学习笔记——Shader和渲染管线 转载请注明出处:http://www.cnblogs.com/-867259206/p/5595924.html 写作本系列文章时使用 ...

  4. 【Unity Shaders】Diffuse Shading——在Surface Shader中使用properties

    本系列主要参考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同时会加上一点个人理解或拓展. 这里是本书所有的插图.这里是本书所需的代码和资源 ...

  5. Unity Shaders Vertex & Fragment Shader入门

    http://blog.csdn.net/candycat1992/article/details/40212735 三个月以前,在一篇讲卡通风格的Shader的最后,我们说到在Surface Sha ...

  6. 【Unity Shaders】使用CgInclude让你的Shader模块化——创建CgInclude文件存储光照模型

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...

  7. 【Unity Shaders】使用CgInclude让你的Shader模块化——Unity内置的CgInclude文件

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...

  8. 【Unity Shaders】使用Unity Render Textures实现画面特效——画面特效中的亮度、饱和度和对照度

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图. 这里是本书所需的代码 ...

  9. 【Unity Shaders】Mobile Shader Adjustment —— 为手机定制Shader

    本系列主要參考<Unity Shaders and Effects Cookbook>一书(感谢原书作者),同一时候会加上一点个人理解或拓展. 这里是本书全部的插图.这里是本书所需的代码和 ...

随机推荐

  1. js原生碰撞检测

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  2. Python的高级特性8:你真的了解类,对象,实例,方法吗

    Python的高级特性1-7系列是本人从Python2过渡3时写下的一些个人见解(不敢说一定对),接下来的系列主要会以类级为主. 类,对象,实例,方法是几个面向对象的几个基本概念,其实我觉得很多人并不 ...

  3. javascript中的链表结构—双向链表

    1.概念 上一个文章里我们已经了解到链表结构,链表的特点是长度不固定,不用担心插入新元素的时候新增位置的问题.插入一个元素的时候,只要找到插入点就可以了,不需要整体移动整个结构. 这里我们了解一下双向 ...

  4. Windows 8.1 新增控件之 Flyout

    本篇为大家介绍Flyout 控件,Flyout 属于一种轻量级交互控件,可以支持信息提示或用户交互.与传统Dialog 控件不同的是Flyout 控件可通过直接点击对话框外部区域忽略. Flyout ...

  5. JavaScript操作XML

    JavaScript操作XML (一) JavaScript操作XML是通过XML DOM来完成的.那么什么是XML DOM呢?XML DOM 是: 用于 XML 的标准对象模型 用于 XML 的标准 ...

  6. iptables案例手册

    Linux防火墙Iptable如何设置只允许某个ip访问80端口,只允许特定ip访问某端口 iptables常用实例备查(更新中) 9个常用iptables配置实例 案例: http://www.cn ...

  7. python数字图像处理(17):边缘与轮廓

    在前面的python数字图像处理(10):图像简单滤波 中,我们已经讲解了很多算子用来检测边缘,其中用得最多的canny算子边缘检测. 本篇我们讲解一些其它方法来检测轮廓. 1.查找轮廓(find_c ...

  8. iptables实现负载均衡

    例子: iptables -t nat -A PREROUTING -d 10.192.0.65/32 -p tcp -m tcp --dport 8080 -m statistic --mode n ...

  9. 我的Logo设计简史

    近日,日本东京奥运会会微因涉嫌抄袭而被弃用的新闻引起设计界的一翻热论.在此我想到自己的LOGO设计,虽说并一定不好看甚至自己看回来都觉得略丑,但 几乎没有过抄袭的念头.有句话说,不想当设计师的程序猿不 ...

  10. 似魔鬼的 『 document.write 』

    在平时的工作中,楼主很少用 document.write 方法,一直觉得 document.write 是个危险的方法.楼主不用,并不代表别人不用,最近给维护的项目添了一点代码,更加深了我对 &quo ...