很多游戏Logo中可以看到这种流光效果,一般的实现方案就是对带有光条的图片uv根据时间进行移动,然后和原图就行叠加实现,不过实现过程中稍稍有点需要注意的地方。之前考虑过风宇冲的实现方式,但是考虑到shader中太多的计算,还是放弃了。

基础版本

Shader "UICustom/ImageFlashEffect2"
{
Properties
{
_MainTex ("Main Texture", 2D) = "white" {} _LightTex ("Light Texture", 2D) = "white" {} _LightColor("Light Color",Color) = (1,1,1,1) _LightPower("Light Power",Range(0,5)) = 1 //每次持续时间,受Angle和Scale影响
_LightDuration("Light Duration",Range(0,10)) = 1
//时间间隔,受Angle和Scale影响
_LightInterval("Light Interval",Range(0,20)) = 3
} SubShader
{
Tags
{
"Queue"="Transparent"
"IgnoreProjector"="True"
"RenderType"="Transparent"
} Cull Off
Lighting Off
ZWrite Off
Fog { Mode Off }
Offset -1, -1
Blend SrcAlpha OneMinusSrcAlpha
AlphaTest Greater 0.1 Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag #include "UnityCG.cginc" struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
}; struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float2 lightuv : TEXCOORD1;
}; sampler2D _MainTex;
float4 _MainTex_ST; sampler2D _LightTex ;
float4 _LightTex_ST; half _LightInterval ;
half _LightDuration ; half4 _LightColor ;
half _LightPower ; half _LightOffSetX ;
half _LightOffSetY ; v2f vert (appdata v)
{
v2f o;
o.vertex = mul(UNITY_MATRIX_MVP, v.vertex);
fixed currentTimePassed = fmod(_Time.y,_LightInterval);
//uv offset, Sprite wrap mode need "Clamp"
fixed offsetX = currentTimePassed / _LightDuration;
fixed offsetY = currentTimePassed / _LightDuration;
fixed2 offset ;
offset.x = offsetX - 0.5f;
offset.y = offsetY - 0.5f; o.lightuv = v.uv + offset ; o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.lightuv = TRANSFORM_TEX(o.lightuv, _LightTex);
return o;
} fixed4 frag (v2f i) : SV_Target
{
fixed4 mainCol = tex2D(_MainTex, i.uv);
fixed4 lightCol = tex2D(_LightTex, i.lightuv);
lightCol *= _LightColor ; //need blend
//lightCol.rgb *= mainCol.rgb ;
fixed4 fininalCol ;
fininalCol.rgb = mainCol.rgb + lightCol.rgb * _LightPower;
fininalCol.a = mainCol.a * lightCol.a ;
return fininalCol ;
}
ENDCG
}
}
}

需要注意的点:

  1. 时间间隔问题
fixed currentTimePassed = fmod(_Time.y,_LightInterval);
//uv offset, Sprite wrap mode need "Clamp"
fixed offsetX = currentTimePassed / _LightDuration;
fixed offsetY = currentTimePassed / _LightDuration;

offsetX 、offsetY其实是0~_LightInterval的数值,需要设置图片为光线图片的Wrap模式为Clamp,才能实现时间间隔控制

  1. 色彩融合

    Pixel着色器中frag()函数是通过原始颜色和光线颜色叠加的方式实现的,也有将光线颜色和原图混合后再叠加的做法,这个我觉得看实际应用。注意alpha的控制

优化

1. 增加角度和大小控制

基本版本的实现中光线只能根据流光图片中亮线的宽度和方向决定实际的滚动方向和大小。有时候如果需要经常调节方向和大小,可以考虑加入相关因素。流光的Uv是通过原图当前Uv加上时间轴参数获得,可以考虑通过修改流光uv的计算方式来实现。如下面代码。不过这种方式增加了一定计算量,不需要的话则直接跳过。还有一点就是流光贴图必须是垂直或者水平。

float2 base = v.uv ;
base.x -= _LightOffSetX ;
base.y -= _LightOffSetX ;
base = base / _LightScale ; float2 base2 = v.uv;
base2.x = base.x * cosInRad - base.y * sinInRad ;
base2.y = base.y * cosInRad + base.x * sinInRad ; o.lightuv = base2 + offset ;
材质复用

只是想不同的图片都是使用相同的材质,应该保证每个图片的效果都可以独立进行修改保存,可以考虑每张图片都创建一份材质,然后修改其参数。

   void UpdateParam()
{
if (Material == null)
{
Debug.LogWarning("Metarial is miss");
return;
} if (mGraphic == null)
{
mGraphic = GetComponent<MaskableGraphic>();
} if (mGraphic is Text)
{
Debug.LogError("FlashEffec need component type of Image、RawImage");
return;
} if (mDynaMaterial == null)
{
mDynaMaterial = new Material(Material);
mDynaMaterial.name = mDynaMaterial.name + "(Copy)";
mDynaMaterial.hideFlags = HideFlags.DontSave | HideFlags.NotEditable;
} if (mDynaMaterial == null)
{
return;
} mDynaMaterial.mainTexture = null;
if (OverrideTexture != null)
{
mDynaMaterial.mainTexture = OverrideTexture; if (mGraphic is RawImage)
{
RawImage img = mGraphic as RawImage;
img.texture = null;
}
else if (mGraphic is Image)
{
Image img = mGraphic as Image;
img.sprite = null;
}
}
else
{
mDynaMaterial.mainTexture = mGraphic.mainTexture;
} if (Duration > Interval)
{
Debug.LogWarning("ImageFlashEffect.UpdateParam:Duration need less Interval");
Interval = Duration + 0.5f;
} mDynaMaterial.SetColor("_LightColor", Color);
mDynaMaterial.SetFloat("_LightPower", Power);
mDynaMaterial.SetFloat("_LightScale", Scale);
mDynaMaterial.SetFloat("_LightAngle", Angle);
mDynaMaterial.SetFloat("_LightDuration", Duration);
mDynaMaterial.SetFloat("_LightInterval", Interval);
mDynaMaterial.SetFloat("_LightOffSetX", OffSet);
mGraphic.material = mDynaMaterial;
mGraphic.SetMaterialDirty();
}

