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

Particle dynamic size #3550

Merged
merged 3 commits into from Mar 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
13 changes: 13 additions & 0 deletions apps/vaporgui/ParticleEventRouter.cpp
Expand Up @@ -8,6 +8,14 @@ using namespace VAPoR;

static RenderEventRouterRegistrar<ParticleEventRouter> registrar(ParticleEventRouter::GetClassType());

struct PParticleRadiusVariableSelector : public PVariableSelector {
PParticleRadiusVariableSelector()
: PVariableSelector(ParticleParams::RenderRadiusVariableTag, "Particle Radius Scalar") {
AddNullOption();
ShowParticleVars();
}
};

ParticleEventRouter::ParticleEventRouter(QWidget *parent, ControlExec *ce) : RenderEventRouterGUI(ce, BarbParams::GetClassType())
{
// clang-format off
Expand All @@ -18,6 +26,7 @@ ParticleEventRouter::ParticleEventRouter(QWidget *parent, ControlExec *ce) : Ren
(new PXFieldVariableSelector)->ShowParticleVars(),
(new PYFieldVariableSelector)->ShowParticleVars(),
(new PZFieldVariableSelector)->ShowParticleVars(),
(new PParticleRadiusVariableSelector()),
}),
new PSection("Data Fidelity", {
(new PIntegerInput(ParticleParams::StrideTag, "Stride"))->SetRange(1, 1000)
Expand All @@ -28,6 +37,10 @@ ParticleEventRouter::ParticleEventRouter(QWidget *parent, ControlExec *ce) : Ren
new PTFEditor,
new PSection("Particles", {
(new PDoubleSliderEdit(ParticleParams::RenderRadiusScalarTag, "Radius"))->SetRange(0.5, 25)->AllowUserRange(true)->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::RenderLegacyTag, false),
(new PParticleRadiusVariableSelector()),
// (new PShowIf(ParticleParams::RenderRadiusVariableTag))->Not()->Equals("")->Then({
// (new PDoubleSliderEdit(ParticleParams::RenderRadiusVariableStrengthTag, "Radius Variable Strength"))->SetRange(0.001, 1)->AllowUserRange(true)->EnableDynamicUpdate()
// }),
new PCheckbox(ParticleParams::ShowDirectionTag, "Show direction"),
(new PDoubleSliderEdit(ParticleParams::DirectionScaleTag, "Length scale"))->SetRange(0.0001, 10)->AllowUserRange(true)->EnableDynamicUpdate()->EnableBasedOnParam(ParticleParams::ShowDirectionTag),
(new PXFieldVariableSelector)->ShowParticleVars()->EnableBasedOnParam(ParticleParams::ShowDirectionTag),
Expand Down
2 changes: 2 additions & 0 deletions include/vapor/ParamsBase.h
Expand Up @@ -28,6 +28,8 @@
#include <vapor/MyBase.h>
#include <vapor/XmlNode.h>

#define PARAMS_IMPL_TAG(class, tag) const std::string class::tag = #tag;

namespace VAPoR {

//
Expand Down
2 changes: 2 additions & 0 deletions include/vapor/ParticleParams.h
Expand Up @@ -36,6 +36,8 @@ class PARAMS_API ParticleParams : public RenderParams {

//! Scale the rendered particle size
static const std::string RenderRadiusScalarTag;
static const std::string RenderRadiusVariableTag;
static const std::string RenderRadiusVariableStrengthTag;

static const std::string RenderRadiusBaseTag;
static const std::string RenderLegacyTag;
Expand Down
2 changes: 2 additions & 0 deletions include/vapor/ParticleRenderer.h
Expand Up @@ -64,6 +64,7 @@ class RENDER_API ParticleRenderer : public Renderer {
float directionScale;
size_t stride;
string varName;
string radiusVarName;
std::vector<std::string> fieldVars;
} _cacheParams;

Expand Down Expand Up @@ -93,6 +94,7 @@ class RENDER_API ParticleRenderer : public Renderer {
int _generateParticlesLegacy(Grid*& grid, std::vector<Grid*>& vecGrids);
int _getGrids(Grid*& grid, std::vector<Grid*>& vecGrids) const;
void _generateTextureData(const Grid* grid, const std::vector<Grid*>& vecGrids);
void _computeBaseRadius();
void _renderParticlesLegacy(const Grid* grid, const std::vector<Grid*>& vecGrids) const;
int _renderParticlesHelper();
void _prepareColormap();
Expand Down
3 changes: 3 additions & 0 deletions lib/params/ParticleParams.cpp
Expand Up @@ -13,6 +13,8 @@ const std::string ParticleParams::ShowDirectionTag = "ShowDirectionTag";
const std::string ParticleParams::DirectionScaleTag = "DirectionScaleTag";
const std::string ParticleParams::StrideTag = "StrideTag";
const std::string ParticleParams::RenderRadiusScalarTag = "RenderRadiusScalarTag";
PARAMS_IMPL_TAG(ParticleParams, RenderRadiusVariableTag);
PARAMS_IMPL_TAG(ParticleParams, RenderRadiusVariableStrengthTag);
const std::string ParticleParams::LightingEnabledTag = "LightingEnabledTag";
const std::string ParticleParams::RenderRadiusBaseTag = "RenderRadiusBaseTag";
const std::string ParticleParams::RenderLegacyTag = "RenderLegacyTag";
Expand Down Expand Up @@ -47,6 +49,7 @@ void ParticleParams::_init()
SetValueDouble(DirectionScaleTag, "", 1);
SetValueLong(StrideTag, "", 1);
SetValueDouble(RenderRadiusScalarTag, "", 8.);
SetValueDouble(RenderRadiusVariableStrengthTag, "", 1.);
SetValueDouble(RenderRadiusBaseTag, "", -1);
SetValueLong(RenderLegacyTag, "", false);
SetValueLong(LightingEnabledTag, "", true);
Expand Down
131 changes: 88 additions & 43 deletions lib/render/ParticleRenderer.cpp
Expand Up @@ -116,8 +116,10 @@ int ParticleRenderer::_paintGL(bool)
_renderParticlesLegacy(grid, vecGrids);
}
else {
if (regenerateParticles)
if (regenerateParticles) {
_generateTextureData(grid, vecGrids);
_computeBaseRadius();
}
_renderParticlesHelper();
}

Expand Down Expand Up @@ -159,26 +161,38 @@ int ParticleRenderer::_initializeGL() {
return 0;
}

static void SetupParticlePointGL(const int VAO, const int VBO) {
static void SetupParticlePointGL(const int VAO, const int VBO, const bool dynamicSize) {
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), NULL);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, sizeof(glm::vec4), (void *)sizeof(glm::vec3));
int elSize = sizeof(glm::vec4);
if (dynamicSize) elSize += sizeof(float);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, elSize, NULL);
glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec3));
shaomeng marked this conversation as resolved.
Show resolved Hide resolved
if (dynamicSize)
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec4));
shaomeng marked this conversation as resolved.
Show resolved Hide resolved
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
if (dynamicSize)
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}

