aboutsummaryrefslogtreecommitdiff
path: root/demo/DemoApp/sceneSimpleFlame.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'demo/DemoApp/sceneSimpleFlame.cpp')
-rw-r--r--demo/DemoApp/sceneSimpleFlame.cpp1156
1 files changed, 1156 insertions, 0 deletions
diff --git a/demo/DemoApp/sceneSimpleFlame.cpp b/demo/DemoApp/sceneSimpleFlame.cpp
new file mode 100644
index 0000000..60b134b
--- /dev/null
+++ b/demo/DemoApp/sceneSimpleFlame.cpp
@@ -0,0 +1,1156 @@
+/*
+ * Copyright (c) 2014-2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * NVIDIA CORPORATION and its licensors retain all intellectual property
+ * and proprietary rights in and to this software, related documentation
+ * and any modifications thereto. Any use, reproduction, disclosure or
+ * distribution of this software and related documentation without an express
+ * license agreement from NVIDIA CORPORATION is strictly prohibited.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "loader.h"
+#include "imgui.h"
+#include "imguiser.h"
+
+namespace PresetFlame
+{
+#include "presetFlame.h"
+}
+
+#include "scene.h"
+
+#include <SDL.h>
+
+void SceneSimpleFlame::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ // configure emitter params
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = 8.f;
+ m_emitParams.fuel = 1.9f;
+ m_emitParams.smoke = 0.5f;
+
+ m_shouldLoadPreset = true;
+}
+
+void SceneSimpleFlame::init(AppGraphCtx* appctx, int winw, int winh)
+{
+ m_appctx = appctx;
+
+ if (!m_shouldReset || m_isFirstRun)
+ {
+ initParams();
+ m_isFirstRun = false;
+ }
+
+ m_flowContext.init(appctx);
+
+ m_flowGridActor.init(&m_flowContext, appctx);
+
+ // more compute resources
+ NvFlowShapeSDFDesc shapeDesc;
+ NvFlowShapeSDFDescDefaults(&shapeDesc);
+ m_shape = NvFlowCreateShapeSDF(m_flowContext.m_gridContext, &shapeDesc);
+
+ // generate sphere SDF
+ const float radius = 0.8f;
+ auto mappedData = NvFlowShapeSDFMap(m_shape, m_flowContext.m_gridContext);
+ if (mappedData.data)
+ {
+ for (NvFlowUint k = 0; k < mappedData.dim.z; k++)
+ for (NvFlowUint j = 0; j < mappedData.dim.y; j++)
+ for (NvFlowUint i = 0; i < mappedData.dim.x; i++)
+ {
+ float& val = mappedData.data[k * mappedData.depthPitch + j * mappedData.rowPitch + i];
+
+ float x = 2.f * (float(i) + 0.5f) / float(mappedData.dim.x) - 1.f;
+ float y = 2.f * (float(j) + 0.5f) / float(mappedData.dim.y) - 1.f;
+ float z = 2.f * (float(k) + 0.5f) / float(mappedData.dim.z) - 1.f;
+
+ float d = sqrtf(x*x + y*y + z*z);
+ float v = d - radius;
+
+ val = v;
+ }
+ NvFlowShapeSDFUnmap(m_shape, m_flowContext.m_gridContext);
+ }
+
+ // create default color map
+ {
+ const int numPoints = 5;
+ const CurvePoint pts[numPoints] = {
+ {0.f, 0.f,0.f,0.f,0.f},
+ {0.05f, 0.f,0.f,0.f,0.5f},
+ {0.6f, 213.f / 255.f,100.f / 255.f,30.f / 255.f,0.8f},
+ {0.85f, 255.f / 255.f,240.f / 255.f,0.f,0.8f},
+ {1.f, 1.f,1.f,1.f,0.7f}
+ };
+
+ auto& colorMap = m_flowGridActor.m_colorMap;
+ colorMap.initColorMap(m_flowContext.m_renderContext, pts, numPoints, (colorMap.m_curvePointsDefault.size() == 0));
+ }
+
+ m_projectile.init(m_appctx, m_flowContext.m_gridContext);
+
+ resize(winw, winh);
+}
+
+void SceneSimpleFlame::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // emit
+ {
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+ }
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlame::preDraw()
+{
+ m_flowContext.preDrawBegin();
+
+ m_flowGridActor.preDraw(&m_flowContext);
+
+ m_flowContext.preDrawEnd();
+}
+
+void SceneSimpleFlame::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ m_flowContext.drawBegin();
+
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+
+ m_flowContext.drawEnd();
+}
+
+void SceneSimpleFlame::release()
+{
+ m_projectile.release();
+
+ m_flowGridActor.release();
+
+ NvFlowReleaseShapeSDF(m_shape);
+
+ m_flowContext.release();
+}
+
+void SceneSimpleFlame::imgui(int xIn, int yIn, int wIn, int hIn)
+{
+ SceneFluid::imgui(xIn, yIn, wIn, hIn);
+
+ if (m_shouldLoadPreset)
+ {
+ imguiserLoadC(PresetFlame::g_root, sizeof(PresetFlame::g_root));
+ m_shouldLoadPreset = false;
+ }
+}
+
+// *************************** SceneSimpleFlameDouble **********************
+
+void SceneSimpleFlameDouble::init(AppGraphCtx* context, int winw, int winh)
+{
+ SceneSimpleFlame::init(context, winw, winh);
+
+ NvFlowGridMaterialParams materialParams = {};
+ NvFlowGridMaterialParamsDefaults(&materialParams);
+
+ m_materialA = NvFlowGridCreateMaterial(m_flowGridActor.m_grid, &materialParams);
+
+ materialParams.vorticityStrength = 5.f;
+ materialParams.vorticityVelocityMask = 0.f;
+ materialParams.velocity.macCormackBlendFactor = 0.f;
+ materialParams.smoke.macCormackBlendFactor = 0.75f;
+ materialParams.buoyancyPerTemp *= 5.f;
+
+ m_materialB = NvFlowGridCreateMaterial(m_flowGridActor.m_grid, &materialParams);
+
+ m_flowGridActor.m_renderMaterialMat0Params.material = m_materialA;
+ m_flowGridActor.m_renderMaterialMat1Params.material = m_materialB;
+}
+
+void SceneSimpleFlameDouble::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // emit
+ {
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ m_emitParamsA = m_emitParams;
+ m_emitParamsA.material = m_materialA;
+ m_emitParamsA.bounds.w.x = +0.25f;
+ m_emitParamsA.localToWorld = m_emitParamsA.bounds;
+ m_emitParamsA.velocityLinear.x = -8.f;
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParamsA, 1u);
+
+ m_emitParamsB = m_emitParams;
+ m_emitParamsB.material = m_materialB;
+ m_emitParamsB.bounds.w.x = -0.25f;
+ m_emitParamsB.localToWorld = m_emitParamsB.bounds;
+ m_emitParamsB.velocityLinear.x = +8.f;
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParamsB, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+ }
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameDouble::preDraw()
+{
+ SceneSimpleFlame::preDraw();
+}
+
+void SceneSimpleFlameDouble::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ SceneSimpleFlame::draw(projection, view);
+}
+
+void SceneSimpleFlameDouble::release()
+{
+ SceneSimpleFlame::release();
+}
+
+void SceneSimpleFlameDouble::imgui(int x, int y, int w, int h)
+{
+ SceneSimpleFlame::imgui(x, y, w, h);
+}
+
+void SceneSimpleFlameDouble::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ // configure emitter params
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = 8.f;
+ m_emitParams.fuel = 1.9f;
+ m_emitParams.smoke = 0.5f;
+
+ m_shouldLoadPreset = true;
+}
+
+// *************************** SceneSimpleFlameFuelMap **********************
+
+void SceneSimpleFlameFuelMap::init(AppGraphCtx* context, int winw, int winh)
+{
+ SceneSimpleFlame::init(context, winw, winh);
+
+ m_flowGridActor.m_renderMaterialMat0Params.material = NvFlowGridGetDefaultMaterial(m_flowGridActor.m_grid);
+
+ m_flowGridActor.m_renderMaterialMat0Params.colorMapCompMask = { 0.f, 4.f, 0.f, 0.f };
+ m_flowGridActor.m_renderMaterialMat0Params.alphaCompMask = { 0.f, 1.f, 0.f, 0.f };
+ m_flowGridActor.m_renderMaterialMat0Params.alphaBias = 0.f;
+
+ //m_flowGridActor.m_renderMaterialMat1Params.material = m_materialB;
+}
+
+void SceneSimpleFlameFuelMap::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // emit
+ {
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+ }
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameFuelMap::preDraw()
+{
+ SceneSimpleFlame::preDraw();
+}
+
+void SceneSimpleFlameFuelMap::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ SceneSimpleFlame::draw(projection, view);
+}
+
+void SceneSimpleFlameFuelMap::release()
+{
+ SceneSimpleFlame::release();
+}
+
+void SceneSimpleFlameFuelMap::imgui(int x, int y, int w, int h)
+{
+ SceneSimpleFlame::imgui(x, y, w, h);
+}
+
+void SceneSimpleFlameFuelMap::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ // configure emitter params
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = 8.f;
+ m_emitParams.fuel = 1.9f;
+ m_emitParams.smoke = 0.5f;
+
+ m_shouldLoadPreset = true;
+}
+
+// *************************** SceneSimpleFlameParticleSurface **********************
+
+void SceneSimpleFlameParticleSurface::init(AppGraphCtx* context, int winw, int winh)
+{
+ SceneSimpleFlame::init(context, winw, winh);
+
+ NvFlowParticleSurfaceDesc surfaceDesc = {};
+ surfaceDesc.initialLocation = { 0.f, 0.f, 0.f };
+ surfaceDesc.halfSize = { 8.f, 8.f, 8.f };
+ surfaceDesc.virtualDim = NvFlowDim{512u, 512u, 512u};
+ surfaceDesc.residentScale = 0.125f * 0.125f;
+ surfaceDesc.maxParticles = 64u * 1024u;
+
+ m_particleSurface = NvFlowCreateParticleSurface(m_flowContext.m_gridContext, &surfaceDesc);
+
+ if (!m_visualizeSurface)
+ {
+ NvFlowGridEmitCustomRegisterAllocFunc(m_flowGridActor.m_grid, emitCustomAllocFunc, this);
+ NvFlowGridEmitCustomRegisterEmitFunc(m_flowGridActor.m_grid, eNvFlowGridTextureChannelVelocity, emitCustomEmitVelocityFunc, this);
+ NvFlowGridEmitCustomRegisterEmitFunc(m_flowGridActor.m_grid, eNvFlowGridTextureChannelDensity, emitCustomEmitDensityFunc, this);
+ }
+
+ // generate positions
+ const NvFlowUint r = 32u;
+
+ m_positions.clear();
+ m_positions.resize(4u * r * r);
+ const float scale = 4.f;
+ const float scaleXInv = scale / float(r);
+ const float scaleYInv = scale / float(r);
+ for (NvFlowUint j = 0u; j < r; j++)
+ {
+ for (NvFlowUint i = 0u; i < r; i++)
+ {
+ float x = scaleXInv * float(i) - scale * 0.5f;
+ float y = scaleYInv * float(j) - scale * 0.5f;
+
+ m_positions[4 * (j * r + i) + 0u] = x;
+ m_positions[4 * (j * r + i) + 1u] = 0.f;
+ m_positions[4 * (j * r + i) + 2u] = y;
+ m_positions[4 * (j * r + i) + 3u] = 1.f;
+ }
+ }
+
+ m_flowGridActor.m_renderMaterialDefaultParams.material = NvFlowGridMaterialHandle{ nullptr, 1u };
+ m_flowGridActor.m_renderMaterialMat0Params.material = NvFlowGridGetDefaultMaterial(m_flowGridActor.m_grid);
+
+ m_particleParams.smoothRadius = 16.f;
+ m_particleParams.surfaceThreshold = 0.001f;
+ m_particleParams.separableSmoothing = true;
+}
+
+void SceneSimpleFlameParticleSurface::emitCustomAllocFunc(void* userdata, const NvFlowGridEmitCustomAllocParams* params)
+{
+ ((SceneSimpleFlameParticleSurface*)(userdata))->doEmitCustomAllocFunc(params);
+}
+
+void SceneSimpleFlameParticleSurface::emitCustomEmitVelocityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ ((SceneSimpleFlameParticleSurface*)(userdata))->doEmitCustomEmitVelocityFunc(dataFrontIdx, params);
+}
+
+void SceneSimpleFlameParticleSurface::emitCustomEmitDensityFunc(void* userdata, NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ ((SceneSimpleFlameParticleSurface*)(userdata))->doEmitCustomEmitDensityFunc(dataFrontIdx, params);
+}
+
+void SceneSimpleFlameParticleSurface::doEmitCustomAllocFunc(const NvFlowGridEmitCustomAllocParams* params)
+{
+ NvFlowParticleSurfaceAllocFunc(m_particleSurface, m_flowContext.m_gridContext, params);
+}
+
+void SceneSimpleFlameParticleSurface::doEmitCustomEmitVelocityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ NvFlowParticleSurfaceEmitVelocityFunc(m_particleSurface, m_flowContext.m_gridContext, dataFrontIdx, params, &m_surfaceEmitParams);
+}
+
+void SceneSimpleFlameParticleSurface::doEmitCustomEmitDensityFunc(NvFlowUint* dataFrontIdx, const NvFlowGridEmitCustomEmitParams* params)
+{
+ NvFlowParticleSurfaceEmitDensityFunc(m_particleSurface, m_flowContext.m_gridContext, dataFrontIdx, params, &m_surfaceEmitParams);
+}
+
+void SceneSimpleFlameParticleSurface::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ // update emit params
+ {
+ // set surface emit params
+ const float coupleRate = 0.5f;
+ m_surfaceEmitParams.deltaTime = dt;
+ m_surfaceEmitParams.velocityLinear = m_emitParams.velocityLinear;
+ m_surfaceEmitParams.velocityCoupleRate = NvFlowFloat3{ coupleRate, coupleRate, coupleRate };
+ m_surfaceEmitParams.smoke = m_emitParams.smoke;
+ m_surfaceEmitParams.smokeCoupleRate = coupleRate;
+ m_surfaceEmitParams.temperature = m_emitParams.temperature;
+ m_surfaceEmitParams.temperatureCoupleRate = coupleRate;
+ m_surfaceEmitParams.fuel = m_emitParams.fuel;
+ m_surfaceEmitParams.fuelCoupleRate = coupleRate;
+ }
+
+ AppGraphCtxProfileBegin(m_appctx, "ParticleSurface");
+
+ {
+ // animate wave surface
+ {
+ const NvFlowUint r = 32u;
+ const float k = 0.125f;
+ const float timeScale = 4.f;
+ const float spaceScale = 32.f;
+ const float pi = 3.14159f;
+
+ const float period = 2.f * pi / (timeScale);
+
+ m_time += dt;
+
+ float offsetX = 0.f; // 3.f * cosf(m_time);
+ float offsetY = 0.f; // 3.f * sinf(m_time);
+
+ const float scale = 4.f;
+ const float scaleInv = 1.f / scale;
+ const float scaleXInv = scale / float(r);
+ const float scaleYInv = scale / float(r);
+ for (NvFlowUint j = 0u; j < r; j++)
+ {
+ for (NvFlowUint i = 0u; i < r; i++)
+ {
+ float x = scaleXInv * float(i) - scale * 0.5f;
+ float y = scaleYInv * float(j) - scale * 0.5f;
+ float d = scaleInv * sqrtf(x * x + y * y);
+
+ m_positions[4 * (j * r + i) + 0u] = x + offsetX;
+ m_positions[4 * (j * r + i) + 2u] = y + offsetY;
+ m_positions[4 * (j * r + i) + 1u] = k * cosf(-timeScale * m_time + spaceScale * d);
+ }
+ }
+ }
+
+ NvFlowParticleSurfaceData particleData = {};
+ particleData.positions = &m_positions[0u];
+ particleData.positionStride = 4 * sizeof(float);
+ particleData.numParticles = NvFlowUint(m_positions.size() / 4u);
+
+ NvFlowParticleSurfaceUpdateParticles(m_particleSurface, m_flowContext.m_gridContext, &particleData);
+
+ NvFlowParticleSurfaceUpdateSurface(m_particleSurface, m_flowContext.m_gridContext, &m_particleParams);
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "ParticleSurface");
+
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // emit
+ {
+ /*
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeSphere;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+ */
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+ }
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameParticleSurface::preDraw()
+{
+ SceneSimpleFlame::preDraw();
+}
+
+void SceneSimpleFlameParticleSurface::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ m_projectile.draw(projection, view);
+
+ m_flowContext.drawBegin();
+
+ if (!m_visualizeSurface)
+ {
+ m_flowGridActor.draw(&m_flowContext, projection, view);
+ }
+ else
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Render");
+
+ auto m_renderParams = m_flowGridActor.m_renderParams;
+
+ memcpy(&m_renderParams.projectionMatrix, &projection, sizeof(m_renderParams.projectionMatrix));
+ memcpy(&m_renderParams.viewMatrix, &view, sizeof(m_renderParams.viewMatrix));
+
+ m_renderParams.depthStencilView = m_flowContext.m_dsv;
+ m_renderParams.renderTargetView = m_flowContext.m_rtv;
+
+ auto gridExport = NvFlowParticleSurfaceDebugGridExport(m_particleSurface, m_flowContext.m_renderContext);
+
+ NvFlowVolumeRenderGridExport(m_flowGridActor.m_volumeRender, m_flowContext.m_renderContext, gridExport, &m_renderParams);
+
+ AppGraphCtxProfileEnd(m_appctx, "Render");
+ }
+
+ m_flowContext.drawEnd();
+}
+
+void SceneSimpleFlameParticleSurface::release()
+{
+ SceneSimpleFlame::release();
+
+ NvFlowReleaseParticleSurface(m_particleSurface);
+}
+
+void SceneSimpleFlameParticleSurface::imgui(int x, int y, int w, int h)
+{
+ SceneSimpleFlame::imgui(x, y, w, h);
+}
+
+void SceneSimpleFlameParticleSurface::imguiFluidRenderExtra()
+{
+ imguiLabel("Particle Surface");
+ if (imguiserCheck("SurfaceVis", m_visualizeSurface, true))
+ {
+ m_visualizeSurface = !m_visualizeSurface;
+ m_shouldReset = true;
+ }
+ imguiserSlider("Smooth Radius", &m_particleParams.smoothRadius, 1.f, 16.f, 1.f, true);
+ imguiserSlider("Threshold", &m_particleParams.surfaceThreshold, 0.001f, 0.01f, 0.001f, true);
+ if (imguiserCheck("SeparableSmooth", m_particleParams.separableSmoothing, true))
+ {
+ m_particleParams.separableSmoothing = !m_particleParams.separableSmoothing;
+ }
+}
+
+void SceneSimpleFlameParticleSurface::initParams()
+{
+ m_flowGridActor.initParams(AppGraphCtxDedicatedVideoMemory(m_appctx));
+
+ // set emitter defaults
+ NvFlowGridEmitParamsDefaults(&m_emitParams);
+
+ // configure emitter params
+ m_emitParams.bounds.x.x = 0.25f;
+ m_emitParams.bounds.y.y = 0.25f;
+ m_emitParams.bounds.z.z = 0.25f;
+ m_emitParams.velocityLinear.y = -1.f;
+ m_emitParams.fuel = 0.2f;
+ m_emitParams.smoke = 0.1f;
+ m_emitParams.temperature = 8.f;
+
+ m_flowGridActor.m_materialParams.coolingRate = 3.f;
+
+ m_shouldLoadPreset = true;
+}
+
+// *************************** SceneDynamicCoupleRate **********************
+
+void SceneDynamicCoupleRate::initParams()
+{
+ SceneSimpleFlame::initParams();
+ m_emitParams.allocationPredict = 0.3f;
+}
+
+float SceneDynamicCoupleRate::positionFunc(float theta)
+{
+ return 2.f * cosf(theta);
+}
+
+float SceneDynamicCoupleRate::velocityFunc(float theta, float rate)
+{
+ return -2.f * rate * sinf(theta);
+}
+
+void SceneDynamicCoupleRate::doUpdate(float dt)
+{
+ const float pi2 = 2.f * 3.14159265f;
+
+ theta += pi2 * rate * dt;
+
+ if (theta > pi2) theta -= pi2;
+
+ // get position and velocity
+ float position = positionFunc(theta);
+ float velocity = velocityFunc(theta, pi2 * rate);
+
+ // update emitter bounds
+ m_emitParams.bounds.x.x = 0.25f * emitterScale;
+ m_emitParams.bounds.y.y = 0.25f * emitterScale;
+ m_emitParams.bounds.z.z = 0.25f * emitterScale;
+
+ // modulate couple rate as a function of velocity and emitter width
+ const float defaultCoupleRate = 0.5f;
+
+ float emitWidth = m_emitParams.bounds.x.x;
+
+ float coupleRate = fmaxf(coupleRateScale * fabsf(velocity) / emitWidth, defaultCoupleRate);
+
+ m_emitParams.smokeCoupleRate = coupleRate;
+ m_emitParams.temperatureCoupleRate = coupleRate;
+ m_emitParams.fuelCoupleRate = coupleRate;
+ m_emitParams.velocityCoupleRate = { coupleRate, coupleRate, coupleRate };
+
+ m_emitParams.bounds.w.x = position;
+ m_emitParams.velocityLinear.x = velocity;
+
+ m_emitParams.predictVelocityWeight = 1.f;
+ m_emitParams.predictVelocity.x = velocity;
+ m_emitParams.predictVelocity.y = 0.f;
+ m_emitParams.predictVelocity.z = 0.f;
+
+ SceneSimpleFlame::doUpdate(dt);
+}
+
+void SceneDynamicCoupleRate::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+ imguiLabel("Dynamic Couple Rate");
+
+ imguiserSlider("Anim Cycle Time", &rate, 0.f, 0.5f, 0.01f, true);
+ imguiserSlider("Couple Rate Scale", &coupleRateScale, 0.f, 1.0f, 0.01f, true);
+ imguiserSlider("Emitter Scale", &emitterScale, 0.5f, 2.0f, 0.01f, true);
+}
+
+// *************************** SceneSimpleFlameMesh ************************
+
+void SceneSimpleFlameMesh::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ NvFlowGridEmitParamsDefaults(&m_teapotEmitParams);
+
+ m_teapotEmitParams.allocationScale = { 0.f, 0.f, 0.f };
+
+ m_teapotEmitParams.maxActiveDist = -0.08f;
+ m_teapotEmitParams.slipThickness = 0.25f;
+ m_teapotEmitParams.slipFactor = 0.9f;
+}
+
+void SceneSimpleFlameMesh::init(AppGraphCtx* context, int winw, int winh)
+{
+ using namespace DirectX;
+
+ m_meshContext = MeshInteropContextCreate(context);
+ m_mesh = MeshCreate(m_meshContext);
+
+ MeshLoadFromFile(m_mesh, m_meshPath);
+
+ SceneSimpleFlame::init(context, winw, winh);
+
+ NvFlowSDFGenDesc sdfDesc;
+ sdfDesc.resolution = { 128u, 128u, 128u };
+
+ m_sdfGen = NvFlowCreateSDFGen(m_flowContext.m_gridContext, &sdfDesc);
+
+ MeshData meshData;
+ MeshGetData(m_mesh, &meshData);
+
+ NvFlowSDFGenReset(m_sdfGen, m_flowContext.m_gridContext);
+
+ XMMATRIX modelMatrix = XMMatrixMultiply(
+ XMMatrixScaling(m_sdfScale.x, m_sdfScale.y, m_sdfScale.z),
+ XMMatrixTranslation(0.f, 0.f, 0.f)
+ );
+
+ NvFlowSDFGenMeshParams meshParams;
+ meshParams.numVertices = meshData.numVertices;
+ meshParams.positions = meshData.positions;
+ meshParams.positionStride = meshData.positionStride;
+ meshParams.normals = meshData.normals;
+ meshParams.normalStride = meshData.normalStride;
+ meshParams.numIndices = meshData.numIndices;
+ meshParams.indices = meshData.indices;
+ XMStoreFloat4x4((XMFLOAT4X4*)&meshParams.modelMatrix, modelMatrix);
+ meshParams.renderTargetView = m_flowContext.m_multiGPUActive ? nullptr : m_flowContext.m_rtv;
+ meshParams.depthStencilView = m_flowContext.m_multiGPUActive ? nullptr : m_flowContext.m_dsv;
+
+ NvFlowSDFGenVoxelize(m_sdfGen, m_flowContext.m_gridContext, &meshParams);
+
+ NvFlowSDFGenUpdate(m_sdfGen, m_flowContext.m_gridContext);
+
+ // create shape from SDF
+ m_teapotShape = NvFlowCreateShapeSDFFromTexture3D(
+ m_flowContext.m_gridContext,
+ NvFlowSDFGenShape(m_sdfGen, m_flowContext.m_gridContext)
+ );
+}
+
+void SceneSimpleFlameMesh::release()
+{
+ MeshRelease(m_mesh);
+ MeshContextRelease(m_meshContext);
+ NvFlowReleaseShapeSDF(m_teapotShape);
+ NvFlowReleaseSDFGen(m_sdfGen);
+ SceneSimpleFlame::release();
+}
+
+void SceneSimpleFlameMesh::doUpdate(float dt)
+{
+ NvFlowGridEmitParams& emitParams = m_teapotEmitParams;
+ emitParams.bounds.x.x = m_emitterScale.x;
+ emitParams.bounds.y.y = m_emitterScale.y;
+ emitParams.bounds.z.z = m_emitterScale.z;
+ emitParams.bounds.w.x = m_emitterOffset.x;
+ emitParams.bounds.w.y = m_emitterOffset.y;
+ emitParams.bounds.w.z = m_emitterOffset.z;
+
+ emitParams.velocityCoupleRate = { 1000.f, 1000.f, 1000.f };
+
+ emitParams.temperature = 0.f;
+ emitParams.temperatureCoupleRate = 10.f;
+
+ emitParams.fuel = 0.f;
+ emitParams.fuelCoupleRate = 10.f;
+
+ emitParams.smoke = 0.f;
+ emitParams.smokeCoupleRate = 10.f;
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sdf.sdfOffset = 0u; // m_teapotShape;
+
+ emitParams.localToWorld = emitParams.bounds;
+ emitParams.shapeType = eNvFlowShapeTypeSDF;
+ emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &emitParams, 1u);
+
+ NvFlowShapeSDF* sdfs[] = { m_teapotShape };
+ NvFlowGridUpdateEmitSDFs(m_flowGridActor.m_grid, sdfs, 1u);
+
+ // animate emitter
+ if (m_animate)
+ {
+ m_time += dt;
+
+ const float rate = 2.f;
+ const float period = 2.f * 3.14159265f / rate;
+ if (m_time > period) m_time -= period;
+
+ m_emitParams.bounds.w.x = 0.15f * sinf(rate * m_time);
+ m_emitParams.bounds.w.z = 0.f;
+ }
+ else
+ {
+ m_emitParams.bounds.w.x = 0.f;
+ m_emitParams.bounds.w.z = 0.f;
+
+ m_time = 0.f;
+ }
+
+ SceneSimpleFlame::doUpdate(dt);
+}
+
+void SceneSimpleFlameMesh::draw(DirectX::CXMMATRIX projection, DirectX::CXMMATRIX view)
+{
+ MeshInteropContextUpdate(m_meshContext, m_appctx);
+
+ MeshDrawParams meshDrawParams;
+ meshDrawParams.renderMode = MESH_RENDER_SOLID;
+ meshDrawParams.projection = projection;
+ meshDrawParams.view = view;
+ meshDrawParams.model = DirectX::XMMatrixMultiply(
+ DirectX::XMMatrixScaling(m_emitterScale.x * m_sdfScale.x, m_emitterScale.y * m_sdfScale.y, m_emitterScale.z * m_sdfScale.z),
+ DirectX::XMMatrixTranslation(m_emitterOffset.x, m_emitterOffset.y, m_emitterOffset.z)
+ );
+
+ if (m_shouldDrawMesh)
+ {
+ MeshDraw(m_mesh, &meshDrawParams);
+ }
+
+ SceneSimpleFlame::draw(projection, view);
+}
+
+void SceneSimpleFlameMesh::imguiFluidRenderExtra()
+{
+ if (imguiserCheck("Draw Mesh", m_shouldDrawMesh, true))
+ {
+ m_shouldDrawMesh = !m_shouldDrawMesh;
+ }
+}
+
+void SceneSimpleFlameMesh::imguiFluidEmitterExtra()
+{
+ if (imguiserCheck("Animate", m_animate, true))
+ {
+ m_animate = !m_animate;
+ }
+ imguiSeparatorLine();
+ imguiLabel("Teapot");
+ imguiserBeginGroup("Teapot", nullptr);
+
+ imguiserSlider("Max Emit Dist", &m_teapotEmitParams.maxActiveDist, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("Min Emit Dist", &m_teapotEmitParams.minActiveDist, -1.f, 1.f, 0.01f, true);
+ imguiserSlider("Slip Thickness", &m_teapotEmitParams.slipThickness, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Slip Factor", &m_teapotEmitParams.slipFactor, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel Release Temp", &m_teapotEmitParams.fuelReleaseTemp, 0.f, 1.f, 0.01f, true);
+ imguiserSlider("Fuel Release", &m_teapotEmitParams.fuelRelease, 0.f, 10.f, 0.1f, true);
+
+ imguiserEndGroup();
+}
+
+// *************************** SceneSimpleFlameCulling ************************
+
+void SceneSimpleFlameCulling::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ m_emitParams.allocationScale = { 2.f, 2.f, 2.f };
+ m_emitParams.allocationPredict = 0.4f;
+}
+
+void SceneSimpleFlameCulling::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ {
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ // main emitter
+ {
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.box.halfSize = { 0.8f, 0.8f, 0.8f };
+
+ m_emitParams.localToWorld = m_emitParams.bounds;
+ m_emitParams.shapeType = eNvFlowShapeTypeBox;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &m_emitParams, 1u);
+ }
+
+ // grid of emitters
+ {
+ const int r = m_emitGridR;
+ const float scale = 0.125f;
+
+ NvFlowShapeDesc shapeDesc;
+ shapeDesc.sphere.radius = 0.8f;
+
+ NvFlowGridEmitParams emitParams;
+
+ NvFlowGridEmitParamsDefaults(&emitParams);
+
+ emitParams.bounds.x.x = 0.25f;
+ emitParams.bounds.y.y = 0.25f;
+ emitParams.bounds.z.z = 0.25f;
+
+ emitParams.maxActiveDist = -0.08f;
+ emitParams.slipThickness = 0.25f;
+ emitParams.slipFactor = 0.9f;
+
+ emitParams.velocityCoupleRate = { 1000.f, 1000.f, 1000.f };
+
+ emitParams.temperature = 0.f;
+ emitParams.temperatureCoupleRate = 10.f;
+
+ emitParams.fuel = 0.f;
+ emitParams.fuelCoupleRate = 10.f;
+
+ emitParams.smoke = 0.f;
+ emitParams.smokeCoupleRate = 10.f;
+
+ emitParams.allocationScale = { 1.f, 1.f, 1.f };
+ emitParams.allocationPredict = 0.f;
+
+ for (int j = -r; j <= r; j++)
+ {
+ for (int i = -r; i <= r; i++)
+ {
+ if (i == 0 && j == 0) continue;
+
+ emitParams.bounds.w.x = scale * float(i);
+ emitParams.bounds.w.y = 0.f;
+ emitParams.bounds.w.z = scale * float(j);
+
+ emitParams.localToWorld = emitParams.bounds;
+ emitParams.shapeType = eNvFlowShapeTypeSphere;
+ emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, &shapeDesc, 1u, &emitParams, 1u);
+ }
+ }
+ }
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameCulling::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+ imguiLabel("Culling");
+ imguiserBeginGroup("Culling", nullptr);
+
+ float r = float(m_emitGridR);
+ imguiserSlider("Emit Grid R", &r, 0.f, 16.f, 1.f, true);
+ m_emitGridR = NvFlowUint(r);
+
+ imguiserEndGroup();
+}
+
+// *************************** SceneSimpleFlameConvex ************************
+
+void SceneSimpleFlameConvex::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ m_emitParams.minActiveDist = -0.3f;
+ m_emitParams.fuel = 2.5f;
+
+ m_flowGridActor.m_materialParams.smoke.damping = 0.5f;
+ m_flowGridActor.m_materialParams.smoke.fade = 0.5f;
+}
+
+void SceneSimpleFlameConvex::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ {
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc[8];
+ const float a = 0.866f;
+ const float b = 0.5f;
+ const float d = 4.f * m_size;
+ shapeDesc[0].plane = { +1.f, 0.f, 0.f, d };
+ shapeDesc[1].plane = { -1.f, 0.f, 0.f, d };
+ shapeDesc[2].plane = { +b, 0.f, +a, d };
+ shapeDesc[3].plane = { +b, 0.f, -a, d };
+ shapeDesc[4].plane = { -b, 0.f, +a, d };
+ shapeDesc[5].plane = { -b, 0.f, -a, d };
+ shapeDesc[6].plane = { 0.f, +1.f, 0.f, 0.8f };
+ shapeDesc[7].plane = { 0.f, -1.f, 0.f, 0.8f };
+
+ m_emitParams.bounds.x.x = m_size + 0.25f;
+ //m_emitParams.bounds.y.y = m_barLength;
+ m_emitParams.bounds.z.z = m_size + 0.25f;
+
+ m_emitParams.localToWorld = NvFlowFloat4x4{
+ 0.25f, 0.f, 0.f, 0.f,
+ 0.f, 0.25f, 0.f, 0.f,
+ 0.f, 0.f, 0.25f, 0.f,
+ m_emitParams.bounds.w.x, m_emitParams.bounds.w.y, m_emitParams.bounds.w.z, 1.f
+ };
+ m_emitParams.shapeType = eNvFlowShapeTypePlane;
+ m_emitParams.shapeDistScale = m_distanceScale;
+ m_emitParams.shapeRangeOffset = 0u;
+ m_emitParams.shapeRangeSize = 8u;
+ m_emitParams.deltaTime = dt;
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, shapeDesc, 8u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameConvex::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+ imguiLabel("Bar");
+ imguiserBeginGroup("Bar", nullptr);
+
+ imguiserSlider("Size", &m_size, 0.f, 4.f, 0.1f, true);
+ imguiserSlider("Distance Scale", &m_distanceScale, 0.1f, 3.f, 0.025f, true);
+
+ imguiserEndGroup();
+}
+
+// *************************** SceneSimpleFlameCapsule ************************
+
+void SceneSimpleFlameCapsule::initParams()
+{
+ SceneSimpleFlame::initParams();
+
+ m_emitParams.minActiveDist = -0.3f;
+ m_emitParams.fuel = 2.5f;
+
+ m_flowGridActor.m_materialParams.smoke.damping = 0.5f;
+ m_flowGridActor.m_materialParams.smoke.fade = 0.5f;
+}
+
+void SceneSimpleFlameCapsule::doUpdate(float dt)
+{
+ bool shouldUpdate = m_flowContext.updateBegin();
+ if (shouldUpdate)
+ {
+ AppGraphCtxProfileBegin(m_appctx, "Simulate");
+
+ if (shouldUpdate)
+ {
+ m_flowGridActor.updatePreEmit(&m_flowContext, dt);
+
+ NvFlowShapeDesc shapeDesc[1];
+ shapeDesc[0].capsule.radius = m_capsuleRadius;
+ shapeDesc[0].capsule.length = m_capsuleLength;
+
+ // generate bounds based on radius and length
+ const float boundInflate = 0.25f;
+ float xbound = 2.f * m_capsuleRadius + m_capsuleLength + boundInflate;
+ float yzbound = 2.f * m_capsuleRadius + boundInflate;
+ m_emitParams.bounds.x.x = 0.5f * xbound;
+ m_emitParams.bounds.y.y = 0.5f * yzbound;
+ m_emitParams.bounds.z.z = 0.5f * yzbound;
+
+ m_emitParams.localToWorld = NvFlowFloat4x4{
+ 1.f, 0.f, 0.f, 0.f,
+ 0.f, 1.f, 0.f, 0.f,
+ 0.f, 0.f, 1.f, 0.f,
+ m_emitParams.bounds.w.x, m_emitParams.bounds.w.y, m_emitParams.bounds.w.z, 1.f
+ };
+
+ m_emitParams.shapeType = eNvFlowShapeTypeCapsule;
+ m_emitParams.shapeDistScale = m_distanceScale;
+ m_emitParams.deltaTime = dt;
+
+ if (m_boxMode)
+ {
+ m_emitParams.shapeType = eNvFlowShapeTypeBox;
+ shapeDesc[0].box.halfSize.x = 0.5f * m_capsuleLength + m_capsuleRadius;
+ shapeDesc[0].box.halfSize.y = m_capsuleRadius;
+ shapeDesc[0].box.halfSize.z = 0.5f * m_capsuleRadius;
+ }
+
+ NvFlowGridEmit(m_flowGridActor.m_grid, shapeDesc, 1u, &m_emitParams, 1u);
+
+ m_projectile.update(m_flowContext.m_gridContext, m_flowGridActor.m_grid, dt);
+
+ m_flowGridActor.updatePostEmit(&m_flowContext, dt, shouldUpdate, m_shouldGridReset);
+
+ m_shouldGridReset = false;
+ }
+
+ AppGraphCtxProfileEnd(m_appctx, "Simulate");
+ }
+ m_flowContext.updateEnd();
+}
+
+void SceneSimpleFlameCapsule::imguiFluidEmitterExtra()
+{
+ imguiSeparatorLine();
+ imguiLabel("Bar");
+ imguiserBeginGroup("Bar", nullptr);
+
+ imguiserSlider("Capsule Radius", &m_capsuleRadius, 0.f, 1.f, 0.1f, true);
+ imguiserSlider("Capsule Length", &m_capsuleLength, 0.f, 3.f, 0.1f, true);
+ imguiserSlider("Distance Scale", &m_distanceScale, 0.1f, 5.f, 0.025f, true);
+
+ if (imguiserCheck("Box mode", m_boxMode, true))
+ {
+ m_boxMode = !m_boxMode;
+ }
+
+ imguiserEndGroup();
+} \ No newline at end of file