Merge pull request #5433 from hyperlogic/ajt/particle-render-fix

Improved ParticleEffectEntityItem rendering and updates
This commit is contained in:
Brad Hefta-Gaub 2015-07-27 11:47:09 -07:00
commit 9464fe8f90
10 changed files with 462 additions and 86 deletions

View file

@ -44,6 +44,7 @@
emitStrength: emitStrength,
emitDirection: emitDirection,
color: color,
lifespan: 1.0,
visible: true,
locked: false });
@ -67,13 +68,13 @@
var objs = [];
function Init() {
objs.push(new TestBox());
objs.push(new TestFx({ red: 255, blue: 0, green: 0 },
objs.push(new TestFx({ red: 255, green: 0, blue: 0 },
{ x: 0.5, y: 1.0, z: 0.0 },
100, 3, 1));
objs.push(new TestFx({ red: 0, blue: 255, green: 0 },
objs.push(new TestFx({ red: 0, green: 255, blue: 0 },
{ x: 0, y: 1, z: 0 },
1000, 5, 0.5));
objs.push(new TestFx({ red: 0, blue: 0, green: 255 },
objs.push(new TestFx({ red: 0, green: 0, blue: 255 },
{ x: -0.5, y: 1, z: 0 },
100, 3, 1));
}

View file

@ -1,5 +1,7 @@
set(TARGET_NAME entities-renderer)
AUTOSCRIBE_SHADER_LIB(gpu model render)
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
setup_hifi_library(Widgets OpenGL Network Script)

View file

@ -14,22 +14,141 @@
#include <DeferredLightingEffect.h>
#include <PerfStat.h>
#include <GeometryCache.h>
#include <AbstractViewStateInterface.h>
#include "EntitiesRendererLogging.h"
#include "RenderableParticleEffectEntityItem.h"
#include "untextured_particle_vert.h"
#include "untextured_particle_frag.h"
#include "textured_particle_vert.h"
#include "textured_particle_frag.h"
class ParticlePayload {
public:
typedef render::Payload<ParticlePayload> Payload;
typedef Payload::DataPointer Pointer;
typedef RenderableParticleEffectEntityItem::Vertex Vertex;
ParticlePayload() : _vertexFormat(std::make_shared<gpu::Stream::Format>()),
_vertexBuffer(std::make_shared<gpu::Buffer>()),
_indexBuffer(std::make_shared<gpu::Buffer>()) {
_vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC3F_XYZ, 0);
_vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), offsetof(Vertex, uv));
_vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, offsetof(Vertex, rgba));
}
void setPipeline(gpu::PipelinePointer pipeline) { _pipeline = pipeline; }
const gpu::PipelinePointer& getPipeline() const { return _pipeline; }
const Transform& getModelTransform() const { return _modelTransform; }
void setModelTransform(const Transform& modelTransform) { _modelTransform = modelTransform; }
const AABox& getBound() const { return _bound; }
void setBound(AABox& bound) { _bound = bound; }
gpu::BufferPointer getVertexBuffer() { return _vertexBuffer; }
const gpu::BufferPointer& getVertexBuffer() const { return _vertexBuffer; }
gpu::BufferPointer getIndexBuffer() { return _indexBuffer; }
const gpu::BufferPointer& getIndexBuffer() const { return _indexBuffer; }
void setTexture(gpu::TexturePointer texture) { _texture = texture; }
const gpu::TexturePointer& getTexture() const { return _texture; }
bool getVisibleFlag() const { return _visibleFlag; }
void setVisibleFlag(bool visibleFlag) { _visibleFlag = visibleFlag; }
void render(RenderArgs* args) const {
assert(_pipeline);
gpu::Batch& batch = *args->_batch;
batch.setPipeline(_pipeline);
if (_texture) {
batch.setResourceTexture(0, _texture);
}
batch.setModelTransform(_modelTransform);
batch.setInputFormat(_vertexFormat);
batch.setInputBuffer(0, _vertexBuffer, 0, sizeof(Vertex));
batch.setIndexBuffer(gpu::UINT16, _indexBuffer, 0);
auto numIndices = _indexBuffer->getSize() / sizeof(uint16_t);
batch.drawIndexed(gpu::TRIANGLES, numIndices);
}
protected:
Transform _modelTransform;
AABox _bound;
gpu::PipelinePointer _pipeline;
gpu::Stream::FormatPointer _vertexFormat;
gpu::BufferPointer _vertexBuffer;
gpu::BufferPointer _indexBuffer;
gpu::TexturePointer _texture;
bool _visibleFlag = true;
};
namespace render {
template <>
const ItemKey payloadGetKey(const ParticlePayload::Pointer& payload) {
if (payload->getVisibleFlag()) {
return ItemKey::Builder::transparentShape();
} else {
return ItemKey::Builder().withInvisible().build();
}
}
template <>
const Item::Bound payloadGetBound(const ParticlePayload::Pointer& payload) {
return payload->getBound();
}
template <>
void payloadRender(const ParticlePayload::Pointer& payload, RenderArgs* args) {
payload->render(args);
}
}
gpu::PipelinePointer RenderableParticleEffectEntityItem::_texturedPipeline;
gpu::PipelinePointer RenderableParticleEffectEntityItem::_untexturedPipeline;
EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
return std::make_shared<RenderableParticleEffectEntityItem>(entityID, properties);
}
RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
ParticleEffectEntityItem(entityItemID, properties) {
_cacheID = DependencyManager::get<GeometryCache>()->allocateID();
// lazy creation of particle system pipeline
if (!_untexturedPipeline && !_texturedPipeline) {
createPipelines();
}
}
void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
Q_ASSERT(getType() == EntityTypes::ParticleEffect);
PerformanceTimer perfTimer("RenderableParticleEffectEntityItem::render");
bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self,
render::ScenePointer scene,
render::PendingChanges& pendingChanges) {
auto particlePayload = std::shared_ptr<ParticlePayload>(new ParticlePayload());
particlePayload->setPipeline(_untexturedPipeline);
_renderItemId = scene->allocateID();
auto renderData = ParticlePayload::Pointer(particlePayload);
auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData));
pendingChanges.resetItem(_renderItemId, renderPayload);
_scene = scene;
return true;
}
void RenderableParticleEffectEntityItem::removeFromScene(EntityItemPointer self,
render::ScenePointer scene,
render::PendingChanges& pendingChanges) {
pendingChanges.removeItem(_renderItemId);
_scene = nullptr;
};
void RenderableParticleEffectEntityItem::update(const quint64& now) {
ParticleEffectEntityItem::update(now);
if (_texturesChangedFlag) {
if (_textures.isEmpty()) {
@ -42,71 +161,155 @@ void RenderableParticleEffectEntityItem::render(RenderArgs* args) {
_texturesChangedFlag = false;
}
bool textured = _texture && _texture->isLoaded();
updateQuads(args, textured);
Q_ASSERT(args->_batch);
gpu::Batch& batch = *args->_batch;
if (textured) {
batch.setResourceTexture(0, _texture->getGPUTexture());
}
batch.setModelTransform(getTransformToCenter());
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram(batch, textured);
DependencyManager::get<GeometryCache>()->renderVertices(batch, gpu::QUADS, _cacheID);
};
updateRenderItem();
}
static glm::vec3 zSortAxis;
static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) {
return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis);
}
void RenderableParticleEffectEntityItem::updateQuads(RenderArgs* args, bool textured) {
float particleRadius = getParticleRadius();
glm::vec4 particleColor(toGlm(getXColor()), getLocalRenderAlpha());
glm::vec3 upOffset = args->_viewFrustum->getUp() * particleRadius;
glm::vec3 rightOffset = args->_viewFrustum->getRight() * particleRadius;
QVector<glm::vec3> vertices;
QVector<glm::vec3> positions;
QVector<glm::vec2> textureCoords;
vertices.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE);
if (textured) {
textureCoords.reserve(getLivingParticleCount() * VERTS_PER_PARTICLE);
}
positions.reserve(getLivingParticleCount());
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
positions.append(_particlePositions[i]);
if (textured) {
textureCoords.append(glm::vec2(0, 1));
textureCoords.append(glm::vec2(1, 1));
textureCoords.append(glm::vec2(1, 0));
textureCoords.append(glm::vec2(0, 0));
}
}
// sort particles back to front
::zSortAxis = args->_viewFrustum->getDirection();
qSort(positions.begin(), positions.end(), zSort);
for (int i = 0; i < positions.size(); i++) {
glm::vec3 pos = (textured) ? positions[i] : _particlePositions[i];
// generate corners of quad aligned to face the camera.
vertices.append(pos + rightOffset + upOffset);
vertices.append(pos - rightOffset + upOffset);
vertices.append(pos - rightOffset - upOffset);
vertices.append(pos + rightOffset - upOffset);
}
if (textured) {
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, textureCoords, particleColor);
} else {
DependencyManager::get<GeometryCache>()->updateVertices(_cacheID, vertices, particleColor);
}
uint32_t toRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return ((uint32_t)r | (uint32_t)g << 8 | (uint32_t)b << 16 | (uint32_t)a << 24);
}
void RenderableParticleEffectEntityItem::updateRenderItem() {
if (!_scene) {
return;
}
float particleRadius = getParticleRadius();
auto xcolor = getXColor();
auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f);
auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha);
// make a copy of each particle position
std::vector<glm::vec3> positions;
positions.reserve(getLivingParticleCount());
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
positions.push_back(_particlePositions[i]);
}
// sort particles back to front
// NOTE: this is view frustum might be one frame out of date.
auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum();
::zSortAxis = frustum->getDirection();
qSort(positions.begin(), positions.end(), zSort);
// allocate vertices
_vertices.clear();
// build vertices from particle positions
const glm::vec3 upOffset = frustum->getUp() * particleRadius;
const glm::vec3 rightOffset = frustum->getRight() * particleRadius;
for (auto&& pos : positions) {
// generate corners of quad aligned to face the camera.
_vertices.emplace_back(pos + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), rgba);
_vertices.emplace_back(pos - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba);
_vertices.emplace_back(pos - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba);
_vertices.emplace_back(pos + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba);
}
render::PendingChanges pendingChanges;
pendingChanges.updateItem<ParticlePayload>(_renderItemId, [&](ParticlePayload& payload) {
// update vertex buffer
auto vertexBuffer = payload.getVertexBuffer();
size_t numBytes = sizeof(Vertex) * _vertices.size();
vertexBuffer->resize(numBytes);
gpu::Byte* data = vertexBuffer->editData();
memcpy(data, &(_vertices[0]), numBytes);
// FIXME, don't update index buffer if num particles has not changed.
// update index buffer
auto indexBuffer = payload.getIndexBuffer();
const size_t NUM_VERTS_PER_PARTICLE = 4;
const size_t NUM_INDICES_PER_PARTICLE = 6;
auto numQuads = (_vertices.size() / NUM_VERTS_PER_PARTICLE);
numBytes = sizeof(uint16_t) * numQuads * NUM_INDICES_PER_PARTICLE;
indexBuffer->resize(numBytes);
data = indexBuffer->editData();
auto indexPtr = reinterpret_cast<uint16_t*>(data);
for (size_t i = 0; i < numQuads; ++i) {
indexPtr[i * NUM_INDICES_PER_PARTICLE + 0] = i * NUM_VERTS_PER_PARTICLE + 0;
indexPtr[i * NUM_INDICES_PER_PARTICLE + 1] = i * NUM_VERTS_PER_PARTICLE + 1;
indexPtr[i * NUM_INDICES_PER_PARTICLE + 2] = i * NUM_VERTS_PER_PARTICLE + 3;
indexPtr[i * NUM_INDICES_PER_PARTICLE + 3] = i * NUM_VERTS_PER_PARTICLE + 1;
indexPtr[i * NUM_INDICES_PER_PARTICLE + 4] = i * NUM_VERTS_PER_PARTICLE + 2;
indexPtr[i * NUM_INDICES_PER_PARTICLE + 5] = i * NUM_VERTS_PER_PARTICLE + 3;
}
// update transform
glm::quat rot = _transform.getRotation();
glm::vec3 pos = _transform.getTranslation();
Transform t;
t.setRotation(rot);
t.setTranslation(pos);
payload.setModelTransform(t);
// transform _particleMinBound and _particleMaxBound corners into world coords
glm::vec3 d = _particleMaxBound - _particleMinBound;
const size_t NUM_BOX_CORNERS = 8;
glm::vec3 corners[NUM_BOX_CORNERS] = {
pos + rot * (_particleMinBound + glm::vec3(0.0f, 0.0f, 0.0f)),
pos + rot * (_particleMinBound + glm::vec3(d.x, 0.0f, 0.0f)),
pos + rot * (_particleMinBound + glm::vec3(0.0f, d.y, 0.0f)),
pos + rot * (_particleMinBound + glm::vec3(d.x, d.y, 0.0f)),
pos + rot * (_particleMinBound + glm::vec3(0.0f, 0.0f, d.z)),
pos + rot * (_particleMinBound + glm::vec3(d.x, 0.0f, d.z)),
pos + rot * (_particleMinBound + glm::vec3(0.0f, d.y, d.z)),
pos + rot * (_particleMinBound + glm::vec3(d.x, d.y, d.z))
};
glm::vec3 min(FLT_MAX, FLT_MAX, FLT_MAX);
glm::vec3 max = -min;
for (size_t i = 0; i < NUM_BOX_CORNERS; i++) {
min.x = std::min(min.x, corners[i].x);
min.y = std::min(min.y, corners[i].y);
min.z = std::min(min.z, corners[i].z);
max.x = std::max(max.x, corners[i].x);
max.y = std::max(max.y, corners[i].y);
max.z = std::max(max.z, corners[i].z);
}
AABox bound(min, max - min);
payload.setBound(bound);
bool textured = _texture && _texture->isLoaded();
if (textured) {
payload.setTexture(_texture->getGPUTexture());
payload.setPipeline(_texturedPipeline);
} else {
payload.setTexture(nullptr);
payload.setPipeline(_untexturedPipeline);
}
});
_scene->enqueuePendingChanges(pendingChanges);
}
void RenderableParticleEffectEntityItem::createPipelines() {
if (!_untexturedPipeline) {
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD,
gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA,
gpu::State::BLEND_OP_ADD, gpu::State::ONE);
auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(untextured_particle_vert)));
auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(untextured_particle_frag)));
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader));
_untexturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
}
if (!_texturedPipeline) {
auto state = std::make_shared<gpu::State>();
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD,
gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA,
gpu::State::BLEND_OP_ADD, gpu::State::ONE);
auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(textured_particle_vert)));
auto fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_frag)));
auto program = gpu::ShaderPointer(gpu::Shader::createProgram(vertShader, fragShader));
_texturedPipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
}
}

