Interview project updates.

Tried to address all of Brad's notes, most of which were related to
matching the coding style for the project.  Also used GeometryCache
instead of making direct calls to OpenGL to do drawing, took a different
approach to seeding rand(), updated the packet version, and fixed a bug
that I noticed in the setting of the dimensions for the particle effect
entity.
This commit is contained in:
Jason 2015-03-06 15:52:21 -08:00
parent 3522357c8c
commit 7a5669f14e
8 changed files with 581 additions and 585 deletions

View file

@ -15,6 +15,7 @@
#include <DependencyManager.h>
#include <DeferredLightingEffect.h>
#include <PerfStat.h>
#include <GeometryCache.h>
#include "RenderableParticleEffectEntityItem.h"
@ -22,6 +23,11 @@ EntityItem* RenderableParticleEffectEntityItem::factory(const EntityItemID& enti
return new RenderableParticleEffectEntityItem(entityID, properties);
}
RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ParticleEffectEntityItem(entityItemID, properties) {
_cacheID = DependencyManager::get<GeometryCache>()->allocateID();
}
void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
PerformanceTimer perfTimer("RenderableParticleEffectEntityItem::render");
assert(getType() == EntityTypes::ParticleEffect);
@ -31,9 +37,43 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
float pa_rad = getParticleRadius();
const float MAX_COLOR = 255.0f;
glm::vec4 sphereColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
glm::vec4 paColor(getColor()[RED_INDEX] / MAX_COLOR, getColor()[GREEN_INDEX] / MAX_COLOR,
getColor()[BLUE_INDEX] / MAX_COLOR, getLocalRenderAlpha());
// Right now we're just iterating over particles and rendering as a cross of four quads.
// This is pretty dumb, it was quick enough to code up. Really, there should be many
// rendering modes, including the all-important textured billboards.
QVector<glm::vec3>* pointVec = new QVector<glm::vec3>(_paCount * VERTS_PER_PARTICLE);
quint32 paIter = _paHead;
while (_paLife[paIter] > 0.0f) {
int j = paIter * XYZ_STRIDE;
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] + pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] - pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j] + pa_rad, _paPosition[j + 1] - pa_rad, _paPosition[j + 2]));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] + pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] + pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] - pa_rad));
pointVec->append(glm::vec3(_paPosition[j], _paPosition[j + 1] - pa_rad, _paPosition[j + 2] + pa_rad));
paIter = (paIter + 1) % _maxParticles;
}
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, *pointVec, paColor);
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glm::vec3 axis = glm::axis(rotation);
@ -44,45 +84,9 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
glm::vec3 positionToCenter = center - position;
glTranslatef(positionToCenter.x, positionToCenter.y, positionToCenter.z);
const int SLICES = 8;
const int STACKS = 5;
glBegin(GL_QUADS);
glColor4f(sphereColor.r, sphereColor.g, sphereColor.b, sphereColor.a);
// Right now we're just iterating over particles and rendering as a cross of four quads.
// This is pretty dumb, it was quick enough to code up. Really, there should be many
// rendering modes, including the all-important textured billboards.
quint32 paiter = pa_head;
while (pa_life[paiter] > 0.0f)
{
int j = paiter * 3;
glVertex3f(pa_position[j] - pa_rad, pa_position[j + 1] + pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] + pa_rad, pa_position[j + 1] + pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] + pa_rad, pa_position[j + 1] - pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] - pa_rad, pa_position[j + 1] - pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] + pa_rad, pa_position[j + 1] + pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] - pa_rad, pa_position[j + 1] + pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] - pa_rad, pa_position[j + 1] - pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j] + pa_rad, pa_position[j + 1] - pa_rad, pa_position[j + 2]);
glVertex3f(pa_position[j], pa_position[j + 1] + pa_rad, pa_position[j + 2] - pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] + pa_rad, pa_position[j + 2] + pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] - pa_rad, pa_position[j + 2] + pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] - pa_rad, pa_position[j + 2] - pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] + pa_rad, pa_position[j + 2] + pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] + pa_rad, pa_position[j + 2] - pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] - pa_rad, pa_position[j + 2] - pa_rad);
glVertex3f(pa_position[j], pa_position[j + 1] - pa_rad, pa_position[j + 2] + pa_rad);
paiter = (paiter + 1) % _maxParticles;
}
glEnd();
DependencyManager::get<GeometryCache>()->renderVertices(gpu::QUADS, _cacheID);
glPopMatrix();
glPopMatrix();
delete pointVec;
};

View file

@ -16,13 +16,12 @@
class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem {
public:
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ParticleEffectEntityItem(entityItemID, properties)
{ }
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual void render(RenderArgs* args);
protected:
int _cacheID;
const int VERTS_PER_PARTICLE = 16;
};

View file

@ -62,8 +62,7 @@ EntityItem* ParticleEffectEntityItem::factory(const EntityItemID& entityID, cons
// our non-pure virtual subclass for now...
ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
EntityItem(entityItemID, properties)
{
EntityItem(entityItemID, properties) {
_type = EntityTypes::ParticleEffect;
_maxParticles = DEFAULT_MAX_PARTICLES;
_lifespan = DEFAULT_LIFESPAN;
@ -78,20 +77,20 @@ EntityItem(entityItemID, properties)
// at least time efficient (though not space efficient).
// Also, this being a real-time application, it's doubtful we'll ever have millions of particles
// to keep track of, so this really isn't all that bad.
pa_life = (float*) malloc(sizeof(float) * _maxParticles);
pa_position = (float*)malloc(sizeof(float) * _maxParticles * 3); // x,y,z
pa_velocity = (float*)malloc(sizeof(float) * _maxParticles * 3); // x,y,z
pa_xmax = pa_ymax = pa_zmax = 1.0f;
pa_xmin = pa_ymin = pa_zmin = -1.0f;
resetSim();
_paLife = new float[_maxParticles];
_paPosition = new float[_maxParticles * XYZ_STRIDE]; // x,y,z
_paVelocity = new float[_maxParticles * XYZ_STRIDE]; // x,y,z
_paXmax = _paYmax = _paZmax = 1.0f;
_paXmin = _paYmin = _paZmin = -1.0f;
_randSeed = (unsigned int) glm::abs(_lifespan + _emitRate + _localGravity + getPosition().x + getPosition().y + getPosition().z);
resetSimulation();
_lastAnimated = usecTimestampNow();
}
ParticleEffectEntityItem::~ParticleEffectEntityItem()
{
free(pa_life);
free(pa_position);
free(pa_velocity);
ParticleEffectEntityItem::~ParticleEffectEntityItem() {
delete [] _paLife;
delete [] _paPosition;
delete [] _paVelocity;
}
EntityItemProperties ParticleEffectEntityItem::getProperties() const {
@ -253,16 +252,14 @@ void ParticleEffectEntityItem::update(const quint64& now) {
float lastFrame = _animationLoop.getFrameIndex();
_animationLoop.simulate(deltaTime);
float curFrame = _animationLoop.getFrameIndex();
if (curFrame > lastFrame)
{
stepSim(deltaTime);
if (curFrame > lastFrame) {
stepSimulation(deltaTime);
}
else if (curFrame < lastFrame)
{
else if (curFrame < lastFrame) {
// we looped around, so restart the sim and only sim up to the point
// since the beginning of the frame range.
resetSim();
stepSim((curFrame - _animationLoop.getFirstFrame()) / _animationLoop.getFPS());
resetSimulation();
stepSimulation((curFrame - _animationLoop.getFirstFrame()) / _animationLoop.getFPS());
}
}
else {
@ -271,9 +268,9 @@ void ParticleEffectEntityItem::update(const quint64& now) {
// update the dimensions
glm::vec3 dims;
dims.x = glm::max(glm::abs(pa_xmin), glm::abs(pa_xmax));
dims.y = glm::max(glm::abs(pa_xmin), glm::abs(pa_xmax));
dims.z = glm::max(glm::abs(pa_xmin), glm::abs(pa_xmax));
dims.x = glm::max(glm::abs(_paXmin), glm::abs(_paXmax)) * 2.0;
dims.y = glm::max(glm::abs(_paYmin), glm::abs(_paYmax)) * 2.0;
dims.z = glm::max(glm::abs(_paZmin), glm::abs(_paZmax)) * 2.0;
setDimensionsInMeters(dims);
EntityItem::update(now); // let our base class handle it's updates...
@ -420,103 +417,96 @@ QString ParticleEffectEntityItem::getAnimationSettings() const {
return jsonByteString;
}
void ParticleEffectEntityItem::stepSim(float deltaTime)
{
pa_xmin = pa_ymin = pa_zmin = -1.0;
pa_xmax = pa_ymax = pa_zmax = 1.0;
void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_paXmin = _paYmin = _paZmin = -1.0;
_paXmax = _paYmax = _paZmax = 1.0;
// update particles
quint32 updateIter = pa_head;
while (pa_life[updateIter] > 0.0f)
{
pa_life[updateIter] -= deltaTime;
if (pa_life[updateIter] <= 0.0f)
{
pa_life[updateIter] = -1.0f;
pa_head = (pa_head + 1) % _maxParticles;
pa_count--;
quint32 updateIter = _paHead;
while (_paLife[updateIter] > 0.0f) {
_paLife[updateIter] -= deltaTime;
if (_paLife[updateIter] <= 0.0f) {
_paLife[updateIter] = -1.0f;
_paHead = (_paHead + 1) % _maxParticles;
_paCount--;
}
else
{
else {
// DUMB FORWARD EULER just to get it done
int j = updateIter * 3;
pa_position[j] += pa_velocity[j] * deltaTime;
pa_position[j+1] += pa_velocity[j+1] * deltaTime;
pa_position[j+2] += pa_velocity[j+2] * deltaTime;
int j = updateIter * XYZ_STRIDE;
_paPosition[j] += _paVelocity[j] * deltaTime;
_paPosition[j+1] += _paVelocity[j+1] * deltaTime;
_paPosition[j+2] += _paVelocity[j+2] * deltaTime;
pa_xmin = glm::min(pa_xmin, pa_position[j]);
pa_ymin = glm::min(pa_ymin, pa_position[j+1]);
pa_zmin = glm::min(pa_zmin, pa_position[j+2]);
pa_xmax = glm::max(pa_xmax, pa_position[j]);
pa_ymax = glm::max(pa_ymax, pa_position[j + 1]);
pa_zmax = glm::max(pa_zmax, pa_position[j + 2]);
_paXmin = glm::min(_paXmin, _paPosition[j]);
_paYmin = glm::min(_paYmin, _paPosition[j+1]);
_paZmin = glm::min(_paZmin, _paPosition[j+2]);
_paXmax = glm::max(_paXmax, _paPosition[j]);
_paYmax = glm::max(_paYmax, _paPosition[j + 1]);
_paZmax = glm::max(_paZmax, _paPosition[j + 2]);
// massless particles
pa_velocity[j + 1] += deltaTime * _localGravity;
_paVelocity[j + 1] += deltaTime * _localGravity;
}
updateIter = (updateIter + 1) % _maxParticles;
}
// emit new particles
quint32 pa_emit_idx = updateIter;
partial_emit += ((float)_emitRate) * deltaTime;
quint32 birthed = (quint32)partial_emit;
partial_emit -= (float)birthed;
quint32 emitIdx = updateIter;
_partialEmit += ((float)_emitRate) * deltaTime;
quint32 birthed = (quint32)_partialEmit;
_partialEmit -= (float)birthed;
glm::vec3 randOffset;
for (quint32 i = 0; i < birthed; i++)
{
if (pa_life[pa_emit_idx] < 0.0f)
{
int j = pa_emit_idx * 3;
pa_life[pa_emit_idx] = _lifespan;
for (quint32 i = 0; i < birthed; i++) {
if (_paLife[emitIdx] < 0.0f) {
int j = emitIdx * XYZ_STRIDE;
_paLife[emitIdx] = _lifespan;
randOffset.x = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
randOffset.y = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
randOffset.z = (((double)rand() / (double)RAND_MAX) - 0.5) * 0.25 * _emitStrength;
pa_velocity[j] = (_emitDirection.x * _emitStrength) + randOffset.x;
pa_velocity[j + 1] = (_emitDirection.y * _emitStrength) + randOffset.y;
pa_velocity[j + 2] = (_emitDirection.z * _emitStrength) + randOffset.z;
_paVelocity[j] = (_emitDirection.x * _emitStrength) + randOffset.x;
_paVelocity[j + 1] = (_emitDirection.y * _emitStrength) + randOffset.y;
_paVelocity[j + 2] = (_emitDirection.z * _emitStrength) + randOffset.z;
// DUMB FORWARD EULER just to get it done
pa_position[j] += pa_velocity[j] * deltaTime;
pa_position[j + 1] += pa_velocity[j + 1] * deltaTime;
pa_position[j + 2] += pa_velocity[j + 2] * deltaTime;
_paPosition[j] += _paVelocity[j] * deltaTime;
_paPosition[j + 1] += _paVelocity[j + 1] * deltaTime;
_paPosition[j + 2] += _paVelocity[j + 2] * deltaTime;
pa_xmin = glm::min(pa_xmin, pa_position[j]);
pa_ymin = glm::min(pa_ymin, pa_position[j + 1]);
pa_zmin = glm::min(pa_zmin, pa_position[j + 2]);
pa_xmax = glm::max(pa_xmax, pa_position[j]);
pa_ymax = glm::max(pa_ymax, pa_position[j + 1]);
pa_zmax = glm::max(pa_zmax, pa_position[j + 2]);
_paXmin = glm::min(_paXmin, _paPosition[j]);
_paYmin = glm::min(_paYmin, _paPosition[j + 1]);
_paZmin = glm::min(_paZmin, _paPosition[j + 2]);
_paXmax = glm::max(_paXmax, _paPosition[j]);
_paYmax = glm::max(_paYmax, _paPosition[j + 1]);
_paZmax = glm::max(_paZmax, _paPosition[j + 2]);
// massless particles
pa_velocity[j + 1] += deltaTime * _localGravity;
// and simple gravity down
_paVelocity[j + 1] += deltaTime * _localGravity;
pa_emit_idx = (pa_emit_idx + 1) % _maxParticles;
pa_count++;
emitIdx = (emitIdx + 1) % _maxParticles;
_paCount++;
}
else
break;
}
}
void ParticleEffectEntityItem::resetSim()
{
for (int i = 0; i < _maxParticles; i++)
{
int j = i * 3;
pa_life[i] = -1.0f;
pa_position[j] = 0.0f;
pa_position[j+1] = 0.0f;
pa_position[j+2] = 0.0f;
pa_velocity[j] = 0.0f;
pa_velocity[j+1] = 0.0f;
pa_velocity[j+2] = 0.0f;
void ParticleEffectEntityItem::resetSimulation() {
for (int i = 0; i < _maxParticles; i++) {
int j = i * XYZ_STRIDE;
_paLife[i] = -1.0f;
_paPosition[j] = 0.0f;
_paPosition[j+1] = 0.0f;
_paPosition[j+2] = 0.0f;
_paVelocity[j] = 0.0f;
_paVelocity[j+1] = 0.0f;
_paVelocity[j+2] = 0.0f;
}
pa_count = 0;
pa_head = 0;
partial_emit = 0.0f;
_paCount = 0;
_paHead = 0;
_partialEmit = 0.0f;
srand((unsigned int) this);
srand(_randSeed);
}

View file

@ -144,8 +144,8 @@ public:
protected:
bool isAnimatingSomething() const;
void stepSim(float deltaTime);
void resetSim();
void stepSimulation(float deltaTime);
void resetSimulation();
// the properties of this entity
rgbColor _color;
@ -162,18 +162,20 @@ protected:
ShapeType _shapeType = SHAPE_TYPE_NONE;
// all the internals of running the particle sim
float* pa_life;
float* pa_position;
float* pa_velocity;
float partial_emit;
quint32 pa_count;
quint32 pa_head;
float pa_xmin;
float pa_xmax;
float pa_ymin;
float pa_ymax;
float pa_zmin;
float pa_zmax;
const quint32 XYZ_STRIDE = 3;
float* _paLife;
float* _paPosition;
float* _paVelocity;
float _partialEmit;
quint32 _paCount;
quint32 _paHead;
float _paXmin;
float _paXmax;
float _paYmin;
float _paYmax;
float _paZmin;
float _paZmax;
unsigned int _randSeed;
};

View file

@ -72,7 +72,7 @@ PacketVersion versionForPacketType(PacketType type) {
return 1;
case PacketTypeEntityAddOrEdit:
case PacketTypeEntityData:
return VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE;
return VERSION_ENTITIES_HAS_PARTICLES;
case PacketTypeEntityErase:
return 2;
case PacketTypeAudioStreamStats:

View file

@ -129,5 +129,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_USER_DATA = 6;
const PacketVersion VERSION_ENTITIES_HAS_LAST_SIMULATED_TIME = 7;
const PacketVersion VERSION_MODEL_ENTITIES_SUPPORT_SHAPE_TYPE = 8;
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
const PacketVersion VERSION_ENTITIES_HAS_PARTICLES = 10;
#endif // hifi_PacketHeaders_h