Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Moving particle emitter problems #268

Closed
kentbarber opened this issue Nov 10, 2019 · 25 comments
Closed

Moving particle emitter problems #268

kentbarber opened this issue Nov 10, 2019 · 25 comments
Assignees
Labels

Comments

@kentbarber
Copy link
Contributor

I have found that if I move the Surface3 for a particle emitter (used in FLIP or PIC) then the particles don't get emitted.

I have tracked this down to the region BoundingBox calculated in VolumeParticleEmitter3::emit(...)

Specifically this code here

BoundingBox3D region = _bounds; if (_implicitSurface->isBounded()) { BoundingBox3D surfaceBBox = _implicitSurface->boundingBox(); region.lowerCorner = max(region.lowerCorner, surfaceBBox.lowerCorner); region.upperCorner = min(region.upperCorner, surfaceBBox.upperCorner); }

Since my moving emitter is an implicit surface created from a Sphere this code runs. It then calculates the lowerCorner of my box to be greater than the upperCorner.

This means that in the forEachPoint method

_pointsGen->forEachPoint(...)

It can't loop over the points in the box because lower.x > upper.x. Which means that this

double boxWidth = boundingBox.width();

Produces a negative number, so no points are emitted.

@doyubkim
Copy link
Owner

It is possible if you provided tight maxRegion to the VolumeParticleEmitter3 instance.

One option is to provide bigger maxRegion such as the whole bounding box of the solver to the emitter. Here's a code snippet from one of the Python examples:

sphere = Sphere3(center=(0.5, 1.0, 0.5), radius=0.15)
emitter = VolumeParticleEmitter3(
    implicitSurface=sphere,
    maxRegion=solver.gridSystemData.boundingBox,
    spacing=1.0 / (2 * resX),
    isOneShot=False,
    initialVelocity=(0, 0, 0))
solver.particleEmitter = emitter

Note that the code above only works when the implicitSurface is bounded, meaning we know its bounding box analytically such as a sphere. This can be checked by calling isBounded function. In case isBounded returns false, you need to move the maxRegion every frame before updating the solver by calling setMaxRegion.

Let me know if this helps!!

@kentbarber
Copy link
Contributor Author

kentbarber commented Nov 10, 2019

I am already passing in the bounding box of the solver to the emitter. The issue seems to be when the bounding box and sphere are positioned negatively.

Solver bbox is lower(1,-1,-1) upper(3,1,1).
Sphere bbox is lower(1.67,-0.5,-1.08), upper(2.67,0.5,-0.08)

The logic of the min/max to calculate the actual bounding box to test if a particle is inside may not be correct. At least that is where I am looking into now.

@doyubkim
Copy link
Owner

Huh, it does sound like a bug for sure! Let me take a look more into it. Thanks for providing a test case! :D

@doyubkim doyubkim self-assigned this Nov 10, 2019
@kentbarber
Copy link
Contributor Author

My hunch is that the boundbox test for width, height, depth etc... doesn't take into account if the numbers are negative. But I don't want to change these since it will impact everything else. Maybe just need to change the forEachPoint methods instead.

@kentbarber
Copy link
Contributor Author

I am seeing a similar issue for SPH where particles are only emitted if the solver and sphere in positive space. Anywhere in negative space no particles are emitted.

@kentbarber
Copy link
Contributor Author

Forgot to mention that the SPH issue happens even when the emitter is not moving.

But with the FLIP solver when the emitter is not moving (ie Surface3 is not being translated) then it emits fine. But when it is moving, when I translate the Surface3 before the solver update, then it doesn't emit.

Sorry I may be mixing up multiple issues here. But my main issue right now is the moving emitters. Hope some of this helps you hunt down the problem. Really enjoying working with the engine again.

@doyubkim
Copy link
Owner

No problem at all! Thanks for reporting the issues you are having. It will make the engine more robust.

Quick question: what were the emitter spacing parameter for both FLIP and SPH simulations? Trying to replicate the bug in more compact unit test-like code.

@kentbarber
Copy link
Contributor Author

kentbarber commented Nov 10, 2019

FLIP

  • Solver size is 2x2x2
  • Solver Resolution (50,50,50)
  • Solver Grid Spacing (0.04)
  • Solver offset (-1,-1,-1)
  • VolumeParticleEmitter3 withMaxRegion = same as Solver size so should be (2,2,2).
  • VolumeParticleEmitter3 withSpacing = 0.02 (half the grid spacing)

SPH
Will update this part tomorrow with the details.

@doyubkim
Copy link
Owner

Thanks for the info @kentbarber!

I made a simple test based on your setup in an attempt to reproduce the bug:

auto sphere = std::make_shared<SurfaceToImplicit3>(
    std::make_shared<Sphere3>(Vector3D(2.17, 0.0, -0.58), 0.5));

BoundingBox3D box({1.0, -1.0, -1.0}, {3.0, 1.0, 1.0});