View file

@ -16,20 +16,35 @@
#include "RenderableEntityItem.h"
class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem {
friend class ParticlePayload;
public:
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
virtual void render(RenderArgs* args);
void updateQuads(RenderArgs* args, bool textured);
virtual void update(const quint64& now) override;
SIMPLE_RENDERABLE();
void updateRenderItem();
virtual bool addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges);
virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges);
protected:
render::ItemID _renderItemId;
int _cacheID;
const int VERTS_PER_PARTICLE = 4;
struct Vertex {
Vertex(glm::vec3 xyzIn, glm::vec2 uvIn, uint32_t rgbaIn) : xyz(xyzIn), uv(uvIn), rgba(rgbaIn) {}
glm::vec3 xyz;
glm::vec2 uv;
uint32_t rgba;
};
static void createPipelines();
std::vector<Vertex> _vertices;
static gpu::PipelinePointer _untexturedPipeline;
static gpu::PipelinePointer _texturedPipeline;
render::ScenePointer _scene;
NetworkTexturePointer _texture;
};

View file

@ -0,0 +1,20 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// fragment shader
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
uniform sampler2D colorMap;
varying vec4 varColor;
varying vec2 varTexCoord;
void main(void) {
vec4 color = texture2D(colorMap, varTexCoord);
gl_FragColor = color * varColor;
}

