Commit d79f3c70 authored by Nicholas Milef's avatar Nicholas Milef Committed by Nicholas Milef

CLEANUP: added animation classes

parent 922eda28
......@@ -343,6 +343,7 @@ add_subdirectory(Source/SimulationManager)
add_subdirectory(Source/Constraint)
add_subdirectory(Source/Materials)
add_subdirectory(Source/GUIOverlay)
add_subdirectory(Source/Animation)
#--------------------------------------------------------------------------
# Export Targets
......
......@@ -20,6 +20,8 @@
=========================================================================*/
#include "imstkSimulationManager.h"
#include "imstkAnimationObject.h"
#include "imstkRenderParticles.h"
#include "imstkRenderParticleEmitter.h"
#include "imstkAPIUtilities.h"
......@@ -42,28 +44,36 @@ int main()
// Smoke
{
// Create sparks material
auto particleMaterial = std::make_shared<RenderMaterial>();
auto particleTexture = std::make_shared<Texture>
(iMSTK_DATA_ROOT "/particles/smoke_01.png", Texture::Type::DIFFUSE);
particleMaterial->addTexture(particleTexture);
particleMaterial->setBlendMode(RenderMaterial::BlendMode::ALPHA);
auto particleEmitter = std::make_shared<RenderParticleEmitter>(128, 2000.0f);
// Create particle geometry (for visual and animation)
auto particles = std::make_shared<RenderParticles>(128);
particles->setParticleSize(0.4f);
// Create particle animation model
auto particleEmitter = std::make_shared<RenderParticleEmitter>(particles, 2000.0f);
particleEmitter->setInitialVelocityRange(Vec3f(-1, 5, -1), Vec3f(1, 5, 1),
0.5, 1.0,
-1.0, 1.0);
particleEmitter->setEmitterSize(0.3f);
particleEmitter->setParticleSize(0.4f);
// Modify the first keyframe
auto startKeyFrame = particleEmitter->getStartKeyFrame();
startKeyFrame->m_color = Color(1.0, 0.7, 0.0, 1.0);
// Add another keyframe
RenderParticleKeyFrame midFrame0;
midFrame0.m_time = 700.0f;
midFrame0.m_color = Color::Red;
midFrame0.m_scale = 1.5f;
particleEmitter->addKeyFrame(midFrame0);
// Add another keyframe
RenderParticleKeyFrame midFrame1;
midFrame1.m_time = 1300.0f;
midFrame1.m_color = Color::DarkGray;
......@@ -71,48 +81,58 @@ int main()
midFrame1.m_scale = 2.0f;
particleEmitter->addKeyFrame(midFrame1);
// Modify the last keyframe
auto endKeyFrame = particleEmitter->getEndKeyFrame();
endKeyFrame->m_color = Color::Black;
endKeyFrame->m_color.a = 0.0;
endKeyFrame->m_scale = 4.0;
auto particleObject = std::make_shared<VisualObject>("Smoke");
auto particleModel = std::make_shared<VisualModel>(particleEmitter);
// Create and add animation scene object
auto particleObject = std::make_shared<AnimationObject>("Smoke");
auto particleModel = std::make_shared<VisualModel>(particles);
particleModel->setRenderMaterial(particleMaterial);
particleObject->addVisualModel(particleModel);
particleObject->setAnimationModel(particleEmitter);
scene->addSceneObject(particleObject);
}
// Sparks
{
// Create sparks material
auto particleMaterial = std::make_shared<RenderMaterial>();
auto particleTexture = std::make_shared<Texture>
(iMSTK_DATA_ROOT "/particles/flare_01.png", Texture::Type::DIFFUSE);
particleMaterial->addTexture(particleTexture);
particleMaterial->setBlendMode(RenderMaterial::BlendMode::ALPHA);
auto particleEmitter = std::make_shared<RenderParticleEmitter>(128,
// Create particle geometry (for visual and animation)
auto particles = std::make_shared<RenderParticles>(128);
particles->setTranslation(2, 0.1, 0);
particles->setParticleSize(0.3f);
// Create animation model
auto particleEmitter = std::make_shared<RenderParticleEmitter>(particles,
850.0f, RenderParticleEmitter::Mode::BURST);
particleEmitter->setTranslation(2, 0.1, 0);
particleEmitter->setInitialVelocityRange(Vec3f(-1, 5, -1), Vec3f(1, 5, 1),
4.0, 5.0,
-1.0, 1.0);
particleEmitter->setEmitterSize(0.1f);
particleEmitter->setParticleSize(0.3f);
// Modifying the first keyframe
auto startKeyFrame = particleEmitter->getStartKeyFrame();
startKeyFrame->m_acceleration = Vec3f(0, -9.8, 0);
startKeyFrame->m_color = Color::Yellow;
// Modifying the last keyframe
auto endKeyFrame = particleEmitter->getEndKeyFrame();
endKeyFrame->m_color = Color::Orange;
auto particleObject = std::make_shared<VisualObject>("Sparks");
auto particleModel = std::make_shared<VisualModel>(particleEmitter);
// Create and add animation object
auto particleObject = std::make_shared<AnimationObject>("Sparks");
auto particleModel = std::make_shared<VisualModel>(particles);
particleModel->setRenderMaterial(particleMaterial);
particleObject->addVisualModel(particleModel);
particleObject->setAnimationModel(particleEmitter);
scene->addSceneObject(particleObject);
}
......@@ -131,9 +151,9 @@ int main()
// Create a call back on key press of 'b' to trigger the sparks emitter
viewer->setOnCharFunction('b', [&](InteractorStyle* c) -> bool
{
auto geometry = scene->getSceneObject("Sparks")->getVisualModel(0)->getGeometry();
auto sparks = std::static_pointer_cast<RenderParticleEmitter>(geometry);
sparks->reset();
auto sparks = std::static_pointer_cast<AnimationObject>(
scene->getSceneObject("Sparks"));
sparks->getAnimationModel()->reset();
return false;
});
......
#-----------------------------------------------------------------------------
# Create target
#-----------------------------------------------------------------------------
include(imstkAddLibrary)
imstk_add_library( Animation
DEPENDS
Core
Geometry
SceneElements
)
#-----------------------------------------------------------------------------
# Testing
#-----------------------------------------------------------------------------
if( iMSTK_BUILD_TESTING )
add_subdirectory( Testing )
endif()
......@@ -23,20 +23,12 @@
namespace imstk
{
RenderParticleEmitter::RenderParticleEmitter(unsigned int maxNumParticles /*=128*/,
float time /*= 3000*/,
RenderParticleEmitter::Mode mode /*= Mode::BURST*/)
: Geometry(Geometry::Type::RenderParticleEmitter)
RenderParticleEmitter::RenderParticleEmitter(std::shared_ptr<Geometry> geometry,
const float time /*= 3000*/,
RenderParticleEmitter::Mode mode /*= Mode::CONTINUOUS*/)
: AnimationModel(geometry)
{
if (maxNumParticles <= 128)
{
m_maxNumParticles = maxNumParticles;
}
else
{
m_maxNumParticles = 128;
LOG(WARNING) << "The maximum number of decals is 128";
}
this->setGeometry(geometry);
m_time = time;
m_emitTime = m_time;
......@@ -57,25 +49,51 @@ RenderParticleEmitter::RenderParticleEmitter(unsigned int maxNumParticles /*=128
m_keyFrames.push_back(startFrame);
m_keyFrames.push_back(endFrame);
m_vertexPositions[0] = glm::vec3(0.5, 0.5, 0);
m_vertexPositions[1] = glm::vec3(0.5, -0.5, 0);
m_vertexPositions[2] = glm::vec3(-0.5, 0.5, 0);
m_vertexPositions[3] = glm::vec3(-0.5, -0.5, 0);
this->initializeParticles();
}
m_vertexNormals[0] = glm::vec3(0.0, 0.0, 1.0);
m_vertexNormals[1] = glm::vec3(0.0, 0.0, 1.0);
m_vertexNormals[2] = glm::vec3(0.0, 0.0, 1.0);
m_vertexNormals[3] = glm::vec3(0.0, 0.0, 1.0);
void
RenderParticleEmitter::setGeometry(
std::shared_ptr<Geometry> geometry)
{
if (geometry->getType() != Geometry::Type::RenderParticles)
{
LOG(FATAL) << "Geometry must be RenderParticles";
return;
}
m_vertexUVs[0] = glm::vec2(1.0, 1.0);
m_vertexUVs[1] = glm::vec2(1.0, 0);
m_vertexUVs[2] = glm::vec2(0, 1.0);
m_vertexUVs[3] = glm::vec2(0, 0);
m_animationGeometry = geometry;
m_particles = &std::static_pointer_cast<RenderParticles>(m_animationGeometry)->getParticles();
}
m_triangles[0] = glm::ivec3(1, 0, 3);
m_triangles[1] = glm::ivec3(0, 2, 3);
RenderParticleEmitter::Mode
RenderParticleEmitter::getEmitterMode() const
{
return m_mode;
}
this->initializeParticles();
void
RenderParticleEmitter::setEmitterSize(const float size)
{
m_emitterSize = size;
}
void
RenderParticleEmitter::setInitialVelocityRange(const Vec3f minDirection,
const Vec3f maxDirection,
const float minSpeed,
const float maxSpeed,
const float minRotationSpeed,
const float maxRotationSpeed)
{
m_minDirection = minDirection;
m_maxDirection = maxDirection;
m_minDirection.normalize();
m_maxDirection.normalize();
m_minSpeed = minSpeed;
m_maxSpeed = maxSpeed;
m_minRotationSpeed = minRotationSpeed;
m_maxRotationSpeed = maxRotationSpeed;
}
bool
......@@ -90,27 +108,63 @@ RenderParticleEmitter::addKeyFrame(RenderParticleKeyFrame keyFrame)
return true;
}
RenderParticleEmitter::Mode
RenderParticleEmitter::getEmitterMode()
RenderParticleKeyFrame *
RenderParticleEmitter::getStartKeyFrame()
{
return m_mode;
unsigned int index = 0;
for (unsigned int i = 0; i < m_keyFrames.size(); i++)
{
if (m_keyFrames[i].m_time < m_keyFrames[index].m_time)
{
index = i;
}
}
return &m_keyFrames[index];
}
void
RenderParticleEmitter::setEmitterSize(float size)
RenderParticleKeyFrame *
RenderParticleEmitter::getEndKeyFrame()
{
m_emitterSize = size;
unsigned int index = 0;
for (unsigned int i = 0; i < m_keyFrames.size(); i++)
{
if (m_keyFrames[i].m_time > m_keyFrames[index].m_time)
{
index = i;
}
}
return &m_keyFrames[index];
}
std::vector<RenderParticleKeyFrame>&
RenderParticleEmitter::getKeyFrames()
{
return m_keyFrames;
}
void
RenderParticleEmitter::setParticleSize(float size)
RenderParticleEmitter::reset()
{
m_particleSize = size;
if (m_mode != Mode::BURST)
{
return;
}
auto renderParticles = std::static_pointer_cast<RenderParticles>(m_geometry);
renderParticles->reset();
this->initializeParticles();
}
void
RenderParticleEmitter::updateParticleEmitter(Vec3d cameraPosition)
RenderParticleEmitter::update()
{
auto renderParticles = std::static_pointer_cast<RenderParticles>(m_geometry);
if (!m_started)
{
m_stopWatch.start();
......@@ -121,7 +175,7 @@ RenderParticleEmitter::updateParticleEmitter(Vec3d cameraPosition)
float dt = (float)(time - m_lastUpdateTime);
m_lastUpdateTime = time;
for (auto&& particle : m_particles)
for (auto&& particle : (*m_particles))
{
auto startKeyFrameTemp = *this->getStartKeyFrame();
auto startKeyFrame = &startKeyFrameTemp;
......@@ -134,7 +188,7 @@ RenderParticleEmitter::updateParticleEmitter(Vec3d cameraPosition)
{
particle->m_created = true;
this->emitParticle(particle);
m_numParticles++;
renderParticles->incrementNumOfParticles();
}
else if (particle->m_age < 0)
{
......@@ -179,17 +233,32 @@ RenderParticleEmitter::updateParticleEmitter(Vec3d cameraPosition)
particle->m_scale = (alpha * endKeyFrame->m_scale)
+ ((1.0f - alpha) * startKeyFrame->m_scale);
interpolateColor(particle->m_color,
this->interpolateColor(particle->m_color,
endKeyFrame->m_color,
startKeyFrame->m_color,
alpha);
}
}
void
RenderParticleEmitter::initializeParticles()
{
m_particles->clear();
auto particles = std::static_pointer_cast<RenderParticles>(m_animationGeometry);
for (unsigned int i = 0; i < particles->getMaxNumParticles(); i++)
{
m_particles->push_back(std::unique_ptr<RenderParticle>(new RenderParticle()));
(*m_particles)[i]->m_age = -(i / (float)(particles->getMaxNumParticles())) * m_emitTime;
(*m_particles)[i]->m_created = false;
}
}
void
RenderParticleEmitter::emitParticle(std::unique_ptr<RenderParticle>& particle)
{
auto position = this->getTranslation();
auto position = m_animationGeometry->getTranslation();
if (m_shape == Shape::CUBE)
{
......@@ -226,9 +295,9 @@ RenderParticleEmitter::emitParticle(std::unique_ptr<RenderParticle>& particle)
void
RenderParticleEmitter::interpolateColor(Color& destination,
Color& sourceA,
Color& sourceB,
float alpha)
const Color& sourceA,
const Color& sourceB,
const float alpha)
{
destination.r = (sourceA.r * alpha) + (sourceB.r * (1.0f - alpha));
destination.g = (sourceA.g * alpha) + (sourceB.g * (1.0f - alpha));
......@@ -236,103 +305,9 @@ RenderParticleEmitter::interpolateColor(Color& destination,
destination.a = (sourceA.a * alpha) + (sourceB.a * (1.0f - alpha));
}
unsigned int
RenderParticleEmitter::getNumParticles()
{
return m_numParticles;
}
std::vector<std::unique_ptr<RenderParticle>>&
RenderParticleEmitter::getParticles()
{
return m_particles;
}
std::vector<RenderParticleKeyFrame>&
RenderParticleEmitter::getKeyFrames()
{
return m_keyFrames;
}
RenderParticleKeyFrame *
RenderParticleEmitter::getStartKeyFrame()
{
unsigned int index = 0;
for (unsigned int i = 0; i < m_keyFrames.size(); i++)
{
if (m_keyFrames[i].m_time < m_keyFrames[index].m_time)
{
index = i;
}
}
return &m_keyFrames[index];
}
RenderParticleKeyFrame *
RenderParticleEmitter::getEndKeyFrame()
{
unsigned int index = 0;
for (unsigned int i = 0; i < m_keyFrames.size(); i++)
{
if (m_keyFrames[i].m_time > m_keyFrames[index].m_time)
{
index = i;
}
}
return &m_keyFrames[index];
}
void
RenderParticleEmitter::setInitialVelocityRange(Vec3f minDirection,
Vec3f maxDirection,
float minSpeed,
float maxSpeed,
float minRotationSpeed,
float maxRotationSpeed)
{
m_minDirection = minDirection;
m_maxDirection = maxDirection;
m_minDirection.normalize();
m_maxDirection.normalize();
m_minSpeed = minSpeed;
m_maxSpeed = maxSpeed;
m_minRotationSpeed = minRotationSpeed;
m_maxRotationSpeed = maxRotationSpeed;
}
float
RenderParticleEmitter::getRandomNormalizedFloat()
{
return (float)std::rand() / RAND_MAX;
}
void
RenderParticleEmitter::initializeParticles()
{
m_particles.clear();
for (unsigned int i = 0; i < m_maxNumParticles; i++)
{
m_particles.push_back(std::make_unique<RenderParticle>());
m_particles[i]->m_age = -(i / (float)(m_maxNumParticles)) * m_emitTime;
m_particles[i]->m_created = false;
}
}
void
RenderParticleEmitter::reset()
{
if (m_mode != Mode::BURST)
{
return;
}
m_numParticles = 0;
this->initializeParticles();
}
}
\ No newline at end of file
/*=========================================================================
Library: iMSTK
Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
& Imaging in Medicine, Rensselaer Polytechnic Institute.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.txt
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#include "imstkRenderParticles.h"
namespace imstk
{
RenderParticles::RenderParticles(const unsigned int maxNumParticles /*=128*/)
: Geometry(Geometry::Type::RenderParticles)
{
if (maxNumParticles <= 128)
{
m_maxNumParticles = maxNumParticles;
}
else
{
m_maxNumParticles = 128;
LOG(WARNING) << "The maximum number of decals is 128";
}
m_vertexPositions[0] = glm::vec3(0.5, 0.5, 0);
m_vertexPositions[1] = glm::vec3(0.5, -0.5, 0);
m_vertexPositions[2] = glm::vec3(-0.5, 0.5, 0);
m_vertexPositions[3] = glm::vec3(-0.5, -0.5, 0);
m_vertexNormals[0] = glm::vec3(0.0, 0.0, 1.0);
m_vertexNormals[1] = glm::vec3(0.0, 0.0, 1.0);
m_vertexNormals[2] = glm::vec3(0.0, 0.0, 1.0);
m_vertexNormals[3] = glm::vec3(0.0, 0.0, 1.0);
m_vertexUVs[0] = glm::vec2(1.0, 1.0);
m_vertexUVs[1] = glm::vec2(1.0, 0);
m_vertexUVs[2] = glm::vec2(0, 1.0);
m_vertexUVs[3] = glm::vec2(0, 0);
m_triangles[0] = glm::ivec3(1, 0, 3);
m_triangles[1] = glm::ivec3(0, 2, 3);
}
void
RenderParticles::setParticleSize(const float size)
{
m_particleSize = size;
}
std::vector<std::unique_ptr<RenderParticle>>&
RenderParticles::getParticles()
{
return m_particles;
}
void
RenderParticles::reset()
{
m_numParticles = 0;
}
void
RenderParticles::incrementNumOfParticles()
{
m_numParticles++;
}
unsigned int
RenderParticles::getNumParticles()
{
return m_numParticles;
}
unsigned int
RenderParticles::getMaxNumParticles()
{
return m_maxNumParticles;
}
}
\ No newline at end of file
/*=========================================================================
Library: iMSTK
Copyright (c) Kitware, Inc. & Center for Modeling, Simulation,
& Imaging in Medicine, Rensselaer Polytechnic Institute.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0.txt
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
=========================================================================*/
#ifndef imstkRenderParticles_h
#define imstkRenderParticles_h
#include <vector>
#include <climits>
#include <memory>
#include "glm/glm.hpp"
#include "imstkGeometry.h"
#include "imstkMath.h"
#include "imstkColor.h"
#include "imstkTimer.h"
namespace imstk
{
///
/// \struct RenderParticle
///
/// \brief Particle data
///
struct RenderParticle
{
Vec3f m_position = Vec3f(0, 0, 0);
Vec3f m_velocity = Vec3f(0, 0, 0);
Vec3f m_acceleration = Vec3f(0, 0, 0);
Color m_color = Color::White;
float m_age = 0;
bool m_created = false;
float m_scale = 1.0f;
float m_rotation = 0;
float m_rotationalVelocity = 0;
float m_rotationalAcceleration = 0;
};
///
/// \class RenderParticles
///
/// \brief Particles for rendering
///
class RenderParticles : public Geometry
{
public:
///
/// \brief Constructor
/// \param maxNumParticles Number of particles this emitter can produce
/// \param time Lifespan of each particle (in milliseconds)
/// \param mode Mode for emitter
///
RenderParticles(const unsigned int maxNumParticles = 128);
///
/// \brief Set size of particle
/// \param size Particle size, this determines how much each keyframe
/// scales by
///
void setParticleSize(const float size);
///
/// \brief Get particles
/// \returns particles
///
std::vector<std::unique_ptr<RenderParticle>>& getParticles();
///
/// \brief Reset number of particles
///
void reset();
///
/// \brief Increment number of particles
///
void incrementNumOfParticles();
///
/// \brief Get number of particles
///
unsigned int getNumParticles();
///
/// \brief Get maximum number of particles
///
unsigned int getMaxNumParticles();
///
/// \brief Get volume
/// As these are particles, the volume is 0
///
double getVolume() const override { return 0; };
protected:
friend class VulkanParticleRenderDelegate;
friend class RenderParticles;
unsigned int m_maxNumParticles = 128; ///< Maximum particles
float m_particleSize = 0.1f;
std::vector<std::unique_ptr<RenderParticle>> m_particles; ///< Particle objects