Skip to content

Instantly share code, notes, and snippets.

@ASxa86
Last active August 29, 2015 14:00
Show Gist options
  • Save ASxa86/11188762 to your computer and use it in GitHub Desktop.
Save ASxa86/11188762 to your computer and use it in GitHub Desktop.
#include "ParticleSystem.h"
#include <chrono>
ParticleSystem::ParticleSystem() :
m_maxParticles(50),
m_gForce(0,-0.0098f,0),
m_northTriangleNormal(0,0,0),
m_southTriangleNormal(0,0,0),
m_eastTriangleNormal(0,0,0),
m_westTriangleNormal(0,0,0)
{
this->m_container.setColor(1,0,0);
const auto time = std::chrono::system_clock::now().time_since_epoch();
const auto seed = static_cast<unsigned long>(std::chrono::duration_cast<std::chrono::seconds>(time).count());
this->m_dre.seed(seed);
// build north triangle
this->m_northTriangle.push_back(Vector3f(1, -1, -1));
this->m_northTriangle.push_back(Vector3f(-1, -1, -1));
this->m_northTriangle.push_back(Vector3f(0, -0.90f, 0));
this->m_northTriangleNormal = this->getBaseTriangleUnitNormal(this->m_northTriangle);
// build south triangle
this->m_southTriangle.push_back(Vector3f(-1, -1, 1));
this->m_southTriangle.push_back(Vector3f(1, -1, 1));
this->m_southTriangle.push_back(Vector3f(0, -0.90f, 0));
this->m_southTriangleNormal = this->getBaseTriangleUnitNormal(this->m_southTriangle);
// build east triangle
this->m_eastTriangle.push_back(Vector3f(1, -1, 1));
this->m_eastTriangle.push_back(Vector3f(1, -1, -1));
this->m_eastTriangle.push_back(Vector3f(0, -0.90f, 0));
this->m_eastTriangleNormal = this->getBaseTriangleUnitNormal(this->m_eastTriangle);
// build west triangle
this->m_westTriangle.push_back(Vector3f(-1, -1, -1));
this->m_westTriangle.push_back(Vector3f(-1, -1, 1));
this->m_westTriangle.push_back(Vector3f(0, -0.90f, 0));
this->m_westTriangleNormal = this->getBaseTriangleUnitNormal(this->m_westTriangle);
}
void ParticleSystem::generateParticles()
{
const auto diff = this->m_maxParticles - this->m_particals.size();
std::uniform_int_distribution<int> gen(-1000, 1000);
for(auto i = 0u; i < diff; i++)
{
const auto x = gen(this->m_dre) / 1000.0f;
const auto z = gen(this->m_dre) / 1000.0f;
Particle p;
p.setColor(0,1,0);
p.setPosition(x, 1, z);
p.setRadius(0.02f);
this->m_particals.push_back(p);
}
}
void ParticleSystem::simulate(const float dt)
{
// apply gravity
for(auto& p : this->m_particals)
{
const auto acceleration = this->m_gForce / p.getWeight();
const auto velocity = acceleration * dt;
const auto newVel = p.getVelocity() + velocity;
p.setVelocity(newVel);
}
// particle collisions
for(auto i = 0u; i < this->m_particals.size(); i++)
{
auto& p = this->m_particals[i];
for(auto j = i + 1; j < this->m_particals.size(); j++)
{
auto& p2 = this->m_particals[j];
// determine collision and direction change // untested
if(p.contains(p2) == true)
{
const auto n = (p.getPosition() - p2.getPosition()).unit();
const auto a1 = p.getVelocity().dot(n);
const auto a2 = p2.getVelocity().dot(n);
const auto scalar = a1 - a2;
const auto v1 = p.getVelocity() - (n * scalar);
const auto v2 = p2.getVelocity() - (n * scalar);
p.setVelocity(v1);
p2.setVelocity(v2);
}
}
if(this->isCollisionWithNorthBase(p) == true ||
this->isCollisionWithSouthBase(p) == true ||
this->isCollisionWithEastBase(p) == true ||
this->isCollisionWithWestBase(p) == true)
{
// place holder
const auto vel = p.getVelocity();
p.setVelocity(vel.x, -vel.y, vel.z);
}
// Attempt at finding new velocity's direction
//
//if(this->isCollisionWithNorthBase(p) == true)
//{
// const auto cPoint = Vector3f(0, -0.90f, 0);
// const auto sphereCenter = p.getPosition();
// const auto sphereVector = sphereCenter - cPoint;
// const auto radiusVector = (this->m_northTriangleNormal * -1.0f) * p.getRadius();
// const auto vectorAtCollision = sphereVector + radiusVector;
//
// const auto theta = p.getVelocity().getAngle(vectorAtCollision);
//}
p.setPosition(p.getPosition() + p.getVelocity());
}
}
bool ParticleSystem::isCollisionWithNorthBase(const Particle& p) const
{
const auto sphereCenter = p.getPosition();
if(this->isPointInBaseTriangle(sphereCenter, this->m_northTriangle[0], this->m_northTriangle[1], this->m_northTriangle[2]) == true)
{
const auto pointInPlane = Vector3f(0, -1, -1);
const auto sphereVector = sphereCenter - pointInPlane;
const auto distance = sphereVector.dot(this->m_northTriangleNormal);
return p.getRadius() >= distance;
}
return false;
}
bool ParticleSystem::isCollisionWithSouthBase(const Particle& p) const
{
const auto sphereCenter = p.getPosition();
if(this->isPointInBaseTriangle(sphereCenter, this->m_southTriangle[0], this->m_southTriangle[1], this->m_southTriangle[2]) == true)
{
const auto pointInPlane = Vector3f(0, -1, 1);
const auto sphereVector = sphereCenter - pointInPlane;
const auto distance = sphereVector.dot(this->m_southTriangleNormal);
return p.getRadius() >= distance;
}
return false;
}
bool ParticleSystem::isCollisionWithEastBase(const Particle& p) const
{
const auto sphereCenter = p.getPosition();
if(this->isPointInBaseTriangle(sphereCenter, this->m_eastTriangle[0], this->m_eastTriangle[1], this->m_eastTriangle[2]) == true)
{
const auto pointInPlane = Vector3f(1, -1, 0);
const auto sphereVector = sphereCenter - pointInPlane;
const auto distance = sphereVector.dot(this->m_eastTriangleNormal);
return p.getRadius() >= distance;
}
return false;
}
bool ParticleSystem::isCollisionWithWestBase(const Particle& p) const
{
const auto sphereCenter = p.getPosition();
if(this->isPointInBaseTriangle(sphereCenter, this->m_westTriangle[0], this->m_westTriangle[1], this->m_westTriangle[2]) == true)
{
const auto pointInPlane = Vector3f(-1, -1, 0);
const auto sphereVector = sphereCenter - pointInPlane;
const auto distance = sphereVector.dot(this->m_westTriangleNormal);
return p.getRadius() >= distance;
}
return false;
}
Vector3f ParticleSystem::getBaseTriangleUnitNormal(const std::vector<Vector3f>& triangle) const
{
const auto triVec1 = triangle[2] - triangle[0];
const auto triVec2 = triangle[2] - triangle[1];
return triVec1.cross(triVec2).unit();
}
bool ParticleSystem::isPointInBaseTriangle(const Vector3f& point, const Vector3f& aPoint, const Vector3f& bPoint, const Vector3f& cPoint) const
{
const auto alpha = ((bPoint.z - cPoint.z)*(point.x - cPoint.x) + (cPoint.x - bPoint.x)*(point.z - cPoint.z)) /
((bPoint.z - cPoint.z)*(aPoint.x - cPoint.x) + (cPoint.x - bPoint.x)*(aPoint.z - cPoint.z));
const auto beta = ((cPoint.z - aPoint.z)*(point.x - cPoint.x) + (aPoint.x - cPoint.x)*(point.z - cPoint.z)) /
((bPoint.z - cPoint.z)*(aPoint.x - cPoint.x) + (cPoint.x - bPoint.x)*(aPoint.z - cPoint.z));
const auto gamma = 1.0f - alpha - beta;
return (alpha > 0 && beta > 0 && gamma > 0);
}
void ParticleSystem::setMaxParticles(const int x)
{
this->m_maxParticles = x;
}
void ParticleSystem::setGravitationalForce(const float x)
{
this->m_gForce = Vector3f(0, x, 0);
}
void ParticleSystem::draw() const
{
this->m_container.draw();
for(const auto& p : this->m_particals)
{
p.draw();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment