[Unity Shader] 高级护罩Shader
2019-02-04 本文已影响0人
m969
MagicShield.png
MagicShield3.gif
MagicShield.gif
C#脚本代码(需要导入DOTween插件):
这个脚本用于监听检测球体的射线碰撞事件,然后把碰撞的点存到数组里传给shader
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using DG.Tweening;
public class MagicShield : MonoBehaviour {
public Material shieldMaterial;
public int pointsCount = 20;
public float pointRange = 0.5f;
public float inTime = 0.5f;
public float outTime = 0.5f;
public Ease ease;
public List<HitPoint> hitPoints = new List<HitPoint>();
public List<Vector4> vecArray = new List<Vector4>();
void Start () {
for (int i = 0; i < pointsCount; i++)
{
hitPoints.Add(new HitPoint());
vecArray.Add(Vector4.zero);
}
}
void Update () {
if (Input.GetMouseButtonDown(0))
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit raycastHit;
if (Physics.Raycast(ray, out raycastHit, 100))
{
var index = -1;
foreach (var item in hitPoints)
{
if (item.complete)
{
index = hitPoints.IndexOf(item);
break;
}
}
if (index >= 0)
{
var hitPoint = new HitPoint();
hitPoint.complete = false;
hitPoint.position = new Vector4(raycastHit.point.x, raycastHit.point.y, raycastHit.point.z, 0);
hitPoints[index] = hitPoint;
DOTween.To(() => hitPoint.range, x => hitPoint.range = x, pointRange, inTime).OnComplete(() => { DOTween.To(() => hitPoint.range, x => hitPoint.range = x, 0f, outTime).OnComplete(() => { hitPoint.complete = true; }).SetEase(ease); }).SetEase(ease);
}
}
}
foreach (var item in hitPoints)
{
var p = item.position;
item.position = new Vector4(p.x, p.y, p.z, item.range);
vecArray[hitPoints.IndexOf(item)] = item.position;
}
shieldMaterial.SetVectorArray("_Array", vecArray);
}
}
public class HitPoint
{
public Vector4 position = Vector4.zero;
public float time = 0;
public float range = 0.1f;
public bool complete = true;
}
Shader代码:
Shader "MagicFire/MagicShield"
{
Properties
{
_Main("Main", 2D) = "bump" {}
_Emission("Emission", Color) = (0,0,0,0)
_Light("Light", Range(0 , 2)) = 0.4
_Opacity("Opacity", Range(0 , 1)) = 0.4823529
_Eimssion("Eimssion", Range(0 , 1)) = 2
_Smoothness("Smoothness", Range(0 , 1)) = 1
[HideInInspector] _texcoord("", 2D) = "white" {}
[HideInInspector] __dirty("", Int) = 1
}
SubShader
{
Tags{ "RenderType" = "Transparent" "Queue" = "Transparent+0" "IgnoreProjector" = "True" "IsEmissive" = "true" }
Cull Back
CGPROGRAM
#include "UnityPBSLighting.cginc"
#include "UnityShaderVariables.cginc"
#pragma target 3.0
#pragma surface surf StandardCustomLighting alpha:fade keepalpha noshadow
struct Input
{
float2 uv_texcoord;
float3 worldNormal;
float3 worldPos;
};
struct SurfaceOutputCustomLightingCustom
{
half3 Albedo;
half3 Normal;
half3 Emission;
half Metallic;
half Smoothness;
half Occlusion;
half Alpha;
Input SurfInput;
UnityGIInput GIData;
};
uniform float4 _Emission;
uniform float _Eimssion;
uniform sampler2D _Main;
uniform float4 _Main_ST;
uniform float _Opacity;
uniform float _Light;
uniform float _Smoothness;
uniform float4 _Array[20];
void surf(Input i , inout SurfaceOutputCustomLightingCustom o)
{
float dist = 0;
float4 color = float4(0.0, 0.0, 0.0, 1.0);
float4 color1 = float4(1.0, 1.0, 1.0, 1.0);
float3 ase_vertex3Pos = mul(unity_WorldToObject, float4(i.worldPos, 1));
//下面的for循环是实现碰撞点高亮功能的主要代码
int count = 0;
for (count = 0; count < 20; count++)
{
float3 hitPos = mul(unity_WorldToObject, float4(_Array[count].xyz, 1));
dist = distance(ase_vertex3Pos, hitPos);
color = (((dist < _Array[count].w) ? ((_Array[count].w - dist) * color1 * 10) : float4(0.0, 0.0, 0.0, 1.0))).xxxx + color;
}
o.SurfInput = i;
o.Emission = (_Emission * _Eimssion).rgb + color;
}
inline void LightingStandardCustomLighting_GI(inout SurfaceOutputCustomLightingCustom s, UnityGIInput data, inout UnityGI gi)
{
s.GIData = data;
}
inline half4 LightingStandardCustomLighting(inout SurfaceOutputCustomLightingCustom s, half3 viewDir, UnityGI gi)
{
UnityGIInput data = s.GIData;
Input i = s.SurfInput;
half4 c = 0;
float2 uv_Main = i.uv_texcoord * _Main_ST.xy + _Main_ST.zw;
float2 panner72 = (0.5 * _Time.y * float2(0.1, 0.1) + uv_Main);
float4 tex2DNode69 = tex2D(_Main, panner72);
SurfaceOutputStandard s82 = (SurfaceOutputStandard)0;
float4 temp_output_75_0 = ((tex2DNode69 * _Emission) + _Light);
s82.Albedo = temp_output_75_0.rgb;
float3 ase_worldNormal = i.worldNormal;
s82.Normal = ase_worldNormal;
s82.Emission = temp_output_75_0.rgb;
s82.Metallic = 0.0;
s82.Smoothness = _Smoothness;
s82.Occlusion = 1.0;
data.light = gi.light;
UnityGI gi82 = gi;
#ifdef UNITY_PASS_FORWARDBASE
Unity_GlossyEnvironmentData g82 = UnityGlossyEnvironmentSetup(s82.Smoothness, data.worldViewDir, s82.Normal, float3(0, 0, 0));
gi82 = UnityGlobalIllumination(data, s82.Occlusion, s82.Normal, g82);
#endif
float3 surfResult82 = LightingStandard(s82, viewDir, gi82).rgb;
surfResult82 += s82.Emission;
c.rgb = surfResult82;
c.a = (tex2DNode69 * _Opacity).r;
return c;
}
ENDCG
}
}
贴图素材:
dissolve-guide.png总结与发现
这个护罩shader我是在ASE里拖出一个大概的护罩效果,然后再在源码的基础上套一个for循环实现碰撞点高亮的效果的。我看了它生成的源码发现Unity的Standard光照模型还可以这样套用,get到了。