最近遇到了一个需求,想要一种在刀剑上带有光晕的酷炫效果,甚至是还想要有闪烁呼吸效果,于是就写了一个简单的叫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. linux 统计 程序 运行时间

    测试 代码运行时间 linux 中的 <sys/time.h> 中 有个函数可以获取当前时间,精确到 微秒 ---->  gettimeofday() #include <sy ...

  2. 1. sqlmap超详细笔记+思维导图

    sqlmap思维导图: 基本操作笔记: -u #注入点 -f #指纹判别数据库类型 -b #获取数据库版本信息 -p #指定可测试的参数(?page=1&id=2 -p "page, ...

  3. eclipse中导入项目后提示错误:The project was not built due to"Could not delete'/文件夹路径名

    eclipse中导入项目 1.新建一个项目: 2.把已存在的项目的所有文件复制到该新建的项目下: 3.把lib文件夹中的jar导入:(右键-)add into path……): 4.常见问题如下 ec ...

  4. Python:列表也能拆包?

    前几天,微信学习群里有个小伙伴在看书时遇到了这样一个问题,在群里提问,看下图: 这是常用的 matplotlib 库,只是一般我们调用 plot 方法绘图时,不会去关心它的返回值.然而 plt1, = ...

  5. 萌新在线模板--keyboarder_zsq

    好像马上就要出去打铁了QAQ,所以是不是要做个模板带过去也玩一玩? 那就做吧... 标题就设为萌新模板吧...各种萌新讲解对吧.... 图论 拓扑排序 最短路 最小生成树 二分匹配 强连通Tarjan ...

  6. python之02数据类型学习-作业练习2

    引用博客地址:http://www.cnblogs.com/yuanchenqi/articles/5782764.html 作业描述: 省 市 县的三层数据通过字典 元祖 列表 保存起来执行程序后 ...

  7. elasticsearch 基本介绍

    1. Elasticsearch的适用场景: (1)类似百度百科的全文检索,高亮,搜索推荐(2)新闻类的搜索,用户行为日志(点击,浏览,收藏,评论)+社交网络数据(对某某新闻的相关看法),数据分析,给 ...

  8. 796D(bfs)

    题目链接: http://codeforces.com/problemset/problem/796/D 题意: 给出一颗 n 个节点树, 树枝连接的两个定点距离为 1, 树中有 k 个特殊点, 问最 ...

  9. iOS常用设计模式——工厂方法(简单工厂模式,工厂方法模式, 抽象工厂模式)

    1. 简单工厂模式 如何理解简单工厂,工厂方法, 抽象工厂三种设计模式? 简单工厂方法包含:父类拥有共同基础接口,具体子类实现子类特殊功能,工厂类根据参数区分创建不同子类实例.该场景对应的UML图如下 ...

  10. EIGRP-5-EIGRP数据包格式

    EIGRP数据包直接承戟在IP数据包中.协议号为88.EIGRP数据包的最大长度取决于具体接口上的最大IP MTU设置——通常完整IP数据包为1500字节.其中1480字节可以用于 EIGRP数据包. ...