Shader "Elastic"
{
Properties
{
_MainTex("Texture", 2D) = "white" {}
_Position("xyz:position,w:range",vector) = (0,0,0,1)
_Normal("xyz:normal,w:intensity",vector) = (0,1,0,0)
_PointTime("point time",float) = 0
_Duration("duration",float) = 2
_Frequency("frequency",float) = 5
}
SubShader
{
Tags { "RenderType" = "Opaque" }
LOD 100
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
// make fog work
#pragma multi_compile_fog
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
UNITY_FOG_COORDS(1)
float4 vertex : SV_POSITION;
};
sampler2D _MainTex;
float4 _MainTex_ST;
float4 _Position;
float4 _Normal;
float _PointTime;
float _Duration;
float _Frequency;
v2f vert(appdata v)
{
v2f o;
float t = _Time.y - _PointTime;
if (t>0&&t<_Duration)
{
float r = 1 - saturate(length(v.vertex.xyz - _Position.xyz) / _Position.w);
float l = 1 - t / _Duration;
v.vertex.xyz += r * l * _Normal.xyz * _Normal.w * cos(t * _Frequency);
}
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
UNITY_TRANSFER_FOG(o, o.vertex);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
UNITY_APPLY_FOG(i.fogCoord, col);
return col;
}
ENDCG
}
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
interface IElastic
{
void OnElastic(RaycastHit hit);
}
[RequireComponent(typeof(MeshRenderer))]
public class ElasticObject : MonoBehaviour, IElastic
{
private static int s_pos, s_nor, s_time;
static ElasticObject()
{
s_pos = Shader.PropertyToID("_Position");
s_nor = Shader.PropertyToID("_Normal");
s_time = Shader.PropertyToID("_PointTime");
}
private MeshRenderer mesh;
private void Start()
{
mesh = GetComponent<MeshRenderer>();
}
//调用该方法
public void OnElastic(RaycastHit hit)
{
//反弹的坐标
Vector4 v = transform.InverseTransformPoint(hit.point);
//受影响顶点范围的半径
v.w = 0.6f;
mesh.material.SetVector(s_pos, v);
//法线方向,该值为顶点偏移方向,可自己根据需求传。
v = transform.InverseTransformDirection(hit.normal.normalized);
//反弹力度
v.w = 0.2f;
mesh.material.SetVector(s_nor, v);
//重置时间
mesh.material.SetFloat(s_time, Time.time);
}
private void Update()
{
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Input.GetMouseButtonDown(0))
{
if (Physics.Raycast(ray, out hit))
{
OnElastic(hit);
}
}
}
}