最近遇到了一个需求,想要一种在刀剑上带有光晕的酷炫效果,甚至是还想要有闪烁呼吸效果,于是就写了一个简单的叫LightSwrod的Shader去实现,先上图看看效果吧。

简单展示

这是剑本身的样子

这是用了LightSword后的效果

(原谅我的审美吧~~~调了半天也就这难看的样子T_T)

这是Inspector里面Material的参数

参数的解释将在后面进行细致讲解

创建流程

来讲述一下创建光剑效果的流程吧

1.准备两张贴图:

一张是剑体本身的贴图,是真正要显示出来的剑体

一张是要展现光晕效果,给Shader用的Alpha贴图

Alpha贴图可以拿剑体本身的贴图复制一份来修改,由于Shader只取Alpha贴图的Alpha值,所以修改方式是在剑体周围加上渐变透明的颜色,最终光晕颜色越浅的地方Alpha值越低。

2.创建Sprite:

先将贴图转换成sprite格式

将图片子节点下的sprite拖到Hierarchy下变成一个GameObject

再将贴图调到Advanced格式

注意:需要将Mesh Type调成FullRect模式,使Sprite生成的Mesh是一个完整的矩形,

否则Unity会自动 生成一个被裁减的Mesh,在这部分之外是不会被渲染的,导致光晕有被裁剪的感觉,如下图

3.创建Material和Shader:

Material可以直接在Project里面右键->Create->Material来创建,Shader同理 。

如下,我们创建了Material和Shader

接着将Shader拖到Material上,但你你看到的Inspector的样子一定跟上面给不一样,因为Shader还没有改写好,下面就开始讲述如何编写这个Shader。

4.Shader编写:

先把完整的Shader贴出来吧:

// 发光剑的光晕实现
// By XiaoZeFeng
Shader "custom/LightSword"
{
Properties
{
_MainTex("Main Texture (RGB)", 2D) = "white" {} // 主贴图 //
_MainColorTimes("MainColorTimes", Range(0, 30)) = 1 // 主图颜色增强倍数 //
_EmissionTex("_EmissionTex", 2D) = "white" {} // 光晕Alpha图,取Alpha值填补Emission颜色 //
_EmissionAlphaTimes("EmissionAlphaTimes", Range(0, 50)) = 1 // 光晕Alpha增强倍数 //
_EmissionAlphaExponent("EmissionAlphaExponent", Range(0, 10)) = 1 // 光晕Alpha指数,用于消除黑边 // _Emission1("Emmisive Color1", Color) = (0,0,0,0) // 剑体本身的发光颜色 //
_EmissionColorTimes1("EmissionColorTimes1", float) = 1 // 剑体本身的发光颜色倍数 // _Emission2("Emmisive Color2", Color) = (0,0,0,0) // 剑体光晕的发光颜色 //
_EmissionColorTimes2("EmissionColorTimes2", float) = 1 // 剑体光晕的发光颜色倍数 // _AllAlpha("AllAlpha", Range(0, 1)) = 1 // 整体Alpha值 //
} SubShader
{
Tags
{
"Queue" = "Transparent+100"
"IgnoreProjector" = "True"
"RenderType" = "Transparent"
} LOD 100
Cull Off
ZWrite Off
AlphaTest Off
Blend SrcAlpha OneMinusSrcAlpha
Fog{ Mode Off } Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc" sampler2D _MainTex;
uniform fixed _MainColorTimes;
sampler2D _EmissionTex;
uniform float _EmissionAlphaTimes;
uniform float _EmissionAlphaExponent;
uniform fixed4 _Emission1;
uniform fixed _EmissionColorTimes1;
uniform fixed4 _Emission2;
uniform fixed _EmissionColorTimes2;
uniform fixed _AllAlpha; struct appdata_t
{
float4 vertex : POSITION;
fixed4 color : COLOR;
float2 texcoord : TEXCOORD;
}; struct v2f
{
float4 vertex : SV_POSITION;
fixed4 color : COLOR;
half2 texcoord : TEXCOORD;
}; v2f vert(appdata_t IN)
{
v2f OUT;
OUT.vertex = mul(UNITY_MATRIX_MVP, IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.color = IN.color; return OUT;
} fixed4 frag(v2f IN) : COLOR
{
fixed4 mainColor = tex2D(_MainTex, IN.texcoord);
fixed4 emisionColor = tex2D(_EmissionTex, IN.texcoord); mainColor.rgb = mainColor.rgb * _MainColorTimes
+ _Emission1 * mainColor.a * _EmissionColorTimes1
+ _Emission2 * (1 - mainColor.a) * emisionColor.a * _EmissionColorTimes2; mainColor.a = max(mainColor.a, pow(emisionColor.a, _EmissionAlphaExponent)
* _EmissionAlphaTimes) * _AllAlpha; return mainColor;
}
ENDCG
}
}
}