static void SetupParticleDirectionGL(const int VAO, const int VBO) {
static void SetupParticleDirectionGL(const int VAO, const int VBO, const bool dynamicSize) {
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float)*7, NULL);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(float)*7, (void *)sizeof(glm::vec3));
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, sizeof(float)*7, (void *)(2*sizeof(glm::vec3)));
int elSize = sizeof(float)*7;
if (dynamicSize) elSize += sizeof(float);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, elSize, NULL);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, elSize, (void *)sizeof(glm::vec3));
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, elSize, (void *)(2*sizeof(glm::vec3)));
if (dynamicSize)
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, elSize, (void *)(sizeof(float)*7));
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
if (dynamicSize)
glEnableVertexAttribArray(3);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
Expand All @@ -198,6 +212,7 @@ bool ParticleRenderer::_particleCacheIsDirty() const {
if (_cacheParams.stride != p->GetValueLong( ParticleParams::StrideTag, 1)) return true;
if (_cacheParams.varName != p->GetVariableName() ) return true;
if (_cacheParams.fieldVars != p->GetFieldVariableNames() ) return true;
if (_cacheParams.radiusVarName != p->GetValueString( ParticleParams::RenderRadiusVariableTag, "")) return true;
if (_cacheParams.direction != (bool)p->GetValueLong( ParticleParams::ShowDirectionTag, false)) return true;
if (_cacheParams.directionScale != p->GetValueDouble( ParticleParams::DirectionScaleTag, false)) return true;

Expand All @@ -220,6 +235,7 @@ void ParticleRenderer::_resetParticleCache() {
_cacheParams.stride = p->GetValueLong(ParticleParams::StrideTag, 1);
_cacheParams.varName = p->GetVariableName();
_cacheParams.fieldVars = p->GetFieldVariableNames();
_cacheParams.radiusVarName = p->GetValueString( ParticleParams::RenderRadiusVariableTag, "");
}

bool ParticleRenderer::_colormapCacheIsDirty() const {
Expand All @@ -245,31 +261,19 @@ void ParticleRenderer::_resetColormapCache() {
int ParticleRenderer::_renderParticlesHelper()
{
auto rp = GetActiveParams();

float radiusBase = rp->GetValueDouble(ParticleParams::RenderRadiusBaseTag, -1);
if (radiusBase == -1) {
CoordType mind, maxd;

// Need to find a non-empty variable from color mapping or velocity variables.
std::string nonEmptyVarName = rp->GetColorMapVariableName();
assert(!nonEmptyVarName.empty());

_dataMgr->GetVariableExtents(_cacheParams.ts, nonEmptyVarName, _cacheParams.rLevel, _cacheParams.cLevel, mind, maxd);
glm::vec3 min(mind[0], mind[1], mind[2]);
glm::vec3 max(maxd[0], maxd[1], maxd[2]);
glm::vec3 lens = max - min;
float largestDim = glm::max(lens.x, glm::max(lens.y, lens.z));
radiusBase = largestDim / 560.f;
rp->SetValueDouble(ParticleParams::RenderRadiusBaseTag, "", radiusBase);
}
float radius = radiusBase * rp->GetValueDouble(ParticleParams::RenderRadiusScalarTag, 1.);

ShaderProgram *shader = nullptr;

string shaderKey;
if (_cacheParams.direction)
shader = _glManager->shaderManager->GetShader("ParticleDirection");
shaderKey = "ParticleDirection";
else
shader = _glManager->shaderManager->GetShader("ParticlePoint");
shaderKey = "ParticlePoint";

if (!_cacheParams.radiusVarName.empty())
shaderKey += ":DYNAMIC_RADIUS";

ShaderProgram *shader = _glManager->shaderManager->GetShader(shaderKey);
if (!shader) return -1;

double m[16];
Expand Down Expand Up @@ -367,33 +371,41 @@ int ParticleRenderer::_getGrids(Grid*& grid, std::vector<Grid*>& vecGrids) const
}
}

if (!_cacheParams.radiusVarName.empty()) {
vecGrids.push_back(_dataMgr->GetVariable(_cacheParams.ts, _cacheParams.radiusVarName, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, true));
}

return 0;
}

template<typename T> static void UploadDataBuffer(T buffer) {
glBufferData(GL_ARRAY_BUFFER, sizeof(T) * buffer.size(), buffer.data(), GL_STATIC_DRAW);
}

void ParticleRenderer::_generateTextureData(const Grid* grid, const std::vector<Grid*>& vecGrids) {
bool showDir = _cacheParams.direction;
bool dynamicSize = !_cacheParams.radiusVarName.empty();
size_t stride = max(1L, (long)_cacheParams.stride);
float dirScale = _cacheParams.directionScale;
auto node = grid->ConstNodeBegin(_cacheParams.boxMin, _cacheParams.boxMax);
auto nodeEnd = grid->ConstNodeEnd();
CoordType coordsBuf;
vector<Grid::ConstIterator> dirs;

if (showDir) for (auto g : vecGrids) dirs.push_back(g->cbegin(_cacheParams.boxMin, _cacheParams.boxMax));
if (showDir) for (int i = 0; i < 3; i++) dirs.push_back(vecGrids[i]->cbegin(_cacheParams.boxMin, _cacheParams.boxMax));
if (dynamicSize) dirs.push_back(vecGrids[vecGrids.size()-1]);

struct PointDataT {vec3 pos; float val;};
vector<PointDataT> pointData;

struct DirectionDataT {vec3 pos; vec3 norm; float val;};
vector<DirectionDataT> directionData;
struct PointDataT {vec3 pos; float val;}; vector<PointDataT> pointData;
struct DirectionDataT {vec3 pos; vec3 norm; float val;}; vector<DirectionDataT> directionData;
struct PointDynSizeDataT {vec3 pos; float val; float radius;}; vector<PointDynSizeDataT> pointDynSizeData;
struct DirectionDynSizeDataT {vec3 pos; vec3 norm; float val; float radius;}; vector<DirectionDynSizeDataT> directionDynSizeData;

_particlesCount = grid->GetCoordDimensions(1)[0] / stride;

if (showDir) {
SetupParticleDirectionGL(_VAO, _VBO);
SetupParticleDirectionGL(_VAO, _VBO, dynamicSize);
directionData.reserve(_particlesCount);
} else {
SetupParticlePointGL(_VAO, _VBO);
SetupParticlePointGL(_VAO, _VBO, dynamicSize);
pointData.reserve(_particlesCount);
}
assert(glIsVertexArray(_VAO) == GL_TRUE);
Expand All @@ -408,9 +420,15 @@ void ParticleRenderer::_generateTextureData(const Grid* grid, const std::vector<

if (showDir){
const glm::vec3 norm(*(dirs[0]), *(dirs[1]), *(dirs[2]));
directionData.push_back({p, norm, value});
if (dynamicSize)
directionDynSizeData.push_back({p, norm, value, *(dirs[dirs.size()-1])});
else
directionData.push_back({p, norm, value});
} else {
pointData.push_back({p, value});
if (dynamicSize)
pointDynSizeData.push_back({p, value, *(dirs[dirs.size()-1])});
else
pointData.push_back({p, value});
}
}
step:
Expand All @@ -420,13 +438,40 @@ void ParticleRenderer::_generateTextureData(const Grid* grid, const std::vector<

glBindVertexArray(_VAO);
glBindBuffer(GL_ARRAY_BUFFER, _VBO);
if (showDir)
glBufferData(GL_ARRAY_BUFFER, sizeof(DirectionDataT) * directionData.size(), directionData.data(), GL_STATIC_DRAW);
else
glBufferData(GL_ARRAY_BUFFER, sizeof(PointDataT) * pointData.size(), pointData.data(), GL_STATIC_DRAW);
if (dynamicSize) {
if (showDir) UploadDataBuffer(directionDynSizeData);
else UploadDataBuffer(pointDynSizeData);
} else {
if (showDir) UploadDataBuffer(directionData);
else UploadDataBuffer(pointData);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void ParticleRenderer::_computeBaseRadius() {
auto rp = GetActiveParams();
CoordType mind, maxd;

// Need to find a non-empty variable from color mapping or velocity variables.
std::string nonEmptyVarName = rp->GetColorMapVariableName();
assert(!nonEmptyVarName.empty());

_dataMgr->GetVariableExtents(_cacheParams.ts, nonEmptyVarName, _cacheParams.rLevel, _cacheParams.cLevel, mind, maxd);
glm::vec3 min(mind[0], mind[1], mind[2]);
glm::vec3 max(maxd[0], maxd[1], maxd[2]);
glm::vec3 lens = max - min;
float largestDim = glm::max(lens.x, glm::max(lens.y, lens.z));
float radiusBase = largestDim / 560.f;

if (!_cacheParams.radiusVarName.empty()) {
vector<double> dataRange;
_dataMgr->GetDataRange(_cacheParams.ts, _cacheParams.radiusVarName, _cacheParams.rLevel, _cacheParams.cLevel, _cacheParams.boxMin, _cacheParams.boxMax, dataRange);
radiusBase /= (dataRange[0]+dataRange[1])/2;
}

rp->SetValueDouble(ParticleParams::RenderRadiusBaseTag, "", radiusBase);
}

void ParticleRenderer::_renderParticlesLegacy(const Grid* grid, const std::vector<Grid*>& vecGrids) const {
auto p = GetActiveParams();
MapperFunction* mf = p->GetMapperFunc(p->GetVariableName());
Expand Down
19 changes: 15 additions & 4 deletions share/shaders/ParticleDirection.geom
Expand Up @@ -24,14 +24,19 @@ out float fValue;
out vec3 fNormal;


#ifdef DYNAMIC_RADIUS
in float gRadius[];
#endif


uniform mat4 P;
uniform mat4 MV;
uniform vec3 scales;
uniform float radius = 0.05;
uniform float dirScale = 0.05;

void EmitWorld(const vec3 v);
void CylinderVert(const vec3 v, const vec3 d, const float value);
void CylinderVert(const vec3 v, const vec3 d, const float value, const float radius);


void main()
Expand Down Expand Up @@ -61,6 +66,12 @@ void main()
XH = normalize(cross(N, up));
YH = normalize(cross(XH, N));

#ifdef DYNAMIC_RADIUS
float finalRadius = radius * gRadius[0];
#else
float finalRadius = radius;
#endif

vec2 fade = CalculateFade();

//fNormal = vec3(1,0,0); fValue = 1; EmitWorld(gl_in[0].gl_Position.xyz); EmitWorld(gl_in[1].gl_Position.xyz); EndPrimitive(); return;
Expand All @@ -70,8 +81,8 @@ void main()
vec3 D;
D = XH*cos(t) + YH*sin(t);

CylinderVert(V[0], D, gValue[0]);
CylinderVert(V[1], D, gValue[0]);
CylinderVert(V[0], D, gValue[0], finalRadius);
CylinderVert(V[1], D, gValue[0], finalRadius);
}
EndPrimitive();
}
Expand All @@ -84,7 +95,7 @@ void EmitWorld(const vec3 v)
}


void CylinderVert(const vec3 v, const vec3 d, const float value)
void CylinderVert(const vec3 v, const vec3 d, const float value, const float radius)
{
fNormal = d;
fValue = value;
Expand Down
9 changes: 9 additions & 0 deletions share/shaders/ParticleDirection.vert
Expand Up @@ -7,8 +7,17 @@ layout (location = 2) in float vValue;
out vec3 gNorm;
out float gValue;

#ifdef DYNAMIC_RADIUS
layout (location = 3) in float vRadius;
out float gRadius;
#endif

void main() {
gValue = vValue;
gNorm = vNorm;
gl_Position = vec4(vPos, 1.0f);

#ifdef DYNAMIC_RADIUS
gRadius = vRadius;
#endif
}