443 lines
21 KiB
C++
443 lines
21 KiB
C++
#include <glm/geometric.hpp>
|
|
#include <limits>
|
|
#include "fluids/VolumeFluidCodec.h"
|
|
#include "fluids/VolumeFluidEmitter.h"
|
|
#include "zeroerr/assert.h"
|
|
#include "zeroerr/unittest.h"
|
|
using namespace eve::fluids;
|
|
|
|
TEST_CASE("fluids.volumeEmitter.movingNozzleInheritsVelocityAndRejectsBadPose") {
|
|
auto created = VolumeFluid::create({});
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
VolumeFluidJetEmitter jet;
|
|
VolumeFluidEmission e;
|
|
e.shape = VolumeFluidEmissionShape::Edge;
|
|
e.extent = {0, 0, 0};
|
|
e.speed = 12.f;
|
|
VolumeFluidNozzlePose begin{{0, 1, 0}, {0, 0, 0, 1}}, end{{.3f, 1, 0}, {0, 0, 0, 1}};
|
|
auto bad = end;
|
|
bad.rotation = {0, 0, 0, 0};
|
|
const auto saved = jet.snapshot();
|
|
REQUIRE(!jet.advanceMoving(*solver, e, begin, bad, .025f, 16, 0.f, 1.f).ok());
|
|
REQUIRE(jet.snapshot().phase == saved.phase);
|
|
REQUIRE(solver->particleCount() == 0);
|
|
REQUIRE(jet.advanceMoving(*solver, e, begin, end, .025f, 16, 0.f, 1.f).ok());
|
|
for (const auto& p : solver->particles()) {
|
|
REQUIRE(std::abs(p.position.x - .3f) < 1e-5f);
|
|
REQUIRE(std::abs(p.velocity.x - 12.f) < 1e-5f);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.rotatingNozzleInterpolatesOrientation") {
|
|
auto created = VolumeFluid::create({});
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
VolumeFluidJetEmitter jet;
|
|
VolumeFluidEmission e;
|
|
e.shape = VolumeFluidEmissionShape::Edge;
|
|
e.extent = {0, 0, 0};
|
|
e.speed = 6.f;
|
|
VolumeFluidNozzlePose begin{{0, 1, 0}, {0, 0, 0, 1}}, end{{0, 1, 0}, {0, .70710678118f, 0, .70710678118f}};
|
|
auto result = jet.advanceMoving(*solver, e, begin, end, .025f, 16, 0.f, 0.f);
|
|
REQUIRE(result.ok());
|
|
REQUIRE(result.value() == 1);
|
|
const auto p = solver->particles()[0];
|
|
REQUIRE(std::abs(p.velocity.x - 5.1961524f) < .0001f);
|
|
REQUIRE(std::abs(p.velocity.z - 3.f) < .0001f);
|
|
REQUIRE(std::abs(p.position.x - .04330127f) < .0001f);
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.rotatingNozzleSurfaceVelocity") {
|
|
auto created = VolumeFluid::create({});
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
VolumeFluidJetEmitter jet;
|
|
VolumeFluidEmission e;
|
|
e.shape = VolumeFluidEmissionShape::Edge;
|
|
e.extent = {.1f, 0, 0};
|
|
e.speed = 6.f;
|
|
VolumeFluidNozzlePose begin{{0, 1, 0}, {0, 0, 0, 1}}, end{{0, 1, 0}, {0, .70710678118f, 0, .70710678118f}};
|
|
auto result = jet.advanceMoving(*solver, e, begin, end, .025f, 16, 0.f, 1.f);
|
|
REQUIRE(result.ok());
|
|
REQUIRE(result.value() == 3);
|
|
const auto particles = solver->particles();
|
|
const auto tangent = particles[2].velocity - particles[1].velocity;
|
|
REQUIRE(std::abs(glm::length(tangent) - 6.2831853f) < .001f);
|
|
REQUIRE(std::abs(tangent.x + 5.441398f) < .001f);
|
|
REQUIRE(std::abs(tangent.z + 3.1415927f) < .001f);
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.nozzleRotatesEllipsoidOrientation") {
|
|
VolumeFluidSettings settings;
|
|
settings.gravity = {0, 0, 0};
|
|
auto created = VolumeFluid::create(settings);
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
VolumeFluidEmission emission;
|
|
emission.shape = VolumeFluidEmissionShape::Disk;
|
|
emission.origin = {0, 1, 0};
|
|
emission.direction = {0, 1, 0};
|
|
emission.extent = {0, 0, 0};
|
|
emission.prototype.radii = {.2f, .05f, .05f};
|
|
REQUIRE(emitVolumeFluidBurst(*solver, emission, 1).ok());
|
|
auto majorAxis = solver->querySphere({0.f, 1.f, .3f}, 0.f, 0.f, 1.f, 1);
|
|
REQUIRE(majorAxis.ok());
|
|
REQUIRE(majorAxis.value().size() == 1);
|
|
REQUIRE(std::abs(majorAxis.value()[0].distance - .1f) < 1e-5f);
|
|
solver->clear();
|
|
VolumeFluidJetEmitter jet;
|
|
VolumeFluidNozzlePose pose;
|
|
pose.position = {0, 1, 0};
|
|
pose.rotation = {0, 0, .70710678f, .70710678f};
|
|
emission.direction = {0, 0, 1};
|
|
emission.speed = 12.f;
|
|
REQUIRE(jet.advanceMoving(*solver, emission, pose, pose, 1.f / 60.f, 1, 0.f, 0.f).ok());
|
|
REQUIRE(solver->particleCount() == 1);
|
|
const auto particle = solver->particles()[0];
|
|
REQUIRE(std::abs(particle.orientation.z) > .7f);
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.boundedLifecycleEventsCoverEmissionExplicitKillAndExpiry") {
|
|
VolumeFluidSettings settings;
|
|
settings.gravity = {0, 0, 0};
|
|
settings.capacity = 8;
|
|
auto created = VolumeFluid::create(settings);
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
|
|
VolumeFluidParticle first, second, third;
|
|
first.actorGroup = 7;
|
|
first.position = {0, 1, 0};
|
|
first.color = {.1f, .2f, .3f, 1.f};
|
|
second = first;
|
|
second.position.x = .2f;
|
|
second.life = .01f;
|
|
third = first;
|
|
third.position.x = .4f;
|
|
third.actorGroup = 9;
|
|
|
|
REQUIRE(solver->emit(std::array{first}).ok());
|
|
REQUIRE(solver->drainParticleEvents().events.empty());
|
|
REQUIRE(!solver->configureParticleEvents(65537).ok());
|
|
REQUIRE(solver->configureParticleEvents(3).ok());
|
|
REQUIRE(solver->emit(std::array{second, third}).ok());
|
|
auto emitted = solver->drainParticleEvents();
|
|
REQUIRE(emitted.dropped == 0);
|
|
REQUIRE(emitted.events.size() == 2);
|
|
REQUIRE(emitted.events[0].type == VolumeFluidParticleEventType::Emitted);
|
|
REQUIRE(emitted.events[0].particleIndex == 1);
|
|
REQUIRE(emitted.events[0].actorGroup == 7);
|
|
REQUIRE(glm::length(emitted.events[0].particle.color - first.color) < 1e-6f);
|
|
|
|
REQUIRE(solver->killParticle(2).ok());
|
|
REQUIRE(solver->step(.01f, 2).ok());
|
|
auto killed = solver->drainParticleEvents();
|
|
REQUIRE(killed.dropped == 0);
|
|
REQUIRE(killed.events.size() == 2);
|
|
REQUIRE(killed.events[0].type == VolumeFluidParticleEventType::Killed);
|
|
REQUIRE(killed.events[0].actorGroup == 9);
|
|
REQUIRE(killed.events[1].type == VolumeFluidParticleEventType::Killed);
|
|
REQUIRE(killed.events[1].actorGroup == 7);
|
|
|
|
REQUIRE(solver->emit(std::array{second, second, second, second}).ok());
|
|
auto overflow = solver->drainParticleEvents();
|
|
REQUIRE(overflow.events.size() == 3);
|
|
REQUIRE(overflow.dropped == 1);
|
|
REQUIRE(solver->killActorParticles(7).value() == 5);
|
|
auto killedActor = solver->drainParticleEvents();
|
|
REQUIRE(killedActor.events.size() == 3);
|
|
REQUIRE(killedActor.dropped == 2);
|
|
for (const auto& event : killedActor.events) REQUIRE(event.type == VolumeFluidParticleEventType::Killed);
|
|
REQUIRE(solver->configureParticleEvents(0).ok());
|
|
REQUIRE(solver->emit(std::array{first}).ok());
|
|
REQUIRE(solver->killActorParticles(7).ok());
|
|
REQUIRE(solver->drainParticleEvents().events.empty());
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.combinedCheckpointRestoresSolverDescriptionAndControllerAtomically") {
|
|
VolumeFluidSettings settings;
|
|
settings.gravity = {0, 0, 0};
|
|
settings.capacity = 8;
|
|
auto sourceResult = VolumeFluid::create(settings), targetResult = VolumeFluid::create(settings);
|
|
REQUIRE(sourceResult.ok());
|
|
REQUIRE(targetResult.ok());
|
|
auto source = std::move(sourceResult).takeValue(), target = std::move(targetResult).takeValue();
|
|
VolumeFluidEmission emission;
|
|
emission.shape = VolumeFluidEmissionShape::Edge;
|
|
emission.extent = {0, 0, 0};
|
|
emission.speed = 3.f;
|
|
emission.seed = 47;
|
|
emission.prototype.actorGroup = 5;
|
|
emission.prototype.color = {.2f, .4f, .6f, 1.f};
|
|
VolumeFluidEmitter sourceController, targetController;
|
|
REQUIRE(sourceController.advance(*source, emission, .02f, 120.f, 2, 0.f).value() == 2);
|
|
auto checkpoint = captureVolumeFluidEmitterCheckpoint(*source, emission, sourceController);
|
|
auto encoded = encodeVolumeFluidEmitterCheckpoint(checkpoint);
|
|
auto decoded = decodeVolumeFluidEmitterCheckpoint(encoded);
|
|
REQUIRE(decoded.ok());
|
|
REQUIRE(decoded.value().emission.seed == 47);
|
|
|
|
VolumeFluidEmission other = emission;
|
|
other.prototype.actorGroup = 9;
|
|
REQUIRE(targetController.advance(*target, other, .02f, 60.f, 1, 0.f).value() == 1);
|
|
const auto beforeParticle = target->particles()[0];
|
|
const auto beforeController = targetController.snapshot();
|
|
auto invalid = decoded.value();
|
|
invalid.controller.kind = 1;
|
|
REQUIRE(!restoreVolumeFluidEmitterCheckpoint(*target, targetController, invalid).ok());
|
|
REQUIRE(target->particleCount() == 1);
|
|
REQUIRE(target->particles()[0].actorGroup == beforeParticle.actorGroup);
|
|
REQUIRE(targetController.snapshot().phase == beforeController.phase);
|
|
REQUIRE(targetController.snapshot().sequence == beforeController.sequence);
|
|
|
|
REQUIRE(restoreVolumeFluidEmitterCheckpoint(*target, targetController, decoded.value()).ok());
|
|
REQUIRE(target->particleCount() == source->particleCount());
|
|
REQUIRE(target->particles()[0].actorGroup == 5);
|
|
REQUIRE(glm::length(target->particles()[0].color - emission.prototype.color) < 1e-6f);
|
|
REQUIRE(targetController.snapshot().phase == sourceController.snapshot().phase);
|
|
REQUIRE(targetController.snapshot().sequence == sourceController.snapshot().sequence);
|
|
REQUIRE(sourceController.advance(*source, emission, .01f, 100.f, 2, 0.f).ok());
|
|
REQUIRE(targetController.advance(*target, decoded.value().emission, .01f, 100.f, 2, 0.f).ok());
|
|
REQUIRE(target->particleCount() == source->particleCount());
|
|
|
|
encoded.set("extra", 1);
|
|
REQUIRE(!decodeVolumeFluidEmitterCheckpoint(encoded).ok());
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.activeParticleCountReadsOnlyItsActorWithoutMassWork") {
|
|
VolumeFluidSettings settings;
|
|
settings.gravity = {0, 0, 0};
|
|
settings.capacity = 8;
|
|
auto created = VolumeFluid::create(settings);
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
VolumeFluidParticle a, b;
|
|
a.position = {0, 1, 0};
|
|
a.actorGroup = 4;
|
|
b = a;
|
|
b.position.x = .2f;
|
|
b.actorGroup = 8;
|
|
REQUIRE(solver->emit(std::array{a, a, b}).ok());
|
|
REQUIRE(solver->actorParticleCount(4).value() == 2);
|
|
REQUIRE(solver->actorParticleCount(8).value() == 1);
|
|
REQUIRE(solver->actorParticleCount(9).value() == 0);
|
|
REQUIRE(!solver->actorParticleCount(0x01000000u).ok());
|
|
REQUIRE(solver->particleCount() == 3);
|
|
REQUIRE(solver->killParticle(0).ok());
|
|
REQUIRE(solver->actorParticleCount(4).value() == 1);
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.actorCapacityIsIndependentAndPreflightsAllControllers") {
|
|
auto created = VolumeFluid::create(VolumeFluidSettings{.capacity = 12});
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
|
|
VolumeFluidEmission a;
|
|
a.shape = VolumeFluidEmissionShape::Edge;
|
|
a.extent = glm::vec3(0.f);
|
|
a.prototype.actorGroup = 4;
|
|
a.actorCapacity = 2;
|
|
VolumeFluidEmission b = a;
|
|
b.prototype.actorGroup = 8;
|
|
VolumeFluidEmitter streamA, streamB;
|
|
|
|
REQUIRE(streamA.advance(*solver, a, .02f, 1000.f, 8, 0.f).value() == 2);
|
|
REQUIRE(streamA.advance(*solver, a, .02f, 1000.f, 8, 0.f).value() == 0);
|
|
REQUIRE(streamB.advance(*solver, b, .02f, 1000.f, 8, 0.f).value() == 2);
|
|
REQUIRE(solver->actorParticleCount(4).value() == 2);
|
|
REQUIRE(solver->actorParticleCount(8).value() == 2);
|
|
REQUIRE(solver->particleCount() == 4);
|
|
|
|
auto burst = a;
|
|
burst.prototype.actorGroup = 12;
|
|
burst.actorCapacity = 1;
|
|
const auto before = solver->snapshot();
|
|
REQUIRE(!emitVolumeFluidBurst(*solver, burst, 2).ok());
|
|
REQUIRE(solver->snapshot().particles.size() == before.particles.size());
|
|
|
|
auto jetEmission = a;
|
|
jetEmission.prototype.actorGroup = 16;
|
|
jetEmission.actorCapacity = 2;
|
|
jetEmission.speed = 10.f;
|
|
VolumeFluidJetEmitter jet;
|
|
REQUIRE(jet.advance(*solver, jetEmission, 1.f / 30.f, 8, 0.f).value() == 2);
|
|
REQUIRE(jet.advance(*solver, jetEmission, 1.f / 30.f, 8, 0.f).value() == 0);
|
|
REQUIRE(solver->actorParticleCount(16).value() == 2);
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.descriptionV13MigratesActorCapacityStrictly") {
|
|
VolumeFluidEmission emission;
|
|
emission.actorCapacity = 37;
|
|
auto encoded = encodeVolumeFluidEmission(emission);
|
|
REQUIRE(encoded.find("version")->asInt() == 14);
|
|
REQUIRE(decodeVolumeFluidEmission(encoded).value().actorCapacity == 37);
|
|
|
|
eve::Value legacyDescription(eve::Value::Object{});
|
|
const auto& currentDescription = *encoded.find("description");
|
|
for (const auto& key : currentDescription.keys())
|
|
if (key != "actorCapacity") legacyDescription.set(key, *currentDescription.find(key));
|
|
encoded.set("version", 13);
|
|
encoded.set("description", legacyDescription);
|
|
auto migrated = decodeVolumeFluidEmission(encoded);
|
|
REQUIRE(migrated.ok());
|
|
REQUIRE(migrated.value().actorCapacity == 1000);
|
|
|
|
auto invalidDescription = *encodeVolumeFluidEmission(emission).find("description");
|
|
invalidDescription.set("actorCapacity", 0);
|
|
encoded = encodeVolumeFluidEmission(emission);
|
|
encoded.set("description", invalidDescription);
|
|
REQUIRE(!decodeVolumeFluidEmission(encoded).ok());
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.killParticleUsesActorLocalIndexWithoutCrossActorDeletion") {
|
|
auto created = VolumeFluid::create(VolumeFluidSettings{.capacity = 8});
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
std::vector<VolumeFluidParticle> particles(3);
|
|
particles[0].actorGroup = 4;
|
|
particles[0].position = {-.2f, 1.f, 0.f};
|
|
particles[0].color = {1, 0, 0, 1};
|
|
particles[1].actorGroup = 8;
|
|
particles[1].position = {0.f, 1.f, 0.f};
|
|
particles[1].color = {0, 1, 0, 1};
|
|
particles[2].actorGroup = 4;
|
|
particles[2].position = {.2f, 1.f, 0.f};
|
|
particles[2].color = {0, 0, 1, 1};
|
|
REQUIRE(solver->emit(particles).ok());
|
|
REQUIRE(solver->configureParticleEvents(4).ok());
|
|
const auto emittedEvents = solver->drainParticleEvents();
|
|
REQUIRE(emittedEvents.events.empty());
|
|
|
|
REQUIRE(solver->killActorParticle(4, 1).ok());
|
|
REQUIRE(solver->particleCount() == 2);
|
|
REQUIRE(solver->actorParticleCount(4).value() == 1);
|
|
REQUIRE(solver->actorParticleCount(8).value() == 1);
|
|
REQUIRE(solver->particles()[0].color == glm::vec4(1, 0, 0, 1));
|
|
REQUIRE(solver->particles()[1].color == glm::vec4(0, 1, 0, 1));
|
|
auto events = solver->drainParticleEvents();
|
|
REQUIRE(events.events.size() == 1);
|
|
REQUIRE(events.events[0].actorGroup == 4);
|
|
REQUIRE(events.events[0].particle.color == glm::vec4(0, 0, 1, 1));
|
|
|
|
const auto before = solver->snapshot();
|
|
REQUIRE(!solver->killActorParticle(4, 1).ok());
|
|
REQUIRE(!solver->killActorParticle(0x01000000u, 0).ok());
|
|
REQUIRE(solver->snapshot().particles.size() == before.particles.size());
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.emitParticleUsesDistributionSequenceOffsetAndCapacity") {
|
|
auto created = VolumeFluid::create(VolumeFluidSettings{.capacity = 8});
|
|
REQUIRE(created.ok());
|
|
auto solver = std::move(created).takeValue();
|
|
VolumeFluidEmission emission;
|
|
emission.shape = VolumeFluidEmissionShape::Distribution;
|
|
emission.origin = {0.f, 1.f, 0.f};
|
|
emission.direction = {0.f, 0.f, 1.f};
|
|
emission.speed = 3.f;
|
|
emission.actorCapacity = 2;
|
|
emission.prototype.actorGroup = 19;
|
|
emission.prototype.color = glm::vec4(1.f);
|
|
emission.distribution = {{{.1f, 0.f, 0.f}, {1, 0, 0, 1}, {1, 0, 0}}, {{0.f, .1f, 0.f}, {0, 1, 0, 1}, {0, 1, 0}}};
|
|
VolumeFluidEmitter emitter;
|
|
|
|
REQUIRE(emitter.emitParticle(*solver, emission, .5f, .02f).value() == 1);
|
|
REQUIRE(emitter.emitParticle(*solver, emission, 1.f, .02f).value() == 1);
|
|
REQUIRE(emitter.emitParticle(*solver, emission, 0.f, .02f).value() == 0);
|
|
REQUIRE(glm::length(solver->particles()[0].position - glm::vec3(.13f, 1.f, 0.f)) < 1e-6f);
|
|
REQUIRE(glm::length(solver->particles()[1].position - glm::vec3(0.f, 1.16f, 0.f)) < 1e-6f);
|
|
REQUIRE(solver->particles()[0].color == glm::vec4(1, 0, 0, 1));
|
|
REQUIRE(solver->particles()[1].color == glm::vec4(0, 1, 0, 1));
|
|
|
|
const auto before = solver->snapshot();
|
|
const auto controllerBefore = emitter.snapshot();
|
|
REQUIRE(!emitter.emitParticle(*solver, emission, -0.1f, .02f).ok());
|
|
REQUIRE(!emitter.emitParticle(*solver, emission, .5f, .04f).ok());
|
|
REQUIRE(solver->snapshot().particles.size() == before.particles.size());
|
|
REQUIRE(emitter.snapshot().sequence == controllerBefore.sequence);
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.blueprintMetricsMatchFluid3DThreeDimensionalFormulas") {
|
|
auto defaults = evaluateVolumeFluidEmitterBlueprint3D(1.f, 1000.f, 2.f);
|
|
REQUIRE(defaults.ok());
|
|
REQUIRE(std::abs(defaults.value().particleSize - .1f) < 1e-7f);
|
|
REQUIRE(std::abs(defaults.value().particleMass - 1.f) < 1e-6f);
|
|
REQUIRE(std::abs(defaults.value().smoothingRadius - .2f) < 1e-7f);
|
|
|
|
auto denser = evaluateVolumeFluidEmitterBlueprint3D(8.f, 1000.f, 2.f);
|
|
REQUIRE(denser.ok());
|
|
REQUIRE(std::abs(denser.value().particleSize - .05f) < 1e-7f);
|
|
REQUIRE(std::abs(denser.value().particleMass - .125f) < 1e-6f);
|
|
REQUIRE(std::abs(denser.value().smoothingRadius - .1f) < 1e-7f);
|
|
|
|
REQUIRE(!evaluateVolumeFluidEmitterBlueprint3D(0.f, 1000.f, 2.f).ok());
|
|
REQUIRE(!evaluateVolumeFluidEmitterBlueprint3D(1.f, 0.f, 2.f).ok());
|
|
REQUIRE(!evaluateVolumeFluidEmitterBlueprint3D(1.f, 1000.f, .99f).ok());
|
|
REQUIRE(!evaluateVolumeFluidEmitterBlueprint3D(std::numeric_limits<float>::quiet_NaN(), 1000.f, 2.f).ok());
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.fluidBlueprintPreparesAllFluid3DMaterialFieldsAtomically") {
|
|
VolumeFluidEmitterBlueprint3D blueprint;
|
|
blueprint.capacity = 321;
|
|
blueprint.resolution = 8.f;
|
|
blueprint.restDensity = 875.f;
|
|
blueprint.smoothing = 3.f;
|
|
blueprint.viscosity = .7f;
|
|
blueprint.surfaceTension = 1.5f;
|
|
blueprint.buoyancy = -.25f;
|
|
blueprint.atmosphericDrag = .4f;
|
|
blueprint.atmosphericPressure = 2.5f;
|
|
blueprint.vorticity = .8f;
|
|
blueprint.diffusion = .6f;
|
|
blueprint.diffusionData = {1.f, 2.f, 3.f, 4.f};
|
|
auto prepared = prepareVolumeFluidEmitterBlueprint3D(blueprint);
|
|
REQUIRE(prepared.ok());
|
|
REQUIRE(prepared.value().settings.capacity == 321);
|
|
REQUIRE(std::abs(prepared.value().settings.spacing - .05f) < 1e-7f);
|
|
REQUIRE(prepared.value().emission.actorCapacity == 321);
|
|
const auto& particle = prepared.value().emission.prototype;
|
|
REQUIRE(particle.material.phase == VolumeFluidPhase::Liquid);
|
|
REQUIRE(particle.material.density == 875.f);
|
|
REQUIRE(particle.material.smoothing == 3.f);
|
|
REQUIRE(particle.material.viscosity == .7f);
|
|
REQUIRE(particle.material.cohesion == 1.5f);
|
|
REQUIRE(particle.material.buoyancy == -.25f);
|
|
REQUIRE(particle.material.drag == .4f);
|
|
REQUIRE(particle.material.atmosphericPressure == 2.5f);
|
|
REQUIRE(particle.material.vorticity == .8f);
|
|
REQUIRE(particle.material.diffusion == .6f);
|
|
REQUIRE(particle.data == glm::vec4(1.f, 2.f, 3.f, 4.f));
|
|
auto encoded = encodeVolumeFluidEmitterBlueprint3D(blueprint);
|
|
auto decoded = decodeVolumeFluidEmitterBlueprint3D(encoded);
|
|
REQUIRE(decoded.ok());
|
|
REQUIRE(decoded.value().capacity == 321);
|
|
REQUIRE(decoded.value().diffusionData == glm::vec4(1.f, 2.f, 3.f, 4.f));
|
|
encoded.set("futureField", 1.0);
|
|
REQUIRE(!decodeVolumeFluidEmitterBlueprint3D(encoded).ok());
|
|
blueprint.atmosphericDrag = -1.f;
|
|
REQUIRE(!prepareVolumeFluidEmitterBlueprint3D(blueprint).ok());
|
|
}
|
|
|
|
TEST_CASE("fluids.volumeEmitter.granularBlueprintPreparesCapacityRadiusAndDensity") {
|
|
VolumeGranularEmitterBlueprint3D blueprint;
|
|
blueprint.capacity = 64;
|
|
blueprint.resolution = 8.f;
|
|
blueprint.restDensity = 1450.f;
|
|
blueprint.randomness = 35.f;
|
|
auto prepared = prepareVolumeGranularEmitterBlueprint3D(blueprint);
|
|
REQUIRE(prepared.ok());
|
|
REQUIRE(prepared.value().settings.capacity == 64);
|
|
REQUIRE(std::abs(prepared.value().settings.spacing - .05f) < 1e-7f);
|
|
REQUIRE(prepared.value().emission.actorCapacity == 64);
|
|
REQUIRE(prepared.value().emission.granularRadiusRandomness == 35.f);
|
|
REQUIRE(prepared.value().emission.prototype.material.phase == VolumeFluidPhase::Granular);
|
|
REQUIRE(prepared.value().emission.prototype.material.density == 1450.f);
|
|
REQUIRE(prepared.value().metrics.smoothingRadius == 0.f);
|
|
auto encoded = encodeVolumeGranularEmitterBlueprint3D(blueprint);
|
|
REQUIRE(decodeVolumeGranularEmitterBlueprint3D(encoded).ok());
|
|
encoded.set("futureField", int64_t(1));
|
|
REQUIRE(!decodeVolumeGranularEmitterBlueprint3D(encoded).ok());
|
|
blueprint.randomness = 100.01f;
|
|
REQUIRE(!prepareVolumeGranularEmitterBlueprint3D(blueprint).ok());
|
|
}
|