359 lines
12 KiB
C#
Raw Normal View History

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeshLiquidEmission : MonoBehaviour {
// Use this for initialization
[System.Serializable]
private class BVertex
{
public Vector3 p;
public Vector3 n;
public bool b;
}
[HideInInspector]
[SerializeField]
private MeshFilter r;
public LiquidVolumeAnimator LVA;
[HideInInspector]
[SerializeField]
int[] calculatedTriangles;
[HideInInspector]
[SerializeField]
BVertex[] calculatedVerts;
public ParticleSystem system;
float particlesToEmit = 0;
public float emissionSpeed = 0.0f;
private Mesh m;
[HideInInspector]
[SerializeField]
int[] tris;
[HideInInspector]
[SerializeField]
Vector3[] verts, norms;
public bool debug = false;
public float debugScale = 1.0f;
public bool CullNullNormals = false;
public Rigidbody Cork;
public float volumeOfParticles = 70.0f;
public bool emitting = true;
public BottleSmash bottleSmash;
public float angleSpeedScalar = 1.0f;
int CVOB = 0;
void Start () {
r = GetComponent<MeshFilter>();
m = r.mesh;
calculatedVerts = new BVertex[m.vertexCount * 6];
for(int i = 0; i < calculatedVerts.Length; ++i)
{
calculatedVerts[i] = new BVertex();
}
verts = m.vertices;
tris = m.triangles;
norms = m.normals;
}
bool LinePlaneIntersection(Vector3 p0, Vector3 p1, Vector3 planePoint, Vector3 planeNormal, out Vector3 coordinate)
{
Vector3 line = p1 - p0;
coordinate = Vector3.zero;
float d = Vector3.Dot(planeNormal.normalized, line);
if(Mathf.Abs(d) > float.Epsilon)
{
Vector3 w = p0 - planePoint;
float fac = (Vector3.Dot(planeNormal.normalized, w) * -1) / d;
line = line * fac;
coordinate = p0 + line;
return true;
}
else
{
return false;
}
}
void OnDrawGizmos()
{
if (!debug)
return;
if(calculatedVerts != null)
{
for(int i =0; i < calculatedVerts.Length; ++i)
{
if (!calculatedVerts[i].b)
break;
Gizmos.DrawSphere(transform.TransformPoint(calculatedVerts[i].p), 0.01f * transform.lossyScale.magnitude * debugScale);
}
}
}
// Update is called once per frame
void SetDual(int under1, int under2, int above, ref Vector3 dir, ref Vector3 lpos, ref int currentVOB, ref Vector3 tmpV)
{
calculatedVerts[currentVOB].p = verts[under1];
calculatedVerts[currentVOB].n = norms[under1];
calculatedVerts[currentVOB].b = true;
LinePlaneIntersection(verts[under1], verts[above], lpos, (dir * -1), out tmpV);
calculatedVerts[currentVOB + 1].p = tmpV;
calculatedVerts[currentVOB + 1].n = Vector3.Lerp(norms[under1], norms[above], (tmpV - verts[under1]).magnitude / (verts[under1] - verts[above]).magnitude);
calculatedVerts[currentVOB + 1].b = true;
calculatedVerts[currentVOB + 2].p = verts[under2];
calculatedVerts[currentVOB + 2].n = norms[under2];
calculatedVerts[currentVOB + 2].b = true;
calculatedVerts[currentVOB + 3].p = verts[under2];
calculatedVerts[currentVOB + 3].n = norms[under2];
calculatedVerts[currentVOB + 3].b = true;
calculatedVerts[currentVOB + 4].p = tmpV;
calculatedVerts[currentVOB + 4].n = calculatedVerts[currentVOB + 1].n;
calculatedVerts[currentVOB + 4].b = true;
LinePlaneIntersection(verts[under2], verts[above], lpos, (dir * -1), out tmpV);
calculatedVerts[currentVOB + 5].p = tmpV;
calculatedVerts[currentVOB + 5].n = Vector3.Lerp(norms[under2], norms[above], (tmpV - verts[under2]).magnitude / (verts[under2] - verts[above]).magnitude);
calculatedVerts[currentVOB + 5].b = true;
}
void SetDualInverted(int under1, int above1, int above2, ref Vector3 dir, ref Vector3 lpos, ref int currentVOB, ref Vector3 tmpV)
{
calculatedVerts[currentVOB].p = verts[under1];
calculatedVerts[currentVOB].n = norms[under1];
calculatedVerts[currentVOB].b = true;
LinePlaneIntersection(verts[under1], verts[above1], lpos, (dir * -1), out tmpV);
calculatedVerts[currentVOB + 1].p = tmpV;
calculatedVerts[currentVOB + 1].n = Vector3.Lerp(norms[under1], norms[above1], (tmpV - verts[under1]).magnitude / (verts[under1] - verts[above1]).magnitude);
calculatedVerts[currentVOB + 1].b = true;
LinePlaneIntersection(verts[under1], verts[above2], lpos, (dir * -1), out tmpV);
calculatedVerts[currentVOB + 2].p = tmpV;
calculatedVerts[currentVOB + 2].n = Vector3.Lerp(norms[under1], norms[above2], (tmpV - verts[under1]).magnitude / (verts[under1] - verts[above2]).magnitude);
calculatedVerts[currentVOB + 2].b = true;
}
void CalculateTrianglesToEmitFrom(int[] tris, Vector3[] verts)
{
Vector3 dir = (LVA.finalAnchor - LVA.finalPoint).normalized;
Vector3 lpos = transform.InverseTransformPoint(LVA.finalPoint);
dir = transform.InverseTransformDirection(dir).normalized;
int currentVOB = 0;
Vector3 tmpV = Vector3.zero;
//for every triangle, check if ANY vertex is below the level.
for (int i = 2; i < tris.Length; i+=3)
{
int v1i = tris[i - 2], v2i = tris[i - 1], v3i = tris[i];
Vector3 v1 = verts[v1i], v2 = verts[v2i], v3 = verts[v3i];
Vector3 v1d = v1 - lpos;
bool v1b = Vector3.Dot(dir, v1d) >= 0;
Vector3 v2d = v2 - lpos;
bool v2b = Vector3.Dot(dir, v2d) >= 0;
Vector3 v3d = v3 - lpos;
bool v3b = Vector3.Dot(dir, v3d) >= 0;
//all are under
if(v3b && v2b && v1b)
{
//add ALL vertices to buffer
calculatedVerts[currentVOB].p = v1;
calculatedVerts[currentVOB].n = norms[v1i];
calculatedVerts[currentVOB].b = true;
calculatedVerts[currentVOB+1].p = v2;
calculatedVerts[currentVOB+1].n = norms[v2i];
calculatedVerts[currentVOB+1].b = true;
calculatedVerts[currentVOB+2].p = v3;
calculatedVerts[currentVOB+2].n = norms[v2i];
calculatedVerts[currentVOB+2].b = true;
currentVOB += 3;
continue;
}
else if(!(v3b || v2b || v1b))
{
//none are in, do nothing
continue;
}
else
{
//one or TWO of them out of 3 are under;
bool found = false;
if(v1b && v2b)
{
//subdivide face with projected vertices
SetDual(v1i, v2i, v3i, ref dir, ref lpos, ref currentVOB, ref tmpV);
currentVOB += 6;
found = true;
}
if (v1b && v3b)
{
SetDual(v1i, v3i, v2i, ref dir, ref lpos, ref currentVOB, ref tmpV);
currentVOB += 6;
found = true;
}
if (v2b && v3b)
{
SetDual(v3i, v2i, v1i, ref dir, ref lpos, ref currentVOB, ref tmpV);
currentVOB += 6;
found = true;
}
if(found)
{
continue;
}
if(v1b)
{
SetDualInverted(v1i, v2i, v3i, ref dir, ref lpos, ref currentVOB, ref tmpV);
currentVOB += 3;
continue;
}
if (v2b)
{
SetDualInverted(v2i, v1i, v3i, ref dir, ref lpos, ref currentVOB, ref tmpV);
currentVOB += 3;
continue;
}
if (v3b)
{
SetDualInverted(v3i, v2i, v1i, ref dir, ref lpos, ref currentVOB, ref tmpV);
currentVOB += 3;
continue;
}
continue;
}
}
if(currentVOB < calculatedVerts.Length)
{
calculatedVerts[currentVOB].b = false;
}
CVOB = currentVOB;
}
float GetPS_StartSpeed()
{
switch (system.main.startSpeed.mode)
{
case ParticleSystemCurveMode.TwoConstants:
return UnityEngine.Random.Range(system.main.startSpeed.constantMin, system.main.startSpeed.constantMax);
case ParticleSystemCurveMode.Constant:
return system.main.startSpeed.constant;
case ParticleSystemCurveMode.Curve:
return system.main.startSpeed.Evaluate(UnityEngine.Random.value);
case ParticleSystemCurveMode.TwoCurves:
return system.main.startSpeed.Evaluate(UnityEngine.Random.value);
default:
return 0.0f;
}
}
bool EmitFromSubmesh()
{
//randomly select ONE triangle;
// div by 3
int index = UnityEngine.Random.Range(0,(CVOB / 3)-1);
//multiply out to corresponding id;
index *= 3;
//find the position to emit from;
//pick vert1, lerp to v2 randomly, then v3 randomly.
float r1 = UnityEngine.Random.value;
float r2 = UnityEngine.Random.value;
Vector3 pos = Vector3.Lerp(calculatedVerts[index].p, calculatedVerts[index + 1].p, r1);
Vector3 nrm = Vector3.Lerp(calculatedVerts[index].n, calculatedVerts[index + 1].n, r1).normalized;
pos = Vector3.Lerp(pos, calculatedVerts[index + 2].p, r2);
nrm = Vector3.Lerp(nrm, calculatedVerts[index + 2].n, r2).normalized;
//ParticleSystem.Particle p = new ParticleSystem.Particle();
//p.position = pos;
//p.angularVelocity3D =
ParticleSystem.EmitParams param = new ParticleSystem.EmitParams();
float pouringAngle = 1;
if (bottleSmash != null)
{
Vector3 wNrm = transform.TransformDirection(nrm).normalized;
pouringAngle = ((1.0f + Vector3.Dot((LVA.finalAnchor - LVA.finalPoint).normalized, wNrm))/2.0f);
param.velocity = wNrm * GetPS_StartSpeed() * pouringAngle * angleSpeedScalar;
}
else
{
param.velocity = transform.TransformDirection(nrm).normalized * GetPS_StartSpeed();
}
param.position = transform.TransformPoint(pos);
if (param.velocity == Vector3.zero && CullNullNormals)
return false;
particlesToEmit -= 1;
//adjust level
if (Cork != null)
{
if (Cork.isKinematic && volumeOfParticles > 0)
{
//
LVA.level = Mathf.Clamp01((volumeOfParticles * LVA.level - 1) / volumeOfParticles);
}
}
else if(volumeOfParticles > 0)
{
LVA.level = Mathf.Clamp01((volumeOfParticles * LVA.level - 1) / volumeOfParticles);
}
system.Emit(param, 1);
return true;
}
void Update () {
if (!emitting || Cork != null)
return;
if (LVA.level <= 0)
return;
CalculateTrianglesToEmitFrom(tris, verts);
//triangles are in order
particlesToEmit += emissionSpeed * Time.deltaTime;
if(calculatedVerts.Length == 0)
{
particlesToEmit = 0;
}
else
{
if(calculatedVerts[0].b == false)
particlesToEmit = 0;
}
int maxFailInASeq = 10;
int seq = maxFailInASeq;
while(particlesToEmit > 0 && (GetPS_StartSpeed() > 0 || !CullNullNormals))
{
if (EmitFromSubmesh())
{
seq = maxFailInASeq;
}
else
{
seq -= 1;
}
if (seq <= 0)
{
break;
}
}
}
}