H_SafeExperienceDrivingSystem/U3D_DrivingSystem/Assets/Plugin/FXVShieldEffect/Scripts/FXVShield.cs

455 lines
17 KiB
C#

using UnityEngine;
using System.Collections;
using UnityEngine.Rendering;
using System.Collections.Generic;
namespace FXV
{
public enum FXVRenderSidesOptions
{
OUTSIDE_ONLY = 0,
OUTSIDE_AND_INSIDE,
INSIDE_ONLY
};
public class FXVShield : MonoBehaviour
{
public bool shieldActive = true;
public float shieldActivationSpeed = 1.0f;
private float shieldActivationRim = 0.2f;
public float hitEffectDuration = 0.5f;
public Light shieldLight;
public Material hitMaterial;
public Color hitColor;
public bool autoHitPatternScale = true;
public FXVRenderSidesOptions renderSides = FXVRenderSidesOptions.OUTSIDE_ONLY;
private Color lightColor;
private GameObject inside = null;
private Renderer insideRenderer = null;
private Material baseMaterial;
private Material activationMaterial;
private Material postprocessMaterial;
private Material postprocessActivationMaterial;
private Collider myCollider;
private CommandBuffer cmdBuffer;
private Renderer myRenderer;
private float shieldActivationTime;
private float shieldActivationDir;
private int activationTimeProperty;
private int shieldDirectionProperty;
private int mainColorProperty;
private int texColorProperty;
private int patternColorProperty;
private int currentHitIndex = 1;
private static Dictionary<string, Mesh> insideMeshes = new Dictionary<string, Mesh>();
void Awake()
{
myRenderer = GetComponent<Renderer>();
activationTimeProperty = Shader.PropertyToID("_ActivationTime");
shieldDirectionProperty = Shader.PropertyToID("_ShieldDirection");
mainColorProperty = Shader.PropertyToID("_Color");
texColorProperty = Shader.PropertyToID("_TextureColor");
patternColorProperty = Shader.PropertyToID("_PatternColor");
if (Camera.main)
{
FXVShieldPostprocess shieldPostrocess = Camera.main.GetComponent<FXVShieldPostprocess>();
if (shieldPostrocess)
shieldPostrocess.AddShield(this);
}
shieldActivationDir = 0.0f;
if (shieldLight)
lightColor = shieldLight.color;
myCollider = transform.GetComponent<Collider>();
if (shieldActive)
{
shieldActivationTime = 1.0f;
myCollider.enabled = true;
}
else
{
shieldActivationTime = 0.0f;
myCollider.enabled = false;
}
if (shieldLight)
shieldLight.color = Color.Lerp(Color.black, lightColor, shieldActivationTime);
if (renderSides == FXVRenderSidesOptions.OUTSIDE_AND_INSIDE || renderSides == FXVRenderSidesOptions.INSIDE_ONLY)
{
inside = new GameObject("inside");
inside.transform.parent = transform;
inside.transform.localPosition = Vector3.zero;
inside.transform.localScale = Vector3.one;
inside.transform.localRotation = Quaternion.identity;
inside.layer = gameObject.layer;
inside.AddComponent<MeshRenderer>();
MeshFilter mf = inside.AddComponent<MeshFilter>();
Mesh baseMesh = gameObject.GetComponent<MeshFilter>().mesh;
string insideMeshName = baseMesh.name + "_inside";
Mesh flippedMesh = null;
if (insideMeshes.ContainsKey(insideMeshName))
flippedMesh = insideMeshes[insideMeshName];
else
{
//Debug.Log("create inside mesh " + insideMeshName);
flippedMesh = Instantiate(baseMesh);
Vector3[] normals = flippedMesh.normals;
for (int i = 0; i < normals.Length; i++)
normals[i] = -normals[i];
flippedMesh.normals = normals;
for (int m = 0; m < flippedMesh.subMeshCount; m++)
{
int[] triangles = flippedMesh.GetTriangles(m);
for (int i = 0; i < triangles.Length; i += 3)
{
int temp = triangles[i + 0];
triangles[i + 0] = triangles[i + 1];
triangles[i + 1] = temp;
}
flippedMesh.SetTriangles(triangles, m);
}
insideMeshes.Add(insideMeshName, flippedMesh);
}
mf.mesh = flippedMesh;
insideRenderer = inside.GetComponent<Renderer>();
insideRenderer.sortingOrder = insideRenderer.sortingOrder - 1;
MeshCollider mc = inside.AddComponent<MeshCollider>();
mc.sharedMesh = flippedMesh;
}
if (renderSides == FXVRenderSidesOptions.INSIDE_ONLY)
myRenderer.enabled = false;
SetMaterial(myRenderer.material);
SetHitMaterial(hitMaterial);
}
void OnDestroy()
{
if (Camera.main)
{
FXVShieldPostprocess shieldPostrocess = Camera.main.GetComponent<FXVShieldPostprocess>();
if (shieldPostrocess)
shieldPostrocess.RemoveShield(this);
}
if (inside)
{
Destroy(inside.GetComponent<MeshFilter>().mesh);
}
if (baseMaterial)
Destroy(baseMaterial);
if (postprocessMaterial)
Destroy(postprocessMaterial);
if (postprocessActivationMaterial)
Destroy(postprocessActivationMaterial);
if (activationMaterial)
Destroy(activationMaterial);
}
public void SetHitMaterial(Material newMat)
{
hitMaterial = newMat;
}
public void SetMaterial(Material newMat)
{
if (baseMaterial)
Destroy(baseMaterial);
if (postprocessMaterial)
Destroy(postprocessMaterial);
if (postprocessActivationMaterial)
Destroy(postprocessActivationMaterial);
if (activationMaterial)
Destroy(activationMaterial);
baseMaterial = new Material(newMat);
baseMaterial.SetFloat(activationTimeProperty, 1.0f);
postprocessMaterial = new Material(baseMaterial);
List<string> keywords = new List<string>(postprocessMaterial.shaderKeywords);
if (keywords.Contains("USE_REFRACTION"))
keywords.Remove("USE_REFRACTION");
if (keywords.Contains("ACTIVATION_EFFECT_ON"))
keywords.Remove("ACTIVATION_EFFECT_ON");
postprocessMaterial.shaderKeywords = keywords.ToArray();
postprocessMaterial.SetVector(shieldDirectionProperty, new Vector4(1.0f, 0.0f, 0.0f, 0.0f));
postprocessActivationMaterial = new Material(baseMaterial);
keywords = new List<string>(postprocessActivationMaterial.shaderKeywords);
if (keywords.Contains("USE_REFRACTION"))
keywords.Remove("USE_REFRACTION");
postprocessActivationMaterial.shaderKeywords = keywords.ToArray();
postprocessActivationMaterial.SetVector(shieldDirectionProperty, new Vector4(1.0f, 0.0f, 0.0f, 0.0f));
activationMaterial = new Material(baseMaterial);
shieldActivationRim = activationMaterial.GetFloat("_ActivationRim");
keywords = new List<string>(baseMaterial.shaderKeywords);
if (keywords.Contains("ACTIVATION_EFFECT_ON"))
{
//Debug.Log("remove ACTIVATION_EFFECT_ON");
keywords.Remove("ACTIVATION_EFFECT_ON");
}
baseMaterial.shaderKeywords = keywords.ToArray();
myRenderer.sharedMaterial = baseMaterial;
if (insideRenderer)
insideRenderer.sharedMaterial = baseMaterial;
SetShieldEffectDirection(new Vector3(1.0f, 0.0f, 0.0f));
}
public void SetMainColor(Color c)
{
activationMaterial.color = c;
baseMaterial.color = c;
myRenderer.sharedMaterial.color = c;
postprocessMaterial.color = c;
postprocessActivationMaterial.color = c;
}
public void SetTextureColor(Color c)
{
activationMaterial.SetColor(texColorProperty, c);
baseMaterial.SetColor(texColorProperty, c);
myRenderer.sharedMaterial.SetColor(texColorProperty, c);
postprocessMaterial.SetColor(texColorProperty, c);
postprocessActivationMaterial.SetColor(texColorProperty, c);
}
public void SetPatternColor(Color c)
{
activationMaterial.SetColor(patternColorProperty, c);
baseMaterial.SetColor(patternColorProperty, c);
myRenderer.sharedMaterial.SetColor(patternColorProperty, c);
postprocessMaterial.SetColor(patternColorProperty, c);
postprocessActivationMaterial.SetColor(patternColorProperty, c);
}
public void SetHitColor(Color c)
{
hitColor = c;
}
void Update()
{
if (shieldActivationDir > 0.0f)
{
shieldActivationTime += shieldActivationSpeed * Time.deltaTime;
if (shieldActivationTime >= 1.0f)
{
shieldActivationTime = 1.0f;
shieldActivationDir = 0.0f;
myRenderer.sharedMaterial = baseMaterial;
if (insideRenderer)
insideRenderer.sharedMaterial = baseMaterial;
}
if (shieldLight)
shieldLight.color = Color.Lerp(Color.black, lightColor, shieldActivationTime);
}
else if (shieldActivationDir < 0.0f)
{
shieldActivationTime -= shieldActivationSpeed * Time.deltaTime;
if (shieldActivationTime <= -shieldActivationRim)
{
shieldActivationTime = -shieldActivationRim;
shieldActivationDir = 0.0f;
myRenderer.enabled = false;
myRenderer.sharedMaterial = baseMaterial;
if (insideRenderer)
{
insideRenderer.enabled = false;
insideRenderer.sharedMaterial = baseMaterial;
}
}
if (shieldLight)
shieldLight.color = Color.Lerp(Color.black, lightColor, shieldActivationTime);
}
myRenderer.sharedMaterial.SetFloat(activationTimeProperty, shieldActivationTime);
postprocessActivationMaterial.SetFloat(activationTimeProperty, shieldActivationTime);
}
public bool GetIsShieldActive()
{
return (shieldActivationTime == 1.0f) || (shieldActivationDir == 1.0f);
}
public bool GetIsDuringActivationAnim()
{
return shieldActivationDir != 0.0f;
}
public void SetShieldActive(bool active, bool animated = true)
{
if (animated)
{
shieldActivationDir = (active) ? 1.0f : -1.0f;
if (activationMaterial)
{
activationMaterial.SetFloat("_ActivationRim", shieldActivationRim);
activationMaterial.SetFloat(activationTimeProperty, shieldActivationTime);
postprocessActivationMaterial.SetFloat("_ActivationRim", shieldActivationRim);
postprocessActivationMaterial.SetFloat(activationTimeProperty, shieldActivationTime);
myRenderer.sharedMaterial = activationMaterial;
if (insideRenderer)
insideRenderer.sharedMaterial = activationMaterial;
}
if (active)
{
myRenderer.enabled = (renderSides != FXVRenderSidesOptions.INSIDE_ONLY);
if (insideRenderer)
insideRenderer.enabled = true;
}
}
else
{
shieldActivationTime = (active) ? 1.0f : 0.0f;
shieldActivationDir = 0.0f;
myRenderer.enabled = active;
if (insideRenderer)
insideRenderer.enabled = active;
}
myCollider.enabled = active;
}
public void SetShieldEffectDirection(Vector3 dir)
{
Vector4 dir4 = new Vector4(dir.x, dir.y, dir.z, 0.0f);
myRenderer.material.SetVector(shieldDirectionProperty, dir4);
baseMaterial.SetVector(shieldDirectionProperty, dir4);
activationMaterial.SetVector(shieldDirectionProperty, dir4);
postprocessMaterial.SetVector(shieldDirectionProperty, dir4);
postprocessActivationMaterial.SetVector(shieldDirectionProperty, dir4);
}
public void OnHit(Vector3 hitPos, float hitScale)
{
AddHitMeshAtPos(gameObject.GetComponent<MeshFilter>().mesh, hitPos, hitScale);
Debug.Log(renderSides == FXVRenderSidesOptions.OUTSIDE_AND_INSIDE || renderSides == FXVRenderSidesOptions.INSIDE_ONLY);
if (renderSides == FXVRenderSidesOptions.OUTSIDE_AND_INSIDE || renderSides == FXVRenderSidesOptions.INSIDE_ONLY)
AddHitMeshAtPos(insideRenderer.GetComponent<MeshFilter>().mesh, hitPos, hitScale);
}
private void AddHitMeshAtPos(Mesh mesh, Vector3 hitPos, float hitScale)
{
if(transform.childCount==0)
MBOXManager.Instance.Bonk();
GameObject hitObject = new GameObject("hitFX");
hitObject.transform.parent = transform;
hitObject.transform.position = transform.position;
hitObject.transform.localScale = Vector3.one;
hitObject.transform.rotation = transform.rotation;
Vector3 hitLocalSpace = transform.InverseTransformPoint(hitPos);
Vector3 dir = hitLocalSpace.normalized;
Vector3 tan1 = Vector3.up - dir * Vector3.Dot(dir, Vector3.up);
tan1.Normalize();
Vector3 tan2 = Vector3.Cross(dir, tan1);
MeshRenderer mr = hitObject.AddComponent<MeshRenderer>();
MeshFilter mf = hitObject.AddComponent<MeshFilter>();
mr.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;//--------------------------
mf.mesh = mesh;
mr.material = new Material(hitMaterial);
mr.material.SetVector("_HitPos", hitLocalSpace);
mr.material.SetVector("_HitTan1", tan1);
mr.material.SetVector("_HitTan2", tan2);
mr.material.SetFloat("_HitRadius", hitScale);
mr.material.SetVector("_WorldScale", transform.lossyScale);
mr.material.SetFloat("_HitShieldCovering", 1.0f);
mr.material.renderQueue = mr.material.renderQueue + currentHitIndex;
if (autoHitPatternScale)
{
if (myRenderer.material.HasProperty("_PatternScale"))
mr.material.SetFloat("_PatternScale", myRenderer.material.GetFloat("_PatternScale"));
else
autoHitPatternScale = false;
}
mr.material.color = hitColor;
FXVShieldHit hit = hitObject.AddComponent<FXVShieldHit>();
hit.StartHitFX(hitEffectDuration);
currentHitIndex++;
if (currentHitIndex > 100)
currentHitIndex = 1;
}
public void RenderPostprocess(CommandBuffer cmd)
{
if (myRenderer && gameObject.activeSelf && gameObject.activeInHierarchy)
{
if (myRenderer.enabled)
cmd.DrawRenderer(myRenderer, GetPostprocessMaterial());
if (insideRenderer && insideRenderer.enabled)
cmd.DrawRenderer(insideRenderer, GetPostprocessMaterial());
}
}
public Material GetPostprocessMaterial()
{
if (GetIsDuringActivationAnim())
return postprocessActivationMaterial;
return postprocessMaterial;
}
public Renderer GetRenderer()
{
return myRenderer;
}
}
}