下载:https://github.com/carlosCn/Unity_Image_Flash_Effect

参考

http://blog.csdn.net/qq992817263/article/details/51200424

http://qkxue.net/info/169189/Unity-Simple-Shaderlab-uGui-shader-1

Unity Shader 效果(1) :图片流光效果的更多相关文章

  1. Unity shader学习之屏幕后期处理效果之高斯模糊

    高斯模糊,见 百度百科. 也使用卷积来实现,每个卷积元素的公式为: 其中б是标准方差,一般取值为1. x和y分别对应当前位置到卷积中心的整数距离. 由于需要对高斯核中的权重进行归一化,即使所有权重相加 ...

  2. Flash 用FLASH遮罩效果做图片切换效果

    本教程是关于FLASH应用遮罩效果制作好看的图片切换效果.该教程选用FLASH遮罩中最简单的一种作为例子,当然你可以用自己的想象力来做出更多更好的图片动画.希望本教程能带你带来帮助. 让我们先看看效果 ...

  3. Unity shader学习之屏幕后期效果之调整屏幕亮度,饱和度,对比度

    Unity的屏幕后期处理效果,使用MonoBehaviour.OnRenderImage来实现. 转载请注明出处:http://www.cnblogs.com/jietian331/p/7228063 ...

  4. Unity shader学习之屏幕后期处理效果之运动模糊

    运动模糊,代码如下: using UnityEngine; public class MotionBlurRenderer : PostEffectRenderer { [Range(0.1f, 0. ...

  5. Unity shader学习之屏幕后期处理效果之Bloom效果

    Bloom特效是游戏中常见的一种屏幕效果.这种特效可以模拟真实摄像机的一种图像效果,它让画面中较亮的区域“扩散”到周围的区域中,造成一种朦胧的效果. Bloom的实现原理很简单,首先根据一个阈值提取出 ...

  6. Unity shader学习之屏幕后期处理效果之均值模糊

    均值模糊,也使用卷积来实现,之不过卷积中每个值均相等,且相加等于1. 代码如下, 子类: using UnityEngine; public class MeanBlurRenderer : Post ...

  7. Unity shader学习之屏幕后期处理效果之边缘检测

    边缘检测的原理是利用一些边缘检测算子对图像进行卷积操作. 转载请注明出处:http://www.cnblogs.com/jietian331/p/7232707.html 例如: 代码如下: usin ...

  8. Unity shader学习之屏幕后期处理效果之高度雾,重建world pos方法2

    这里使用一种更高效地从深度纹理中重建世界坐标的方法. 首先计算摄像机的视锥体的四条射线向量进行线性插值,插值后的值便是该像素在世界空间坐标下到摄像机的方向. 然后通过与深度值相乘即可得到摄像机位置到该 ...

  9. Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础

    来源作者:candycat   http://blog.csdn.net/candycat1992/article/ 概述 总体来说,在Unity中我们需要配合使用材质和Unity Shader才能达 ...

随机推荐

  1. multipart upload

    org.springframework.web.multipart.MultipartException: Could not parse multipart servlet request; nes ...

  2. [转]如何在Angular4中引入jquery

    本文转自:https://blog.csdn.net/home_zhang/article/details/77992734 1.anjq是我的项目名称: 在anjq目录下打开dos命令窗口,然后依次 ...

  3. c# 调用微吼直播API

    /// <summary> /// 调用微吼直播API /// </summary> /// <param name="appKey">< ...

  4. 【Spring】17、spring cache 与redis缓存整合

    spring cache,基本能够满足一般应用对缓存的需求,但现实总是很复杂,当你的用户量上去或者性能跟不上,总需要进行扩展,这个时候你或许对其提供的内存缓存不满意了,因为其不支持高可用性,也不具备持 ...

  5. Java基础IO流(一)

    IO概念: 大多数应用程序都需要实现与设备之间的数据传输,例如键盘可以输入数据,显示器可以显示程序的运行结果等.在Java中,将这种通过不同输入输出设备(键盘,内存,显示器,网络等)之间的数据传输抽象 ...

  6. Vue Document

    目录 VUE笔记 环境搭建 Vue学习笔记 1.Vue指令 VUE笔记 环境搭建 node -v npm -v npm i -g cnpm --registry=https://registry.np ...

  7. [代码笔记]VUE路由根据返回状态判断添加响应拦截器

    //返回状态判断(添加响应拦截器) Axios.interceptors.response.use( res => { //对响应数据做些事 if (res.data && !r ...

  8. Vue2 几种常见开局方式

    在SF问题中看到了一个关于vue-cli中的template问题,问题是这样的:用vue-cli工具生成的main.js中: import Vue from 'vue' import App from ...

  9. HDU 2586 How far away ?

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission( ...

  10. 进入root提示Authentication failure错误

    新安装Ubuntu 18.4,想进入root角色,提示“Authentication failure” 失败. 因为是新安装,并无root的密码,所以需要新增加: sudo passwd root,之 ...