View file

@ -0,0 +1,28 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// particle vertex shader
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
varying vec4 varColor;
varying vec2 varTexCoord;
void main(void) {
// pass along the color & uvs to fragment shader
varColor = gl_Color;
varTexCoord = gl_MultiTexCoord0.xy;
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$>
}

View file

@ -0,0 +1,16 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
// fragment shader
//
// Copyright 2015 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
varying vec4 varColor;
void main(void) {
gl_FragColor = varColor;
}

View file

@ -0,0 +1,24 @@
<@include gpu/Config.slh@>
<$VERSION_HEADER$>
// Generated on <$_SCRIBE_DATE$>
//
// particle vertex shader
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
varying vec4 varColor;
void main(void) {
// pass along the diffuse color
varColor = gl_Color;
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$>
}

View file

@ -39,6 +39,7 @@
#include "EntityTree.h"
#include "EntityTreeElement.h"
#include "EntitiesLogging.h"
#include "EntityScriptingInterface.h"
#include "ParticleEffectEntityItem.h"
const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 };
@ -92,6 +93,75 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte
ParticleEffectEntityItem::~ParticleEffectEntityItem() {
}
void ParticleEffectEntityItem::setDimensions(const glm::vec3& value) {
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::setLifespan(float lifespan) {
_lifespan = lifespan;
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::setEmitDirection(glm::vec3 emitDirection) {
_emitDirection = glm::normalize(emitDirection);
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::setEmitStrength(float emitStrength) {
_emitStrength = emitStrength;
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::setLocalGravity(float localGravity) {
_localGravity = localGravity;
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::setParticleRadius(float particleRadius) {
_particleRadius = particleRadius;
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::computeAndUpdateDimensions() {
const float t = _lifespan * 1.1f; // add 10% extra time, to account for incremental timer accumulation error.
const float MAX_RANDOM_FACTOR = (0.5f * 0.25f);
const float maxOffset = (MAX_RANDOM_FACTOR * _emitStrength) + _particleRadius;
// bounds for x and z is easy to compute because there is no at^2 term.
float xMax = (_emitDirection.x * _emitStrength + maxOffset) * t;
float xMin = (_emitDirection.x * _emitStrength - maxOffset) * t;
float zMax = (_emitDirection.z * _emitStrength + maxOffset) * t;
float zMin = (_emitDirection.z * _emitStrength - maxOffset) * t;
// yEnd is where the particle will end.
float a = _localGravity;
float atSquared = a * t * t;
float v = _emitDirection.y * _emitStrength + maxOffset;
float vt = v * t;
float yEnd = 0.5f * atSquared + vt;
// yApex is where the particle is at it's apex.
float yApexT = (-v / a);
float yApex = 0.0f;
// only set apex if it's within the lifespan of the particle.
if (yApexT >= 0.0f && yApexT <= t) {
yApex = -(v * v) / (2.0f * a);
}
float yMax = std::max(yApex, yEnd);
float yMin = std::min(yApex, yEnd);
// times 2 because dimensions are diameters not radii.
glm::vec3 dims(2.0f * std::max(fabs(xMin), fabs(xMax)),
2.0f * std::max(fabs(yMin), fabs(yMax)),
2.0f * std::max(fabs(zMin), fabs(zMax)));
EntityItem::setDimensions(dims);
}
EntityItemProperties ParticleEffectEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
@ -245,7 +315,7 @@ bool ParticleEffectEntityItem::isAnimatingSomething() const {
}
bool ParticleEffectEntityItem::needsToCallUpdate() const {
return isAnimatingSomething() ? true : EntityItem::needsToCallUpdate();
return true;
}
void ParticleEffectEntityItem::update(const quint64& now) {
@ -260,13 +330,6 @@ void ParticleEffectEntityItem::update(const quint64& now) {
if (isAnimatingSomething()) {
stepSimulation(deltaTime);
// update the dimensions
glm::vec3 dims;
dims.x = glm::max(glm::abs(_particleMinBound.x), glm::abs(_particleMaxBound.x)) * 2.0f;
dims.y = glm::max(glm::abs(_particleMinBound.y), glm::abs(_particleMaxBound.y)) * 2.0f;
dims.z = glm::max(glm::abs(_particleMinBound.z), glm::abs(_particleMaxBound.z)) * 2.0f;
setDimensions(dims);
}
EntityItem::update(now); // let our base class handle it's updates...
@ -319,7 +382,7 @@ void ParticleEffectEntityItem::setAnimationSettings(const QString& value) {
qCDebug(entities) << "ParticleEffectEntityItem::setAnimationSettings() calling setAnimationFrameIndex()...";
qCDebug(entities) << " settings:" << value;
qCDebug(entities) << " settingsMap[frameIndex]:" << settingsMap["frameIndex"];
qCDebug(entities" frameIndex: %20.5f", frameIndex);
qCDebug(entities, " frameIndex: %20.5f", frameIndex);
}
#endif

View file

@ -86,12 +86,14 @@ public:
void setAnimationLastFrame(float lastFrame) { _animationLoop.setLastFrame(lastFrame); }
float getAnimationLastFrame() const { return _animationLoop.getLastFrame(); }
virtual void setDimensions(const glm::vec3& value) override;
static const quint32 DEFAULT_MAX_PARTICLES;
void setMaxParticles(quint32 maxParticles);
quint32 getMaxParticles() const { return _maxParticles; }
static const float DEFAULT_LIFESPAN;
void setLifespan(float lifespan) { _lifespan = lifespan; }
void setLifespan(float lifespan);
float getLifespan() const { return _lifespan; }
static const float DEFAULT_EMIT_RATE;
@ -99,21 +101,23 @@ public:
float getEmitRate() const { return _emitRate; }
static const glm::vec3 DEFAULT_EMIT_DIRECTION;
void setEmitDirection(glm::vec3 emitDirection) { _emitDirection = glm::normalize(emitDirection); }
void setEmitDirection(glm::vec3 emitDirection);
const glm::vec3& getEmitDirection() const { return _emitDirection; }
static const float DEFAULT_EMIT_STRENGTH;
void setEmitStrength(float emitStrength) { _emitStrength = emitStrength; }
void setEmitStrength(float emitStrength);
float getEmitStrength() const { return _emitStrength; }
static const float DEFAULT_LOCAL_GRAVITY;
void setLocalGravity(float localGravity) { _localGravity = localGravity; }
void setLocalGravity(float localGravity);
float getLocalGravity() const { return _localGravity; }
static const float DEFAULT_PARTICLE_RADIUS;
void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; }
void setParticleRadius(float particleRadius);
float getParticleRadius() const { return _particleRadius; }
void computeAndUpdateDimensions();
bool getAnimationIsPlaying() const { return _animationLoop.isRunning(); }
float getAnimationFrameIndex() const { return _animationLoop.getFrameIndex(); }
float getAnimationFPS() const { return _animationLoop.getFPS(); }