This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/extern/mantaflow/preprocessed/plugin/surfaceturbulence.cpp
2020-11-06 12:06:05 +01:00

2190 lines
72 KiB
C++

// DO NOT EDIT !
// This file is generated using the MantaFlow preprocessor (prep generate).
/******************************************************************************
*
* MantaFlow fluid solver framework
* Copyright 2016 Olivier Mercier, oli.mercier@gmail.com
*
* This program is free software, distributed under the terms of the
* Apache License, Version 2.0
* http://www.apache.org/licenses/LICENSE-2.0
*
* Surface Turbulence for Particle-Based Liquid Simulations
* Mercier et al., SIGGRAPH Asia 2015
*
* Possible speedups :
* - only initialize surface points around coarse particles near the surface. Use the flags in the
*fluid grid and only use cells with non-fluid neighbors.
*
******************************************************************************/
// use chrono stl for detailed timing only if available
#ifdef __GNUC__
# if __GNUC__ < 5
# define USE_CHRONO 0
# endif
#endif
#if MANTA_WITHCPP11 == 1
# ifndef USE_CHRONO
# define USE_CHRONO 1
# endif
#endif
#include <iomanip>
#if USE_CHRONO == 1
# include <chrono>
#endif
#include "particle.h"
using namespace std;
namespace Manta {
// own namespace for globals
namespace SurfaceTurbulence {
//
// **** surface turbulence parameters ****
//
struct SurfaceTurbulenceParameters {
int res;
Real outerRadius;
int surfaceDensity;
int nbSurfaceMaintenanceIterations;
Real dt;
Real waveSpeed;
Real waveDamping;
Real waveSeedFrequency;
Real waveMaxAmplitude;
Real waveMaxFrequency;
Real waveMaxSeedingAmplitude; // as ratio of max amp;
Real waveSeedingCurvatureThresholdRegionCenter;
Real waveSeedingCurvatureThresholdRegionRadius;
Real waveSeedStepSizeRatioOfMax;
Real innerRadius;
Real meanFineDistance;
Real constraintA;
Real normalRadius;
Real tangentRadius;
Real bndXm, bndXp, bndYm, bndYp, bndZm, bndZp;
};
SurfaceTurbulenceParameters params;
//
// **** acceleration grid for particle neighbor queries ****
//
struct ParticleAccelGrid {
int res;
vector<int> ***indices;
void init(int inRes)
{
res = inRes;
indices = new vector<int> **[res];
for (int i = 0; i < res; i++) {
indices[i] = new vector<int> *[res];
for (int j = 0; j < res; j++) {
indices[i][j] = new vector<int>[res];
}
}
}
void fillWith(const BasicParticleSystem &particles)
{
// clear
for (int i = 0; i < res; i++) {
for (int j = 0; j < res; j++) {
for (int k = 0; k < res; k++) {
indices[i][j][k].clear();
}
}
}
// fill
for (int id = 0; id < particles.size(); id++) {
Vec3 pos = particles.getPos(id);
int i = clamp<int>(floor(pos.x / params.res * res), 0, res - 1);
int j = clamp<int>(floor(pos.y / params.res * res), 0, res - 1);
int k = clamp<int>(floor(pos.z / params.res * res), 0, res - 1);
indices[i][j][k].push_back(id);
}
}
void fillWith(const ParticleDataImpl<Vec3> &particles)
{
// clear
for (int i = 0; i < res; i++) {
for (int j = 0; j < res; j++) {
for (int k = 0; k < res; k++) {
indices[i][j][k].clear();
}
}
}
// fill
for (int id = 0; id < particles.size(); id++) {
Vec3 pos = particles[id];
int i = clamp<int>(floor(pos.x / params.res * res), 0, res - 1);
int j = clamp<int>(floor(pos.y / params.res * res), 0, res - 1);
int k = clamp<int>(floor(pos.z / params.res * res), 0, res - 1);
indices[i][j][k].push_back(id);
}
}
};
#define LOOP_NEIGHBORS_BEGIN(points, center, radius) \
int minI = clamp<int>( \
floor((center.x - radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
int maxI = clamp<int>( \
floor((center.x + radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
int minJ = clamp<int>( \
floor((center.y - radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
int maxJ = clamp<int>( \
floor((center.y + radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
int minK = clamp<int>( \
floor((center.z - radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
int maxK = clamp<int>( \
floor((center.z + radius) / params.res * points.accel->res), 0, points.accel->res - 1); \
for (int i = minI; i <= maxI; i++) { \
for (int j = minJ; j <= maxJ; j++) { \
for (int k = minK; k <= maxK; k++) { \
for (int idLOOPNEIGHBORS = 0; \
idLOOPNEIGHBORS < (int)points.accel->indices[i][j][k].size(); \
idLOOPNEIGHBORS++) { \
int idn = points.accel->indices[i][j][k][idLOOPNEIGHBORS]; \
if (points.isActive(idn)) {
#define LOOP_NEIGHBORS_END \
} \
} \
} \
} \
}
#define LOOP_GHOSTS_POS_BEGIN(pos, radius) \
int flagLOOPGHOSTS = -1; \
Vec3 gPos; \
while (flagLOOPGHOSTS < 6) { \
if (flagLOOPGHOSTS < 0 && pos.x - params.bndXm <= radius) { \
flagLOOPGHOSTS = 0; \
gPos = Vec3(2.f * params.bndXm - pos.x, pos.y, pos.z); \
} \
else if (flagLOOPGHOSTS < 1 && params.bndXp - pos.x <= radius) { \
flagLOOPGHOSTS = 1; \
gPos = Vec3(2.f * params.bndXp - pos.x, pos.y, pos.z); \
} \
else if (flagLOOPGHOSTS < 2 && pos.y - params.bndYm <= radius) { \
flagLOOPGHOSTS = 2; \
gPos = Vec3(pos.x, 2.f * params.bndYm - pos.y, pos.z); \
} \
else if (flagLOOPGHOSTS < 3 && params.bndYp - pos.y <= radius) { \
flagLOOPGHOSTS = 3; \
gPos = Vec3(pos.x, 2.f * params.bndYp - pos.y, pos.z); \
} \
else if (flagLOOPGHOSTS < 4 && pos.z - params.bndZm <= radius) { \
flagLOOPGHOSTS = 4; \
gPos = Vec3(pos.x, pos.y, 2.f * params.bndZm - pos.z); \
} \
else if (flagLOOPGHOSTS < 5 && params.bndZp - pos.Z <= radius) { \
flagLOOPGHOSTS = 5; \
gPos = Vec3(pos.x, pos.y, 2.f * params.bndZp - pos.z); \
} \
else { \
flagLOOPGHOSTS = 6; \
gPos = Vec3(pos.x, pos.y, pos.z); \
}
#define LOOP_GHOSTS_POS_NORMAL_BEGIN(pos, normal, radius) \
int flagLOOPGHOSTS = -1; \
Vec3 gPos, gNormal; \
while (flagLOOPGHOSTS < 6) { \
if (flagLOOPGHOSTS < 0 && pos.x - params.bndXm <= radius) { \
flagLOOPGHOSTS = 0; \
gPos = Vec3(2.f * params.bndXm - pos.x, pos.y, pos.z); \
gNormal = Vec3(-normal.x, normal.y, normal.z); \
} \
else if (flagLOOPGHOSTS < 1 && params.bndXp - pos.x <= radius) { \
flagLOOPGHOSTS = 1; \
gPos = Vec3(2.f * params.bndXp - pos.x, pos.y, pos.z); \
gNormal = Vec3(-normal.x, normal.y, normal.z); \
} \
else if (flagLOOPGHOSTS < 2 && pos.y - params.bndYm <= radius) { \
flagLOOPGHOSTS = 2; \
gPos = Vec3(pos.x, 2.f * params.bndYm - pos.y, pos.z); \
gNormal = Vec3(normal.x, -normal.y, normal.z); \
} \
else if (flagLOOPGHOSTS < 3 && params.bndYp - pos.y <= radius) { \
flagLOOPGHOSTS = 3; \
gPos = Vec3(pos.x, 2.f * params.bndYp - pos.y, pos.z); \
gNormal = Vec3(normal.x, -normal.y, normal.z); \
} \
else if (flagLOOPGHOSTS < 4 && pos.z - params.bndZm <= radius) { \
flagLOOPGHOSTS = 4; \
gPos = Vec3(pos.x, pos.y, 2.f * params.bndZm - pos.z); \
gNormal = Vec3(normal.x, normal.y, -normal.z); \
} \
else if (flagLOOPGHOSTS < 5 && params.bndZp - pos.Z <= radius) { \
flagLOOPGHOSTS = 5; \
gPos = Vec3(pos.x, pos.y, 2.f * params.bndZp - pos.z); \
gNormal = Vec3(normal.x, normal.y, -normal.z); \
} \
else { \
flagLOOPGHOSTS = 6; \
gPos = pos; \
gNormal = normal; \
}
#define LOOP_GHOSTS_END }
//
// **** Wrappers around point sets to attach it an acceleration grid ****
//
struct PointSetWrapper {
ParticleAccelGrid *accel;
PointSetWrapper(ParticleAccelGrid *inAccel)
{
accel = inAccel;
}
virtual void updateAccel() = 0;
};
struct BasicParticleSystemWrapper : PointSetWrapper {
BasicParticleSystem *points;
BasicParticleSystemWrapper(ParticleAccelGrid *inAccel) : PointSetWrapper(inAccel)
{
}
Vec3 getPos(int id) const
{
return points->getPos(id);
}
void setPos(int id, Vec3 pos)
{
points->setPos(id, pos);
}
void updateAccel()
{
accel->fillWith(*points);
}
void clear()
{
points->clear();
}
int size() const
{
return points->size();
}
bool isActive(int id) const
{
return points->isActive(id);
}
void addParticle(Vec3 pos)
{
points->addParticle(pos);
}
int getStatus(int id) const
{
return points->getStatus(id);
}
void addBuffered(Vec3 pos)
{
points->addBuffered(pos);
}
void doCompress()
{
points->doCompress();
}
void insertBufferedParticles()
{
points->insertBufferedParticles();
}
void kill(int id)
{
points->kill(id);
}
bool hasNeighbor(Vec3 pos, Real radius) const
{
bool answer = false;
int minI = clamp<int>(floor((pos.x - radius) / params.res * accel->res), 0, accel->res - 1);
int maxI = clamp<int>(floor((pos.x + radius) / params.res * accel->res), 0, accel->res - 1);
int minJ = clamp<int>(floor((pos.y - radius) / params.res * accel->res), 0, accel->res - 1);
int maxJ = clamp<int>(floor((pos.y + radius) / params.res * accel->res), 0, accel->res - 1);
int minK = clamp<int>(floor((pos.z - radius) / params.res * accel->res), 0, accel->res - 1);
int maxK = clamp<int>(floor((pos.z + radius) / params.res * accel->res), 0, accel->res - 1);
for (int i = minI; i <= maxI; i++) {
for (int j = minJ; j <= maxJ; j++) {
for (int k = minK; k <= maxK; k++) {
for (int id = 0; id < (int)accel->indices[i][j][k].size(); id++) {
if (points->isActive(accel->indices[i][j][k][id]) &&
norm(points->getPos(accel->indices[i][j][k][id]) - pos) <= radius) {
answer = true;
break;
}
}
if (answer)
break;
}
if (answer)
break;
}
if (answer)
break;
}
return answer;
}
bool hasNeighborOtherThanItself(int idx, Real radius) const
{
bool answer = false;
Vec3 pos = points->getPos(idx);
int minI = clamp<int>(floor((pos.x - radius) / params.res * accel->res), 0, accel->res - 1);
int maxI = clamp<int>(floor((pos.x + radius) / params.res * accel->res), 0, accel->res - 1);
int minJ = clamp<int>(floor((pos.y - radius) / params.res * accel->res), 0, accel->res - 1);
int maxJ = clamp<int>(floor((pos.y + radius) / params.res * accel->res), 0, accel->res - 1);
int minK = clamp<int>(floor((pos.z - radius) / params.res * accel->res), 0, accel->res - 1);
int maxK = clamp<int>(floor((pos.z + radius) / params.res * accel->res), 0, accel->res - 1);
for (int i = minI; i <= maxI; i++) {
for (int j = minJ; j <= maxJ; j++) {
for (int k = minK; k <= maxK; k++) {
for (int id = 0; id < (int)accel->indices[i][j][k].size(); id++) {
if (accel->indices[i][j][k][id] != idx &&
points->isActive(accel->indices[i][j][k][id]) &&
norm(points->getPos(accel->indices[i][j][k][id]) - pos) <= radius) {
answer = true;
break;
}
}
if (answer)
break;
}
if (answer)
break;
}
if (answer)
break;
}
return answer;
}
void removeInvalidIndices(vector<int> &indices)
{
vector<int> copy;
copy.resize(indices.size());
for (int i = 0; i < (int)indices.size(); i++) {
copy[i] = indices[i];
}
indices.clear();
for (int i = 0; i < (int)copy.size(); i++) {
if (points->isActive(copy[i])) {
indices.push_back(copy[i]);
}
}
}
};
struct ParticleDataImplVec3Wrapper : PointSetWrapper {
ParticleDataImpl<Vec3> *points;
ParticleDataImplVec3Wrapper(ParticleAccelGrid *inAccel) : PointSetWrapper(inAccel)
{
}
Vec3 getVec3(int id) const
{
return (*points)[id];
}
void setVec3(int id, Vec3 vec)
{
(*points)[id] = vec;
}
void updateAccel()
{
accel->fillWith(*points);
}
bool isActive(int i) const
{
return true;
}
};
//
// **** globals ****
//
ParticleAccelGrid accelCoarse, accelSurface;
BasicParticleSystemWrapper coarseParticles(&accelCoarse), surfacePoints(&accelSurface);
ParticleDataImplVec3Wrapper coarseParticlesPrevPos(
&accelCoarse); // WARNING: reusing the coarse accel grid to save space, don't query
// coarseParticlesPrevPos and coarseParticles at the same time.
vector<Vec3> tempSurfaceVec3; // to store misc info on surface points
vector<Real> tempSurfaceFloat; // to store misc info on surface points
int frameCount = 0;
//
//**** weighting kernels *****
//
Real triangularWeight(Real distance, Real radius)
{
return 1.0f - distance / radius;
}
Real exponentialWeight(Real distance, Real radius, Real falloff)
{
if (distance > radius)
return 0;
Real tmp = distance / radius;
return expf(-falloff * tmp * tmp);
}
Real weightKernelAdvection(Real distance)
{
if (distance > 2.f * params.outerRadius) {
return 0;
}
else {
return triangularWeight(distance, 2.f * params.outerRadius);
}
}
Real weightKernelCoarseDensity(Real distance)
{
return exponentialWeight(distance, params.outerRadius, 2.0f);
}
Real weightSurfaceNormal(Real distance)
{
if (distance > params.normalRadius) {
return 0;
}
else {
return triangularWeight(distance, params.normalRadius);
}
}
Real weightSurfaceTangent(Real distance)
{
if (distance > params.tangentRadius) {
return 0;
}
else {
return triangularWeight(distance, params.tangentRadius);
}
}
//
// **** utility ****
//
bool isInDomain(Vec3 pos)
{
return params.bndXm <= pos.x && pos.x <= params.bndXp && params.bndYm <= pos.y &&
pos.y <= params.bndYp && params.bndZm <= pos.z && pos.z <= params.bndZp;
}
Real smoothstep(Real edgeLeft, Real edgeRight, Real val)
{
Real x = clamp((val - edgeLeft) / (edgeRight - edgeLeft), Real(0.), Real(1.));
return x * x * (3 - 2 * x);
}
//
// **** surface initialization ****
//
void initFines(const BasicParticleSystemWrapper &coarseParticles,
BasicParticleSystemWrapper &surfacePoints,
const FlagGrid &flags)
{
unsigned int discretization = (unsigned int)M_PI * (params.outerRadius + params.innerRadius) /
params.meanFineDistance;
Real dtheta = 2 * params.meanFineDistance / (params.outerRadius + params.innerRadius);
Real outerRadius2 = params.outerRadius * params.outerRadius;
surfacePoints.clear();
for (int idx = 0; idx < (int)coarseParticles.size(); idx++) {
if (idx % 500 == 0) {
cout << "Initializing surface points : " << setprecision(4)
<< 100.f * idx / coarseParticles.size() << "%" << endl;
}
if (coarseParticles.isActive(idx)) {
// check flags if we are near surface
bool nearSurface = false;
Vec3 pos = coarseParticles.getPos(idx);
for (int i = -1; i <= 1; i++) {
for (int j = -1; j <= 1; j++) {
for (int k = -1; k <= 1; k++) {
if (!flags.isFluid(((int)pos.x) + i, ((int)pos.y) + j, ((int)pos.z) + k)) {
nearSurface = true;
break;
}
}
}
}
if (nearSurface) {
for (unsigned int i = 0; i <= discretization / 2; ++i) {
Real discretization2 = Real(floor(2 * M_PI * sin(i * dtheta) / dtheta) + 1);
for (Real phi = 0; phi < 2 * M_PI; phi += Real(2 * M_PI / discretization2)) {
Real theta = i * dtheta;
Vec3 normal(sin(theta) * cos(phi), cos(theta), sin(theta) * sin(phi));
Vec3 position = coarseParticles.getPos(idx) + params.outerRadius * normal;
bool valid = true;
LOOP_NEIGHBORS_BEGIN(coarseParticles, position, 2.f * params.outerRadius)
if (idx != idn && normSquare(position - coarseParticles.getPos(idn)) < outerRadius2) {
valid = false;
break;
}
LOOP_NEIGHBORS_END
if (valid) {
surfacePoints.addParticle(position);
}
}
}
}
}
}
}
//
// **** surface advection ****
//
struct advectSurfacePoints : public KernelBase {
advectSurfacePoints(BasicParticleSystemWrapper &surfacePoints,
const BasicParticleSystemWrapper &coarseParticles,
const ParticleDataImplVec3Wrapper &coarseParticlesPrevPos)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
coarseParticles(coarseParticles),
coarseParticlesPrevPos(coarseParticlesPrevPos)
{
runMessage();
run();
}
inline void op(IndexInt idx,
BasicParticleSystemWrapper &surfacePoints,
const BasicParticleSystemWrapper &coarseParticles,
const ParticleDataImplVec3Wrapper &coarseParticlesPrevPos) const
{
if (surfacePoints.isActive(idx)) {
Vec3 avgDisplacement(0, 0, 0);
Real totalWeight = 0;
Vec3 p = surfacePoints.getPos(idx);
LOOP_NEIGHBORS_BEGIN(
coarseParticlesPrevPos, surfacePoints.getPos(idx), 2.0f * params.outerRadius)
if ((coarseParticles.getStatus(idn) & ParticleBase::PNEW) == 0 &&
(coarseParticles.getStatus(idn) & ParticleBase::PDELETE) == 0) {
Vec3 disp = coarseParticles.getPos(idn) - coarseParticlesPrevPos.getVec3(idn);
Real distance = norm(coarseParticlesPrevPos.getVec3(idn) - p);
Real w = weightKernelAdvection(distance);
avgDisplacement += w * disp;
totalWeight += w;
}
LOOP_NEIGHBORS_END
if (totalWeight != 0)
avgDisplacement /= totalWeight;
surfacePoints.setPos(idx, p + avgDisplacement);
}
}
inline BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline const BasicParticleSystemWrapper &getArg1()
{
return coarseParticles;
}
typedef BasicParticleSystemWrapper type1;
inline const ParticleDataImplVec3Wrapper &getArg2()
{
return coarseParticlesPrevPos;
}
typedef ParticleDataImplVec3Wrapper type2;
void runMessage()
{
debMsg("Executing kernel advectSurfacePoints ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, coarseParticles, coarseParticlesPrevPos);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
BasicParticleSystemWrapper &surfacePoints;
const BasicParticleSystemWrapper &coarseParticles;
const ParticleDataImplVec3Wrapper &coarseParticlesPrevPos;
};
//
// **** value and gradient of level-set band constraint ****
//
Real computeConstraintLevel(const BasicParticleSystemWrapper &coarseParticles, Vec3 pos)
{
Real lvl = 0.0f;
LOOP_NEIGHBORS_BEGIN(coarseParticles, pos, 1.5f * params.outerRadius)
lvl += expf(-params.constraintA * normSquare(coarseParticles.getPos(idn) - pos));
LOOP_NEIGHBORS_END
if (lvl > 1.0f)
lvl = 1.0f;
lvl = (sqrtf(-logf(lvl) / params.constraintA) - params.innerRadius) /
(params.outerRadius - params.innerRadius);
return lvl;
}
Vec3 computeConstraintGradient(const BasicParticleSystemWrapper &coarseParticles, Vec3 pos)
{
Vec3 gradient(0, 0, 0);
LOOP_NEIGHBORS_BEGIN(coarseParticles, pos, 1.5f * params.outerRadius)
gradient += 2.f * params.constraintA *
(Real)(expf(-params.constraintA * normSquare(coarseParticles.getPos(idn) - pos))) *
(pos - coarseParticles.getPos(idn));
LOOP_NEIGHBORS_END
return getNormalized(gradient);
}
//
// **** compute surface normals ****
//
struct computeSurfaceNormals : public KernelBase {
computeSurfaceNormals(const BasicParticleSystemWrapper &surfacePoints,
const BasicParticleSystemWrapper &coarseParticles,
ParticleDataImpl<Vec3> &surfaceNormals)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
coarseParticles(coarseParticles),
surfaceNormals(surfaceNormals)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
const BasicParticleSystemWrapper &coarseParticles,
ParticleDataImpl<Vec3> &surfaceNormals) const
{
Vec3 pos = surfacePoints.getPos(idx);
// approx normal with gradient
Vec3 gradient = computeConstraintGradient(coarseParticles, pos);
// get tangent frame
Vec3 n = getNormalized(gradient);
Vec3 vx(1, 0, 0);
Vec3 vy(0, 1, 0);
Real dotX = dot(n, vx);
Real dotY = dot(n, vy);
Vec3 t1 = getNormalized(fabs(dotX) < fabs(dotY) ? cross(n, vx) : cross(n, vy));
Vec3 t2 = getNormalized(cross(n, t1)); // initial frame
// linear fit of neighboring surface points in approximated tangent frame
Real sw = 0, swx = 0, swy = 0, swxy = 0, swx2 = 0, swy2 = 0, swxz = 0, swyz = 0, swz = 0;
LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.normalRadius)
Real x = dot(gPos - pos, t1);
Real y = dot(gPos - pos, t2);
Real z = dot(gPos - pos, n);
Real w = weightSurfaceNormal(norm(pos - gPos));
swx2 += w * x * x;
swy2 += w * y * y;
swxy += w * x * y;
swxz += w * x * z;
swyz += w * y * z;
swx += w * x;
swy += w * y;
swz += w * z;
sw += w;
LOOP_GHOSTS_END
LOOP_NEIGHBORS_END
Real det = -sw * swxy * swxy + 2.f * swx * swxy * swy - swx2 * swy * swy - swx * swx * swy2 +
sw * swx2 * swy2;
if (det == 0) {
surfaceNormals[idx] = Vec3(0, 0, 0);
}
else {
Vec3 abc = 1.f / det *
Vec3(swxz * (-swy * swy + sw * swy2) + swyz * (-sw * swxy + swx * swy) +
swz * (swxy * swy - swx * swy2),
swxz * (-sw * swxy + swx * swy) + swyz * (-swx * swx + sw * swx2) +
swz * (swx * swxy - swx2 * swy),
swxz * (swxy * swy - swx * swy2) + swyz * (swx * swxy - swx2 * swy) +
swz * (-swxy * swxy + swx2 * swy2));
Vec3 normal = -getNormalized(t1 * abc.x + t2 * abc.y - n);
if (dot(gradient, normal) < 0) {
normal = -normal;
}
surfaceNormals[idx] = normal;
}
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline const BasicParticleSystemWrapper &getArg1()
{
return coarseParticles;
}
typedef BasicParticleSystemWrapper type1;
inline ParticleDataImpl<Vec3> &getArg2()
{
return surfaceNormals;
}
typedef ParticleDataImpl<Vec3> type2;
void runMessage()
{
debMsg("Executing kernel computeSurfaceNormals ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, coarseParticles, surfaceNormals);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
const BasicParticleSystemWrapper &coarseParticles;
ParticleDataImpl<Vec3> &surfaceNormals;
};
//
// **** smooth surface normals ****
//
struct computeAveragedNormals : public KernelBase {
computeAveragedNormals(const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceNormals(surfaceNormals)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals) const
{
Vec3 pos = surfacePoints.getPos(idx);
Vec3 newNormal = Vec3(0, 0, 0);
LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
Real w = weightSurfaceNormal(norm(pos - surfacePoints.getPos(idn)));
newNormal += w * surfaceNormals[idn];
LOOP_NEIGHBORS_END
tempSurfaceVec3[idx] = getNormalized(newNormal);
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline const ParticleDataImpl<Vec3> &getArg1()
{
return surfaceNormals;
}
typedef ParticleDataImpl<Vec3> type1;
void runMessage()
{
debMsg("Executing kernel computeAveragedNormals ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceNormals);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
const ParticleDataImpl<Vec3> &surfaceNormals;
};
struct assignNormals : public KernelBase {
assignNormals(const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Vec3> &surfaceNormals)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceNormals(surfaceNormals)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Vec3> &surfaceNormals) const
{
surfaceNormals[idx] = tempSurfaceVec3[idx];
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline ParticleDataImpl<Vec3> &getArg1()
{
return surfaceNormals;
}
typedef ParticleDataImpl<Vec3> type1;
void runMessage()
{
debMsg("Executing kernel assignNormals ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceNormals);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
ParticleDataImpl<Vec3> &surfaceNormals;
};
void smoothSurfaceNormals(const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Vec3> &surfaceNormals)
{
tempSurfaceVec3.resize(surfacePoints.size());
computeAveragedNormals(surfacePoints, surfaceNormals);
assignNormals(surfacePoints, surfaceNormals);
}
//
// **** addition/deletion of particles. Not parallel to prevent write/delete conflicts ****
//
void addDeleteSurfacePoints(BasicParticleSystemWrapper &surfacePoints)
{
int fixedSize = surfacePoints.size();
for (int idx = 0; idx < fixedSize; idx++) {
// compute proxy tangent displacement
Vec3 pos = surfacePoints.getPos(idx);
Vec3 gradient = computeConstraintGradient(coarseParticles, pos);
Real wt = 0;
Vec3 tangentDisplacement(0, 0, 0);
LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
if (idn != idx) {
Vec3 dir = pos - surfacePoints.getPos(idn);
Real length = norm(dir);
dir = getNormalized(dir);
// Decompose direction into normal and tangent directions.
Vec3 dn = dot(dir, gradient) * gradient;
Vec3 dt = dir - dn;
Real w = weightSurfaceTangent(length);
wt += w;
tangentDisplacement += w * dt;
}
LOOP_NEIGHBORS_END
if (norm(tangentDisplacement) != 0) {
tangentDisplacement = getNormalized(tangentDisplacement);
}
// check density criterion, add surface point if necessary
Vec3 creationPos = pos + params.meanFineDistance * tangentDisplacement;
if (isInDomain(creationPos) &&
!surfacePoints.hasNeighbor(creationPos, params.meanFineDistance - (1e-6))) {
// create point
surfacePoints.addBuffered(creationPos);
}
}
surfacePoints.doCompress();
surfacePoints.insertBufferedParticles();
// check density criterion, delete surface points if necessary
fixedSize = surfacePoints.size();
for (int idx = 0; idx < fixedSize; idx++) {
if (!isInDomain(surfacePoints.getPos(idx)) ||
surfacePoints.hasNeighborOtherThanItself(idx, 0.67 * params.meanFineDistance)) {
surfacePoints.kill(idx);
}
}
// delete surface points if no coarse neighbors in advection radius
fixedSize = surfacePoints.size();
for (int idx = 0; idx < fixedSize; idx++) {
Vec3 pos = surfacePoints.getPos(idx);
if (!coarseParticles.hasNeighbor(pos, 2.f * params.outerRadius)) {
surfacePoints.kill(idx);
}
}
// delete surface point if too far from constraint
fixedSize = surfacePoints.size();
for (int idx = 0; idx < fixedSize; idx++) {
Real level = computeConstraintLevel(coarseParticles, surfacePoints.getPos(idx));
if (level < -0.2 || level > 1.2) {
surfacePoints.kill(idx);
}
}
surfacePoints.doCompress();
surfacePoints.insertBufferedParticles();
}
//
// **** surface maintenance ****
//
struct computeSurfaceDensities : public KernelBase {
computeSurfaceDensities(const BasicParticleSystemWrapper &surfacePoints, void *dummy)
: KernelBase(surfacePoints.size()), surfacePoints(surfacePoints), dummy(dummy)
{
runMessage();
run();
}
inline void op(IndexInt idx, const BasicParticleSystemWrapper &surfacePoints, void *dummy) const
{
Vec3 pos = surfacePoints.getPos(idx);
Real density = 0;
LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.normalRadius)
density += weightSurfaceNormal(norm(pos - gPos));
LOOP_GHOSTS_END
LOOP_NEIGHBORS_END
tempSurfaceFloat[idx] = density;
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline void *getArg1()
{
return dummy;
}
typedef void type1;
void runMessage()
{
debMsg("Executing kernel computeSurfaceDensities ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, dummy);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
void *dummy;
};
struct computeSurfaceDisplacements : public KernelBase {
computeSurfaceDisplacements(const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceNormals(surfaceNormals)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals) const
{
Vec3 pos = surfacePoints.getPos(idx);
Vec3 normal = surfaceNormals[idx];
Vec3 displacementNormal(0, 0, 0);
Vec3 displacementTangent(0, 0, 0);
Real wTotal = 0;
LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.normalRadius)
LOOP_GHOSTS_POS_NORMAL_BEGIN(
surfacePoints.getPos(idn), surfaceNormals[idn], params.normalRadius)
Vec3 dir = pos - gPos;
Real length = norm(dir);
Vec3 dn = dot(dir, surfaceNormals[idx]) * surfaceNormals[idx];
Vec3 dt = dir - dn;
if (tempSurfaceFloat[idn] == 0) {
continue;
}
Real w = weightSurfaceNormal(length) / tempSurfaceFloat[idn];
Vec3 crossVec = getNormalized(cross(normal, -dir));
Vec3 projectedNormal = getNormalized(gNormal - dot(crossVec, gNormal) * crossVec);
if (dot(projectedNormal, normal) < 0 || abs(dot(normal, normal + projectedNormal)) < 1e-6) {
continue;
}
dn = -dot(normal + projectedNormal, dir) / dot(normal, normal + projectedNormal) * normal;
displacementNormal += w * dn;
displacementTangent += w * getNormalized(dt);
wTotal += w;
LOOP_GHOSTS_END
LOOP_NEIGHBORS_END
if (wTotal != 0) {
displacementNormal /= wTotal;
displacementTangent /= wTotal;
}
displacementNormal *= .75f;
displacementTangent *= .25f * params.meanFineDistance;
tempSurfaceVec3[idx] = displacementNormal + displacementTangent;
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline const ParticleDataImpl<Vec3> &getArg1()
{
return surfaceNormals;
}
typedef ParticleDataImpl<Vec3> type1;
void runMessage()
{
debMsg("Executing kernel computeSurfaceDisplacements ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceNormals);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
const ParticleDataImpl<Vec3> &surfaceNormals;
};
struct applySurfaceDisplacements : public KernelBase {
applySurfaceDisplacements(BasicParticleSystemWrapper &surfacePoints, void *dummy)
: KernelBase(surfacePoints.size()), surfacePoints(surfacePoints), dummy(dummy)
{
runMessage();
run();
}
inline void op(IndexInt idx, BasicParticleSystemWrapper &surfacePoints, void *dummy) const
{
surfacePoints.setPos(idx, surfacePoints.getPos(idx) + tempSurfaceVec3[idx]);
}
inline BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline void *getArg1()
{
return dummy;
}
typedef void type1;
void runMessage()
{
debMsg("Executing kernel applySurfaceDisplacements ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, dummy);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
BasicParticleSystemWrapper &surfacePoints;
void *dummy;
};
void regularizeSurfacePoints(BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals)
{
tempSurfaceVec3.resize(surfacePoints.size());
tempSurfaceFloat.resize(surfacePoints.size());
computeSurfaceDensities(surfacePoints, 0);
computeSurfaceDisplacements(surfacePoints, surfaceNormals);
applySurfaceDisplacements(surfacePoints, 0);
}
struct constrainSurface : public KernelBase {
constrainSurface(BasicParticleSystemWrapper &surfacePoints,
const BasicParticleSystemWrapper &coarseParticles)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
coarseParticles(coarseParticles)
{
runMessage();
run();
}
inline void op(IndexInt idx,
BasicParticleSystemWrapper &surfacePoints,
const BasicParticleSystemWrapper &coarseParticles) const
{
Vec3 pos = surfacePoints.getPos(idx);
Real level = computeConstraintLevel(coarseParticles, surfacePoints.getPos(idx));
if (level > 1) {
surfacePoints.setPos(
idx,
pos - (params.outerRadius - params.innerRadius) * (level - 1) *
computeConstraintGradient(coarseParticles, surfacePoints.getPos(idx)));
}
else if (level < 0) {
surfacePoints.setPos(
idx,
pos - (params.outerRadius - params.innerRadius) * level *
computeConstraintGradient(coarseParticles, surfacePoints.getPos(idx)));
}
}
inline BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline const BasicParticleSystemWrapper &getArg1()
{
return coarseParticles;
}
typedef BasicParticleSystemWrapper type1;
void runMessage()
{
debMsg("Executing kernel constrainSurface ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, coarseParticles);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
BasicParticleSystemWrapper &surfacePoints;
const BasicParticleSystemWrapper &coarseParticles;
};
struct interpolateNewWaveData : public KernelBase {
interpolateNewWaveData(const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveH,
ParticleDataImpl<Real> &surfaceWaveDtH,
ParticleDataImpl<Real> &surfaceWaveSeed,
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceWaveH(surfaceWaveH),
surfaceWaveDtH(surfaceWaveDtH),
surfaceWaveSeed(surfaceWaveSeed),
surfaceWaveSeedAmplitude(surfaceWaveSeedAmplitude)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveH,
ParticleDataImpl<Real> &surfaceWaveDtH,
ParticleDataImpl<Real> &surfaceWaveSeed,
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude) const
{
if (surfacePoints.getStatus(idx) & ParticleBase::PNEW) {
Vec3 pos = surfacePoints.getPos(idx);
surfaceWaveH[idx] = 0;
surfaceWaveDtH[idx] = 0;
Real wTotal = 0;
LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
if (!(surfacePoints.getStatus(idn) & ParticleBase::PNEW)) {
Real w = weightSurfaceTangent(norm(pos - surfacePoints.getPos(idn)));
surfaceWaveH[idx] += w * surfaceWaveH[idn];
surfaceWaveDtH[idx] += w * surfaceWaveDtH[idn];
surfaceWaveSeed[idx] += w * surfaceWaveSeed[idn];
surfaceWaveSeedAmplitude[idx] += w * surfaceWaveSeedAmplitude[idn];
wTotal += w;
}
LOOP_NEIGHBORS_END
if (wTotal != 0) {
surfaceWaveH[idx] /= wTotal;
surfaceWaveDtH[idx] /= wTotal;
surfaceWaveSeed[idx] /= wTotal;
surfaceWaveSeedAmplitude[idx] /= wTotal;
}
}
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline ParticleDataImpl<Real> &getArg1()
{
return surfaceWaveH;
}
typedef ParticleDataImpl<Real> type1;
inline ParticleDataImpl<Real> &getArg2()
{
return surfaceWaveDtH;
}
typedef ParticleDataImpl<Real> type2;
inline ParticleDataImpl<Real> &getArg3()
{
return surfaceWaveSeed;
}
typedef ParticleDataImpl<Real> type3;
inline ParticleDataImpl<Real> &getArg4()
{
return surfaceWaveSeedAmplitude;
}
typedef ParticleDataImpl<Real> type4;
void runMessage()
{
debMsg("Executing kernel interpolateNewWaveData ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx,
surfacePoints,
surfaceWaveH,
surfaceWaveDtH,
surfaceWaveSeed,
surfaceWaveSeedAmplitude);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
ParticleDataImpl<Real> &surfaceWaveH;
ParticleDataImpl<Real> &surfaceWaveDtH;
ParticleDataImpl<Real> &surfaceWaveSeed;
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude;
};
void surfaceMaintenance(const BasicParticleSystemWrapper &coarseParticles,
BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Vec3> &surfaceNormals,
ParticleDataImpl<Real> &surfaceWaveH,
ParticleDataImpl<Real> &surfaceWaveDtH,
ParticleDataImpl<Real> &surfaceWaveSeed,
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude,
int nbIterations)
{
int countIterations = nbIterations;
while (countIterations > 0) {
addDeleteSurfacePoints(surfacePoints);
surfacePoints.updateAccel();
computeSurfaceNormals(surfacePoints, coarseParticles, surfaceNormals);
smoothSurfaceNormals(surfacePoints, surfaceNormals);
regularizeSurfacePoints(surfacePoints, surfaceNormals);
surfacePoints.updateAccel();
constrainSurface(surfacePoints, coarseParticles);
surfacePoints.updateAccel();
interpolateNewWaveData(
surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed, surfaceWaveSeedAmplitude);
countIterations--;
}
}
//
// **** surface wave seeding and evolution ****
//
struct addSeed : public KernelBase {
addSeed(const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveH,
const ParticleDataImpl<Real> &surfaceWaveSeed)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceWaveH(surfaceWaveH),
surfaceWaveSeed(surfaceWaveSeed)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveH,
const ParticleDataImpl<Real> &surfaceWaveSeed) const
{
surfaceWaveH[idx] += surfaceWaveSeed[idx];
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline ParticleDataImpl<Real> &getArg1()
{
return surfaceWaveH;
}
typedef ParticleDataImpl<Real> type1;
inline const ParticleDataImpl<Real> &getArg2()
{
return surfaceWaveSeed;
}
typedef ParticleDataImpl<Real> type2;
void runMessage()
{
debMsg("Executing kernel addSeed ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceWaveH, surfaceWaveSeed);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
ParticleDataImpl<Real> &surfaceWaveH;
const ParticleDataImpl<Real> &surfaceWaveSeed;
};
struct computeSurfaceWaveNormal : public KernelBase {
computeSurfaceWaveNormal(const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals,
const ParticleDataImpl<Real> &surfaceWaveH)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceNormals(surfaceNormals),
surfaceWaveH(surfaceWaveH)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals,
const ParticleDataImpl<Real> &surfaceWaveH) const
{
Vec3 pos = surfacePoints.getPos(idx);
// get tangent frame
Vec3 n = getNormalized(surfaceNormals[idx]);
Vec3 vx(1, 0, 0);
Vec3 vy(0, 1, 0);
Real dotX = dot(n, vx);
Real dotY = dot(n, vy);
Vec3 t1 = getNormalized(fabs(dotX) < fabs(dotY) ? cross(n, vx) : cross(n, vy));
Vec3 t2 = getNormalized(cross(n, t1));
// linear fit
Real sw = 0, swx = 0, swy = 0, swxy = 0, swx2 = 0, swy2 = 0, swxz = 0, swyz = 0, swz = 0;
LOOP_NEIGHBORS_BEGIN(surfacePoints, pos, params.tangentRadius)
LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.tangentRadius)
Real x = dot(gPos - pos, t1);
Real y = dot(gPos - pos, t2);
Real z = surfaceWaveH[idn];
Real w = weightSurfaceTangent(norm(pos - gPos));
swx2 += w * x * x;
swy2 += w * y * y;
swxy += w * x * y;
swxz += w * x * z;
swyz += w * y * z;
swx += w * x;
swy += w * y;
swz += w * z;
sw += w;
LOOP_GHOSTS_END
LOOP_NEIGHBORS_END
Real det = -sw * swxy * swxy + 2.f * swx * swxy * swy - swx2 * swy * swy - swx * swx * swy2 +
sw * swx2 * swy2;
if (det == 0) {
tempSurfaceVec3[idx] = Vec3(0, 0, 0);
}
else {
Vec3 abc = 1.f / det *
Vec3(swxz * (-swy * swy + sw * swy2) + swyz * (-sw * swxy + swx * swy) +
swz * (swxy * swy - swx * swy2),
swxz * (-sw * swxy + swx * swy) + swyz * (-swx * swx + sw * swx2) +
swz * (swx * swxy - swx2 * swy),
swxz * (swxy * swy - swx * swy2) + swyz * (swx * swxy - swx2 * swy) +
swz * (-swxy * swxy + swx2 * swy2));
Vec3 waveNormal = -getNormalized(vx * abc.x + vy * abc.y - Vec3(0, 0, 1));
tempSurfaceVec3[idx] = waveNormal;
}
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline const ParticleDataImpl<Vec3> &getArg1()
{
return surfaceNormals;
}
typedef ParticleDataImpl<Vec3> type1;
inline const ParticleDataImpl<Real> &getArg2()
{
return surfaceWaveH;
}
typedef ParticleDataImpl<Real> type2;
void runMessage()
{
debMsg("Executing kernel computeSurfaceWaveNormal ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceNormals, surfaceWaveH);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
const ParticleDataImpl<Vec3> &surfaceNormals;
const ParticleDataImpl<Real> &surfaceWaveH;
};
struct computeSurfaceWaveLaplacians : public KernelBase {
computeSurfaceWaveLaplacians(const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals,
const ParticleDataImpl<Real> &surfaceWaveH)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceNormals(surfaceNormals),
surfaceWaveH(surfaceWaveH)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals,
const ParticleDataImpl<Real> &surfaceWaveH) const
{
Real laplacian = 0;
Real wTotal = 0;
Vec3 pPos = surfacePoints.getPos(idx);
Vec3 pNormal = surfaceNormals[idx];
Vec3 vx(1, 0, 0);
Vec3 vy(0, 1, 0);
Real dotX = dot(pNormal, vx);
Real dotY = dot(pNormal, vy);
Vec3 t1 = getNormalized(fabs(dotX) < fabs(dotY) ? cross(pNormal, vx) : cross(pNormal, vy));
Vec3 t2 = getNormalized(cross(pNormal, t1));
Vec3 pWaveNormal = tempSurfaceVec3[idx];
Real ph = surfaceWaveH[idx];
if (pWaveNormal.z == 0) {
tempSurfaceFloat[idx] = 0;
}
else {
LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.tangentRadius)
Real nh = surfaceWaveH[idn];
LOOP_GHOSTS_POS_BEGIN(surfacePoints.getPos(idn), params.tangentRadius)
Vec3 dir = gPos - pPos;
Real lengthDir = norm(dir);
if (lengthDir < 1e-5)
continue;
Vec3 tangentDir = lengthDir * getNormalized(dir - dot(dir, pNormal) * pNormal);
Real dirX = dot(tangentDir, t1);
Real dirY = dot(tangentDir, t2);
Real dz = nh - ph - (-pWaveNormal.x / pWaveNormal.z) * dirX -
(-pWaveNormal.y / pWaveNormal.z) * dirY;
Real w = weightSurfaceTangent(norm(pPos - gPos));
wTotal += w;
laplacian += clamp(w * 4 * dz / (lengthDir * lengthDir), Real(-100.), Real(100.));
LOOP_GHOSTS_END
LOOP_NEIGHBORS_END
if (wTotal != 0) {
tempSurfaceFloat[idx] = laplacian / wTotal;
}
else {
tempSurfaceFloat[idx] = 0;
}
}
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline const ParticleDataImpl<Vec3> &getArg1()
{
return surfaceNormals;
}
typedef ParticleDataImpl<Vec3> type1;
inline const ParticleDataImpl<Real> &getArg2()
{
return surfaceWaveH;
}
typedef ParticleDataImpl<Real> type2;
void runMessage()
{
debMsg("Executing kernel computeSurfaceWaveLaplacians ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceNormals, surfaceWaveH);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
const ParticleDataImpl<Vec3> &surfaceNormals;
const ParticleDataImpl<Real> &surfaceWaveH;
};
struct evolveWave : public KernelBase {
evolveWave(const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveH,
ParticleDataImpl<Real> &surfaceWaveDtH,
const ParticleDataImpl<Real> &surfaceWaveSeed)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceWaveH(surfaceWaveH),
surfaceWaveDtH(surfaceWaveDtH),
surfaceWaveSeed(surfaceWaveSeed)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveH,
ParticleDataImpl<Real> &surfaceWaveDtH,
const ParticleDataImpl<Real> &surfaceWaveSeed) const
{
surfaceWaveDtH[idx] += params.waveSpeed * params.waveSpeed * params.dt * tempSurfaceFloat[idx];
surfaceWaveDtH[idx] /= (1 + params.dt * params.waveDamping);
surfaceWaveH[idx] += params.dt * surfaceWaveDtH[idx];
surfaceWaveH[idx] /= (1 + params.dt * params.waveDamping);
surfaceWaveH[idx] -= surfaceWaveSeed[idx];
// clamp H and DtH (to prevent rare extreme behaviors)
surfaceWaveDtH[idx] = clamp(surfaceWaveDtH[idx],
-params.waveMaxFrequency * params.waveMaxAmplitude,
params.waveMaxFrequency * params.waveMaxAmplitude);
surfaceWaveH[idx] = clamp(
surfaceWaveH[idx], -params.waveMaxAmplitude, params.waveMaxAmplitude);
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline ParticleDataImpl<Real> &getArg1()
{
return surfaceWaveH;
}
typedef ParticleDataImpl<Real> type1;
inline ParticleDataImpl<Real> &getArg2()
{
return surfaceWaveDtH;
}
typedef ParticleDataImpl<Real> type2;
inline const ParticleDataImpl<Real> &getArg3()
{
return surfaceWaveSeed;
}
typedef ParticleDataImpl<Real> type3;
void runMessage()
{
debMsg("Executing kernel evolveWave ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
ParticleDataImpl<Real> &surfaceWaveH;
ParticleDataImpl<Real> &surfaceWaveDtH;
const ParticleDataImpl<Real> &surfaceWaveSeed;
};
struct computeSurfaceCurvature : public KernelBase {
computeSurfaceCurvature(const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceNormals(surfaceNormals)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals) const
{
Vec3 pPos = surfacePoints.getPos(idx);
Real wTotal = 0;
Real curv = 0;
Vec3 pNormal = surfaceNormals[idx];
LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.normalRadius)
LOOP_GHOSTS_POS_NORMAL_BEGIN(
surfacePoints.getPos(idn), surfaceNormals[idn], params.normalRadius)
Vec3 dir = pPos - gPos;
if (dot(pNormal, gNormal) < 0) {
continue;
} // backfacing
Real dist = norm(dir);
if (dist < params.normalRadius / 100.f) {
continue;
}
Real distn = dot(dir, pNormal);
Real w = weightSurfaceNormal(dist);
curv += w * distn;
wTotal += w;
LOOP_GHOSTS_END
LOOP_NEIGHBORS_END
if (wTotal != 0) {
curv /= wTotal;
}
tempSurfaceFloat[idx] = fabs(curv);
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline const ParticleDataImpl<Vec3> &getArg1()
{
return surfaceNormals;
}
typedef ParticleDataImpl<Vec3> type1;
void runMessage()
{
debMsg("Executing kernel computeSurfaceCurvature ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceNormals);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
const ParticleDataImpl<Vec3> &surfaceNormals;
};
struct smoothCurvature : public KernelBase {
smoothCurvature(const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveSource)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceWaveSource(surfaceWaveSource)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveSource) const
{
Vec3 pPos = surfacePoints.getPos(idx);
Real curv = 0;
Real wTotal = 0;
LOOP_NEIGHBORS_BEGIN(surfacePoints, pPos, params.normalRadius)
Real w = weightSurfaceNormal(norm(pPos - surfacePoints.getPos(idn)));
curv += w * tempSurfaceFloat[idn];
wTotal += w;
LOOP_NEIGHBORS_END
if (wTotal != 0) {
curv /= wTotal;
}
surfaceWaveSource[idx] = curv;
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline ParticleDataImpl<Real> &getArg1()
{
return surfaceWaveSource;
}
typedef ParticleDataImpl<Real> type1;
void runMessage()
{
debMsg("Executing kernel smoothCurvature ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceWaveSource);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
ParticleDataImpl<Real> &surfaceWaveSource;
};
struct seedWaves : public KernelBase {
seedWaves(const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveSeed,
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude,
ParticleDataImpl<Real> &surfaceWaveSource)
: KernelBase(surfacePoints.size()),
surfacePoints(surfacePoints),
surfaceWaveSeed(surfaceWaveSeed),
surfaceWaveSeedAmplitude(surfaceWaveSeedAmplitude),
surfaceWaveSource(surfaceWaveSource)
{
runMessage();
run();
}
inline void op(IndexInt idx,
const BasicParticleSystemWrapper &surfacePoints,
ParticleDataImpl<Real> &surfaceWaveSeed,
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude,
ParticleDataImpl<Real> &surfaceWaveSource) const
{
Real source = smoothstep(params.waveSeedingCurvatureThresholdRegionCenter -
params.waveSeedingCurvatureThresholdRegionRadius,
params.waveSeedingCurvatureThresholdRegionCenter +
params.waveSeedingCurvatureThresholdRegionRadius,
(Real)surfaceWaveSource[idx]) *
2.f -
1.f;
Real freq = params.waveSeedFrequency;
Real theta = params.dt * frameCount * params.waveSpeed * freq;
Real costheta = cosf(theta);
Real maxSeedAmplitude = params.waveMaxSeedingAmplitude * params.waveMaxAmplitude;
surfaceWaveSeedAmplitude[idx] = clamp<Real>(surfaceWaveSeedAmplitude[idx] +
source * params.waveSeedStepSizeRatioOfMax *
maxSeedAmplitude,
0.f,
maxSeedAmplitude);
surfaceWaveSeed[idx] = surfaceWaveSeedAmplitude[idx] * costheta;
// source values for display (not used after this point anyway)
surfaceWaveSource[idx] = (source >= 0) ? 1 : 0;
}
inline const BasicParticleSystemWrapper &getArg0()
{
return surfacePoints;
}
typedef BasicParticleSystemWrapper type0;
inline ParticleDataImpl<Real> &getArg1()
{
return surfaceWaveSeed;
}
typedef ParticleDataImpl<Real> type1;
inline ParticleDataImpl<Real> &getArg2()
{
return surfaceWaveSeedAmplitude;
}
typedef ParticleDataImpl<Real> type2;
inline ParticleDataImpl<Real> &getArg3()
{
return surfaceWaveSource;
}
typedef ParticleDataImpl<Real> type3;
void runMessage()
{
debMsg("Executing kernel seedWaves ", 3);
debMsg("Kernel range"
<< " size " << size << " ",
4);
};
void operator()(const tbb::blocked_range<IndexInt> &__r) const
{
for (IndexInt idx = __r.begin(); idx != (IndexInt)__r.end(); idx++)
op(idx, surfacePoints, surfaceWaveSeed, surfaceWaveSeedAmplitude, surfaceWaveSource);
}
void run()
{
tbb::parallel_for(tbb::blocked_range<IndexInt>(0, size), *this);
}
const BasicParticleSystemWrapper &surfacePoints;
ParticleDataImpl<Real> &surfaceWaveSeed;
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude;
ParticleDataImpl<Real> &surfaceWaveSource;
};
void surfaceWaves(const BasicParticleSystemWrapper &surfacePoints,
const ParticleDataImpl<Vec3> &surfaceNormals,
ParticleDataImpl<Real> &surfaceWaveH,
ParticleDataImpl<Real> &surfaceWaveDtH,
ParticleDataImpl<Real> &surfaceWaveSource,
ParticleDataImpl<Real> &surfaceWaveSeed,
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude)
{
addSeed(surfacePoints, surfaceWaveH, surfaceWaveSeed);
computeSurfaceWaveNormal(surfacePoints, surfaceNormals, surfaceWaveH);
computeSurfaceWaveLaplacians(surfacePoints, surfaceNormals, surfaceWaveH);
evolveWave(surfacePoints, surfaceWaveH, surfaceWaveDtH, surfaceWaveSeed);
computeSurfaceCurvature(surfacePoints, surfaceNormals);
smoothCurvature(surfacePoints, surfaceWaveSource);
seedWaves(surfacePoints, surfaceWaveSeed, surfaceWaveSeedAmplitude, surfaceWaveSource);
}
//
// **** main function ****
//
void particleSurfaceTurbulence(const FlagGrid &flags,
BasicParticleSystem &coarseParts,
ParticleDataImpl<Vec3> &coarsePartsPrevPos,
BasicParticleSystem &surfPoints,
ParticleDataImpl<Vec3> &surfaceNormals,
ParticleDataImpl<Real> &surfaceWaveH,
ParticleDataImpl<Real> &surfaceWaveDtH,
BasicParticleSystem &surfacePointsDisplaced,
ParticleDataImpl<Real> &surfaceWaveSource,
ParticleDataImpl<Real> &surfaceWaveSeed,
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude,
int res,
Real outerRadius = 1.0f,
int surfaceDensity = 20,
int nbSurfaceMaintenanceIterations = 4,
Real dt = 0.005f,
Real waveSpeed = 16.0f,
Real waveDamping = 0.0f,
Real waveSeedFrequency = 4,
Real waveMaxAmplitude = 0.25f,
Real waveMaxFrequency = 800,
Real waveMaxSeedingAmplitude = 0.5,
Real waveSeedingCurvatureThresholdRegionCenter = 0.025f,
Real waveSeedingCurvatureThresholdRegionRadius = 0.01f,
Real waveSeedStepSizeRatioOfMax = 0.05f)
{
#if USE_CHRONO == 1
static std::chrono::high_resolution_clock::time_point begin, end;
end = std::chrono::high_resolution_clock::now();
cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count() / 1000000000.f
<< " : time sim" << endl;
begin = std::chrono::high_resolution_clock::now();
#endif
// wrap data
coarseParticles.points = &coarseParts;
coarseParticlesPrevPos.points = &coarsePartsPrevPos;
surfacePoints.points = &surfPoints;
// copy parameters
params.res = res;
params.outerRadius = outerRadius;
params.surfaceDensity = surfaceDensity;
params.nbSurfaceMaintenanceIterations = nbSurfaceMaintenanceIterations;
params.dt = dt;
params.waveSpeed = waveSpeed;
params.waveDamping = waveDamping;
params.waveSeedFrequency = waveSeedFrequency;
params.waveMaxAmplitude = waveMaxAmplitude;
params.waveMaxFrequency = waveMaxFrequency;
params.waveMaxSeedingAmplitude = waveMaxSeedingAmplitude;
params.waveSeedingCurvatureThresholdRegionCenter = waveSeedingCurvatureThresholdRegionCenter;
params.waveSeedingCurvatureThresholdRegionRadius = waveSeedingCurvatureThresholdRegionRadius;
params.waveSeedStepSizeRatioOfMax = waveSeedStepSizeRatioOfMax;
// compute other parameters
params.innerRadius = params.outerRadius / 2.0;
params.meanFineDistance = M_PI * (params.outerRadius + params.innerRadius) /
params.surfaceDensity;
params.constraintA = logf(2.0f / (1.0f + weightKernelCoarseDensity(params.outerRadius +
params.innerRadius))) /
(powf((params.outerRadius + params.innerRadius) / 2, 2) -
params.innerRadius * params.innerRadius);
params.normalRadius = 0.5f * (params.outerRadius + params.innerRadius);
params.tangentRadius = 2.1f * params.meanFineDistance;
params.bndXm = params.bndYm = params.bndZm = 2;
params.bndXp = params.bndYp = params.bndZp = params.res - 2;
if (frameCount == 0) {
// initialize accel grids
accelCoarse.init(2.f * res / params.outerRadius);
accelSurface.init(1.f * res / (2.f * params.meanFineDistance));
// update coarse accel structure
coarseParticles.updateAccel();
// create surface points
initFines(coarseParticles, surfacePoints, flags);
// smooth surface
surfaceMaintenance(coarseParticles,
surfacePoints,
surfaceNormals,
surfaceWaveH,
surfaceWaveDtH,
surfaceWaveSeed,
surfaceWaveSeedAmplitude,
6 * params.nbSurfaceMaintenanceIterations);
// set wave values to zero
for (int idx = 0; idx < surfacePoints.size(); idx++) {
surfaceWaveH[idx] = 0;
surfaceWaveDtH[idx] = 0;
surfaceWaveSeed[idx] = 0;
surfaceWaveSeedAmplitude[idx] = 0;
}
}
else {
// update coarse accel structure with previous coarse particles positions
coarseParticlesPrevPos.updateAccel();
// advect surface points following coarse particles
advectSurfacePoints(surfacePoints, coarseParticles, coarseParticlesPrevPos);
surfacePoints.updateAccel();
// update acceleration structure for surface points
coarseParticles.updateAccel();
// surface maintenance
surfaceMaintenance(coarseParticles,
surfacePoints,
surfaceNormals,
surfaceWaveH,
surfaceWaveDtH,
surfaceWaveSeed,
surfaceWaveSeedAmplitude,
params.nbSurfaceMaintenanceIterations);
// surface waves
surfaceWaves(surfacePoints,
surfaceNormals,
surfaceWaveH,
surfaceWaveDtH,
surfaceWaveSource,
surfaceWaveSeed,
surfaceWaveSeedAmplitude);
}
frameCount++;
// save positions as previous positions for next step
for (int id = 0; id < coarseParticles.size(); id++) {
if ((coarseParticles.getStatus(id) & ParticleBase::PNEW) == 0 &&
(coarseParticles.getStatus(id) & ParticleBase::PDELETE) == 0) {
coarseParticlesPrevPos.setVec3(id, coarseParticles.getPos(id));
}
}
// create displaced points for display
surfacePointsDisplaced.clear();
for (int idx = 0; idx < surfacePoints.size(); idx++) {
if ((surfacePoints.getStatus(idx) & ParticleBase::PDELETE) == 0) {
surfacePointsDisplaced.addParticle(surfacePoints.getPos(idx) +
surfaceNormals[idx] * surfaceWaveH[idx]);
}
}
#if USE_CHRONO == 1
end = std::chrono::high_resolution_clock::now();
cout << std::chrono::duration_cast<std::chrono::nanoseconds>(end - begin).count() / 1000000000.f
<< " : time upres" << endl;
begin = std::chrono::high_resolution_clock::now();
#endif
}
static PyObject *_W_0(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "particleSurfaceTurbulence", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 0, &_lock);
BasicParticleSystem &coarseParts = *_args.getPtr<BasicParticleSystem>(
"coarseParts", 1, &_lock);
ParticleDataImpl<Vec3> &coarsePartsPrevPos = *_args.getPtr<ParticleDataImpl<Vec3>>(
"coarsePartsPrevPos", 2, &_lock);
BasicParticleSystem &surfPoints = *_args.getPtr<BasicParticleSystem>(
"surfPoints", 3, &_lock);
ParticleDataImpl<Vec3> &surfaceNormals = *_args.getPtr<ParticleDataImpl<Vec3>>(
"surfaceNormals", 4, &_lock);
ParticleDataImpl<Real> &surfaceWaveH = *_args.getPtr<ParticleDataImpl<Real>>(
"surfaceWaveH", 5, &_lock);
ParticleDataImpl<Real> &surfaceWaveDtH = *_args.getPtr<ParticleDataImpl<Real>>(
"surfaceWaveDtH", 6, &_lock);
BasicParticleSystem &surfacePointsDisplaced = *_args.getPtr<BasicParticleSystem>(
"surfacePointsDisplaced", 7, &_lock);
ParticleDataImpl<Real> &surfaceWaveSource = *_args.getPtr<ParticleDataImpl<Real>>(
"surfaceWaveSource", 8, &_lock);
ParticleDataImpl<Real> &surfaceWaveSeed = *_args.getPtr<ParticleDataImpl<Real>>(
"surfaceWaveSeed", 9, &_lock);
ParticleDataImpl<Real> &surfaceWaveSeedAmplitude = *_args.getPtr<ParticleDataImpl<Real>>(
"surfaceWaveSeedAmplitude", 10, &_lock);
int res = _args.get<int>("res", 11, &_lock);
Real outerRadius = _args.getOpt<Real>("outerRadius", 12, 1.0f, &_lock);
int surfaceDensity = _args.getOpt<int>("surfaceDensity", 13, 20, &_lock);
int nbSurfaceMaintenanceIterations = _args.getOpt<int>(
"nbSurfaceMaintenanceIterations", 14, 4, &_lock);
Real dt = _args.getOpt<Real>("dt", 15, 0.005f, &_lock);
Real waveSpeed = _args.getOpt<Real>("waveSpeed", 16, 16.0f, &_lock);
Real waveDamping = _args.getOpt<Real>("waveDamping", 17, 0.0f, &_lock);
Real waveSeedFrequency = _args.getOpt<Real>("waveSeedFrequency", 18, 4, &_lock);
Real waveMaxAmplitude = _args.getOpt<Real>("waveMaxAmplitude", 19, 0.25f, &_lock);
Real waveMaxFrequency = _args.getOpt<Real>("waveMaxFrequency", 20, 800, &_lock);
Real waveMaxSeedingAmplitude = _args.getOpt<Real>(
"waveMaxSeedingAmplitude", 21, 0.5, &_lock);
Real waveSeedingCurvatureThresholdRegionCenter = _args.getOpt<Real>(
"waveSeedingCurvatureThresholdRegionCenter", 22, 0.025f, &_lock);
Real waveSeedingCurvatureThresholdRegionRadius = _args.getOpt<Real>(
"waveSeedingCurvatureThresholdRegionRadius", 23, 0.01f, &_lock);
Real waveSeedStepSizeRatioOfMax = _args.getOpt<Real>(
"waveSeedStepSizeRatioOfMax", 24, 0.05f, &_lock);
_retval = getPyNone();
particleSurfaceTurbulence(flags,
coarseParts,
coarsePartsPrevPos,
surfPoints,
surfaceNormals,
surfaceWaveH,
surfaceWaveDtH,
surfacePointsDisplaced,
surfaceWaveSource,
surfaceWaveSeed,
surfaceWaveSeedAmplitude,
res,
outerRadius,
surfaceDensity,
nbSurfaceMaintenanceIterations,
dt,
waveSpeed,
waveDamping,
waveSeedFrequency,
waveMaxAmplitude,
waveMaxFrequency,
waveMaxSeedingAmplitude,
waveSeedingCurvatureThresholdRegionCenter,
waveSeedingCurvatureThresholdRegionRadius,
waveSeedStepSizeRatioOfMax);
_args.check();
}
pbFinalizePlugin(parent, "particleSurfaceTurbulence", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("particleSurfaceTurbulence", e.what());
return 0;
}
}
static const Pb::Register _RP_particleSurfaceTurbulence("", "particleSurfaceTurbulence", _W_0);
extern "C" {
void PbRegister_particleSurfaceTurbulence()
{
KEEP_UNUSED(_RP_particleSurfaceTurbulence);
}
}
void debugCheckParts(const BasicParticleSystem &parts, const FlagGrid &flags)
{
for (int idx = 0; idx < parts.size(); idx++) {
Vec3i p = toVec3i(parts.getPos(idx));
if (!flags.isInBounds(p)) {
debMsg("bad position??? " << idx << " " << parts.getPos(idx), 1);
exit(1);
}
}
}
static PyObject *_W_1(PyObject *_self, PyObject *_linargs, PyObject *_kwds)
{
try {
PbArgs _args(_linargs, _kwds);
FluidSolver *parent = _args.obtainParent();
bool noTiming = _args.getOpt<bool>("notiming", -1, 0);
pbPreparePlugin(parent, "debugCheckParts", !noTiming);
PyObject *_retval = nullptr;
{
ArgLocker _lock;
const BasicParticleSystem &parts = *_args.getPtr<BasicParticleSystem>("parts", 0, &_lock);
const FlagGrid &flags = *_args.getPtr<FlagGrid>("flags", 1, &_lock);
_retval = getPyNone();
debugCheckParts(parts, flags);
_args.check();
}
pbFinalizePlugin(parent, "debugCheckParts", !noTiming);
return _retval;
}
catch (std::exception &e) {
pbSetError("debugCheckParts", e.what());
return 0;
}
}
static const Pb::Register _RP_debugCheckParts("", "debugCheckParts", _W_1);
extern "C" {
void PbRegister_debugCheckParts()
{
KEEP_UNUSED(_RP_debugCheckParts);
}
}
} // namespace SurfaceTurbulence
} // namespace Manta