效果图
因为csdn有图片大小限定,所以适当减去了点。
图中效果为:能量护盾的收缩,以及与外界collider的碰撞交互效果。
准备模型(BLENDER)
使用Blender制作一个棱角球。
点开插件面板添加一个tissue插件
添加后,点击插件面板这个按钮
就能得到这样的网格了
重置uv
网格由五边面和六边面构成,调整uv布局
选中所有的无边面,调整所有的五边面uv布局为左下角,再ctrl+i反选,调整六边面在右上角(uv面板中g移动,s缩放等操作依然适用)
然后导出uv布局图
制作表面贴图(PS)
uv布局图起始效果如下
使用色彩范围选中黑色边缘,在新建图层中填充(可以使用快捷键ctrl+delete填充前景色)为白色。
再反选,新建图层作为背景,填充为黑色。得到如下效果
双击白边所在图层,进入图层样式编辑,选择外发光调整至合适发光边缘
导出贴图放入Unity
实现效果代码
shader方面就是菲涅尔+顶点动画(使用了_SinTime达到波动效果)+HDR颜色模式(在属性名前面加上[HDR]即可)
关键是如何实现互动。
给棱角球加上一个互动脚本,当碰撞发生时(碰撞发生条件是双方都有collider,其中至少一方含有rigbody组件),传入碰撞点的信息到shader中,在shader中比较当前顶点距离碰撞点的距离,使用smoothstep把距离限制在0-1之间,还能根据参数调整遮罩边缘,再把这个距离值乘上一层护盾颜色。
以下为互动脚本:
using UnityEngine;
public class InteractSphere : MonoBehaviour
{
public Material material;
private void OnCollisionEnter(Collision other)
{
material.SetVector("_InteractPoint", other.contacts[0].point);
material.SetFloat("_Toggle", 1);//使用toggle控制是否输入顶点有效
}
private void OnCollisionExit(Collision other)
{
material.SetFloat("_Toggle", 0);
}
}
以下为shader代码:
Shader "Unlit/Shield"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
[HDR]_Color("颜色",Color)=(1,1,1,1)
_Strength("波浪度",Range(0,1))=0
_Distance("扩散距离",Range(0,0.05))=0.01
_FresnelPower("菲涅尔power",Range(0,10))=5
_FresnelScale("菲涅尔比例",Range(0,1))=1
_MaskRadius("遮罩半径",Range(0,3))=0
_MaskSmooth("羽化",Range(0,1))=0
[HDR]_CollisionColor("碰撞颜色",Color)=(1,1,1,1)
}
SubShader
{
Tags { "RenderType"="transparent" "queue"="transparent"}
LOD 100
Pass
{
blend srccolor one
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
float _Strength;
float _Distance;
float _FresnelPower;
float4 _Color;
float _FresnelScale;
float4 _InteractPoint;
float _MaskSmooth;
float4 _CollisionColor;
float _Toggle;
float _MaskRadius;
struct appdata
{
float4 vertex : POSITION;
float3 normal:NORMAL;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 objPos:TEXCOORD1;
float3 worldNormal:TEXCOORD2;
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
v2f vert (appdata v)
{
v2f o;
v.vertex+=_Distance*float4((_Strength+_SinTime.w)*v.normal,0);
o.objPos=v.vertex;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
o.worldNormal=normalize(UnityObjectToWorldNormal(v.normal));
UNITY_TRANSFER_FOG(o,o.vertex);
return o;
}
fixed4 frag (v2f i) : SV_Target
{
float4 worldPos=mul(unity_ObjectToWorld,i.objPos);
float dt=smoothstep(_MaskRadius+_MaskSmooth,_MaskRadius-_MaskSmooth,distance(worldPos,_InteractPoint));
float3 viewDir=normalize(WorldSpaceViewDir(i.objPos));
float fresnel=_FresnelScale*pow(1-abs(dot(viewDir,i.worldNormal)),_FresnelPower);
// sample the texture
fixed4 col =tex2D(_MainTex, i.uv)*(fresnel*_Color+_CollisionColor*dt*_Toggle);
// apply fog
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}