359 lines
12 KiB
C#
359 lines
12 KiB
C#
![]() |
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;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
}
|
|||
|
}
|