Shader讲解

properties

在properties里面定义了10个参数,其中两个是贴图,两个是颜色,其他都是float数值,其他参数所表达的含义都在注释中有标注。

vertex

vertex方法里正常的将物体投影到屏幕上,惯例的做法,没有什么特殊性,就不过多的解释了。

fragment

fragment方法是实现剑光晕效果的主体,将由两个公式来分别计算光晕剑每个像素点的颜色和Alpha值。

首先是取出剑本体和Alpha贴图上关于当前像素点的颜色和Alpha值

	fixed4 mainColor = tex2D(_MainTex, IN.texcoord);
fixed4 emisionColor = tex2D(_EmissionTex, IN.texcoord);

接着是像素点的颜色

mainColor.rgb = mainColor.rgb * _MainColorTimes
+ _Emission1 * mainColor.a * _EmissionColorTimes1
+ _Emission2 * (1 - mainColor.a) * emisionColor.a * _EmissionColorTimes2;

像素点的颜色由三方面组成:

1.剑主体贴图的颜色。

2.剑体自发光的颜色。

3.剑体周围光晕的颜色。

1.剑主体贴图的颜色。

     mainColor.rgb * _MainColorTimes

这里将剑体本身的颜色乘以_MainColorTimes参数来把剑体本身颜色增强,以免在光晕中显得单薄。

2.剑体自发光的颜色。

     _Emission1 * mainColor.a * _EmissionColorTimes1

_Emission1是剑体发光颜色参数,乘以mainColor.a主贴图的Alpha值使其剑本体上有颜色变化,在剑体以外,也就是Alpha值为0的地方无效;最后乘以_EmissionColorTimes1颜色增强参数同样用于将发光色增强。

3.剑体周围光晕的颜色。

     _Emission2 * (1 - mainColor.a) * emissionColor.a * _EmissionColorTimes2

_Emission2是剑体周围发光颜色参数,乘以(1 - mainColor.a) 使其剑本体以外有颜色变化,在剑体本身,也就是Alpha值大于0的地方影响减弱或不影响;接着乘以emissionColor.a 也就是Alpha贴图的Alpha值使光晕效果根据Alpha贴图的Alpha值渐变显示出向周围渐渐变淡的效果,最后乘以_EmissionColorTimes2颜色增强参数同样用于将发光色增强。

通过这三种颜色的叠加,实现了剑体颜色,剑体自发光和周围光晕的效果。

最后是像素点颜色透明度Alpha值的计算:

 mainColor.a = max(mainColor.a, pow(emisionColor.a, _EmissionAlphaExponent) * _EmissionAlphaTimes) * _AllAlpha;

输出颜色的透明度等于剑主体的透明度和周围光晕的透明度间的最大值最后乘以_AllAlpha参数,取最大值的原因在于使剑体和光晕得以显示,因为在第一张贴图中,除剑体以外部分的Alpha值都是0,所以需要将周围光晕本身的Alpha值也给计算进去。

CGpow(emisionClolor.a, _EmissionAlphaExponent) * _EmissionAlphaTimes是计算剑体周围光晕Alpha值的公式,也许你有疑问,这里直接取第二章贴图的Alpha值不就好了,为啥要搞这么复杂的计算?

首先pow()是一个指数运算方法,他将Alpha贴图的Alpha值进行了指数运算,使得其渐变率变得更加明显,这么做的原因是在Shader的实现过程中发现在Alpha贴图外侧,也就是Alpha值变低时会有黑边的效果,样子如下

通过这个指数运算,可以明显的减缓这种问题,接着乘以_EmissionAlphaTimes参数同样是为了增强Alpha值的效果,以达到让光晕更加明显的效果但同时也会增强黑边的问题,所以这个值需要跟_EmissionAlphaExponent参数进行配合使用。

在Alpha值计算的最后,还将总的Alpha值乘以_AllAlpha参数,这是为了实现光晕的呼吸闪烁效果,通过在Unity里面创建Animation来变化这个_AllAlpha参数,可以实现想要的效果。