VolumeParticleEmitter3 emitter =
        VolumeParticleEmitter3::builder()
                .withSurface(sphere)
                .withMaxRegion(box)
                .withSpacing(0.02)
                .withIsOneShot(false)
                .withAllowOverlapping(true)
                .build();

auto particles = std::make_shared<ParticleSystemData3>();
emitter.setTarget(particles);

Frame frame(0, 1.0);
emitter.update(frame.timeInSeconds(), frame.timeIntervalInSeconds);

// numberOfParticles is 128893
EXPECT_GT(particles->numberOfParticles(), 0u);

but it does generate enough particles even in the negative region. Can you spot anything different from your setup?

@kentbarber
Copy link
Contributor Author

kentbarber commented Nov 10, 2019

AllowOverLapping is set to the default, so it will be false. And the other differences is that the sphere is being translated every update. This is the main difference, the sphere is moving. When its moving it doesn't emit particles. When it's static it does.

I will see if I can produce a cut down version of the code that reproduces the issue for you tomorrow.

@doyubkim
Copy link
Owner

Ah, that's right. Does it stop emitting particles immediately when the sphere starts moving, or only when it enters the negative region? Thanks for helping me out on the bug hunting!

@doyubkim
Copy link
Owner

It would be also helpful to see how you are setting the emitter.surface.transform.

@kentbarber
Copy link
Contributor Author

kentbarber commented Nov 11, 2019

In this gif you can see the sphere moving along the spline. The one where it emits particles is FLIP. The one where there are no particles emitted is PIC ( the other two are grid based LevelSet and Smoke, which work perfectly as you can see).

emitter is being changed by just keeping a pointer to the Surface3 and changing it directly before the solver->Update method is called.

surf->transform.setOrientation(jet::QuaternionD(quat.w, -quat.v.x, -quat.v.y, -quat.v.z));
surf->transform.setTranslation(jet::Vector3D(p.x, p.y, p.z));

I will spend some more time on it tonight to see if I can hunt down what the issue might be. Just seems too strange to me and maybe I am doing something wrong.

But as I mentioned before, if the emitter isn't moving, then the particles emit fine from a static sphere emitter in each of those boxes.

multi_fluid_test

There center of this is the origin (0,0,0). The Red axis is X, Blue axis is Z.

@doyubkim
Copy link
Owner

Thanks for more information! I will continue looking at this as well. Something obvious seems wrong.

@kentbarber
Copy link
Contributor Author

kentbarber commented Nov 11, 2019

I also have the following set for the emitters, which is the same as in your examples files.

emitter->setPointGenerator(std::make_sharedjet::GridPointGenerator3());

I noticed above that you didn't set this, so in your test you would have been using BccLatticePointGenerator.

@doyubkim
Copy link
Owner

Incredible find @kentbarber !! Let me work on the fix.

@kentbarber
Copy link
Contributor Author

kentbarber commented Nov 12, 2019

Last night I found a way around the problems I am having. But I haven't yet tracked down the proper solution.

I have a surface, converted to a ImplicitSurface3, this is added to a vector.
The vector is then added to an ImplicitSurfaceSet3. This set is then used in the emitter.

If I transform the original Surfaces transform then nothing happens. But if I change the transform of the ImplicitSurfaceSet3 itself then it works as intended. Although this is not the real fix since it will only then work for a single surface. Will have another look again tonight, might be something related to BoundBox calculations or the BVH.

I think I may just have to retain a pointer to the ImpicitSurfaceSet3 and call invalidateBvh() each frame on it. Will try that tonight.

@kentbarber
Copy link
Contributor Author

Incredible find @kentbarber !! Let me work on the fix.

I changed my post. Please have another read. My initial reply was incorrect.

@doyubkim
Copy link
Owner

Ok thanks for the update!

@kentbarber
Copy link
Contributor Author

Making ImpicitSurfaceSet3::invalidateBvh() public and calling it after changing any child surface seems to work for FLIP. I will look into SPH another day and open a new issue if that has problems.

@doyubkim
Copy link
Owner

@kentbarber I was also heading to the same route. I also have a compact repro case as well. Thanks for tracking this!

@doyubkim
Copy link
Owner

I just created a branch with a potential fix! It would be great if you can test your code with this branch.

@doyubkim
Copy link
Owner

@kentbarber please let me know if the master branch works for you. Should be fixed now.

@kentbarber
Copy link
Contributor Author

kentbarber commented Nov 27, 2019

Yes the master branch works for me now with this fix for implicit surfaces. But I am still unable to move Triangle3 surfaces. But I will open a separate issue for this at a later time.

@doyubkim
Copy link
Owner

Thanks for confirming @kentbarber. Yes, please feel free to open the issue. I will start looking for a solution as well. The dirty flag approach you suggested in the PR seems the best option so far.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants