unity shader教程 读取纹理颜色值是 0 到1 还是 0到255

Unity Shader-后处理:简单的颜色调整(亮度,饱和度,对比度)
好久没坚持写blog了,是时候开始撸一波新博文了!学习Unity有一段时间了,关于Shader的书也看了几本《Unity Shader入门精要》,《Unity 3D ShaderLab 开发实战详解》,开一个系列记录一下学习的心得笔记。原理就不多讲了,一篇一个实际Shader样例就好了。
貌似一开始关于shader的讲解都是diffuse,不过,我赶脚后处理貌似更简单,所以第一篇来一发简单后处理,屏幕的简单颜色校正--调整亮度,饱和度,对比度。
一.概念介绍
我们在做游戏的时候,虽然现在有了Unity等引擎,不用我们自己处理一些繁琐的东西,但是不管怎么样,最后显示在屏幕上的还是一些RGB的像素信息,了解这些基本的概念,肯定对我们做游戏有更大的帮助。
1.颜色模型的概念
既然是校正屏幕的颜色,我们有必要了解一下我们要校正的这几个属性的概念。这里就不得不提到我们常用的颜色定义方式,RGB颜色模型和HSV颜色模型。
1.1RGB颜色模型
RGB颜色模型也就是我们最常用的三原色,红绿蓝。RGB颜色模型在混色时属于加法混色,RGB中每种颜色数值越高,色彩越明亮。RBG为(0,0,0)时为黑色,RGB为(255,255,255)时为白色。计算机在处理颜色信息时一般都采用RGB颜色模型,可以很精确地表示某种颜色。
1.2HSV颜色模型
RGB颜色模型对于计算机来说很容易计算,但是并不适合人类理解,于是就有了HSV颜色模型,所谓HSV代表的是Hue(色相),Saturation(饱和度),Value(色调)也有一种说法是HSB模型,B代表的是Brightness(明度)。当然,还有一些说法,比如HSL模型,L代表的是Lightness(亮度)。HSV模型使用一个圆锥形坐标系,顶面对应的V(Value色调)为1,表示颜色较亮,底面的Value为0,表示颜色较暗;而H(Hue色相)是由绕着V轴的旋转角度给定,从红色开始逆时针方向计算,红色对应0度,绿色对应120度,蓝色对应240度;S(Saturation饱和度)由模型的半径来代表,由内向外Saturation逐渐增大,圆心处为0,边缘处为1。下图是HSV颜色模型的图示:
1.3RGB颜色模型和HSV颜色模型的转化
既然两种颜色模型都可以表示颜色,那么两者之间一定有某种转化关系;
RGB转化到HSV模型:
假设RGB分别用(r,g,b)代表,其中r,g,b分别为0-1之间的实数;max为r,g,b中最大值,min为最小值;HSV分别用(h,s,v)表示,h为0-360之间实数,而s和v分别为0-1之间的实数,转化关系如下:
HSV模型转化到RGB模型:
2.亮度,饱和度,对比度,灰度的概念
图像中RGB值的大小,RGB各个值越大,那么亮度越亮,越小,亮度越暗。比如我们要增加亮度,那么直接增加RGB值即可。
指的是颜色的纯度。一般用彩度除以明度,表征彩色偏离同亮度灰色的程度。简单来说,当颜色越偏向某个值,即越偏离灰度,饱和度越大;当颜色越偏向灰度,饱和度越小。
下面是百度百科关于饱和度的一段定义:
饱和度是指色彩的鲜艳程度,也称色彩的纯度。饱和度取决于该色中含色成分和消色成分(灰色)的比例。含色成分越大,饱和度越大;消色成分越大,饱和度越小。纯的颜色都是高度饱和的,如鲜红,鲜绿。混杂上白色,灰色或其他色调的颜色,是不饱和的颜色,如绛紫,粉红,黄褐等。完全不饱和的颜色根本没有色调,如黑白之间的各种灰色
指的是一幅图像中明暗区域最亮的白和最暗的黑之间不同亮度层级的测量,差异范围越大代表对比越大,差异范围越小代表对比越小。一般来说对比度越大,图像越清晰醒目,色彩也越鲜明艳丽;而对比度小,则会让整个画面都灰蒙蒙的。
灰度使用黑色调表示物体,即用黑色为基准色,不同的饱和度的黑色来显示图像。 每个灰度对象都具有从 0%(白色)到100%(黑色)的亮度值。
了解了一些基本的色彩概念,我们就可以开始进行处理了。首先我们看一下Unity后处理效果的原理。
二.Unity屏幕后处理原理
所谓屏幕后处理,简单来说就是渲染流水线的最后阶段,对由整个场景生成的一张图片进行处理,比如HDR,运动模糊等等效果,通过屏幕空间的后处理,可以整体改变整个游戏的风格或者效果。所以,要制作屏幕后处理,我们需要两样东西,一个是用于渲染后处理效果的shader,而另一个是我们需要调用这个渲染的脚本,好在Unity为我们提供了相关的功能。
1.OnRenderImage函数
该函数在MonoBehaviour中提供,该函数在所有渲染完成后才进行调用,也就是我们上文所说的生成了一张场景图片,函数的原型如下:
void OnRenderImage(RenderTexture sourceTexture,RenderTexture destTexture);
RenderTexture表示的是渲染纹理,我们渲染物体并不是仅仅渲染在屏幕空间,也可以将物体渲染到特定纹理上,也就是RenderTexture。sourceTexture就是我们渲染的场景图片,而destTexture是目标渲染纹理。我们可以在这个函数中进行相关的后处理效果,使用带有后处理效果shader的材质将场景内容重新渲染。
2.Graphics.Blit函数
该函数是Graphics的函数,用于将源纹理拷贝到目标纹理,函数原型如下:
public static void Blit(Texture source,RenderTexture dest);
public static void Blit(Texture source,RenderTexture dest, Material mat, int pass = -1);
public static void Blit(Texture source,Material mat, int pass = -1);
source是源纹理,dest是目标纹理,当dest为null时,直接将源纹理拷贝到屏幕;mat是拷贝时使用的材质,也就是我们后处理时使用的材质,Unity会使用该材质将源纹理进行处理拷贝给目标纹理,pass是使用的材质shader所使用的pass,我们知道,一个shader中可能有多个pass,使用哪个pass进行处理就可以从该参数传入,当然,默认为-1时表示所有的pass都会执行。
在了解了Untiy的后处理流程后,我们就可以着手写我们的亮度对比度饱和度调整后处理了。
三.后处理效果代码
后处理效果需要两部分,分别是脚本部分和shader部分,我们分别来看一下。
1.脚本部分
后处理脚本主要做的是两件事,第一件是获取需要的shader,生成材质,第二件是通过OnRenderImage使用材质处理屏幕效果。第一步具有一些普遍性,不管是什么后处理效果,都要有这一步相同的操作,所以我们将该步骤抽离出来,创建一个后处理效果的基类PostEffectBase,代码如下:
using UnityE
using System.C
//非运行时也触发效果
[ExecuteInEditMode]
//屏幕后处理特效一般都需要绑定在摄像机上
[RequireComponent(typeof(Camera))]
//提供一个后处理的基类,主要功能在于直接通过Inspector面板拖入shader,生成shader对应的材质
public class PostEffectBase : MonoBehaviour {
//Inspector面板上直接拖入
public Shader shader =
private Material _material =
public Material _Material
if (_material == null)
_material = GenerateMaterial(shader);
//根据shader创建用于屏幕特效的材质
protected Material GenerateMaterial(Shader shader)
if (shader == null)
//需要判断shader是否支持
if (shader.isSupported == false)
Material material = new Material(shader);
material.hideFlags = HideFlags.DontS
if (material)
然后,我们以后所有的后处理效果脚本都可以继承该类PostEffectBase,就都自动具有了通过shader生成后处理材质的功能。
接下来就是我们这一篇的亮度,饱和度,对比度调整的脚本,脚本很简单,主要的功能就在于设置几个参数,覆写OnRenderImage函数后将参数实时传入shader,然后通过Blit函数完成后处理效果,代码如下:
using UnityE
using System.C
//继承自PostEffectBase
public class ColorAdjustEffect : PostEffectBase {
//通过Range控制可以输入的参数的范围
[Range(0.0f, 3.0f)]
public float brightness = 1.0f;//亮度
[Range(0.0f, 3.0f)]
public float contrast = 1.0f;
[Range(0.0f, 3.0f)]
public float saturation = 1.0f;//饱和度
//覆写OnRenderImage函数
void OnRenderImage(RenderTexture src, RenderTexture dest)
//仅仅当有材质的时候才进行后处理,如果_Material为空,不进行后处理
if (_Material)
//通过Material.SetXXX(&name&,value)可以设置shader中的参数值
_Material.SetFloat(&_Brightness&, brightness);
_Material.SetFloat(&_Saturation&, saturation);
_Material.SetFloat(&_Contrast&, contrast);
//使用Material处理Texture,dest不一定是屏幕,后处理效果可以叠加的!
Graphics.Blit(src, dest, _Material);
//直接绘制
Graphics.Blit(src, dest);
这样,我们的后处理脚本就完成了。涉及到以下几个知识点:
1.可以通过[Range(min,max)]来控制Inspector面板中的值,限定其范围,并提供滑动条控制。
2.OnRenderImage函数每帧渲染完全部内容后执行,我们在每一帧设置Material的各项参数,通过Material.SetXXX(&name&,value)可以向shader中传递各种参数。
3.各种后处理效果可以叠加,这里的dest并不一定就是屏幕。不过后处理是很耗费性能的,一方面是pixel shader全屏幕overdraw,另一方面,一个rendertexture的内存占用很大,尤其是大分辨率手机上,多个后处理效果可能造成内存耗尽,程序崩溃。
2.shader部分
终于步入正题了,下面看一下后处理效果的shader。由于后处理效果是对于一个场景的渲染图进行处理,所以vertex shader基本没有什么好说的,大部分后处理都是基于pixel shader。先整理一下思路:
最简单的是亮度,我们可以直接在采样texture后乘以一个系数,达到放大或者缩小rgb值的目的,这样就可以调整亮度了。
其次是饱和度,饱和度是离灰度偏离越大,饱和度越大,我们首先可以计算一下同等亮度条件下饱和度最低的值,根据公式:gray = 0.2125 * r + 0.7154 * g + 0.0721 * b即可求出该值(公式应该是一个经验公式),然后我们使用该值和原始图像之间用一个系数进行差值,即可达到调整饱和度的目的。
最后是对比度,对比度表示颜色差异越大对比度越强,当颜色为纯灰色,也就是(0.5,0.5,0.5)时,对比度最小,我们通过在对比度最小的图像和原始图像通过系数差值,达到调整对比度的目的。代码如下:
//shader的目录
Shader &Custom/ColorAdjustEffect&
//属性块,shader用到的属性,可以直接在Inspector面板调整
Properties
_MainTex (&Albedo (RGB)&, 2D) = &white& {}
_Brightness(&Brightness&, Float) = 1
_Saturation(&Saturation&, Float) = 1
_Contrast(&Contrast&, Float) = 1
//每个shader都有Subshaer,各个subshaer之间是平行关系,只可能运行一个subshader,主要针对不同硬件
//真正干活的就是Pass了,一个shader中可能有不同的pass,可以执行多个pass
//设置一些渲染状态,此处先不详细解释
ZTest Always Cull Off ZWrite Off
//在Properties中的内容只是给Inspector面板使用,真正声明在此处,注意与上面一致性
sampler2D _MainT
//vert和frag函数
#pragma vertex vert
#pragma fragment frag
#include &Lighting.cginc&
//从vertex shader传入pixel shader的参数
struct v2f
float4 pos : SV_POSITION; //顶点位置
uv : TEXCOORD0;
//vertex shader
//appdata_img:带有位置和一个纹理坐标的顶点着色器输入
v2f vert(appdata_img v)
//从自身空间转向投影空间
o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
//uv坐标赋值给output
//fragment shader
fixed4 frag(v2f i) : SV_Target
//从_MainTex中根据uv坐标进行采样
fixed4 renderTex = tex2D(_MainTex, i.uv);
//brigtness亮度直接乘以一个系数,也就是RGB整体缩放,调整亮度
fixed3 finalColor = renderTex * _B
//saturation饱和度:首先根据公式计算同等亮度情况下饱和度最低的值:
fixed gray = 0.2125 * renderTex.r + 0.7154 * renderTex.g + 0.0721 * renderTex.b;
fixed3 grayColor = fixed3(gray, gray, gray);
//根据Saturation在饱和度最低的图像和原图之间差值
finalColor = lerp(grayColor, finalColor, _Saturation);
//contrast对比度:首先计算对比度最低的值
fixed3 avgColor = fixed3(0.5, 0.5, 0.5);
//根据Contrast在对比度最低的图像和原图之间差值
finalColor = lerp(avgColor, finalColor, _Contrast);
//返回结果,alpha通道不变
return fixed4(finalColor, renderTex.a);
//防止shader失效的保障措施
FallBack Off
四.效果展示
完成shader和后处理脚本后,我们可以创建一个场景,在场景的MainCamera下挂在上该脚本,然后把ColorAdjustEffect的shader赋给脚本的shader槽,如下图所示:
首先将亮度,对比度,饱和度都置为1,场景如下所示:
调整亮度的图像效果如下:
调整对比度效果如下:
调整饱和度的情况如下图:
(window.slotbydup=window.slotbydup || []).push({
id: '2467140',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467141',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467143',
container: s,
size: '1000,90',
display: 'inlay-fix'
(window.slotbydup=window.slotbydup || []).push({
id: '2467148',
container: s,
size: '1000,90',
display: 'inlay-fix'本系列文章由&出品,转载请注明出处。&& 文章链接: 作者:毛星云(浅墨)&& &微博: 邮箱:&&&本篇文章中。我们学习了Unity Shader的基本写法框架,以及学习了Shader中Properties(属性)的详细写法,光照、材质与颜色的详细写法。写了6个Shader作为本文Shader解说的实战内容,最后创建了一个逼真的暴风雪场景进行了Shader的測试。依然是国际惯例先上本文配套程序的截图。先是一张远眺图:&浅墨在场景中放置了一个自己主动旋转的剑阵,瞬间武侠气息爆棚:<img src="http://img.blog.csdn.net/31546?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />&来一张近距离:&<img src="http://img.blog.csdn.net/35397?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />&&看到银白色的世界漫天飞雪,剑阵列为圈旋转,有没有雪山飞狐的即视感呢?&须要说明的是,由于CSDN的图片上传限制2Mb,这样画质的场景做成GIF上传不了。而静态的图片没有动态的表现力。感受不到风雪吹到自己身上的那种刺骨的感觉。所以在这里贴出的图,表现力已经是大打则扣了,而音效和背景音乐更是听不了。表现力就更是不如亲自执行了。所以浅墨推荐感兴趣的同学能够下载此场景的exe自己执行玩耍,赏玩。且此场景有些庞大。徒步走预计5分钟才干走到场景边界。Please enjoy~&点击,下载此“雪山飞狐”场景的exe。&另外提醒,场景unity源文件和源码在末尾提供下载。OK,我们正式開始。&&&一、一些基本概念认知&1.1 Shader和Material的基本概念认知&先引用一段文字。阐述Shader和Material的基本关系:“Shader(着色器)实际上就是一小段程序,它负责将输入的Mesh(网格)以指定的方式和输入的贴图或者颜色等组合作用。然后输出。画图单元能够根据这个输出来将图像绘制到屏幕上。输入的贴图或者颜色等,加上相应的Shader,以及对Shader的特定的參数设置,将这些内容(Shader及输入參数)打包存储在一起,得到的就是一个Material(材质)。之后,我们便能够将材质赋予合适的renderer(渲染器)来进行渲染(输出)了。所以说Shader并没有什么特别奇妙的,它仅仅是一段规定好输入(颜色,贴图等)和输出(渲染器能够读懂的点和颜色的相应关系)的程序。而Shader开发人员要做的就是根据输入,进行计算变换。产生输出而已。“这段文字出自,是比較好的Unity Shader的入门文章,可惜仅仅写了两篇,后面就没有继续了。浅墨在文章开头懒得写了,就讲这句引用了过来。&1.2 背景知识说明在这里须要说明。学习Unity中的Shader编程。最好是之前对OpenGL或Direct3D的渲染状态等相关知识有一个主要的了解。假设之前没有太接触过这方面的知识。能够看看浅墨写的DirectX相关的教程。而须要大量恶补提升图形编程功力的童鞋,能够在和开发人员站点上能够找一些着色器教程和文档来啃啃。&对于本期的光照和材质。须要的背景知识能够看浅墨之前写的这篇以DirectX为载体的光照和材质导论式的文章:&《》假设对当中的C++&DirectX的代码不太熟悉的话,没关系。看看概念。了解个大概就能够了。&&二、 Unity中Shader的三种基本类型&我们知道,计算机图形学的中渲染管线一般能够分为两种类型:&1.固定功能渲染管线(fixed-functionrendering pipelines)2.可编程渲染管线(programmablerendering pipelines)按这样的分类思路。在Unity中,Shader便能够分成例如以下三种基本类型:&1.固定功能着色器(Fixed Function Shader)&2.表面着色器(Surface Shader)&3.顶点着色器&片段着色器 (Vertex Shader & Fragment Shader)顾名思义,当中的固定功能着色器便是我们所说的固定功能渲染管线(fixed-functionrendering pipelines)的详细表现,而表面着色器、顶点着色器以及片段着色器便属于可编程渲染管线。以下分别对其进行简单的介绍。2.1 关于固定功能着色器这里的固定功能着色器能够说是Unity为Shader的书写自带的一层壳,Unity已经在内部为我们做了大量的工作。我们仅仅要略微记住一些keyword、一些规范就能够实现出非常多不错的效果。固定功能着色器是我们初学Unity Shader的近期几篇文章中的主要学习对象。而后面的表面着色器、顶点着色器以及片段着色器就是在固定功能着色器的基础上嵌套了CG语言的代码而成的更加复杂的着色器。我们来看看他们的一些基本概念。&&2.2 关于表面着色器表面着色器(Surface Shader)这个概念很多其它的仅仅是在Unity中听说,能够说是Unity自己发扬光大的一项使Shader的书写门槛减少和更易用的技术。我们会在接下来的学习中逐渐意识到Unity是怎样为我们把Shader的复杂性包装起来,使其书写的过程更便捷和易用的。&2.3 关于顶点着色器和片段着色器研究过Direct3D和OpenGL着色器编程的童鞋们一定对这两者不陌生。我们来简介一下他们的用途。顶点着色器:产生纹理坐标,颜色。点大小,雾坐标,然后把它们传递给裁剪阶段。片段着色器:进行纹理查找。决定什么时候执行纹理查找。是否进行纹理查找。及把什么作为纹理坐标&2.4 怎样区分Unity中的Shader类型在Unity中想要区分他们非常easy。后面熟悉了自然知道。在这里浅墨先剧透一下:没有嵌套CG语言,也就是代码段中没有CGPROGARAM和ENDCGkeyword的,就是固定功能着色器。嵌套了CG语言。代码段中有surf函数的。就是表面着色器。嵌套了CG语言,代码段中有#pragma vertex name和& #pragma fragment frag声明的,就是顶点着色器&片段着色器。&&&&&&&&三、Unity中将Shader赋给Material的两种方法在Unity中将Shader赋给Material使用的两种方法。&【方法一】直接将Shader拖拽到Material之上。这样的方法我们上篇文章中已经多次讲到,也就是这样:&<img src="http://img.blog.csdn.net/03342?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />【方法二】在Material的Inspector面板中选择。Unity中内建的Shader都是通过这样的方式来让Material使用的。在Material的Inspector中,其名字下方的Shader栏中选择。能够发现Unity已经为我们准备好了非常多种不同的Shader。基本能够满足居家旅行的需求了。&而对于我们自己新写的Shader,也会在这个菜单条中显示出来。细心的朋友们看上图的时候,肯定就已经发现了。这里选择的菜单取决于我们Shader中定义Shader的第一行代码时紧接着Shaderkeyword的引號“”里面的书写方式:&<img src="http://img.blog.csdn.net/34493?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />&&&四、Unity 中Shader的基本框架&由于着色器代码能够说专用性非常强。因此Shader的设计者人为地规定了它的基本结构。而Unity中Shader总体的框架写法能够用例如以下的形式来概括:&Shader &name& { [Properties] SubShaders[Fallback] }&也就是说,Unity中全部着色器都是由Shaderkeyword開始。随后的字符串表示着色器的名字。这个名字会显示在Inspector检视面板中。全部用于这个着色器的代码必须放置在之后的大括号里:{ }(称为“块”)。ps:该名字应该是短且描写叙述性的文字。它并不须要和shader文件名称同样。而想要把着色器增加到Unity的子菜单里。名字须要用斜线(/)。比如:浅墨Shader编程/TheFirstShader就是一个名叫TheFirstShader的着色器,而这个着色器位于“浅墨Shader编程”的子菜单下。这样,我们就能够在Shader后面紧跟着的引號中用“/”来构造出子二级甚至多级的子菜单来,方便了后面Shader写多了时候的合理分类,不至于太乱。OK,我们继续讲。有图有真相,Shader总体的框架写法用图来说就是这样:&&&看图能够知道,首先是一些属性定义,用来指定这段代码将有哪些输入。接下来是一个或者多个的子着色器,在实际执行中。哪一个子着色器被使用是由执行的平台所决定的。子着色器是代码的主体,每一个子着色器中包括一个或者多个的Pass。在计算着色时,平台先选择最优先能够使用的着色器,然后依次执行当中的Pass,然后得到输出的结果。最后指定一个Fallback,可译为“回滚”,俗称备胎。用来处理全部SubShader都不能执行的情况(比方目标设备实在太老,全部SubShader中都有其不支持的特性,于是仅仅好用备胎了。不然就显示不出来)。&不同的图形卡有不同的性能。这对游戏开发人员来说是永恒的问题。而这恰恰就是子着色器为什么能够发光发热的原因。若我们开发出了一种使用了当前业界前沿技术构成的Shader,这样的Shader眼下仅仅有百分之1的牛逼哄哄的显卡能够支持。比較明智的做法是,把这套採用最前沿技术的Shader作为我们众多SubShader的当中的一员,然后还得准备一堆Plan B。应对其它硬件上的执行。也就是说,我们为所期望的採用最新技术的效果编写一个子着色器,然后为之前古老的显卡再编制一些备用的着色器。这些子着色器能选择使用更低层次的方式来实现我们的效果。或者选择放弃实现某些细节。确保不管在什么机器上跑,都能够执行出正确的效果。尽管这些效果会有一些细微的区别,由于使用的SubShader是不一样的,但却保证了我们的Shader在不论什么机器上都跑得起来。&PS:在实际进行表面着色器的开发时。我们就是直接在SubShader这个层次上写代码,系统会将把我们的代码编译成若干个合适的Pass。&用一个实例代码来说明吧。&我们在Project面板中右键-&Create-&Shader。新建一个Shader文件。然后双击打开,删掉原先代码,分分钟,我们依照上文的解说,对比着图示,就能够写出例如以下框架的Shader代码来:&Shader &浅墨Shader编程/0.Shader框架演示样例&
//-------------------------------【属性】-----------------------------------------
Properties
_MainTex(&基本纹理&,2D)=&White&{TexGen ObjectLinear}
//---------------------------------【子着色器1】----------------------------------
//----------------通道---------------
//设置纹理为属性中选择的纹理
SetTexture[_MainTex]{combine texture}
//---------------------------------【备胎】----------------------------------------
//备胎设为Unity自带的普通漫反射
Fallback& Diffuse &
}&解释起来就是:&1.着色器通过properties来可选的定义一个可通过材质设定界面来自己定义的列表。详细到上述代码中写的Properties,就是定义了一个基本属性,參数名叫做_MainTex,在编辑器中显示的名称叫做“基本纹理”。 且纹理生成模式为ObjectLinear。2.后面紧跟着核心部分子着色器SubShader。里面的一个Pass里面设置了纹理为我们属性中定义的那个_ MainTex。3.增加一句Fallback代码用于应对我们Shader中的SubShader不能正确执行的情况。&须要注意的是。SubShader在UnityShader的代码段中必须有且至少有一个,而properties和fallback对于追求简单的Shader。是能够不写出来的。而复杂一点的Shader。当然各种properties、fallback什么的肯定都有,甚至有多个SubShader。而每一个SubShader中又有多个Pass。&这个框架程序我们后面写新的Shader的时候就能够直接复制然后粘贴,接着在Properties中增加新的属性。SubShader中填充新的Pass以及开辟新的SubShader即可。就像做填空题一样。&&&&五、Properties 属性相关内容解说&以下,我们详细地来看一看作为Shader框架中三大组成部分之中的一个的Properties属性的相关内容。properties一般定义在着色器的起始部分,我们能够在Shader书写的时候定义多种多样的属性,而使用Shader的时候能够直接在材质检视面板(Material Inspector)里编辑这些属性,取不同的值或者纹理。这能够说是Unity贴心&可见即所得的又一体现吧。以Unity自带的BasicVertex Lighting 基本顶点光照为例。一张非常直观的图就是这样:&&须要注意。Properties块内的语法都是单行的。每一个属性都是由内部名称開始,后面括号里是显示在检视面板(Inspector)中的名字和该属性的类型。等号后边跟的是默认值。&&5.1 Properties属性 相关代码写法列举这一小节我们列举Unity中Shader的Properties属性相关语法參考,能够在须要时进行查阅:Properties { Property [Property ...] }定义属性块。当中可包括多个属性。其定义例如以下:name (&display name&, Range (min, max)) =number定义浮点数属性,在检视器中可通过一个标注最大最小值的滑条来改动。name (&display name&, Color) =(number,number,number,number)定义颜色属性name (&display name&, 2D) = &name& {options }定义2D纹理属性name (&display name&, Rect) = &name&{ options }定义长方形(非2次方)纹理属性name (&display name&, Cube) = &name&{ options }定义立方贴图纹理属性name (&display name&, Float) = number定义浮点数属性name (&display name&, Vector) =(number,number,number,number)定义一个四元素的容器(相当于Vector4)属性&&&5.2 一些细节说明包括在着色器中的每一个属性通过name索引(在Unity中, 通常使用下划线来開始一个着色器属性的名字)。属性会将display name显示在材质检视器中,还能够通过在等符号后为每一个属性提供缺省值。对于Range和Float类型的属性仅仅能是单精度值。对于Color和Vector类型的属性将包括4个由括号围住的数描写叙述。对于纹理(2D, Rect, Cube) 缺省值既能够是一个空字符串也能够是某个内置的缺省纹理:&white&, &black&, &gray& or&bump&随后在着色器中,属性值通过[name]来訪问。&&接着,让我们看一个演示样例,了解属性Properties的实际使用方法:&Shader &浅墨Shader编程/SimpleWater&
Properties{
//properties for water shader
//水着色器的属性
_WaveScale(&Wave scale&, Range (0.02,0.15)) = 0.07 // 滑动条
_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) // 颜色
_ReflectionTex(&Environment Reflection&, 2D) = && {} // 纹理
_RefractionTex(&Environment Refraction&, 2D) = && {}
_Fresnel(&Fresnel (A) &, 2D) = && {}
_BumpMap(&Bumpmap (RGB) &, 2D) = && {}
//兴许代码省略
}&&5.3 关于纹理属性选项纹理属性在本文的第一个演示样例中就实用到。这里先再贴一遍2D纹理属性的写法:&name (&display name&, 2D) =&name& { options }&须要注意的是,包括在纹理属性的大括号里的选项Options是可选的。可能的选项有例如以下:&TexGen纹理生成类型。即纹理的自己主动生成纹理坐标时的模式,能够是ObjectLinear, EyeLinear,SphereMap, CubeReflect, CubeNormal的当中之中的一个;这些模式和OpenGL纹理生成模式相相应。注意假设使用自己定义顶点程序,那么纹理生成将被忽略。&LightmapMode 光照贴图模式。假设我们给出这个选项,纹理将能被渲染器的光线贴图属性所影响。纹理不能被使用在材质中,而是取自渲染器的设定。这个我们以后会讲到。&&&六、光照、材质与颜色相关内容解说&灯光和材质參数经常被用来控制内置的顶点光照。而Unity中的顶点光照也就是Direct3D/OpenGL标准的按每顶点计算的光照模型—— 光照打开时,光照受材质块,颜色材质和平行高光命令的影响。&&我们来一起看一看光照、材质与颜色详细的语法。&这里讲到的都是採用固定功能渲染的代码写法,以及一些控制选项。讲得有些细了。不用一次全记住,须要的时候回过头来进行查阅即可了。&&&6.1 用于通道Pass中的代码写法列举这些代码通常是写在Pass{ }中的。细节例如以下:&Color Color设定对象的纯色。颜色即能够是括号里的四值(RGBA)。也能够是被方框包围的颜色属性名。&Material { Material Block }材质块被用于定义对象的材质属性。&Lighting On | Off开启光照,也就是定义材质块中的设定是否有效。想要有效的话必须使用Lighting On命令开启光照,而颜色则通过Color命令直接给出。&SeparateSpecular On | Off开启独立镜面反射。这个命令会增加高光光照到着色器通道的末尾,因此贴图对高光没有影响。仅仅在光照开启时有效。&ColorMaterial AmbientAndDiffuse | Emission使用每顶点的颜色替代材质中的颜色集。AmbientAndDiffuse 替代材质的阴影光和漫反射值;Emission 替代 材质中的光发射值。&&&&6.2 材质块Material Block 中相关代码写法列举&例如以下这些代码的使用的地方是在SubShader中的一个Pass{ }中新开一个Material{ }块,在这个Material{ }块中进行这些语句的书写。这些代码包括了包括材质怎样和光线产生作用的一些设置。这些属性默觉得值都被设定为黑色(也就是说不产生作用),也就是说他们普通情况下能够被忽略。当然。还是有非常多时候须要使用到他们的。&Diffuse Color(R,G,B,A)漫反射颜色构成。这是对象的基本颜色。&Ambient Color(R,G,B,A)环境色颜色构成.这是当对象被RenderSettings.中设定的环境色所照耀时对象所表现的颜色。&Specular Color(R,G,B,A)对象反射高光的颜色。(R,G,B,A)四个分量分别代表红绿蓝和Alpha,取值为0到1之间。&Shininess Number加亮时的光泽度,在0和1之间。0的时候你会发现更大的高亮也看起来像漫反射光照。1的时候你会获得一个细微的亮斑。&Emission Color自发光颜色,也就是当不被不论什么光照所照到时,对象的颜色。(R,G,B,A)四个分量分别代表红绿蓝和Alpha,取值为0到1之间。&而打在对象上的完整光照颜色终于是:&&FinalColor= Ambient * RenderSettings ambientsetting +&(Light Color * Diffuse + Light Color *Specular) + Emission&翻译过来的中文式子便是:&终于颜色=环境光反射颜色* 渲染设置环境设置 *(灯光颜色*漫反射颜色+灯光颜色*镜面反射颜色)+自发光&知道了这个式子,我们就知道了。在各种光的综合作用下,我们材质终于的颜色是怎么来的了。须要注意的是:方程式的灯光部分(也就是带括号的部分)对全部打在对象上的光线都是反复使用的。而我们在写Shader的时候经常会将漫反射和环境光光保持一致(全部内置Unity着色器都是如此)。&&&七、Shader书写实战上面讲了一堆一堆的概念。预计大家一遍看下来头都大了。没关系,让我们看一些演示样例Shader的写法,弄清楚上面这一堆堆的概念是怎样应用的。&1.单色Shader首先,用上文讲到的Color命令,写出一个有效代码仅仅四行的袖珍Shader:Shader&浅墨Shader编程/1.基础单色&
//---------------------------------【子着色器】----------------------------------
//----------------通道---------------
//设为蓝色单色
Color(0,0,0.6,0)
}此Shader编译后赋给材质的效果例如以下:&&&&2.材质颜色&开启光照的Shader同样的。我们能够在Pass中加上材质块Material,在当中将将材质的漫反射和环境光反射颜色设为同样,而且在该Pass中开启光照:&Shader&浅墨Shader编程/2.材质颜色设置&开启光照&
//---------------------------------【子着色器1】----------------------------------
//----------------通道---------------
//----------材质------------
//将漫反射和环境光反射颜色设为同样
Diffuse(0.9,0.5,0.4,1)
Ambient(0.9,0.5,0.4,1)
//开启光照
Lighting On
}此Shader编译后赋给材质的效果例如以下:&<img src="http://img.blog.csdn.net/45203?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />&&&&3.可调漫反射光的Shader在上面Shader的基础上,我们引入一个color属性。于是就得到了例如以下可调漫反射光颜色的Shader:&Shader &浅墨Shader编程/3.简单的可调漫反射光照&
//-------------------------------【属性】-----------------------------------------
Properties
_MainColor (&主颜色&, Color) = (1,.1,.5,1)
//---------------------------------【子着色器】----------------------------------
//----------------通道---------------
//-----------材质------------
//可调节的漫反射光和环境光反射颜色
Diffuse [_MainColor]
Ambient[_MainColor]
Lighting On
此Shader编译后赋给材质的效果例如以下:&&&&4.光照材质完备beta版Shader&&我们把余下的Material属性补上。便有了此光照材质完备beta版的shader:&Shader &浅墨Shader编程/4.光照材质完备beta版Shader&
//-------------------------------【属性】-----------------------------------------
Properties
_Color (&主颜色&, Color) = (1,1,1,0)
_SpecColor (&反射高光颜色&, Color) = (1,1,1,1)
_Emission (&自发光颜色&, Color) = (0,0,0,0)
_Shininess (&光泽度&, Range (0.01, 1)) = 0.7
//---------------------------------【子着色器】----------------------------------
//----------------通道---------------
//-----------材质------------
//可调节的漫反射光和环境光反射颜色
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
//高光颜色
Specular [_SpecColor]
//自发光颜色
Emission [_Emission]
//开启光照
Lighting On
此Shader编译后赋给材质的效果例如以下,能够自由定制的选项多了不少:&&&&&&&5.简单的纹理加载Shader&&然后我们看一个简单的纹理加载Shader的写法:&Shader &浅墨Shader编程/5.简单的纹理加载Shader&
//-------------------------------【属性】-----------------------------------------
Properties
_MainTex(&基本纹理&,2D)=&White&{TexGen SphereMap}
//---------------------------------【子着色器1】----------------------------------
//----------------通道---------------
//设置纹理为属性中选择的纹理
SetTexture[_MainTex]{combine texture}
//---------------------------------【备胎】----------------------------------------
//备胎设为Unity自带的普通漫反射
Fallback& Diffuse &
}此Shader编译后赋给材质的效果例如以下:&须要注意,这里用到了一点纹理生成的内容。详细使用方法我们下次再细讲。&&&&6.光照材质完备正式版Shader结合Shader4 beta版的光照材质Shader和Shader5简单的纹理加载,我们写成了这篇文章的终于版Shader:&Shader &浅墨Shader编程/6.光照材质完备正式版Shader&
//-------------------------------【属性】-----------------------------------------
Properties
_Color (&主颜色&, Color) = (1,1,1,0)
_SpecColor (&高光颜色&, Color) = (1,1,1,1)
_Emission (&自发光颜色&, Color) = (0,0,0,0)
_Shininess (&光泽度&, Range (0.01, 1)) = 0.7
_MainTex (&基本纹理&, 2D) = &white& {}
//--------------------------------【子着色器】--------------------------------
//----------------通道---------------
//-----------材质------------
//可调节的漫反射光和环境光反射颜色
Diffuse [_Color]
Ambient [_Color]
Shininess [_Shininess]
//高光颜色
Specular [_SpecColor]
//自发光颜色
Emission [_Emission]
//开启光照
Lighting On
//开启独立镜面反射
SeparateSpecular On
//设置纹理并进行纹理混合
SetTexture [_MainTex]
Combine texture * primary DOUBLE, texture * primary
} 当中,涉及到了纹理混合的知识。我们稍后会解说。此Shader编译后赋给材质的效果例如以下,能够发现。在这么多的可定制选项下。我们能够自由调节出自己喜欢的材质效果来:<img src="http://img.blog.csdn.net/15432?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />&自由调节出各种诡异的材质:<img src="http://img.blog.csdn.net/38520?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="400" height="340" alt="" />&&&<img src="http://img.blog.csdn.net/15864?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" width="400" height="340" alt="" />OK。很多其它的材质效果图就不放出了,大家下载文章末尾处提供的源project,然后找到这个Shader自己调着玩吧。本文中全部的Shader和Material都位于Shaders目录中:&&&&&八、QianMo’s Toolkit升级到v1.1版&&上次公布QianMo’s Toolkit v1.0之后。发现有一些能够改进的地方,以及一些新功能,于是就花了点时间将Tookit更新了一下,写了一点新功能,升级到了v1.1。&8.1 QianMo’s Toolkit v1.1版改动说明:&1.新增加工具SetMaxFPS& 用于突破Unity每秒渲染 60帧的设定,自由设置最大帧率。2.新增加工具ShowObjectInfoInGamePlay。用于公布游戏之后显示文本信息。之前的ShowObjectInfo仅能在Unity測试过程中显示文本信息。3.修复导入后的警告提示“Someare Mac OS X (UNIX) and some are Windows.”&&8.2 QianMo’s Toolkit v1.1版包括内容:&ShowFPS:在游戏执行时显示帧率相关信息ShowObjectInfo:在測试过程里,于场景中和游戏窗体中分别显示增加给随意物体文字标签信息。隐藏和显示可选。基于公告板技术实现。ShowGameInfo:在游戏执行时显示GUI相关说明ShowLogo:在游戏执行时显示LogoShowUI:在游戏执行时显示简单的镶边UI。SetMaxFPS&:用于突破Unity每秒渲染 60帧的设定,自由设置最大帧率。ShowObjectInfoInGamePlay:用于公布游戏之后显示文本信息。&<img src="http://img.blog.csdn.net/05095?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />&点击这里单独下载QianMo’s Toolkit v1.1:【】 &&&&8.3 设置Unity中最大帧率的写法&最好还是在这里贴一下设置最大帧率的代码,便须要的朋友參考:&//-----------------------------------------------【脚本说明】-------------------------------------------------------
脚本功能:
设置在游戏执行时可达到的最大帧率
使用语言:
开发所用IDE版本号:Unity4.5 06f 、Visual Studio 2010
2014年11月 Created by 浅墨
很多其它内容或交流,请訪问浅墨的博客:http://blog.csdn.net/poem_qianmo
//---------------------------------------------------------------------------------------------------------------------
//-----------------------------------------------【使用方法】-------------------------------------------------------
第一步:在Unity中拖拽此脚本到场景随意物体上,或在Inspector中[Add Component]-&[浅墨's Toolkit v1.1]-&[SetMaxFPS]
第二步:在面板中设置MaxFPSValue參数为须要的帧率值,以及其它參数
//---------------------------------------------------------------------------------------------------------------------
using UnityE
using System.C
//垂直同步数
public enum VSyncCountSetting
EveryVBlank,
EverSecondVBlank
[AddComponentMenu(&浅墨's Toolkit v1.1/SetMaxFPS&)]
public class SetMaxFPS : MonoBehaviour
public VSyncCountSetting VSyncCount = VSyncCountSetting.DontS//用于快捷设置Unity Quanity设置中的垂直同步相关參数
public bool MaxNoLimit =//不设限制。保持可达到的最高帧率
public int MaxFPSValue = 80;//帧率的值
void Awake()
//设置垂直同步相关參数
switch (VSyncCount)
//默认设置,不等待垂直同步。能够获取更高的帧率数
case VSyncCountSetting.DontSync:
QualitySettings.vSyncCount = 0;
//EveryVBlank,相当于帧率设为最大60
case VSyncCountSetting.EveryVBlank:
QualitySettings.vSyncCount = 1;
//EverSecondVBlank情况,相当于帧率设为最大30
case VSyncCountSetting.EverSecondVBlank:
QualitySettings.vSyncCount = 2;
//设置没有帧率限制,火力全开!
if (MaxNoLimit)
Application.targetFrameRate = -1;
//设置帧率的值
Application.targetFrameRate = MaxFPSValue - 1;
拖动此脚本到场景的随意物体上,在Inspector新出现的这个脚本选项的Max FPS Value中填上自己期望的最大帧率即可了,前提是你的电脑有能力跑到这么高的帧数。或者直接勾上 Max No Limit的勾勾,便能够让你的电脑火力全开,用最高性能来跑出最大的帧率。&&&&九、终于游戏场景效果演示——雪山飞狐&上一次中我们处于炎热的夏威夷群岛之中,这次的场景,最好还是让我们来到寒冷的冬季,领略刺骨的寒风。以大师级美工鬼斧神工的场景作品为基础,浅墨优化和压缩了此场景资源的尺寸,增加了音乐和音效,并改动了场景布局。增加了很多其它特效,于是便得到了如此这次让人颇显震撼的暴风雪场景。逼真的音效和暴风雪特效。让我们身临其境:<img src="http://img.blog.csdn.net/24000?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />&&浅墨在场景中放置了一个自己主动旋转的剑阵。瞬间武侠气息爆棚:&&有没有要想要随便拿一把兵器,跃跃欲试:&&&我们将一些今天写的这些材质Shader运用到这些剑之上看看效果:&&&最后,放一张今天学的Shader的全家福:<img src="http://img.blog.csdn.net/04828?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />&&本篇文章的演示样例程序请点击此处下载:&&&&今天的文章到这里就基本结束了。这篇的内容算是非常多。信息量是非常大的,希望大家戒骄戒躁,看不懂的地方多看几遍。不用怕,Shader学起来事实上非常easy。<img src="http://img.blog.csdn.net/28937?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvcG9lbV9xaWFubW8=/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/SouthEast" alt="" />新的游戏编程之旅正在继续,下周一。我们不见不散。
阅读(...) 评论()

我要回帖

更多关于 shader 纹理融合 的文章

 

随机推荐