Last active
August 29, 2015 14:00
-
-
Save ASxa86/11188762 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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