09-03-2019, 11:11 AM
Hi All,
First of all - I have to say that i really like this product, simulations are very realistic, fast, configurable - well done! (documentation could be improved
using unity 2018.2.1f1
using Obi 4.0.2
My real scene is a little complex with many moving solvers/emitters, so I built a simple demo scene to demonstrate the problem.
In general: fluid stream collide with a sphere, collided particles are being killed, and for every killed particle a new particle is emitted from a local emitter on the sphere
The demo scene includes the following GameObjects/Components:
1)MainSolver - Empty with a solver (global space) and a script MainCollisionDetection(described bellow)
(solver constraints copied from Obi sample scene "FluidViscosity")
2)MainEmitter - Empty with an ObiEmitter (that uses MainSolver as its solver) and particle renderer
emitter properties: speed: 5, emitter material: Honey, collision material :very sticky
3)Sphere - unity sphere with ObiCollider ,RB, and ObiRB
a)SphereSolver - child of Sphere - Empty with a solver (local space)
(solver constraints copied from Obi sample scene "FluidViscosity")
1. SphereEmitter - child of SphereSolver - empty with an ObiEmitter (that uses SphereSolver as its solver) and particle renderer
emitter properties: speed: controlled by script SphereEmitionControl (described bellow), emitter material: Honey, collision material :very sticky
4)MainCollisionDetection script detects collisions (on MainSolver), kills the hitting particle, and adds the particle collision data to a queue in the SphereEmitionControl script
5)SphereEmitionControl script has a queue of particles positions/normals, it is filled only by data from MainCollisionDetection script. The script repeatedly checks if the queue is not empty, it dequeues the data, move its transform to the stored position/normal and emit for a short while (i didn't know how to emit one particle so i timed the emittion with a coroutine)
Regarding the collisions the scripts run OK , the problem is : the particles (emitted from SphereEmitter) are flickering.
I did some testing and found that:
case a: while running - if i disable the MainSolver (in the editor) the flickering stops (strange, it should not effect the scene because the particles belong to the SphereSolver)
case b: while running - if the MainSolver is enabled, and i disable and than enable the SphereSolver - flickering stops, and everything works well as expected, but now if i disable and than enable the MainSolver, flickering starts again
why does the flickering happen?
how to prevent it?
thanks,
shayk
First of all - I have to say that i really like this product, simulations are very realistic, fast, configurable - well done! (documentation could be improved
using unity 2018.2.1f1
using Obi 4.0.2
My real scene is a little complex with many moving solvers/emitters, so I built a simple demo scene to demonstrate the problem.
In general: fluid stream collide with a sphere, collided particles are being killed, and for every killed particle a new particle is emitted from a local emitter on the sphere
The demo scene includes the following GameObjects/Components:
1)MainSolver - Empty with a solver (global space) and a script MainCollisionDetection(described bellow)
(solver constraints copied from Obi sample scene "FluidViscosity")
2)MainEmitter - Empty with an ObiEmitter (that uses MainSolver as its solver) and particle renderer
emitter properties: speed: 5, emitter material: Honey, collision material :very sticky
3)Sphere - unity sphere with ObiCollider ,RB, and ObiRB
a)SphereSolver - child of Sphere - Empty with a solver (local space)
(solver constraints copied from Obi sample scene "FluidViscosity")
1. SphereEmitter - child of SphereSolver - empty with an ObiEmitter (that uses SphereSolver as its solver) and particle renderer
emitter properties: speed: controlled by script SphereEmitionControl (described bellow), emitter material: Honey, collision material :very sticky
4)MainCollisionDetection script detects collisions (on MainSolver), kills the hitting particle, and adds the particle collision data to a queue in the SphereEmitionControl script
Code:
using System.Collections.Generic;
using UnityEngine;
using Obi;
public class MainCollisionDetection : MonoBehaviour {
public ObiEmitter mainEmitter;
ObiSolver solver;
Obi.ObiSolver.ObiCollisionEventArgs frame;
List<int> allreadyEmittedParticles;
void Awake()
{
solver = GetComponent<Obi.ObiSolver>();
}
void OnEnable()
{
solver.OnCollision += Solver_OnCollision;
}
void OnDisable()
{
solver.OnCollision -= Solver_OnCollision;
}
void Solver_OnCollision(object sender, Obi.ObiSolver.ObiCollisionEventArgs e)
{
frame = e;
if (solver == null || frame == null || frame.contacts == null) return;
allreadyEmittedParticles = new List<int>();
int closeContacts = 0;
for (int i = 0; i < frame.contacts.Count; ++i)
{
if (frame.contacts[i].distance < 0.001f)
{
Component contactColl;
ObiCollider.idToCollider.TryGetValue(frame.contacts[i].other, out contactColl);
if (contactColl != null)
{
ObiSolver.ParticleInActor pa = solver.particleToActor[frame.contacts[i].particle];
ObiEmitter emtr = pa.actor as ObiEmitter;
int particleIndexInEmitter = pa.indexInActor;
if (!allreadyEmittedParticles.Contains(particleIndexInEmitter))
{
allreadyEmittedParticles.Add(particleIndexInEmitter);
closeContacts++;
Vector3 point = frame.contacts[i].point;
Vector3 normal = frame.contacts[i].normal;
//kill hit particle in the main emitter
emtr.life[particleIndexInEmitter] = 0;
//look for the hitted collider emitter
ObiEmitter colliderEmitter = contactColl.GetComponentInChildren<ObiEmitter>();
if (colliderEmitter != null)
{
SphereEmitionControl sphereEmitionControl = colliderEmitter.GetComponent<SphereEmitionControl>();
//add particle to collider emitter queue
sphereEmitionControl.AddParticleToEmit(point, Quaternion.Euler(normal));
}
}
}
}
}
}
}
5)SphereEmitionControl script has a queue of particles positions/normals, it is filled only by data from MainCollisionDetection script. The script repeatedly checks if the queue is not empty, it dequeues the data, move its transform to the stored position/normal and emit for a short while (i didn't know how to emit one particle so i timed the emittion with a coroutine)
Code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Obi;
public class ParticleToEmit
{
public Vector3 pos;
public Quaternion localRot;
}
public class SphereEmitionControl : MonoBehaviour {
ObiEmitter m_emitter;
bool emitting;
Queue<ParticleToEmit> particlesToEmit;
void Start()
{
m_emitter = GetComponent<ObiEmitter>();
m_emitter.speed = 0f;
particlesToEmit = new Queue<ParticleToEmit>();
}
void LateUpdate()
{
if (particlesToEmit.Count > 0 && !emitting)
{
ParticleToEmit par = particlesToEmit.Dequeue();
transform.position = par.pos;
transform.localRotation = par.localRot;
StartCoroutine(ColliderEmitterEmit());
}
}
//add a particle data to queue
public void AddParticleToEmit(Vector3 pos, Quaternion localRot)
{
ParticleToEmit newParticle = new ParticleToEmit();
newParticle.pos = pos;
newParticle.localRot = localRot;
particlesToEmit.Enqueue(newParticle);
}
//emit particle
public IEnumerator ColliderEmitterEmit()
{
emitting = true;
m_emitter.speed = 1f;
m_emitter.EmitParticle(0);
yield return null;
m_emitter.speed = 0f;
emitting = false;
}
}
Regarding the collisions the scripts run OK , the problem is : the particles (emitted from SphereEmitter) are flickering.
I did some testing and found that:
case a: while running - if i disable the MainSolver (in the editor) the flickering stops (strange, it should not effect the scene because the particles belong to the SphereSolver)
case b: while running - if the MainSolver is enabled, and i disable and than enable the SphereSolver - flickering stops, and everything works well as expected, but now if i disable and than enable the MainSolver, flickering starts again
why does the flickering happen?
how to prevent it?
thanks,
shayk