Unity光晕剑效果的Shader简单实现的更多相关文章

  1. 今天写shader流光效果,shader代码少了个括号,unity shader compiler卡死且不提示原因

    今天写shader流光效果,shader代码少了个括号,unity shader compiler卡死且不提示原因 好在找到了原因,shader 代码如下,原理是提高经过的颜色亮度 void surf ...

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

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

  3. unity,荧光效果(bloom)实现过程

    两个月前,刚接触unity的时候费了半天劲儿做了个荧光效果(见:http://www.cnblogs.com/wantnon/p/4430749.html),今天终于抽空整理了一下,把过程写下来. 荧 ...

  4. Android高级控件(四)——VideoView 实现引导页播放视频欢迎效果,超级简单却十分的炫酷

    Android高级控件(四)--VideoView 实现引导页播放视频欢迎效果,超级简单却十分的炫酷 是不是感觉QQ空间什么的每次新版本更新那炫炫的引导页就特别的激动,哈哈,其实他实现起来真的很简单很 ...

  5. Unity 阴影淡入淡出效果中Shader常量 unity_ShadowFadeCenterAndType和_LightShadowData的问题

    由于Universal Render Pipeline目前(2020年4月1日)把阴影淡入淡出这个功能竟然给取消了…我自己拿片元位置到相机位置的距离进行了一个淡化,但是阴影边缘老是被裁切…后来研究了一 ...

  6. Surface Shader简单向导

    Surface Shader 表面着色器 描述 当你的Material要处理光照,则一般使用Surface Shader.Surface Shader隐藏了光照的计算,你只需要在surf函数里设置好反 ...

  7. 解读Unity中的CG编写Shader系列十 (光滑的镜面反射(冯氏着色))

    前文完成了最基本的镜面反射着色器,单平行光源下的逐顶点着色(per-vertex lighting),又称为古罗着色(Gouraud shading).这篇文章作为后续讨论更光滑的镜面反射方式,逐像素 ...

  8. 解读Unity中的CG编写Shader系列八(多光源漫反射)

    转自http://www.itnose.net/detail/6117338.html 前文中完成最简单的漫反射shader只是单个光源下的漫反射,而往往场景中不仅仅只有一个光源,那么多个光源的情况下 ...

  9. 解读Unity中的CG编写Shader系列三

    转自http://www.itnose.net/detail/6096068.html 在上一个例子中,我们得到了由mesh组件传递的信息经过数学转换至合适的颜色区间以颜色的形式着色到物体上.这篇文章 ...

随机推荐

  1. 使用jquery插件实现图片延迟加载--懒加载技术

    原文链接:http://www.cnblogs.com/lei2007/archive/2013/05/31/3110725.html 感谢作者.以下为原文,备忘仅供自己学习. 第一:lazyLoad ...

  2. hdu1054

    /* [题意] 给定一棵树,标记一节点,则与该节点所连的边都被标记,问最少需要标记多少个节点使得所有边都被标记: 或者说给定一个树型城堡,在交叉路口放一个士兵,则与该路口相连的路都被守住, 问最少需要 ...

  3. Enigma模拟-Python

    设计思想 Enigma机的机械结构: 键盘:加密人员通过键盘进行输入 转子:Enigma机上一般装有至少3个转轮.每个转轮有代表26个字母的触头和触点,触点和触头在转轮内部有导线相连(一个转轮相当于一 ...

  4. [Xcode 实际操作]四、常用控件-(4)UILabel文本标签的自动换行

    目录:[Swift]Xcode实际操作 本文将演示标签控件的换行功能, 在项目导航区,打开视图控制器的代码文件[ViewController.swift] import UIKit class Vie ...

  5. Eclipse项目中乱码问题的解决办法

    一.产生的原因: 1.Http协议进行通信的时候是基于请求和响应的,传输的内容我们称之为报文! 2.Http协议会按照一定的规则将报文编码,然后在读取的时候再使用响应的解码格式进行解码! 3.这个一定 ...

  6. Shell操作相关的快捷键 --Linux

    一.shell和bash shell --unix --Bourne shell ,bash --linux --Bourne again shell.bash (GNU Bourne-Again S ...

  7. [sql Server]除非另外还指定了TOP 或 FOR XML,否则,ORDER BY 子句在视图、内联函数、派生表、子查询和公用表表达式中无效

    今天遇到一个奇怪的问题,项目突然要从mysql切换到sql server数据库,包含order by 子句的嵌套子查询报错. 示例:select top 10 name,age,sex from ( ...

  8. 洛谷P5280 [ZJOI2019]线段树

      https://www.luogu.org/problemnew/show/P5280 省选的时候后一半时间开这题,想了接近两个小时的各种假做法,之后想的做法已经接近正解了,但是有一些细节问题理不 ...

  9. java——String、StringBuffer、StringBuilder、包装类、单双引号

    String: String是一个特殊的类,被定义为final类型,为字符串常量,同样的字符串在常量池中不能重复. 但是由于使用关键字new创建新的字符串,java会在对中分配新的空间,这样即使字符串 ...

  10. JavaScript事件模型及事件代理

    事件模型 JavaScript事件使得网页具备互动和交互性,我们应该对其深入了解以便开发工作,在各式各样的浏览器中,JavaScript事件模型主要分为3种:原始事件模型.DOM2事件模型.IE事件模 ...