331 lines
13 KiB
C#
331 lines
13 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
[System.Serializable]
|
|
public class LiquidVolumeAnimator : MonoBehaviour {
|
|
|
|
// Use this for initialization
|
|
//just incase we have multiple materials;
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
public Material[] mats;
|
|
//the level of the liquid on a hyperplane.
|
|
[Range(0,1)]
|
|
[SerializeField]
|
|
public float level = 0.5f;
|
|
private float finalLevel;
|
|
|
|
//the current bound given a direction
|
|
public Vector2 minMaxBounds;
|
|
//the mesh to
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
private MeshFilter mf;
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
private MeshRenderer mr;
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
private Mesh m;
|
|
//in order to see how its working, physics is kind of hacked in
|
|
public bool DebugAnchor = false;
|
|
//debugsize is how large the handles are
|
|
public float debugSize = 1.0f;
|
|
//how much mass it has? kind of?
|
|
public float _anchorLength = 0.5f;
|
|
//how much the rotation and movement applies to the anchor
|
|
[Range(0,1)]
|
|
public float dampening;
|
|
//it always wants to be rotated to down
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
private Vector3 anchor;
|
|
//velocity of the direction of 'gravity'
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
private Vector3 anchorVelocity;
|
|
//direction of velocity after clamp. ALSO used to see if the position has changed and use that as a velocity reference;
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
private Vector3 transformedPoint, prevTransformedPoint;
|
|
public bool calculateTextureProjection = true;
|
|
public float TextureSize = 1.0f;
|
|
public float TextureSizeScalar = 1;
|
|
public AnimationCurve texCurveSize = AnimationCurve.Linear(0, 1, 1, 1);
|
|
//for rotation of the texture;
|
|
Quaternion previous;
|
|
float totalRotation = 0.0f;
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
private Vector3 TopLeft, TopRight, BottomLeft, BottomRight;
|
|
|
|
public Transform ExposedLiquidT;
|
|
public Vector3 GravityDirection = Vector3.down;
|
|
public bool normalizeGravityDirection = true;
|
|
//vert cache
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
Vector3[] verts;
|
|
int shader_Key_localHeight;
|
|
int shader_Key_anchor;
|
|
int shader_Key_point;
|
|
int shader_Key_level;
|
|
float prvLevel = -1;
|
|
Quaternion prevQ = Quaternion.identity;
|
|
//for debugging purposes
|
|
//for caching
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
Vector3 cPos = Vector3.zero;
|
|
|
|
//output values:
|
|
public Vector3 finalAnchor, finalPoint;
|
|
[HideInInspector]
|
|
[SerializeField]
|
|
string[] shaderNames;
|
|
void OnDrawGizmosSelected()
|
|
{
|
|
float anchorLength = _anchorLength * Mathf.Max(transform.lossyScale.x, transform.lossyScale.y, transform.lossyScale.z);
|
|
if(DebugAnchor)
|
|
{
|
|
cPos = transform.position;
|
|
//Vector3 prevTransformedPointD = transform.TransformDirection(Vector3.down);
|
|
Vector3 anchorD = cPos - transform.TransformDirection(Vector3.up) * anchorLength;
|
|
if (anchor == Vector3.zero)
|
|
anchor = anchorD;
|
|
//makes sure something is available (even while not playing).
|
|
|
|
CalculateSquare(anchor);
|
|
//the location of the anchor (static)
|
|
Gizmos.DrawSphere(anchorD, 0.25f * transform.lossyScale.magnitude * 0.1f * debugSize);
|
|
//line between the anchor and the surface
|
|
Gizmos.DrawLine(cPos, anchorD);
|
|
Gizmos.color = Color.blue;
|
|
//the ocation of the anchor (physics)
|
|
Gizmos.DrawSphere(anchor, 0.25f * transform.lossyScale.magnitude * 0.1f * debugSize);
|
|
|
|
Gizmos.color = Color.red;
|
|
Gizmos.DrawSphere(cPos - (anchorD - cPos).normalized * finalLevel, 0.1f * transform.lossyScale.magnitude * 0.01f * debugSize);
|
|
//All four corners of the texture
|
|
Gizmos.color = Color.yellow;
|
|
Gizmos.DrawSphere(TopLeft, 0.25f * transform.lossyScale.magnitude * 0.01f * debugSize);
|
|
Gizmos.DrawSphere(TopRight, 0.25f * transform.lossyScale.magnitude * 0.01f * debugSize);
|
|
Gizmos.DrawSphere(BottomLeft, 0.25f * transform.lossyScale.magnitude * 0.01f * debugSize);
|
|
Gizmos.DrawSphere(BottomRight, 0.25f * transform.lossyScale.magnitude * 0.01f * debugSize);
|
|
Gizmos.color = Color.white;
|
|
CalculateSquare(anchor);
|
|
}
|
|
}
|
|
|
|
void CalculateSquare(Vector3 anch)
|
|
{
|
|
if (!calculateTextureProjection)
|
|
{
|
|
return;
|
|
}
|
|
Vector3 pos1 = cPos - (anch - cPos).normalized * finalLevel;
|
|
Vector3 nrm = (cPos - (anch - cPos).normalized * finalLevel - anch).normalized;
|
|
Vector3 beginningRight = Quaternion.Euler(0, totalRotation, 0) * Vector3.right;
|
|
Vector3 f1 = Vector3.Cross(beginningRight, nrm.normalized).normalized;
|
|
Vector3 r1 = Vector3.Cross(f1, nrm).normalized;
|
|
f1 = Vector3.Cross(r1, nrm).normalized;
|
|
float tSize = TextureSize * texCurveSize.Evaluate(Mathf.Clamp01(level)) * transform.lossyScale.magnitude * 0.001f;
|
|
|
|
TopLeft = r1 * tSize + f1 * tSize + pos1;
|
|
TopRight = r1 * tSize * -1 + f1 * tSize + pos1;
|
|
BottomLeft = r1 * tSize + f1 * tSize * -1 + pos1;
|
|
BottomRight = r1 * tSize * -1 - f1 * tSize + pos1;
|
|
}
|
|
|
|
void Start ()
|
|
{
|
|
cPos = transform.position;
|
|
shader_Key_localHeight = Shader.PropertyToID ("_localHeight");
|
|
shader_Key_anchor = Shader.PropertyToID ("_anchor");
|
|
shader_Key_point = Shader.PropertyToID ("_point");
|
|
shader_Key_level = Shader.PropertyToID ("_level");
|
|
//delta
|
|
prevTransformedPoint = transformedPoint = transform.TransformDirection((normalizeGravityDirection) ? GravityDirection.normalized : GravityDirection);
|
|
//anchor = cPos - transform.TransformDirection(Vector3.up) * anchorLength;
|
|
anchor -= ((normalizeGravityDirection) ? GravityDirection.normalized : GravityDirection) * -1 * Time.deltaTime * (1.0f - dampening);
|
|
anchor.Normalize();
|
|
mr = GetComponent<MeshRenderer>();
|
|
mats = mr.materials;
|
|
shaderNames = new string[mats.Length];
|
|
|
|
for (int i = 0; i < mats.Length; ++i)
|
|
{
|
|
mats[i] = Instantiate(mats[i]);
|
|
shaderNames[i] = mats[i].shader.name;
|
|
|
|
}
|
|
mf = GetComponent<MeshFilter>();
|
|
m = mf.sharedMesh;
|
|
verts = new Vector3[m.vertices.Length];
|
|
verts = m.vertices;
|
|
minMaxBounds.x = minMaxBounds.y = verts[0].y;
|
|
|
|
for (int i = 0; i < verts.Length; ++i)
|
|
{
|
|
Vector3 wPos = transform.TransformDirection(verts[i]);
|
|
if (wPos.y > minMaxBounds.y)
|
|
{
|
|
minMaxBounds.y = wPos.y;
|
|
}
|
|
if (wPos.y < minMaxBounds.x)
|
|
{
|
|
minMaxBounds.x = wPos.y;
|
|
}
|
|
}
|
|
minMaxBounds.x -= cPos.y;
|
|
minMaxBounds.y -= cPos.y;
|
|
for (int i = 0; i < mats.Length; ++i)
|
|
{
|
|
mats[i].SetFloat(shader_Key_localHeight, Mathf.Lerp(minMaxBounds.x,minMaxBounds.y,level));
|
|
}
|
|
|
|
mr.materials = mats;
|
|
|
|
}
|
|
public void AddForce(Vector3 force)
|
|
{
|
|
anchorVelocity += force;
|
|
}
|
|
// Update is called once per frame
|
|
void FixedUpdate ()
|
|
{
|
|
cPos = transform.position;
|
|
float nLength = _anchorLength * Mathf.Max(transform.lossyScale.x, transform.lossyScale.y, transform.lossyScale.z);
|
|
//prevTransformedPoint = transform.TransformDirection(Vector3.down);
|
|
//anchor = transform.position - transform.TransformDirection(Vector3.up) * nLength;
|
|
transformedPoint = transform.TransformDirection((normalizeGravityDirection) ? GravityDirection.normalized : GravityDirection);
|
|
|
|
////Now we need to move the anchor down by gravity;
|
|
//anchorVelocity += Vector3.down * Time.deltaTime * 0.1f;
|
|
anchor += anchorVelocity * (1.0f - dampening);
|
|
Vector3 prevPos = anchor;
|
|
anchor -= ((normalizeGravityDirection) ? GravityDirection.normalized : GravityDirection) * -1 * Time.deltaTime * (1.0f - dampening);
|
|
|
|
//clamp it
|
|
float d = Vector3.Distance(anchor, cPos);
|
|
//float difference = (nLength - d) / d;
|
|
//float d2 = d / nLength;
|
|
|
|
if (d > nLength)
|
|
{
|
|
anchor = cPos + (anchor - cPos).normalized * nLength;
|
|
//connections[i].position = connections[i].position + (cPos - connections[i].position).normalized * difference * 0.5f;
|
|
}
|
|
Vector3 addition = (anchor - prevPos) + (transformedPoint - prevTransformedPoint) * -1 * (1.0f / nLength) * Time.deltaTime;
|
|
//if there is no change dont bother updating.
|
|
if (addition == Vector3.zero)
|
|
{
|
|
if (prvLevel == level && prevQ == transform.rotation)
|
|
return;
|
|
}
|
|
anchorVelocity += addition;
|
|
//find the difference and add it to the velocity;
|
|
|
|
//Vector3 lastPos = anchor;
|
|
//anchor += anchorVelocity * Time.deltaTime;
|
|
//anchor = (anchor - cPos).normalized * anchorLength;
|
|
//add the direction as velocity;
|
|
//anchorVelocity += (b - lastPos);
|
|
Matrix4x4 localToWorld = transform.localToWorldMatrix;
|
|
minMaxBounds.x = minMaxBounds.y = (transform.TransformPoint(verts[0])).y;
|
|
for (int i = 0; i < verts.Length; ++i)
|
|
{
|
|
Vector3 wPos = localToWorld.MultiplyPoint(verts[i]);
|
|
//Vector3 wPos = transform.TransformPoint(verts[i]);
|
|
if (wPos.y > minMaxBounds.y)
|
|
{
|
|
minMaxBounds.y = wPos.y;
|
|
}
|
|
if (wPos.y < minMaxBounds.x)
|
|
{
|
|
minMaxBounds.x = wPos.y;
|
|
}
|
|
}
|
|
minMaxBounds.y -= cPos.y;
|
|
minMaxBounds.x -= cPos.y;
|
|
//minMaxBounds.x += cPos.y;
|
|
//minMaxBounds.y += cPos.y;
|
|
finalLevel = Mathf.Lerp(minMaxBounds.x, minMaxBounds.y, level);
|
|
if(level <= Single.Epsilon * 10)
|
|
{
|
|
//dont render (turn off renderer)
|
|
anchor = Vector3.down * nLength + cPos;
|
|
}
|
|
finalPoint = (cPos - (anchor - cPos).normalized * finalLevel);
|
|
|
|
for (int i = 0; i < mats.Length; ++i)
|
|
{
|
|
mats[i].SetFloat(shader_Key_localHeight, Mathf.Lerp(minMaxBounds.x - Single.Epsilon * 10, minMaxBounds.y + Single.Epsilon * 10, level));
|
|
mats[i].SetVector(shader_Key_anchor, transform.InverseTransformPoint(anchor));
|
|
mats[i].SetVector(shader_Key_point, transform.InverseTransformPoint(cPos - (anchor - cPos).normalized * finalLevel));
|
|
mats[i].SetFloat(shader_Key_level, level - Single.Epsilon);//to make sure its not rendered accidentally by rotations
|
|
}
|
|
|
|
|
|
//lets update the size of the plane (for texture projection);
|
|
// Vector3 anchorD = cPos - transform.TransformDirection(Vector3.up) * anchorLength;
|
|
finalAnchor = anchor;
|
|
CalculateSquare(anchor);
|
|
//lets find the delta y rotation; (global);
|
|
//Quaternion rot = Quaternion.RotateTowards(previous, transform.rotation, 360);
|
|
//make two quaternions static on the xz plane (only rotation about the y)
|
|
Quaternion q1 = Quaternion.LookRotation(previous * Vector3.right, Vector3.up);
|
|
//to find the obtuse angle
|
|
Vector3 vqf = q1 * Vector3.right;
|
|
//returns the acute angle, very cute indeed.
|
|
Quaternion q2 = Quaternion.LookRotation(transform.rotation * Vector3.right, Vector3.up);
|
|
float angle = Quaternion.Angle(q1, q2) * ((Vector3.Dot(vqf,q2 * Vector3.forward) < 0) ? -1 : 1);
|
|
float ydelta = angle;
|
|
//to correct weird rotations (from cross product potentially). (approximation errors)
|
|
if(Mathf.Abs(ydelta) > 0.05f)
|
|
totalRotation += ydelta;
|
|
if(totalRotation > 360)
|
|
{
|
|
totalRotation -= 360;
|
|
}
|
|
else if(totalRotation < 0)
|
|
{
|
|
totalRotation += 360;
|
|
}
|
|
|
|
if (ExposedLiquidT != null)
|
|
{
|
|
ExposedLiquidT.position = cPos - (anchor - cPos).normalized * finalLevel;
|
|
ExposedLiquidT.localScale = Vector3.one *texCurveSize.Evaluate(Mathf.Clamp01(level)) * transform.lossyScale.magnitude * 0.001f * TextureSize * TextureSizeScalar;
|
|
ExposedLiquidT.up = (finalPoint - finalAnchor).normalized;
|
|
|
|
}
|
|
|
|
|
|
prevTransformedPoint = transformedPoint;
|
|
previous = transform.rotation;
|
|
//finally, lets set the plane.
|
|
|
|
Vector4 sTopLeft = transform.InverseTransformPoint(TopLeft);
|
|
Vector4 sTopRight = transform.InverseTransformPoint((TopRight));
|
|
Vector4 sBotLeft = transform.InverseTransformPoint((BottomLeft));
|
|
Vector4 sBotRight = transform.InverseTransformPoint((BottomRight));
|
|
Vector4 sCenter = transform.InverseTransformPoint(cPos - (anchor - cPos).normalized * finalLevel);
|
|
for (int i = 0; i < mats.Length; ++i)
|
|
{
|
|
if (!shaderNames[i].Contains ("_Texture"))
|
|
continue;
|
|
mats[i].SetVector("_TL", sTopLeft);
|
|
mats[i].SetVector("_TR", sTopRight);
|
|
mats[i].SetVector("_BL", sBotLeft);
|
|
mats[i].SetVector("_BR", sBotRight);
|
|
mats[i].SetVector("_CENTER", sCenter);
|
|
}
|
|
prvLevel = level;
|
|
prevQ = transform.rotation;
|
|
|
|
}
|
|
}
|