From 9320623ff5f3bfe1d1a61220028bc3762c8fc474 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 12 Nov 2015 18:07:23 -0800 Subject: [PATCH 01/25] Add AABox functionalities --- libraries/shared/src/AABox.cpp | 45 +++++++++++++++++++++++++++++++--- libraries/shared/src/AABox.h | 7 +++++- 2 files changed, 48 insertions(+), 4 deletions(-) diff --git a/libraries/shared/src/AABox.cpp b/libraries/shared/src/AABox.cpp index b514e171eb..7c001c570e 100644 --- a/libraries/shared/src/AABox.cpp +++ b/libraries/shared/src/AABox.cpp @@ -42,9 +42,48 @@ glm::vec3 AABox::calcCenter() const { return center; } -void AABox::scale(float scale) { - _corner = _corner * scale; - _scale = _scale * scale; +void AABox::rotate(const glm::quat& rotation) { + auto minimum = _corner; + auto maximum = _corner + _scale; + + glm::vec3 bottomLeftNear(minimum.x, minimum.y, minimum.z); + glm::vec3 bottomRightNear(maximum.x, minimum.y, minimum.z); + glm::vec3 bottomLeftFar(minimum.x, minimum.y, maximum.z); + glm::vec3 bottomRightFar(maximum.x, minimum.y, maximum.z); + glm::vec3 topLeftNear(minimum.x, maximum.y, minimum.z); + glm::vec3 topRightNear(maximum.x, maximum.y, minimum.z); + glm::vec3 topLeftFar(minimum.x, maximum.y, maximum.z); + glm::vec3 topRightFar(maximum.x, maximum.y, maximum.z); + + glm::vec3 bottomLeftNearRotated = rotation * bottomLeftNear; + glm::vec3 bottomRightNearRotated = rotation * bottomRightNear; + glm::vec3 bottomLeftFarRotated = rotation * bottomLeftFar; + glm::vec3 bottomRightFarRotated = rotation * bottomRightFar; + glm::vec3 topLeftNearRotated = rotation * topLeftNear; + glm::vec3 topRightNearRotated = rotation * topRightNear; + glm::vec3 topLeftFarRotated = rotation * topLeftFar; + glm::vec3 topRightFarRotated = rotation * topRightFar; + + minimum = glm::min(bottomLeftNearRotated, + glm::min(bottomRightNearRotated, + glm::min(bottomLeftFarRotated, + glm::min(bottomRightFarRotated, + glm::min(topLeftNearRotated, + glm::min(topRightNearRotated, + glm::min(topLeftFarRotated, + topRightFarRotated))))))); + + maximum = glm::max(bottomLeftNearRotated, + glm::max(bottomRightNearRotated, + glm::max(bottomLeftFarRotated, + glm::max(bottomRightFarRotated, + glm::max(topLeftNearRotated, + glm::max(topRightNearRotated, + glm::max(topLeftFarRotated, + topRightFarRotated))))))); + + _corner = minimum; + _scale = maximum - minimum; } glm::vec3 AABox::getVertex(BoxVertex vertex) const { diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index 1f5923dbd8..e5227ade44 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -40,7 +40,12 @@ public: void setBox(const glm::vec3& corner, float scale); glm::vec3 getVertexP(const glm::vec3& normal) const; glm::vec3 getVertexN(const glm::vec3& normal) const; - void scale(float scale); + + void shiftBy(const glm::vec3& delta) { _corner += delta; } + void rotate(const glm::quat& rotation); + void scale(float scale) { _corner *= scale; _scale *= scale; } + void scale(const glm::vec3& scale) { _corner *= scale; _scale *= scale; } + const glm::vec3& getCorner() const { return _corner; } const glm::vec3& getScale() const { return _scale; } const glm::vec3& getDimensions() const { return _scale; } From a71ed7b16657601a8f97bf97a4914b076a7f6fcf Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 12 Nov 2015 18:23:09 -0800 Subject: [PATCH 02/25] Implement particle bounds with Extents --- .../RenderableParticleEffectEntityItem.cpp | 40 +++++-------------- .../entities/src/ParticleEffectEntityItem.cpp | 19 ++------- .../entities/src/ParticleEffectEntityItem.h | 6 +-- 3 files changed, 15 insertions(+), 50 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 05fca343fd..ebe87dec9b 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -272,37 +272,17 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { } // update transform - glm::quat rot = getRotation(); - glm::vec3 pos = getPosition(); - Transform t; - t.setRotation(rot); - payload.setModelTransform(t); + glm::vec3 position = getPosition(); + glm::quat rotation = getRotation(); + Transform transform; + transform.setTranslation(position); + transform.setRotation(rotation); + payload.setModelTransform(transform); - // 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); + AABox bounds(_particlesBounds); + bounds.rotate(rotation); + bounds.shiftBy(position); + payload.setBound(bounds); bool textured = _texture && _texture->isLoaded(); if (textured) { diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 06fcdb495c..f3abeffc20 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -121,8 +121,6 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte _alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), _alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), - _particleMaxBound(glm::vec3(1.0f, 1.0f, 1.0f)), - _particleMinBound(glm::vec3(-1.0f, -1.0f, -1.0f)) , _additiveBlending(DEFAULT_ADDITIVE_BLENDING) { @@ -631,15 +629,6 @@ void ParticleEffectEntityItem::updateAlpha(quint32 index, float age) { _alphaFinishes[index], age); } -void ParticleEffectEntityItem::extendBounds(const glm::vec3& point) { - _particleMinBound.x = glm::min(_particleMinBound.x, point.x); - _particleMinBound.y = glm::min(_particleMinBound.y, point.y); - _particleMinBound.z = glm::min(_particleMinBound.z, point.z); - _particleMaxBound.x = glm::max(_particleMaxBound.x, point.x); - _particleMaxBound.y = glm::max(_particleMaxBound.y, point.y); - _particleMaxBound.z = glm::max(_particleMaxBound.z, point.z); -} - void ParticleEffectEntityItem::integrateParticle(quint32 index, float deltaTime) { glm::vec3 accel = _particleAccelerations[index]; glm::vec3 atSquared = (0.5f * deltaTime * deltaTime) * accel; @@ -649,9 +638,7 @@ void ParticleEffectEntityItem::integrateParticle(quint32 index, float deltaTime) } void ParticleEffectEntityItem::stepSimulation(float deltaTime) { - - _particleMinBound = glm::vec3(-1.0f, -1.0f, -1.0f); - _particleMaxBound = glm::vec3(1.0f, 1.0f, 1.0f); + _particlesBounds.reset(); // update particles between head and tail for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { @@ -667,7 +654,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { updateColor(i, age); updateAlpha(i, age); integrateParticle(i, deltaTime); - extendBounds(_particlePositions[i]); + _particlesBounds.addPoint(_particlePositions[i]); } } @@ -766,7 +753,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particleAccelerations[i] = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } integrateParticle(i, timeLeftInFrame); - extendBounds(_particlePositions[i]); + _particlesBounds.addPoint(_particlePositions[i]); // Color if (_colorSpread == xColor{ 0, 0, 0 }) { diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index e3c5cd895a..7ac115d8e5 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -224,7 +224,6 @@ protected: void updateRadius(quint32 index, float age); void updateColor(quint32 index, float age); void updateAlpha(quint32 index, float age); - void extendBounds(const glm::vec3& point); void integrateParticle(quint32 index, float deltaTime); quint32 getLivingParticleCount() const; // the properties of this entity @@ -289,9 +288,8 @@ protected: quint32 _particleTailIndex = 0; // bounding volume - glm::vec3 _particleMaxBound; - glm::vec3 _particleMinBound; - + Extents _particlesBounds; + bool _additiveBlending; }; From 395822c6cdeb8bc6c7a2c36a4ce342d6e52ffc96 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 17 Nov 2015 11:47:33 -0800 Subject: [PATCH 03/25] Use make_shared --- .../src/RenderableParticleEffectEntityItem.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index ebe87dec9b..f4243db621 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -134,11 +134,11 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) { - auto particlePayload = std::shared_ptr(new ParticlePayload(shared_from_this())); + auto particlePayload = std::make_shared(shared_from_this()); particlePayload->setPipeline(_untexturedPipeline); _renderItemId = scene->allocateID(); auto renderData = ParticlePayload::Pointer(particlePayload); - auto renderPayload = render::PayloadPointer(new ParticlePayload::Payload(renderData)); + auto renderPayload = std::make_shared(renderData); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(shared_from_this(), statusGetters); renderPayload->addStatusGetters(statusGetters); From 40e802bae766b60536b8574f44d8af356679a6c2 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 17 Nov 2015 12:05:43 -0800 Subject: [PATCH 04/25] Get rid of global variable for sort Fix rhs/lhs --- .../src/RenderableParticleEffectEntityItem.cpp | 16 +++++++--------- .../entities/src/ParticleEffectEntityItem.cpp | 6 +++--- libraries/shared/src/AABox.h | 2 +- 3 files changed, 11 insertions(+), 13 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f4243db621..5c65f0bee5 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -184,11 +184,6 @@ public: uint32_t rgba; }; -static glm::vec3 zSortAxis; -static bool zSort(const ParticleDetails& rhs, const ParticleDetails& lhs) { - return glm::dot(rhs.position, ::zSortAxis) > glm::dot(lhs.position, ::zSortAxis); -} - void RenderableParticleEffectEntityItem::updateRenderItem() { if (!_scene) { return; @@ -201,7 +196,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { auto xcolor = _particleColors[i]; auto alpha = (uint8_t)(glm::clamp(_particleAlphas[i] * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); - particleDetails.push_back(ParticleDetails(_particlePositions[i], _particleRadiuses[i], rgba)); + particleDetails.emplace_back(_particlePositions[i], _particleRadiuses[i], rgba); } // sort particles back to front @@ -210,9 +205,12 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum(); // No need to sort if we're doing additive blending - if (_additiveBlending != true) { - ::zSortAxis = frustum->getDirection(); - qSort(particleDetails.begin(), particleDetails.end(), zSort); + if (!_additiveBlending) { + glm::vec3 zSortAxis = frustum->getDirection(); + std::sort(particleDetails.begin(), particleDetails.end(), + [&](const ParticleDetails& lhs, const ParticleDetails& rhs) { + return glm::dot(lhs.position, zSortAxis) > glm::dot(rhs.position, zSortAxis); + }); } diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index f3abeffc20..9d802295f8 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -106,9 +106,9 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte EntityItem(entityItemID), _lastSimulated(usecTimestampNow()), _particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f), - _particlePositions(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), - _particleVelocities(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), - _particleAccelerations(DEFAULT_MAX_PARTICLES, glm::vec3(0.0f, 0.0f, 0.0f)), + _particlePositions(DEFAULT_MAX_PARTICLES, Vectors::ZERO), + _particleVelocities(DEFAULT_MAX_PARTICLES, Vectors::ZERO), + _particleAccelerations(DEFAULT_MAX_PARTICLES, Vectors::ZERO), _particleRadiuses(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), diff --git a/libraries/shared/src/AABox.h b/libraries/shared/src/AABox.h index e5227ade44..8de0462138 100644 --- a/libraries/shared/src/AABox.h +++ b/libraries/shared/src/AABox.h @@ -34,7 +34,7 @@ public: AABox(const glm::vec3& corner, const glm::vec3& dimensions); AABox(); ~AABox() {}; - + void setBox(const glm::vec3& corner, const glm::vec3& scale); void setBox(const glm::vec3& corner, float scale); From c33b6205a80ee09d95f1c3be59705898f599bf5d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 17 Nov 2015 14:02:52 -0800 Subject: [PATCH 05/25] Some cleanup --- .../RenderableParticleEffectEntityItem.cpp | 38 ++++++++----------- .../entities/src/ParticleEffectEntityItem.h | 1 + 2 files changed, 16 insertions(+), 23 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 5c65f0bee5..42b2296529 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -37,8 +37,8 @@ public: _vertexBuffer(std::make_shared()), _indexBuffer(std::make_shared()) { - _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::POSITION, 0, gpu::Element::VEC3F_XYZ, offsetof(Vertex, xyz)); + _vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element::VEC2F_UV, offsetof(Vertex, uv)); _vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, offsetof(Vertex, rgba)); } @@ -134,16 +134,15 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) { + _scene = scene; + _renderItemId = _scene->allocateID(); auto particlePayload = std::make_shared(shared_from_this()); particlePayload->setPipeline(_untexturedPipeline); - _renderItemId = scene->allocateID(); - auto renderData = ParticlePayload::Pointer(particlePayload); - auto renderPayload = std::make_shared(renderData); + auto renderPayload = std::make_shared(particlePayload); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(shared_from_this(), statusGetters); renderPayload->addStatusGetters(statusGetters); pendingChanges.resetItem(_renderItemId, renderPayload); - _scene = scene; return true; } @@ -175,8 +174,7 @@ 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); } -class ParticleDetails { -public: +struct ParticleDetails { ParticleDetails(glm::vec3 position, float radius, uint32_t rgba) : position(position), radius(radius), rgba(rgba) { } glm::vec3 position; @@ -201,15 +199,13 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // sort particles back to front // NOTE: this is view frustum might be one frame out of date. - - auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum(); + auto direction = AbstractViewStateInterface::instance()->getCurrentViewFrustum()->getDirection(); // No need to sort if we're doing additive blending if (!_additiveBlending) { - glm::vec3 zSortAxis = frustum->getDirection(); std::sort(particleDetails.begin(), particleDetails.end(), [&](const ParticleDetails& lhs, const ParticleDetails& rhs) { - return glm::dot(lhs.position, zSortAxis) > glm::dot(rhs.position, zSortAxis); + return glm::dot(lhs.position, direction) > glm::dot(rhs.position, direction); }); } @@ -219,11 +215,9 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { _vertices.clear(); // build vertices from particle positions and radiuses - glm::vec3 dir = frustum->getDirection(); - for (auto&& particle : particleDetails) { - glm::vec3 right = glm::normalize(glm::cross(glm::vec3(0.0f, 1.0f, 0.0f), dir)); - glm::vec3 up = glm::normalize(glm::cross(right, dir)); - + glm::vec3 right = glm::normalize(glm::cross(direction, Vectors::UNIT_Y)); + glm::vec3 up = glm::normalize(glm::cross(right, direction)); + for (const auto& particle : particleDetails) { glm::vec3 upOffset = up * particle.radius; glm::vec3 rightOffset = right * particle.radius; // generate corners of quad aligned to face the camera. @@ -237,28 +231,26 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { pendingChanges.updateItem(_renderItemId, [this](ParticlePayload& payload) { // update vertex buffer auto vertexBuffer = payload.getVertexBuffer(); + auto indexBuffer = payload.getIndexBuffer(); size_t numBytes = sizeof(Vertex) * _vertices.size(); if (numBytes == 0) { vertexBuffer->resize(0); - auto indexBuffer = payload.getIndexBuffer(); indexBuffer->resize(0); return; } - + vertexBuffer->resize(numBytes); - gpu::Byte* data = vertexBuffer->editData(); - memcpy(data, &(_vertices[0]), numBytes); + memcpy(vertexBuffer->editData(), _vertices.data(), 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(); + gpu::Byte* data = indexBuffer->editData(); auto indexPtr = reinterpret_cast(data); for (size_t i = 0; i < numQuads; ++i) { indexPtr[i * NUM_INDICES_PER_PARTICLE + 0] = i * NUM_VERTS_PER_PARTICLE + 0; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 7ac115d8e5..94266402d2 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -226,6 +226,7 @@ protected: void updateAlpha(quint32 index, float age); void integrateParticle(quint32 index, float deltaTime); quint32 getLivingParticleCount() const; + // the properties of this entity rgbColor _color; xColor _colorStart = DEFAULT_COLOR; From 964ac5bad6be4e0ccb57c00cd46a0695f5b47e3d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 17 Nov 2015 17:00:34 -0800 Subject: [PATCH 06/25] More cleanup --- .../RenderableParticleEffectEntityItem.cpp | 8 +- .../entities/src/ParticleEffectEntityItem.cpp | 230 +++++++----------- .../entities/src/ParticleEffectEntityItem.h | 84 +++---- 3 files changed, 135 insertions(+), 187 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 42b2296529..6e86eab135 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -190,11 +190,11 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // make a copy of each particle's details std::vector particleDetails; particleDetails.reserve(getLivingParticleCount()); - for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { - auto xcolor = _particleColors[i]; - auto alpha = (uint8_t)(glm::clamp(_particleAlphas[i] * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); + for (auto& particle : _particles) { + auto xcolor = particle.color; + auto alpha = (uint8_t)(glm::clamp(particle.alpha * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); - particleDetails.emplace_back(_particlePositions[i], _particleRadiuses[i], rgba); + particleDetails.emplace_back(particle.position, particle.radius, rgba); } // sort particles back to front diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 9d802295f8..f82c80a865 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -40,9 +40,6 @@ #include "EntityScriptingInterface.h" #include "ParticleEffectEntityItem.h" -const glm::vec3 X_AXIS = glm::vec3(1.0f, 0.0f, 0.0f); -const glm::vec3 Z_AXIS = glm::vec3(0.0f, 0.0f, 1.0f); - const float SCRIPT_MAXIMUM_PI = 3.1416f; // Round up so that reasonable property values work const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 }; @@ -66,8 +63,8 @@ const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f; const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3 const float ParticleEffectEntityItem::DEFAULT_SPEED_SPREAD = 1.0f; -const glm::quat ParticleEffectEntityItem::DEFAULT_EMIT_ORIENTATION = glm::angleAxis(-PI_OVER_TWO, X_AXIS); // Vertical -const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_DIMENSIONS = glm::vec3(0.0f, 0.0f, 0.0f); // Emit from point +const glm::quat ParticleEffectEntityItem::DEFAULT_EMIT_ORIENTATION = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_X); // Vertical +const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_DIMENSIONS = Vectors::ZERO; // Emit from point const float ParticleEffectEntityItem::MINIMUM_EMIT_DIMENSION = 0.0f; const float ParticleEffectEntityItem::MAXIMUM_EMIT_DIMENSION = (float)TREE_SCALE; const float ParticleEffectEntityItem::DEFAULT_EMIT_RADIUS_START = 1.0f; // Emit from surface (when emitDimensions > 0) @@ -104,35 +101,12 @@ EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID // our non-pure virtual subclass for now... ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : EntityItem(entityItemID), - _lastSimulated(usecTimestampNow()), - _particleLifetimes(DEFAULT_MAX_PARTICLES, 0.0f), - _particlePositions(DEFAULT_MAX_PARTICLES, Vectors::ZERO), - _particleVelocities(DEFAULT_MAX_PARTICLES, Vectors::ZERO), - _particleAccelerations(DEFAULT_MAX_PARTICLES, Vectors::ZERO), - _particleRadiuses(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), - _radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), - _radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), - _radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS), - _particleColors(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), - _colorStarts(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), - _colorMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), - _colorFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_COLOR), - _particleAlphas(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), - _alphaStarts(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), - _alphaMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), - _alphaFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_ALPHA), - _additiveBlending(DEFAULT_ADDITIVE_BLENDING) + _lastSimulated(usecTimestampNow()) { - _type = EntityTypes::ParticleEffect; - setColor(DEFAULT_COLOR); setProperties(properties); } -ParticleEffectEntityItem::~ParticleEffectEntityItem() { -} - - void ParticleEffectEntityItem::setAlpha(float alpha) { if (MINIMUM_ALPHA <= alpha && alpha <= MAXIMUM_ALPHA) { _alpha = alpha; @@ -307,8 +281,8 @@ void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) { void ParticleEffectEntityItem::computeAndUpdateDimensions() { const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error - glm::vec3 velocity = _emitSpeed * (_emitOrientation * Z_AXIS); - glm::vec3 velocitySpread = _speedSpread * (_emitOrientation * Z_AXIS); + glm::vec3 velocity = _emitSpeed * (_emitOrientation * Vectors::UNIT_Z); + glm::vec3 velocitySpread = _speedSpread * (_emitOrientation * Vectors::UNIT_Z); glm::vec3 maxVelocity = glm::abs(velocity) + velocitySpread; glm::vec3 maxAccleration = glm::abs(_acceleration) + _accelerationSpread; @@ -610,51 +584,50 @@ void ParticleEffectEntityItem::updateShapeType(ShapeType type) { } } -void ParticleEffectEntityItem::updateRadius(quint32 index, float age) { - _particleRadiuses[index] = Interpolate::interpolate3Points(_radiusStarts[index], _radiusMiddles[index], - _radiusFinishes[index], age); +void ParticleEffectEntityItem::updateRadius(Particle& particle, float age) { + particle.radius = Interpolate::interpolate3Points(particle.radiusStart, particle.radiusMiddle, + particle.radiusFinish, age); } -void ParticleEffectEntityItem::updateColor(quint32 index, float age) { - _particleColors[index].red = (int)Interpolate::interpolate3Points(_colorStarts[index].red, _colorMiddles[index].red, - _colorFinishes[index].red, age); - _particleColors[index].green = (int)Interpolate::interpolate3Points(_colorStarts[index].green, _colorMiddles[index].green, - _colorFinishes[index].green, age); - _particleColors[index].blue = (int)Interpolate::interpolate3Points(_colorStarts[index].blue, _colorMiddles[index].blue, - _colorFinishes[index].blue, age); +void ParticleEffectEntityItem::updateColor(Particle& particle, float age) { + particle.color.red = (int)Interpolate::interpolate3Points(particle.colorStart.red, particle.colorMiddle.red, + particle.colorFinish.red, age); + particle.color.green = (int)Interpolate::interpolate3Points(particle.colorStart.green, particle.colorMiddle.green, + particle.colorFinish.green, age); + particle.color.blue = (int)Interpolate::interpolate3Points(particle.colorStart.blue, particle.colorMiddle.blue, + particle.colorFinish.blue, age); } -void ParticleEffectEntityItem::updateAlpha(quint32 index, float age) { - _particleAlphas[index] = Interpolate::interpolate3Points(_alphaStarts[index], _alphaMiddles[index], - _alphaFinishes[index], age); +void ParticleEffectEntityItem::updateAlpha(Particle& particle, float age) { + particle.alpha = Interpolate::interpolate3Points(particle.alphaStart, particle.alphaMiddle, + particle.alphaFinish, age); } -void ParticleEffectEntityItem::integrateParticle(quint32 index, float deltaTime) { - glm::vec3 accel = _particleAccelerations[index]; - glm::vec3 atSquared = (0.5f * deltaTime * deltaTime) * accel; - glm::vec3 at = accel * deltaTime; - _particlePositions[index] += _particleVelocities[index] * deltaTime + atSquared; - _particleVelocities[index] += at; +void ParticleEffectEntityItem::integrateParticle(Particle& particle, float deltaTime) { + glm::vec3 atSquared = (0.5f * deltaTime * deltaTime) * particle.acceleration; + glm::vec3 at = particle.acceleration * deltaTime; + particle.position += particle.velocity * deltaTime + atSquared; + particle.velocity += at; } void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particlesBounds.reset(); // update particles between head and tail - for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) { - _particleLifetimes[i] += deltaTime; + for (Particle& particle : _particles) { + particle.lifetime += deltaTime; // if particle has died. - if (_particleLifetimes[i] >= _lifespan || _lifespan < EPSILON) { + if (particle.lifetime >= _lifespan || _lifespan < EPSILON) { // move head forward - _particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles; + _particles.pop_front(); } else { - float age = _particleLifetimes[i] / _lifespan; // 0.0 .. 1.0 - updateRadius(i, age); - updateColor(i, age); - updateAlpha(i, age); - integrateParticle(i, deltaTime); - _particlesBounds.addPoint(_particlePositions[i]); + float age = particle.lifetime / _lifespan; // 0.0 .. 1.0 + updateRadius(particle, age); + updateColor(particle, age); + updateAlpha(particle, age); + integrateParticle(particle, deltaTime); + _particlesBounds.addPoint(particle.position); } } @@ -667,15 +640,22 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { timeLeftInFrame -= _timeUntilNextEmit; _timeUntilNextEmit = 1.0f / _emitRate; + // overflow! move head forward by one. + // because the case of head == tail indicates an empty array, not a full one. + // This can drop an existing older particle, but this is by design, newer particles are a higher priority. + if (_particles.size() >= _maxParticles) { + _particles.pop_front(); + } + // emit a new particle at tail index. - quint32 i = _particleTailIndex; - _particleLifetimes[i] = 0.0f; + _particles.push_back(Particle()); + auto particle = _particles.back(); // Radius if (_radiusSpread == 0.0f) { - _radiusStarts[i] = getRadiusStart(); - _radiusMiddles[i] =_particleRadius; - _radiusFinishes[i] = getRadiusFinish(); + particle.radiusStart = getRadiusStart(); + particle.radiusMiddle = _particleRadius; + particle.radiusFinish = getRadiusFinish(); } else { float spreadMultiplier; if (_particleRadius > 0.0f) { @@ -683,23 +663,21 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } else { spreadMultiplier = 1.0f; } - _radiusStarts[i] = - glm::clamp(spreadMultiplier * getRadiusStart(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - _radiusMiddles[i] = - glm::clamp(spreadMultiplier * _particleRadius, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - _radiusFinishes[i] = - glm::clamp(spreadMultiplier * getRadiusFinish(), MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + particle.radiusStart = glm::clamp(spreadMultiplier * getRadiusStart(), + MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + particle.radiusMiddle = glm::clamp(spreadMultiplier * _particleRadius, + MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + particle.radiusFinish = glm::clamp(spreadMultiplier * getRadiusFinish(), + MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); } - updateRadius(i, 0.0f); + updateRadius(particle, 0.0f); // Position, velocity, and acceleration if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { // Emit along z-axis from position - _particlePositions[i] = getPosition(); - _particleVelocities[i] = - (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Z_AXIS); - _particleAccelerations[i] = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; - + particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z); + particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; + } else { // Emit around point or from ellipsoid // - Distribute directions evenly around point @@ -719,11 +697,9 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { glm::vec3 emitDirection; - if (_emitDimensions == glm::vec3()) { + if (_emitDimensions == Vectors::ZERO) { // Point - emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Z_AXIS; - - _particlePositions[i] = getPosition(); + emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Vectors::UNIT_Z; } else { // Ellipsoid float radiusScale = 1.0f; @@ -745,69 +721,59 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { radiuses.z > 0.0f ? z / (radiuses.z * radiuses.z) : 0.0f )); - _particlePositions[i] = getPosition() + _emitOrientation * emitPosition; + particle.position = _emitOrientation * emitPosition; } - _particleVelocities[i] = - (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); - _particleAccelerations[i] = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; + particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); + particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } - integrateParticle(i, timeLeftInFrame); - _particlesBounds.addPoint(_particlePositions[i]); + integrateParticle(particle, timeLeftInFrame); + _particlesBounds.addPoint(particle.position); // Color if (_colorSpread == xColor{ 0, 0, 0 }) { - _colorStarts[i] = getColorStart(); - _colorMiddles[i] = getXColor(); - _colorFinishes[i] = getColorFinish(); + particle.colorStart = getColorStart(); + particle.colorMiddle = getXColor(); + particle.colorFinish = getColorFinish(); } else { xColor startColor = getColorStart(); xColor middleColor = getXColor(); xColor finishColor = getColorFinish(); float spread = randFloatInRange(-1.0f, 1.0f); - float spreadMultiplierRed = + float spreadMultiplierRed = middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f; float spreadMultiplierGreen = middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green : 1.0f; float spreadMultiplierBlue = middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f; - _colorStarts[i].red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); - _colorStarts[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); - _colorStarts[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f); + particle.colorStart.red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); + particle.colorStart.green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); + particle.colorStart.blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f); - _colorMiddles[i].red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f); - _colorMiddles[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f); - _colorMiddles[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f); + particle.colorMiddle.red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f); + particle.colorMiddle.green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f); + particle.colorMiddle.blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f); - _colorFinishes[i].red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f); - _colorFinishes[i].green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f); - _colorFinishes[i].blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f); + particle.colorFinish.red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f); + particle.colorFinish.green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f); + particle.colorFinish.blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f); } - updateColor(i, 0.0f); + updateColor(particle, 0.0f); // Alpha if (_alphaSpread == 0.0f) { - _alphaStarts[i] = getAlphaStart(); - _alphaMiddles[i] = _alpha; - _alphaFinishes[i] = getAlphaFinish(); + particle.alphaStart = getAlphaStart(); + particle.alphaMiddle = _alpha; + particle.alphaFinish = getAlphaFinish(); } else { float spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _alphaSpread / _alpha; - _alphaStarts[i] = spreadMultiplier * getAlphaStart(); - _alphaMiddles[i] = spreadMultiplier * _alpha; - _alphaFinishes[i] = spreadMultiplier * getAlphaFinish(); - } - updateAlpha(i, 0.0f); - - _particleTailIndex = (_particleTailIndex + 1) % _maxParticles; - - // overflow! move head forward by one. - // because the case of head == tail indicates an empty array, not a full one. - // This can drop an existing older particle, but this is by design, newer particles are a higher priority. - if (_particleTailIndex == _particleHeadIndex) { - _particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles; + particle.alphaStart = spreadMultiplier * getAlphaStart(); + particle.alphaMiddle = spreadMultiplier * _alpha; + particle.alphaFinish = spreadMultiplier * getAlphaFinish(); } + updateAlpha(particle, 0.0f); } _timeUntilNextEmit -= timeLeftInFrame; @@ -818,37 +784,17 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { if (_maxParticles != maxParticles && MINIMUM_MAX_PARTICLES <= maxParticles && maxParticles <= MAXIMUM_MAX_PARTICLES) { _maxParticles = maxParticles; - // TODO: try to do something smart here and preserve the state of existing particles. - - // resize vectors - _particleLifetimes.resize(_maxParticles); - _particlePositions.resize(_maxParticles); - _particleVelocities.resize(_maxParticles); - _particleRadiuses.resize(_maxParticles); - _radiusStarts.resize(_maxParticles); - _radiusMiddles.resize(_maxParticles); - _radiusFinishes.resize(_maxParticles); - _particleColors.resize(_maxParticles); - _colorStarts.resize(_maxParticles); - _colorMiddles.resize(_maxParticles); - _colorFinishes.resize(_maxParticles); - _particleAlphas.resize(_maxParticles); - _alphaStarts.resize(_maxParticles); - _alphaMiddles.resize(_maxParticles); - _alphaFinishes.resize(_maxParticles); + // Pop all the overflowing oldest particles + while (_particles.size() > _maxParticles) { + _particles.pop_front(); + } // effectively clear all particles and start emitting new ones from scratch. - _particleHeadIndex = 0; - _particleTailIndex = 0; _timeUntilNextEmit = 0.0f; } } // because particles are in a ring buffer, this isn't trivial quint32 ParticleEffectEntityItem::getLivingParticleCount() const { - if (_particleTailIndex >= _particleHeadIndex) { - return _particleTailIndex - _particleHeadIndex; - } else { - return (_maxParticles - _particleHeadIndex) + _particleTailIndex; - } + return _particles.size(); } diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 94266402d2..86b3f4fabc 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -11,19 +11,18 @@ #ifndef hifi_ParticleEffectEntityItem_h #define hifi_ParticleEffectEntityItem_h -#include +#include #include "EntityItem.h" class ParticleEffectEntityItem : public EntityItem { public: + ALLOW_INSTANTIATION // This class can be instantiated static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); - virtual ~ParticleEffectEntityItem(); - ALLOW_INSTANTIATION // This class can be instantiated // methods for getting/setting all properties of this entity virtual EntityItemProperties getProperties(EntityPropertyFlags desiredProperties = EntityPropertyFlags()) const; @@ -218,15 +217,43 @@ public: virtual bool supportsDetailedRayIntersection() const { return false; } protected: + struct Particle; + using Particles = std::deque; bool isAnimatingSomething() const; void stepSimulation(float deltaTime); - void updateRadius(quint32 index, float age); - void updateColor(quint32 index, float age); - void updateAlpha(quint32 index, float age); - void integrateParticle(quint32 index, float deltaTime); + void updateRadius(Particle& particle, float age); + void updateColor(Particle& particle, float age); + void updateAlpha(Particle& particle, float age); + void integrateParticle(Particle& particle, float deltaTime); quint32 getLivingParticleCount() const; + struct Particle { + float lifetime { 0.0f }; + glm::vec3 position { Vectors::ZERO}; + glm::vec3 velocity { Vectors::ZERO}; + glm::vec3 acceleration { Vectors::ZERO}; + float radius { DEFAULT_PARTICLE_RADIUS }; + xColor color = DEFAULT_COLOR; + float alpha { DEFAULT_ALPHA }; + + float radiusStart { DEFAULT_PARTICLE_RADIUS }; + float radiusMiddle { DEFAULT_PARTICLE_RADIUS }; + float radiusFinish { DEFAULT_PARTICLE_RADIUS }; + xColor colorStart = DEFAULT_COLOR; + xColor colorMiddle = DEFAULT_COLOR; + xColor colorFinish = DEFAULT_COLOR; + float alphaStart { DEFAULT_ALPHA }; + float alphaMiddle { DEFAULT_ALPHA }; + float alphaFinish { DEFAULT_ALPHA }; + }; + + // Particles container + Particles _particles; + + // bounding volume + Extents _particlesBounds; + // the properties of this entity rgbColor _color; xColor _colorStart = DEFAULT_COLOR; @@ -256,42 +283,17 @@ protected: float _radiusSpread = DEFAULT_RADIUS_SPREAD; - quint64 _lastSimulated; - bool _isEmitting = true; + quint64 _lastSimulated { 0 }; + bool _isEmitting { true }; - QString _textures = DEFAULT_TEXTURES; - bool _texturesChangedFlag = false; - ShapeType _shapeType = SHAPE_TYPE_NONE; - - // all the internals of running the particle sim - QVector _particleLifetimes; - QVector _particlePositions; - QVector _particleVelocities; - QVector _particleAccelerations; - QVector _particleRadiuses; - QVector _radiusStarts; - QVector _radiusMiddles; - QVector _radiusFinishes; - QVector _particleColors; - QVector _colorStarts; - QVector _colorMiddles; - QVector _colorFinishes; - QVector _particleAlphas; - QVector _alphaStarts; - QVector _alphaMiddles; - QVector _alphaFinishes; - - float _timeUntilNextEmit = 0.0f; - - // particle arrays are a ring buffer, use these indices - // to keep track of the living particles. - quint32 _particleHeadIndex = 0; - quint32 _particleTailIndex = 0; - - // bounding volume - Extents _particlesBounds; + QString _textures { DEFAULT_TEXTURES }; + bool _texturesChangedFlag { false }; + ShapeType _shapeType { SHAPE_TYPE_NONE }; - bool _additiveBlending; + float _timeUntilNextEmit { 0.0f }; + + + bool _additiveBlending { DEFAULT_ADDITIVE_BLENDING }; }; #endif // hifi_ParticleEffectEntityItem_h From 7d0a5677faf2ac81d2d1f203c7e979179078c837 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 17 Nov 2015 17:41:39 -0800 Subject: [PATCH 07/25] More code cleanup --- .../entities/src/ParticleEffectEntityItem.cpp | 277 +++++++++--------- .../entities/src/ParticleEffectEntityItem.h | 6 +- 2 files changed, 149 insertions(+), 134 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index f82c80a865..b52cbcd90d 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -610,6 +610,14 @@ void ParticleEffectEntityItem::integrateParticle(Particle& particle, float delta particle.velocity += at; } +void ParticleEffectEntityItem::updateParticle(Particle& particle, float deltaTime) { + float age = particle.lifetime / _lifespan; // 0.0 .. 1.0 + updateRadius(particle, age); + updateColor(particle, age); + updateAlpha(particle, age); + integrateParticle(particle, deltaTime); +} + void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particlesBounds.reset(); @@ -622,11 +630,8 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { // move head forward _particles.pop_front(); } else { - float age = particle.lifetime / _lifespan; // 0.0 .. 1.0 - updateRadius(particle, age); - updateColor(particle, age); - updateAlpha(particle, age); - integrateParticle(particle, deltaTime); + // Otherwise update it + updateParticle(particle, deltaTime); _particlesBounds.addPoint(particle.position); } } @@ -636,10 +641,6 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { float timeLeftInFrame = deltaTime; while (_timeUntilNextEmit < timeLeftInFrame) { - - timeLeftInFrame -= _timeUntilNextEmit; - _timeUntilNextEmit = 1.0f / _emitRate; - // overflow! move head forward by one. // because the case of head == tail indicates an empty array, not a full one. // This can drop an existing older particle, but this is by design, newer particles are a higher priority. @@ -648,138 +649,148 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { } // emit a new particle at tail index. - _particles.push_back(Particle()); + _particles.push_back(createParticle()); auto particle = _particles.back(); - - // Radius - if (_radiusSpread == 0.0f) { - particle.radiusStart = getRadiusStart(); - particle.radiusMiddle = _particleRadius; - particle.radiusFinish = getRadiusFinish(); - } else { - float spreadMultiplier; - if (_particleRadius > 0.0f) { - spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _radiusSpread / _particleRadius; - } else { - spreadMultiplier = 1.0f; - } - particle.radiusStart = glm::clamp(spreadMultiplier * getRadiusStart(), - MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - particle.radiusMiddle = glm::clamp(spreadMultiplier * _particleRadius, - MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - particle.radiusFinish = glm::clamp(spreadMultiplier * getRadiusFinish(), - MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - } - updateRadius(particle, 0.0f); - - // Position, velocity, and acceleration - if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { - // Emit along z-axis from position - particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z); - particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; - - } else { - // Emit around point or from ellipsoid - // - Distribute directions evenly around point - // - Distribute points relatively evenly over ellipsoid surface - // - Distribute points relatively evenly within ellipsoid volume - - float elevationMinZ = sin(PI_OVER_TWO - _polarFinish); - float elevationMaxZ = sin(PI_OVER_TWO - _polarStart); - float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); - - float azimuth; - if (_azimuthFinish >= _azimuthStart) { - azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat(); - } else { - azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat(); - } - - glm::vec3 emitDirection; - - if (_emitDimensions == Vectors::ZERO) { - // Point - emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Vectors::UNIT_Z; - } else { - // Ellipsoid - float radiusScale = 1.0f; - if (_emitRadiusStart < 1.0f) { - float emitRadiusStart = glm::max(_emitRadiusStart, EPSILON); // Avoid math complications at center - float randRadius = - emitRadiusStart + randFloatInRange(0.0f, MAXIMUM_EMIT_RADIUS_START - emitRadiusStart); - radiusScale = 1.0f - std::pow(1.0f - randRadius, 3.0f); - } - - glm::vec3 radiuses = radiusScale * 0.5f * _emitDimensions; - float x = radiuses.x * glm::cos(elevation) * glm::cos(azimuth); - float y = radiuses.y * glm::cos(elevation) * glm::sin(azimuth); - float z = radiuses.z * glm::sin(elevation); - glm::vec3 emitPosition = glm::vec3(x, y, z); - emitDirection = glm::normalize(glm::vec3( - radiuses.x > 0.0f ? x / (radiuses.x * radiuses.x) : 0.0f, - radiuses.y > 0.0f ? y / (radiuses.y * radiuses.y) : 0.0f, - radiuses.z > 0.0f ? z / (radiuses.z * radiuses.z) : 0.0f - )); - - particle.position = _emitOrientation * emitPosition; - } - - particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); - particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; - } - integrateParticle(particle, timeLeftInFrame); + particle.lifetime += timeLeftInFrame; + + // Initialize it + updateParticle(particle, timeLeftInFrame); _particlesBounds.addPoint(particle.position); - - // Color - if (_colorSpread == xColor{ 0, 0, 0 }) { - particle.colorStart = getColorStart(); - particle.colorMiddle = getXColor(); - particle.colorFinish = getColorFinish(); - } else { - xColor startColor = getColorStart(); - xColor middleColor = getXColor(); - xColor finishColor = getColorFinish(); - - float spread = randFloatInRange(-1.0f, 1.0f); - float spreadMultiplierRed = - middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f; - float spreadMultiplierGreen = - middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green : 1.0f; - float spreadMultiplierBlue = - middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f; - - particle.colorStart.red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); - particle.colorStart.green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); - particle.colorStart.blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f); - - particle.colorMiddle.red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f); - particle.colorMiddle.green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f); - particle.colorMiddle.blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f); - - particle.colorFinish.red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f); - particle.colorFinish.green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f); - particle.colorFinish.blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f); - } - updateColor(particle, 0.0f); - - // Alpha - if (_alphaSpread == 0.0f) { - particle.alphaStart = getAlphaStart(); - particle.alphaMiddle = _alpha; - particle.alphaFinish = getAlphaFinish(); - } else { - float spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _alphaSpread / _alpha; - particle.alphaStart = spreadMultiplier * getAlphaStart(); - particle.alphaMiddle = spreadMultiplier * _alpha; - particle.alphaFinish = spreadMultiplier * getAlphaFinish(); - } - updateAlpha(particle, 0.0f); + + // Advance in frame + timeLeftInFrame -= _timeUntilNextEmit; + _timeUntilNextEmit = 1.0f / _emitRate; } _timeUntilNextEmit -= timeLeftInFrame; } } +ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { + Particle particle; + + // Radius + if (_radiusSpread == 0.0f) { + particle.radiusStart = getRadiusStart(); + particle.radiusMiddle = _particleRadius; + particle.radiusFinish = getRadiusFinish(); + } else { + float spreadMultiplier; + if (_particleRadius > 0.0f) { + spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _radiusSpread / _particleRadius; + } else { + spreadMultiplier = 1.0f; + } + particle.radiusStart = glm::clamp(spreadMultiplier * getRadiusStart(), + MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + particle.radiusMiddle = glm::clamp(spreadMultiplier * _particleRadius, + MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + particle.radiusFinish = glm::clamp(spreadMultiplier * getRadiusFinish(), + MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); + } + + // Position, velocity, and acceleration + if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { + // Emit along z-axis from position + particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z); + particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; + + } else { + // Emit around point or from ellipsoid + // - Distribute directions evenly around point + // - Distribute points relatively evenly over ellipsoid surface + // - Distribute points relatively evenly within ellipsoid volume + + float elevationMinZ = sin(PI_OVER_TWO - _polarFinish); + float elevationMaxZ = sin(PI_OVER_TWO - _polarStart); + float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat()); + + float azimuth; + if (_azimuthFinish >= _azimuthStart) { + azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat(); + } else { + azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat(); + } + + glm::vec3 emitDirection; + + if (_emitDimensions == Vectors::ZERO) { + // Point + emitDirection = glm::quat(glm::vec3(PI_OVER_TWO - elevation, 0.0f, azimuth)) * Vectors::UNIT_Z; + } else { + // Ellipsoid + float radiusScale = 1.0f; + if (_emitRadiusStart < 1.0f) { + float emitRadiusStart = glm::max(_emitRadiusStart, EPSILON); // Avoid math complications at center + float randRadius = + emitRadiusStart + randFloatInRange(0.0f, MAXIMUM_EMIT_RADIUS_START - emitRadiusStart); + radiusScale = 1.0f - std::pow(1.0f - randRadius, 3.0f); + } + + glm::vec3 radiuses = radiusScale * 0.5f * _emitDimensions; + float x = radiuses.x * glm::cos(elevation) * glm::cos(azimuth); + float y = radiuses.y * glm::cos(elevation) * glm::sin(azimuth); + float z = radiuses.z * glm::sin(elevation); + glm::vec3 emitPosition = glm::vec3(x, y, z); + emitDirection = glm::normalize(glm::vec3( + radiuses.x > 0.0f ? x / (radiuses.x * radiuses.x) : 0.0f, + radiuses.y > 0.0f ? y / (radiuses.y * radiuses.y) : 0.0f, + radiuses.z > 0.0f ? z / (radiuses.z * radiuses.z) : 0.0f + )); + + particle.position = _emitOrientation * emitPosition; + } + + particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection); + particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; + } + + // Color + if (_colorSpread == xColor{ 0, 0, 0 }) { + particle.colorStart = getColorStart(); + particle.colorMiddle = getXColor(); + particle.colorFinish = getColorFinish(); + } else { + xColor startColor = getColorStart(); + xColor middleColor = getXColor(); + xColor finishColor = getColorFinish(); + + float spread = randFloatInRange(-1.0f, 1.0f); + float spreadMultiplierRed = + middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f; + float spreadMultiplierGreen = + middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green : 1.0f; + float spreadMultiplierBlue = + middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f; + + particle.colorStart.red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); + particle.colorStart.green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); + particle.colorStart.blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f); + + particle.colorMiddle.red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f); + particle.colorMiddle.green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f); + particle.colorMiddle.blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f); + + particle.colorFinish.red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f); + particle.colorFinish.green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f); + particle.colorFinish.blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f); + } + + // Alpha + if (_alphaSpread == 0.0f) { + particle.alphaStart = getAlphaStart(); + particle.alphaMiddle = _alpha; + particle.alphaFinish = getAlphaFinish(); + } else { + float spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _alphaSpread / _alpha; + particle.alphaStart = spreadMultiplier * getAlphaStart(); + particle.alphaMiddle = spreadMultiplier * _alpha; + particle.alphaFinish = spreadMultiplier * getAlphaFinish(); + } + + return particle; +} + void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { if (_maxParticles != maxParticles && MINIMUM_MAX_PARTICLES <= maxParticles && maxParticles <= MAXIMUM_MAX_PARTICLES) { _maxParticles = maxParticles; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 86b3f4fabc..7a3d515f45 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -221,12 +221,16 @@ protected: using Particles = std::deque; bool isAnimatingSomething() const; + quint32 getLivingParticleCount() const; + + Particle createParticle(); void stepSimulation(float deltaTime); + void updateParticle(Particle& particle, float deltaTime); + void updateRadius(Particle& particle, float age); void updateColor(Particle& particle, float age); void updateAlpha(Particle& particle, float age); void integrateParticle(Particle& particle, float deltaTime); - quint32 getLivingParticleCount() const; struct Particle { float lifetime { 0.0f }; From 230a413ec19e6796b124a73dbc0cea780444a5d0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 18 Nov 2015 12:20:07 -0800 Subject: [PATCH 08/25] First pass at new particle shader --- .../RenderableParticleEffectEntityItem.cpp | 82 ++++++------------- .../src/RenderableParticleEffectEntityItem.h | 7 +- .../src/textured_particle.slf | 15 ++-- .../src/textured_particle.slv | 55 +++++++++++-- .../entities/src/ParticleEffectEntityItem.cpp | 2 +- .../entities/src/ParticleEffectEntityItem.h | 2 +- libraries/gpu/src/gpu/GLBackendShader.cpp | 2 +- libraries/gpu/src/gpu/Stream.cpp | 2 +- libraries/gpu/src/gpu/Stream.h | 6 +- libraries/gpu/src/gpu/Transform.slh | 17 +++- 10 files changed, 104 insertions(+), 86 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 6e86eab135..06f5dde300 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -25,21 +25,23 @@ #include "textured_particle_frag.h" #include "textured_particle_alpha_discard_frag.h" +static const uint32_t VERTEX_PER_QUAD = 6; + class ParticlePayload { public: - typedef render::Payload Payload; - typedef Payload::DataPointer Pointer; - typedef RenderableParticleEffectEntityItem::Vertex Vertex; + using Payload = render::Payload; + using Pointer = Payload::DataPointer; + using Vertex = RenderableParticleEffectEntityItem::Vertex; ParticlePayload(EntityItemPointer entity) : _entity(entity), _vertexFormat(std::make_shared()), - _vertexBuffer(std::make_shared()), - _indexBuffer(std::make_shared()) { + _vertexBuffer(std::make_shared()) { - _vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC3F_XYZ, offsetof(Vertex, xyz)); - _vertexFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element::VEC2F_UV, offsetof(Vertex, uv)); - _vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, offsetof(Vertex, rgba)); + _vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC4F_XYZW, + offsetof(Vertex, xyzw), VERTEX_PER_QUAD); + _vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, + offsetof(Vertex, rgba), VERTEX_PER_QUAD); } void setPipeline(gpu::PipelinePointer pipeline) { _pipeline = pipeline; } @@ -54,9 +56,6 @@ public: 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; } @@ -76,10 +75,9 @@ public: 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); + auto numVertices = _vertexBuffer->getSize() / sizeof(Vertex); + batch.draw(gpu::TRIANGLES, numVertices * VERTEX_PER_QUAD); } protected: @@ -89,7 +87,6 @@ protected: gpu::PipelinePointer _pipeline; gpu::Stream::FormatPointer _vertexFormat; gpu::BufferPointer _vertexBuffer; - gpu::BufferPointer _indexBuffer; gpu::TexturePointer _texture; bool _visibleFlag = true; }; @@ -197,70 +194,38 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { particleDetails.emplace_back(particle.position, particle.radius, rgba); } - // sort particles back to front - // NOTE: this is view frustum might be one frame out of date. - auto direction = AbstractViewStateInterface::instance()->getCurrentViewFrustum()->getDirection(); - // No need to sort if we're doing additive blending if (!_additiveBlending) { + // sort particles back to front + // NOTE: this is view frustum might be one frame out of date. + auto direction = AbstractViewStateInterface::instance()->getCurrentViewFrustum()->getDirection(); + // Get direction in the entity space + direction = glm::inverse(getRotation()) * direction; + std::sort(particleDetails.begin(), particleDetails.end(), [&](const ParticleDetails& lhs, const ParticleDetails& rhs) { return glm::dot(lhs.position, direction) > glm::dot(rhs.position, direction); }); } - - - // allocate vertices - _vertices.clear(); - // build vertices from particle positions and radiuses - glm::vec3 right = glm::normalize(glm::cross(direction, Vectors::UNIT_Y)); - glm::vec3 up = glm::normalize(glm::cross(right, direction)); + _vertices.clear(); // clear vertices + _vertices.reserve(particleDetails.size()); // Reserve space for (const auto& particle : particleDetails) { - glm::vec3 upOffset = up * particle.radius; - glm::vec3 rightOffset = right * particle.radius; - // generate corners of quad aligned to face the camera. - _vertices.emplace_back(particle.position + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), particle.rgba); - _vertices.emplace_back(particle.position - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), particle.rgba); - _vertices.emplace_back(particle.position - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), particle.rgba); - _vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), particle.rgba); + _vertices.emplace_back(glm::vec4(particle.position, particle.radius), particle.rgba); } render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [this](ParticlePayload& payload) { // update vertex buffer auto vertexBuffer = payload.getVertexBuffer(); - auto indexBuffer = payload.getIndexBuffer(); size_t numBytes = sizeof(Vertex) * _vertices.size(); - + vertexBuffer->resize(numBytes); if (numBytes == 0) { - vertexBuffer->resize(0); - indexBuffer->resize(0); return; } - - vertexBuffer->resize(numBytes); memcpy(vertexBuffer->editData(), _vertices.data(), numBytes); - // FIXME, don't update index buffer if num particles has not changed. - // update index buffer - 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); - gpu::Byte* data = indexBuffer->editData(); - auto indexPtr = reinterpret_cast(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::vec3 position = getPosition(); glm::quat rotation = getRotation(); @@ -323,8 +288,7 @@ void RenderableParticleEffectEntityItem::createPipelines() { gpu::ShaderPointer fragShader; if (_additiveBlending) { fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_frag))); - } - else { + } else { //If we are sorting and have no additive blending, we want to discard pixels with low alpha to avoid inter-particle entity artifacts fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_alpha_discard_frag))); } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 678f7eb904..5270a29dd5 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -32,10 +32,9 @@ protected: render::ItemID _renderItemId; 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; + Vertex(glm::vec4 xyzwIn, uint32_t rgbaIn) : xyzw(xyzwIn), rgba(rgbaIn) {} + glm::vec4 xyzw; // Position + radius + uint32_t rgba; // Color }; void createPipelines(); diff --git a/libraries/entities-renderer/src/textured_particle.slf b/libraries/entities-renderer/src/textured_particle.slf index 58a3103323..29e683bc4c 100644 --- a/libraries/entities-renderer/src/textured_particle.slf +++ b/libraries/entities-renderer/src/textured_particle.slf @@ -9,14 +9,17 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -uniform sampler2D colorMap; - -in vec4 _color; -in vec2 _texCoord0; +in vec4 varColor; +in vec2 varTexcoord; out vec4 outFragColor; +uniform sampler2D tex; + void main(void) { - vec4 color = texture(colorMap, _texCoord0); - outFragColor = color * _color; + outFragColor = varColor;//texture(tex, varTexcoord.xy) * varColor; + + if (varColor == vec4(0,0,0,1)) { + discard; + } } diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index c741af559d..012f1659ec 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -10,21 +10,58 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -<@include gpu/Inputs.slh@> - <@include gpu/Transform.slh@> <$declareStandardTransform()$> -out vec4 _color; -out vec2 _texCoord0; +in vec4 inPosition; +in vec4 inColor; + +out vec4 varColor; +out vec2 varTexcoord; void main(void) { - // pass along the color & uvs to fragment shader - _color = inColor; - _texCoord0 = inTexCoord0.xy; - + const int NUM_VERTICES_PER_PARTICLE = 6; + const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE]( + vec4(-1.0, -1.0, 0.0, 1.0), + vec4(1.0, -1.0, 0.0, 1.0), + vec4(-1.0, 1.0, 0.0, 1.0), + vec4(-1.0, 1.0, 0.0, 1.0), + vec4(1.0, -1.0, 0.0, 1.0), + vec4(1.0, 1.0, 0.0, 1.0) + ); + + // anchor point in eye space + vec4 anchorPoint = vec4(inPosition.xyz, 1.0); + float radius = inPosition.w; + TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - <$transformModelToClipPos(cam, obj, inPosition, gl_Position)$> + <$transformModelToEyePos(cam, obj, anchorPoint, anchorPoint)$> + + // Which icon are we dealing with ? + int particleID = gl_VertexID / NUM_VERTICES_PER_PARTICLE; + + // Which quad vertex pos? + int twoTriID = gl_VertexID - particleID * NUM_VERTICES_PER_PARTICLE; + vec4 quadPos = radius * UNIT_QUAD[twoTriID]; + + // Pass the texcoord and the z texcoord is representing the texture icon + varTexcoord = vec2((quadPos.xy + 1.0) * 0.5); + varColor = inColor; + + if (particleID == 0) { + varColor = vec4(1,0,0,1); + } else if (particleID == 5) { + varColor = vec4(0,1,0,1); + } else if (particleID == 10) { + varColor = vec4(0,0,1,1); + } else { + varColor = vec4(0,0,0,1); + } + + vec4 clipPos; + vec4 eyePos = vec4(anchorPoint.xyz + quadPos.xyz, 1.0); + <$transformEyeToClip(cam, eyePos, clipPos)$> + gl_Position = clipPos; } diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index b52cbcd90d..e12d7df488 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -91,7 +91,7 @@ const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS; const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS; const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; -const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = false; +const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = true; EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 7a3d515f45..62c9415749 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -211,7 +211,7 @@ public: static const bool DEFAULT_ADDITIVE_BLENDING; bool getAdditiveBlending() const { return _additiveBlending; } void setAdditiveBlending(bool additiveBlending) { - _additiveBlending = additiveBlending; + _additiveBlending = true; } virtual bool supportsDetailedRayIntersection() const { return false; } diff --git a/libraries/gpu/src/gpu/GLBackendShader.cpp b/libraries/gpu/src/gpu/GLBackendShader.cpp index 5a0ab93ec5..19fa94524e 100755 --- a/libraries/gpu/src/gpu/GLBackendShader.cpp +++ b/libraries/gpu/src/gpu/GLBackendShader.cpp @@ -154,7 +154,7 @@ GLBackend::GLShader* compileShader(const Shader& shader) { qCWarning(gpulogging) << "GLShader::compileShader - failed to compile the gl shader object:"; qCWarning(gpulogging) << temp; - + /* filestream.open("debugshader.glsl.info.txt"); if (filestream.is_open()) { diff --git a/libraries/gpu/src/gpu/Stream.cpp b/libraries/gpu/src/gpu/Stream.cpp index 183f2137fb..d43999d3dd 100644 --- a/libraries/gpu/src/gpu/Stream.cpp +++ b/libraries/gpu/src/gpu/Stream.cpp @@ -59,7 +59,7 @@ void Stream::Format::evaluateCache() { } } -bool Stream::Format::setAttribute(Slot slot, Slot channel, Element element, Offset offset, Frequency frequency) { +bool Stream::Format::setAttribute(Slot slot, Slot channel, Element element, Offset offset, uint32 frequency) { _attributes[slot] = Attribute((InputSlot) slot, channel, element, offset, frequency); evaluateCache(); return true; diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index 492af5f62a..6adf9a60a0 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -49,8 +49,8 @@ public: // Frequency describer enum Frequency { + PER_INSTANCE = -1, PER_VERTEX = 0, - PER_INSTANCE, }; // The attribute description @@ -59,7 +59,7 @@ public: public: Attribute() {} - Attribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX) : + Attribute(Slot slot, Slot channel, Element element, Offset offset = 0, uint32 frequency = PER_VERTEX) : _slot(slot), _channel(channel), _element(element), @@ -107,7 +107,7 @@ public: uint32 getElementTotalSize() const { return _elementTotalSize; } - bool setAttribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX); + bool setAttribute(Slot slot, Slot channel, Element element, Offset offset = 0, uint32 frequency = PER_VERTEX); bool setAttribute(Slot slot, Frequency frequency = PER_VERTEX); bool setAttribute(Slot slot, Slot channel, Frequency frequency = PER_VERTEX); diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index e67fbf7f66..de7cdbf7af 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -74,6 +74,16 @@ TransformCamera getTransformCamera() { } <@endfunc@> +<@func $transformModelToEyePos(cameraTransform, objectTransform, modelPos, eyePos)@> + + { // transformModelToEyePos + vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); + <$eyePos$> = (<$cameraTransform$>._view * _worldpos); + // <$eyePos$> = (<$cameraTransform$>._projectionInverse * <$clipPos$>); + } +<@endfunc@> + <@func $transformInstancedModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@> @@ -86,7 +96,6 @@ TransformCamera getTransformCamera() { } <@endfunc@> - <@func transformModelToWorldPos(objectTransform, modelPos, worldPos)@> { // transformModelToWorldPos <$worldPos$> = (<$objectTransform$>._model * <$modelPos$>); @@ -140,4 +149,10 @@ TransformCamera getTransformCamera() { } <@endfunc@> +<@func transformEyeToClip(cameraTransform, eyePos, clipPos)@> + { // transformEyeToClip + <$clipPos$> = <$cameraTransform$>._projection * <$eyePos$>; + } +<@endfunc@> + <@endif@> From cb14fbf4a1ea8326cf1594ef413bdcf403338645 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 18 Nov 2015 15:52:42 -0800 Subject: [PATCH 09/25] Instance particle draw calls --- .../RenderableParticleEffectEntityItem.cpp | 40 +++++++++---------- .../src/RenderableParticleEffectEntityItem.h | 9 +++-- .../src/textured_particle.slf | 6 +-- .../src/textured_particle.slv | 14 +------ libraries/gpu/src/gpu/Stream.cpp | 12 +----- libraries/gpu/src/gpu/Stream.h | 11 ++--- 6 files changed, 32 insertions(+), 60 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 06f5dde300..f2978a4092 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -25,23 +25,23 @@ #include "textured_particle_frag.h" #include "textured_particle_alpha_discard_frag.h" -static const uint32_t VERTEX_PER_QUAD = 6; +static const size_t VERTEX_PER_PARTICLE = 4; class ParticlePayload { public: using Payload = render::Payload; using Pointer = Payload::DataPointer; - using Vertex = RenderableParticleEffectEntityItem::Vertex; + using ParticlePrimitive = RenderableParticleEffectEntityItem::ParticlePrimitive; ParticlePayload(EntityItemPointer entity) : _entity(entity), _vertexFormat(std::make_shared()), - _vertexBuffer(std::make_shared()) { + _particleBuffer(std::make_shared()) { _vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC4F_XYZW, - offsetof(Vertex, xyzw), VERTEX_PER_QUAD); + offsetof(ParticlePrimitive, xyzw), gpu::Stream::PER_INSTANCE); _vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, - offsetof(Vertex, rgba), VERTEX_PER_QUAD); + offsetof(ParticlePrimitive, rgba), gpu::Stream::PER_INSTANCE); } void setPipeline(gpu::PipelinePointer pipeline) { _pipeline = pipeline; } @@ -53,8 +53,8 @@ public: 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 getParticleBuffer() { return _particleBuffer; } + const gpu::BufferPointer& getParticleBuffer() const { return _particleBuffer; } void setTexture(gpu::TexturePointer texture) { _texture = texture; } const gpu::TexturePointer& getTexture() const { return _texture; } @@ -74,10 +74,10 @@ public: batch.setModelTransform(_modelTransform); batch.setInputFormat(_vertexFormat); - batch.setInputBuffer(0, _vertexBuffer, 0, sizeof(Vertex)); + batch.setInputBuffer(0, _particleBuffer, 0, sizeof(ParticlePrimitive)); - auto numVertices = _vertexBuffer->getSize() / sizeof(Vertex); - batch.draw(gpu::TRIANGLES, numVertices * VERTEX_PER_QUAD); + auto numParticles = _particleBuffer->getSize() / sizeof(ParticlePrimitive); + batch.drawInstanced(numParticles, gpu::TRIANGLE_STRIP, VERTEX_PER_PARTICLE); } protected: @@ -86,7 +86,7 @@ protected: AABox _bound; gpu::PipelinePointer _pipeline; gpu::Stream::FormatPointer _vertexFormat; - gpu::BufferPointer _vertexBuffer; + gpu::BufferPointer _particleBuffer; gpu::TexturePointer _texture; bool _visibleFlag = true; }; @@ -208,23 +208,23 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { }); } - // build vertices from particle positions and radiuses - _vertices.clear(); // clear vertices - _vertices.reserve(particleDetails.size()); // Reserve space + // build primitives from particle positions and radiuses + _particlePrimitives.clear(); // clear primitives + _particlePrimitives.reserve(particleDetails.size()); // Reserve space for (const auto& particle : particleDetails) { - _vertices.emplace_back(glm::vec4(particle.position, particle.radius), particle.rgba); + _particlePrimitives.emplace_back(glm::vec4(particle.position, particle.radius), particle.rgba); } render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [this](ParticlePayload& payload) { - // update vertex buffer - auto vertexBuffer = payload.getVertexBuffer(); - size_t numBytes = sizeof(Vertex) * _vertices.size(); - vertexBuffer->resize(numBytes); + // update particle buffer + auto particleBuffer = payload.getParticleBuffer(); + size_t numBytes = sizeof(ParticlePrimitive) * _particlePrimitives.size(); + particleBuffer->resize(numBytes); if (numBytes == 0) { return; } - memcpy(vertexBuffer->editData(), _vertices.data(), numBytes); + memcpy(particleBuffer->editData(), _particlePrimitives.data(), numBytes); // update transform glm::vec3 position = getPosition(); diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 5270a29dd5..b385b6fe41 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -16,7 +16,7 @@ #include "RenderableEntityItem.h" class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem { -friend class ParticlePayload; + friend class ParticlePayload; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); @@ -31,15 +31,16 @@ public: protected: render::ItemID _renderItemId; - struct Vertex { - Vertex(glm::vec4 xyzwIn, uint32_t rgbaIn) : xyzw(xyzwIn), rgba(rgbaIn) {} + struct ParticlePrimitive { + ParticlePrimitive(glm::vec4 xyzwIn, uint32_t rgbaIn) : xyzw(xyzwIn), rgba(rgbaIn) {} glm::vec4 xyzw; // Position + radius uint32_t rgba; // Color }; + using Particles = std::vector; void createPipelines(); - std::vector _vertices; + Particles _particlePrimitives; gpu::PipelinePointer _untexturedPipeline; gpu::PipelinePointer _texturedPipeline; diff --git a/libraries/entities-renderer/src/textured_particle.slf b/libraries/entities-renderer/src/textured_particle.slf index 29e683bc4c..4c718c0b58 100644 --- a/libraries/entities-renderer/src/textured_particle.slf +++ b/libraries/entities-renderer/src/textured_particle.slf @@ -17,9 +17,5 @@ out vec4 outFragColor; uniform sampler2D tex; void main(void) { - outFragColor = varColor;//texture(tex, varTexcoord.xy) * varColor; - - if (varColor == vec4(0,0,0,1)) { - discard; - } + outFragColor = texture(tex, varTexcoord.xy) * varColor; } diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 012f1659ec..615fd1a747 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -21,13 +21,11 @@ out vec4 varColor; out vec2 varTexcoord; void main(void) { - const int NUM_VERTICES_PER_PARTICLE = 6; + const int NUM_VERTICES_PER_PARTICLE = 4; const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE]( vec4(-1.0, -1.0, 0.0, 1.0), vec4(1.0, -1.0, 0.0, 1.0), vec4(-1.0, 1.0, 0.0, 1.0), - vec4(-1.0, 1.0, 0.0, 1.0), - vec4(1.0, -1.0, 0.0, 1.0), vec4(1.0, 1.0, 0.0, 1.0) ); @@ -50,16 +48,6 @@ void main(void) { varTexcoord = vec2((quadPos.xy + 1.0) * 0.5); varColor = inColor; - if (particleID == 0) { - varColor = vec4(1,0,0,1); - } else if (particleID == 5) { - varColor = vec4(0,1,0,1); - } else if (particleID == 10) { - varColor = vec4(0,0,1,1); - } else { - varColor = vec4(0,0,0,1); - } - vec4 clipPos; vec4 eyePos = vec4(anchorPoint.xyz + quadPos.xyz, 1.0); <$transformEyeToClip(cam, eyePos, clipPos)$> diff --git a/libraries/gpu/src/gpu/Stream.cpp b/libraries/gpu/src/gpu/Stream.cpp index d43999d3dd..ff765f3250 100644 --- a/libraries/gpu/src/gpu/Stream.cpp +++ b/libraries/gpu/src/gpu/Stream.cpp @@ -59,7 +59,7 @@ void Stream::Format::evaluateCache() { } } -bool Stream::Format::setAttribute(Slot slot, Slot channel, Element element, Offset offset, uint32 frequency) { +bool Stream::Format::setAttribute(Slot slot, Slot channel, Element element, Offset offset, Frequency frequency) { _attributes[slot] = Attribute((InputSlot) slot, channel, element, offset, frequency); evaluateCache(); return true; @@ -77,16 +77,6 @@ bool Stream::Format::setAttribute(Slot slot, Slot channel, Frequency frequency) return true; } - -BufferStream::BufferStream() : - _buffers(), - _offsets(), - _strides() -{} - -BufferStream::~BufferStream() { -} - void BufferStream::addBuffer(const BufferPointer& buffer, Offset offset, Offset stride) { _buffers.push_back(buffer); _offsets.push_back(offset); diff --git a/libraries/gpu/src/gpu/Stream.h b/libraries/gpu/src/gpu/Stream.h index 6adf9a60a0..9966fceca9 100644 --- a/libraries/gpu/src/gpu/Stream.h +++ b/libraries/gpu/src/gpu/Stream.h @@ -49,8 +49,8 @@ public: // Frequency describer enum Frequency { - PER_INSTANCE = -1, PER_VERTEX = 0, + PER_INSTANCE = 1, }; // The attribute description @@ -59,7 +59,7 @@ public: public: Attribute() {} - Attribute(Slot slot, Slot channel, Element element, Offset offset = 0, uint32 frequency = PER_VERTEX) : + Attribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX) : _slot(slot), _channel(channel), _element(element), @@ -107,7 +107,7 @@ public: uint32 getElementTotalSize() const { return _elementTotalSize; } - bool setAttribute(Slot slot, Slot channel, Element element, Offset offset = 0, uint32 frequency = PER_VERTEX); + bool setAttribute(Slot slot, Slot channel, Element element, Offset offset = 0, Frequency frequency = PER_VERTEX); bool setAttribute(Slot slot, Frequency frequency = PER_VERTEX); bool setAttribute(Slot slot, Slot channel, Frequency frequency = PER_VERTEX); @@ -129,10 +129,7 @@ typedef std::vector< Offset > Offsets; // A Buffer Stream can be assigned to the Batch to set several stream channels in one call class BufferStream { public: - typedef Offsets Strides; - - BufferStream(); - ~BufferStream(); + using Strides = Offsets; void clear() { _buffers.clear(); _offsets.clear(); _strides.clear(); } void addBuffer(const BufferPointer& buffer, Offset offset, Offset stride); From ca17c756319fb02bed2662d243a7c8c36aa2f330 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 18 Nov 2015 16:07:01 -0800 Subject: [PATCH 10/25] Save one array traversal --- .../RenderableParticleEffectEntityItem.cpp | 34 +++++-------------- .../entities/src/ParticleEffectEntityItem.cpp | 7 +--- .../entities/src/ParticleEffectEntityItem.h | 1 - 3 files changed, 10 insertions(+), 32 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f2978a4092..f4117dd790 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -171,27 +171,18 @@ 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); } -struct ParticleDetails { - ParticleDetails(glm::vec3 position, float radius, uint32_t rgba) : position(position), radius(radius), rgba(rgba) { } - - glm::vec3 position; - float radius; - uint32_t rgba; -}; - void RenderableParticleEffectEntityItem::updateRenderItem() { if (!_scene) { return; } - // make a copy of each particle's details - std::vector particleDetails; - particleDetails.reserve(getLivingParticleCount()); + // build primitives from particle positions and radiuses + _particlePrimitives.clear(); // clear primitives + _particlePrimitives.reserve(_particles.size()); // Reserve space for (auto& particle : _particles) { - auto xcolor = particle.color; - auto alpha = (uint8_t)(glm::clamp(particle.alpha * getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f); - auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha); - particleDetails.emplace_back(particle.position, particle.radius, rgba); + auto alpha = glm::clamp(particle.alpha * getLocalRenderAlpha(), 0.0f, 1.0f) * 255; + auto rgba = toRGBA(particle.color.red, particle.color.green, particle.color.blue, alpha); + _particlePrimitives.emplace_back(glm::vec4(particle.position, particle.radius), rgba); } // No need to sort if we're doing additive blending @@ -202,19 +193,12 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // Get direction in the entity space direction = glm::inverse(getRotation()) * direction; - std::sort(particleDetails.begin(), particleDetails.end(), - [&](const ParticleDetails& lhs, const ParticleDetails& rhs) { - return glm::dot(lhs.position, direction) > glm::dot(rhs.position, direction); + std::sort(_particlePrimitives.begin(), _particlePrimitives.end(), + [&](const ParticlePrimitive& lhs, const ParticlePrimitive& rhs) { + return glm::dot(glm::vec3(lhs.xyzw), direction) > glm::dot(glm::vec3(rhs.xyzw), direction); }); } - // build primitives from particle positions and radiuses - _particlePrimitives.clear(); // clear primitives - _particlePrimitives.reserve(particleDetails.size()); // Reserve space - for (const auto& particle : particleDetails) { - _particlePrimitives.emplace_back(glm::vec4(particle.position, particle.radius), particle.rgba); - } - render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [this](ParticlePayload& payload) { // update particle buffer diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index e12d7df488..e7475c30b1 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -549,7 +549,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, bool ParticleEffectEntityItem::isEmittingParticles() const { // keep emitting if there are particles still alive. - return (getIsEmitting() || getLivingParticleCount() > 0); + return (getIsEmitting() || !_particles.empty()); } bool ParticleEffectEntityItem::needsToCallUpdate() const { @@ -804,8 +804,3 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) { _timeUntilNextEmit = 0.0f; } } - -// because particles are in a ring buffer, this isn't trivial -quint32 ParticleEffectEntityItem::getLivingParticleCount() const { - return _particles.size(); -} diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 62c9415749..08074f58fe 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -221,7 +221,6 @@ protected: using Particles = std::deque; bool isAnimatingSomething() const; - quint32 getLivingParticleCount() const; Particle createParticle(); void stepSimulation(float deltaTime); From 61511d57bba8c2ca2adc283133253c51404bbd0b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 18 Nov 2015 16:23:31 -0800 Subject: [PATCH 11/25] Rename struct/Add type aliases --- .../RenderableParticleEffectEntityItem.cpp | 32 ++++++++++--------- .../src/RenderableParticleEffectEntityItem.h | 4 +-- 2 files changed, 19 insertions(+), 17 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f4117dd790..c971813bd0 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -32,20 +32,22 @@ public: using Payload = render::Payload; using Pointer = Payload::DataPointer; using ParticlePrimitive = RenderableParticleEffectEntityItem::ParticlePrimitive; + using PipelinePointer = gpu::PipelinePointer; + using FormatPointer = gpu::Stream::FormatPointer; + using BufferPointer = gpu::BufferPointer; + using TexturePointer = gpu::TexturePointer; + using Format = gpu::Stream::Format; + using Buffer = gpu::Buffer; - ParticlePayload(EntityItemPointer entity) : - _entity(entity), - _vertexFormat(std::make_shared()), - _particleBuffer(std::make_shared()) { - + ParticlePayload(EntityItemPointer entity) : _entity(entity) { _vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC4F_XYZW, offsetof(ParticlePrimitive, xyzw), gpu::Stream::PER_INSTANCE); _vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, offsetof(ParticlePrimitive, rgba), gpu::Stream::PER_INSTANCE); } - void setPipeline(gpu::PipelinePointer pipeline) { _pipeline = pipeline; } - const gpu::PipelinePointer& getPipeline() const { return _pipeline; } + void setPipeline(PipelinePointer pipeline) { _pipeline = pipeline; } + const PipelinePointer& getPipeline() const { return _pipeline; } const Transform& getModelTransform() const { return _modelTransform; } void setModelTransform(const Transform& modelTransform) { _modelTransform = modelTransform; } @@ -53,11 +55,11 @@ public: const AABox& getBound() const { return _bound; } void setBound(AABox& bound) { _bound = bound; } - gpu::BufferPointer getParticleBuffer() { return _particleBuffer; } - const gpu::BufferPointer& getParticleBuffer() const { return _particleBuffer; } + BufferPointer getParticleBuffer() { return _particleBuffer; } + const BufferPointer& getParticleBuffer() const { return _particleBuffer; } - void setTexture(gpu::TexturePointer texture) { _texture = texture; } - const gpu::TexturePointer& getTexture() const { return _texture; } + void setTexture(TexturePointer texture) { _texture = texture; } + const TexturePointer& getTexture() const { return _texture; } bool getVisibleFlag() const { return _visibleFlag; } void setVisibleFlag(bool visibleFlag) { _visibleFlag = visibleFlag; } @@ -84,10 +86,10 @@ protected: EntityItemPointer _entity; Transform _modelTransform; AABox _bound; - gpu::PipelinePointer _pipeline; - gpu::Stream::FormatPointer _vertexFormat; - gpu::BufferPointer _particleBuffer; - gpu::TexturePointer _texture; + PipelinePointer _pipeline; + FormatPointer _vertexFormat { std::make_shared() }; + BufferPointer _particleBuffer { std::make_shared() }; + TexturePointer _texture; bool _visibleFlag = true; }; diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index b385b6fe41..4b3fb608ca 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -36,11 +36,11 @@ protected: glm::vec4 xyzw; // Position + radius uint32_t rgba; // Color }; - using Particles = std::vector; + using ParticlePrimitives = std::vector; void createPipelines(); - Particles _particlePrimitives; + ParticlePrimitives _particlePrimitives; gpu::PipelinePointer _untexturedPipeline; gpu::PipelinePointer _texturedPipeline; From e25ea122d85029ac5559f6819fae1230c5ace630 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 18 Nov 2015 23:07:06 -0800 Subject: [PATCH 12/25] Start moving update to shader --- .../RenderableParticleEffectEntityItem.cpp | 53 +++++++--- .../src/RenderableParticleEffectEntityItem.h | 33 +++++-- .../src/textured_particle.slf | 6 +- .../src/textured_particle.slv | 45 ++++++++- .../src/textured_particle_alpha_discard.slf | 8 +- .../entities/src/ParticleEffectEntityItem.cpp | 96 +------------------ .../entities/src/ParticleEffectEntityItem.h | 21 +--- libraries/model/src/model/Light.cpp | 2 +- libraries/model/src/model/Light.h | 2 - 9 files changed, 119 insertions(+), 147 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index c971813bd0..c7a2e4893c 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -32,18 +32,23 @@ public: using Payload = render::Payload; using Pointer = Payload::DataPointer; using ParticlePrimitive = RenderableParticleEffectEntityItem::ParticlePrimitive; + using ParticleUniforms = RenderableParticleEffectEntityItem::ParticleUniforms; using PipelinePointer = gpu::PipelinePointer; using FormatPointer = gpu::Stream::FormatPointer; using BufferPointer = gpu::BufferPointer; using TexturePointer = gpu::TexturePointer; using Format = gpu::Stream::Format; using Buffer = gpu::Buffer; + using BufferView = gpu::BufferView; ParticlePayload(EntityItemPointer entity) : _entity(entity) { - _vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC4F_XYZW, - offsetof(ParticlePrimitive, xyzw), gpu::Stream::PER_INSTANCE); - _vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32, - offsetof(ParticlePrimitive, rgba), gpu::Stream::PER_INSTANCE); + ParticleUniforms uniforms; + _uniformBuffer = std::make_shared(sizeof(ParticleUniforms), (const gpu::Byte*) &uniforms); + + _vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC3F_XYZ, + offsetof(ParticlePrimitive, xyz), gpu::Stream::PER_INSTANCE); + _vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::VEC2F_UV, + offsetof(ParticlePrimitive, uv), gpu::Stream::PER_INSTANCE); } void setPipeline(PipelinePointer pipeline) { _pipeline = pipeline; } @@ -57,6 +62,9 @@ public: BufferPointer getParticleBuffer() { return _particleBuffer; } const BufferPointer& getParticleBuffer() const { return _particleBuffer; } + + const ParticleUniforms& getParticleUniforms() const { return _uniformBuffer.get(); } + ParticleUniforms& editParticleUniforms() { return _uniformBuffer.edit(); } void setTexture(TexturePointer texture) { _texture = texture; } const TexturePointer& getTexture() const { return _texture; } @@ -75,6 +83,7 @@ public: } batch.setModelTransform(_modelTransform); + batch.setUniformBuffer(0, _uniformBuffer); batch.setInputFormat(_vertexFormat); batch.setInputBuffer(0, _particleBuffer, 0, sizeof(ParticlePrimitive)); @@ -89,6 +98,7 @@ protected: PipelinePointer _pipeline; FormatPointer _vertexFormat { std::make_shared() }; BufferPointer _particleBuffer { std::make_shared() }; + BufferView _uniformBuffer; TexturePointer _texture; bool _visibleFlag = true; }; @@ -169,22 +179,33 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) { updateRenderItem(); } -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); +glm::vec3 toGlm(const rgbColor& color) { + return glm::vec3(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]); } void RenderableParticleEffectEntityItem::updateRenderItem() { if (!_scene) { return; } - - // build primitives from particle positions and radiuses + + // Fill in Uniforms structure + _particleUniforms.radius.start = getRadiusStart(); + _particleUniforms.radius.middle = getParticleRadius(); + _particleUniforms.radius.finish = getRadiusFinish(); + _particleUniforms.radius.spread = getRadiusSpread(); + + _particleUniforms.color.start = glm::vec4(toGlm(getColorStart()), getAlphaStart()); + _particleUniforms.color.middle = glm::vec4(toGlm(getColor()), getAlpha()); + _particleUniforms.color.finish = glm::vec4(toGlm(getColorFinish()), getAlphaFinish()); + _particleUniforms.color.spread = glm::vec4(toGlm(getColorSpread()), getAlphaSpread()); + + _particleUniforms.lifespan = getLifespan(); + + // Build particle primitives _particlePrimitives.clear(); // clear primitives _particlePrimitives.reserve(_particles.size()); // Reserve space for (auto& particle : _particles) { - auto alpha = glm::clamp(particle.alpha * getLocalRenderAlpha(), 0.0f, 1.0f) * 255; - auto rgba = toRGBA(particle.color.red, particle.color.green, particle.color.blue, alpha); - _particlePrimitives.emplace_back(glm::vec4(particle.position, particle.radius), rgba); + _particlePrimitives.emplace_back(particle.position, glm::vec2(particle.lifetime, particle.seed)); } // No need to sort if we're doing additive blending @@ -197,13 +218,16 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { std::sort(_particlePrimitives.begin(), _particlePrimitives.end(), [&](const ParticlePrimitive& lhs, const ParticlePrimitive& rhs) { - return glm::dot(glm::vec3(lhs.xyzw), direction) > glm::dot(glm::vec3(rhs.xyzw), direction); + return glm::dot(lhs.xyz, direction) > glm::dot(rhs.xyz, direction); }); } render::PendingChanges pendingChanges; pendingChanges.updateItem(_renderItemId, [this](ParticlePayload& payload) { - // update particle buffer + // Update particle uniforms + memcpy(&payload.editParticleUniforms(), &_particleUniforms, sizeof(ParticleUniforms)); + + // Update particle buffer auto particleBuffer = payload.getParticleBuffer(); size_t numBytes = sizeof(ParticlePrimitive) * _particlePrimitives.size(); particleBuffer->resize(numBytes); @@ -243,8 +267,7 @@ void RenderableParticleEffectEntityItem::createPipelines() { gpu::State::BlendArg destinationColorBlendArg; if (_additiveBlending) { destinationColorBlendArg = gpu::State::ONE; - } - else { + } else { destinationColorBlendArg = gpu::State::INV_SRC_ALPHA; writeToDepthBuffer = true; } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 4b3fb608ca..0e1dabb6a6 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -29,18 +29,37 @@ public: virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override; protected: - render::ItemID _renderItemId; - + struct ParticleUniforms { + struct { + float start; + float middle; + float finish; + float spread; + } radius; + + struct { + glm::vec4 start; + glm::vec4 middle; + glm::vec4 finish; + glm::vec4 spread; + } color; + + float lifespan; + }; + struct ParticlePrimitive { - ParticlePrimitive(glm::vec4 xyzwIn, uint32_t rgbaIn) : xyzw(xyzwIn), rgba(rgbaIn) {} - glm::vec4 xyzw; // Position + radius - uint32_t rgba; // Color + ParticlePrimitive(glm::vec3 xyzIn, glm::vec2 uvIn) : xyz(xyzIn), uv(uvIn) {} + glm::vec3 xyz; // Position + glm::vec2 uv; // Lifetime + seed }; using ParticlePrimitives = std::vector; - + void createPipelines(); - + + render::ItemID _renderItemId; ParticlePrimitives _particlePrimitives; + ParticleUniforms _particleUniforms; + gpu::PipelinePointer _untexturedPipeline; gpu::PipelinePointer _texturedPipeline; diff --git a/libraries/entities-renderer/src/textured_particle.slf b/libraries/entities-renderer/src/textured_particle.slf index 4c718c0b58..e139c7cc01 100644 --- a/libraries/entities-renderer/src/textured_particle.slf +++ b/libraries/entities-renderer/src/textured_particle.slf @@ -9,13 +9,13 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // +uniform sampler2D colorMap; + in vec4 varColor; in vec2 varTexcoord; out vec4 outFragColor; -uniform sampler2D tex; - void main(void) { - outFragColor = texture(tex, varTexcoord.xy) * varColor; + outFragColor = texture(colorMap, varTexcoord.xy) * varColor; } diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 615fd1a747..0027d70da3 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -14,12 +14,45 @@ <$declareStandardTransform()$> -in vec4 inPosition; -in vec4 inColor; +struct ParticleUniforms { + struct { + float start; + float middle; + float finish; + float spread; + } radius; + + struct { + vec4 start; + vec4 middle; + vec4 finish; + vec4 spread; + } color; + + float lifespan; +}; + +uniform particleBuffer { + ParticleUniforms particle; +}; + +in vec3 inPosition; +in vec2 inExtra; out vec4 varColor; out vec2 varTexcoord; +float mix(float start, float finish, float age) { + return start + (finish - start) * age; +} + +vec4 mixV(vec4 start, vec4 finish, float age) { + return vec4(mix(start.x, finish.x, age), + mix(start.y, finish.y, age), + mix(start.z, finish.z, age), + mix(start.w, finish.w, age)); +} + void main(void) { const int NUM_VERTICES_PER_PARTICLE = 4; const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE]( @@ -29,9 +62,12 @@ void main(void) { vec4(1.0, 1.0, 0.0, 1.0) ); + float age = inExtra.x / particle.lifespan; + float seed = inExtra.y; + // anchor point in eye space vec4 anchorPoint = vec4(inPosition.xyz, 1.0); - float radius = inPosition.w; + float radius = mix(particle.radius.start, particle.radius.finish , age); TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); @@ -46,7 +82,8 @@ void main(void) { // Pass the texcoord and the z texcoord is representing the texture icon varTexcoord = vec2((quadPos.xy + 1.0) * 0.5); - varColor = inColor; + varColor = mixV(particle.color.start, particle.color.finish , age); + varColor.w = particle.color.middle.w; vec4 clipPos; vec4 eyePos = vec4(anchorPoint.xyz + quadPos.xyz, 1.0); diff --git a/libraries/entities-renderer/src/textured_particle_alpha_discard.slf b/libraries/entities-renderer/src/textured_particle_alpha_discard.slf index 389744449a..4d96da943b 100644 --- a/libraries/entities-renderer/src/textured_particle_alpha_discard.slf +++ b/libraries/entities-renderer/src/textured_particle_alpha_discard.slf @@ -11,15 +11,15 @@ uniform sampler2D colorMap; -in vec4 _color; -in vec2 _texCoord0; +in vec4 varColor; +in vec2 varTexcoord; out vec4 outFragColor; void main(void) { - vec4 color = texture(colorMap, _texCoord0); + vec4 color = texture(colorMap, varTexcoord); if (color.a < 0.1) { discard; } - outFragColor = color * _color; + outFragColor = color * varColor; } diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index e7475c30b1..4341dba187 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -91,7 +91,7 @@ const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f; const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS; const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS; const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = ""; -const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = true; +const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = false; EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) { @@ -584,25 +584,6 @@ void ParticleEffectEntityItem::updateShapeType(ShapeType type) { } } -void ParticleEffectEntityItem::updateRadius(Particle& particle, float age) { - particle.radius = Interpolate::interpolate3Points(particle.radiusStart, particle.radiusMiddle, - particle.radiusFinish, age); -} - -void ParticleEffectEntityItem::updateColor(Particle& particle, float age) { - particle.color.red = (int)Interpolate::interpolate3Points(particle.colorStart.red, particle.colorMiddle.red, - particle.colorFinish.red, age); - particle.color.green = (int)Interpolate::interpolate3Points(particle.colorStart.green, particle.colorMiddle.green, - particle.colorFinish.green, age); - particle.color.blue = (int)Interpolate::interpolate3Points(particle.colorStart.blue, particle.colorMiddle.blue, - particle.colorFinish.blue, age); -} - -void ParticleEffectEntityItem::updateAlpha(Particle& particle, float age) { - particle.alpha = Interpolate::interpolate3Points(particle.alphaStart, particle.alphaMiddle, - particle.alphaFinish, age); -} - void ParticleEffectEntityItem::integrateParticle(Particle& particle, float deltaTime) { glm::vec3 atSquared = (0.5f * deltaTime * deltaTime) * particle.acceleration; glm::vec3 at = particle.acceleration * deltaTime; @@ -610,14 +591,6 @@ void ParticleEffectEntityItem::integrateParticle(Particle& particle, float delta particle.velocity += at; } -void ParticleEffectEntityItem::updateParticle(Particle& particle, float deltaTime) { - float age = particle.lifetime / _lifespan; // 0.0 .. 1.0 - updateRadius(particle, age); - updateColor(particle, age); - updateAlpha(particle, age); - integrateParticle(particle, deltaTime); -} - void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particlesBounds.reset(); @@ -631,7 +604,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { _particles.pop_front(); } else { // Otherwise update it - updateParticle(particle, deltaTime); + integrateParticle(particle, deltaTime); _particlesBounds.addPoint(particle.position); } } @@ -654,7 +627,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { particle.lifetime += timeLeftInFrame; // Initialize it - updateParticle(particle, timeLeftInFrame); + integrateParticle(particle, deltaTime); _particlesBounds.addPoint(particle.position); // Advance in frame @@ -669,25 +642,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { Particle particle; - // Radius - if (_radiusSpread == 0.0f) { - particle.radiusStart = getRadiusStart(); - particle.radiusMiddle = _particleRadius; - particle.radiusFinish = getRadiusFinish(); - } else { - float spreadMultiplier; - if (_particleRadius > 0.0f) { - spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _radiusSpread / _particleRadius; - } else { - spreadMultiplier = 1.0f; - } - particle.radiusStart = glm::clamp(spreadMultiplier * getRadiusStart(), - MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - particle.radiusMiddle = glm::clamp(spreadMultiplier * _particleRadius, - MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - particle.radiusFinish = glm::clamp(spreadMultiplier * getRadiusFinish(), - MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS); - } + particle.seed = randFloatInRange(0.0f, 1.0f); // Position, velocity, and acceleration if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) { @@ -745,49 +700,6 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread; } - // Color - if (_colorSpread == xColor{ 0, 0, 0 }) { - particle.colorStart = getColorStart(); - particle.colorMiddle = getXColor(); - particle.colorFinish = getColorFinish(); - } else { - xColor startColor = getColorStart(); - xColor middleColor = getXColor(); - xColor finishColor = getColorFinish(); - - float spread = randFloatInRange(-1.0f, 1.0f); - float spreadMultiplierRed = - middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f; - float spreadMultiplierGreen = - middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green : 1.0f; - float spreadMultiplierBlue = - middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f; - - particle.colorStart.red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f); - particle.colorStart.green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f); - particle.colorStart.blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f); - - particle.colorMiddle.red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f); - particle.colorMiddle.green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f); - particle.colorMiddle.blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f); - - particle.colorFinish.red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f); - particle.colorFinish.green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f); - particle.colorFinish.blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f); - } - - // Alpha - if (_alphaSpread == 0.0f) { - particle.alphaStart = getAlphaStart(); - particle.alphaMiddle = _alpha; - particle.alphaFinish = getAlphaFinish(); - } else { - float spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _alphaSpread / _alpha; - particle.alphaStart = spreadMultiplier * getAlphaStart(); - particle.alphaMiddle = spreadMultiplier * _alpha; - particle.alphaFinish = spreadMultiplier * getAlphaFinish(); - } - return particle; } diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 08074f58fe..090c5e3a80 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -211,7 +211,7 @@ public: static const bool DEFAULT_ADDITIVE_BLENDING; bool getAdditiveBlending() const { return _additiveBlending; } void setAdditiveBlending(bool additiveBlending) { - _additiveBlending = true; + _additiveBlending = additiveBlending; } virtual bool supportsDetailedRayIntersection() const { return false; } @@ -224,31 +224,14 @@ protected: Particle createParticle(); void stepSimulation(float deltaTime); - void updateParticle(Particle& particle, float deltaTime); - - void updateRadius(Particle& particle, float age); - void updateColor(Particle& particle, float age); - void updateAlpha(Particle& particle, float age); void integrateParticle(Particle& particle, float deltaTime); struct Particle { + float seed { 0.0f }; float lifetime { 0.0f }; glm::vec3 position { Vectors::ZERO}; glm::vec3 velocity { Vectors::ZERO}; glm::vec3 acceleration { Vectors::ZERO}; - float radius { DEFAULT_PARTICLE_RADIUS }; - xColor color = DEFAULT_COLOR; - float alpha { DEFAULT_ALPHA }; - - float radiusStart { DEFAULT_PARTICLE_RADIUS }; - float radiusMiddle { DEFAULT_PARTICLE_RADIUS }; - float radiusFinish { DEFAULT_PARTICLE_RADIUS }; - xColor colorStart = DEFAULT_COLOR; - xColor colorMiddle = DEFAULT_COLOR; - xColor colorFinish = DEFAULT_COLOR; - float alphaStart { DEFAULT_ALPHA }; - float alphaMiddle { DEFAULT_ALPHA }; - float alphaFinish { DEFAULT_ALPHA }; }; // Particles container diff --git a/libraries/model/src/model/Light.cpp b/libraries/model/src/model/Light.cpp index 823be727a4..917e3bed7e 100755 --- a/libraries/model/src/model/Light.cpp +++ b/libraries/model/src/model/Light.cpp @@ -18,7 +18,7 @@ Light::Light() : _transform() { // only if created from nothing shall we create the Buffer to store the properties Schema schema; - _schemaBuffer = gpu::BufferView(std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema)); + _schemaBuffer = std::make_shared(sizeof(Schema), (const gpu::Byte*) &schema); } Light::Light(const Light& light) : diff --git a/libraries/model/src/model/Light.h b/libraries/model/src/model/Light.h index efc02e3de4..de7a846a25 100755 --- a/libraries/model/src/model/Light.h +++ b/libraries/model/src/model/Light.h @@ -112,8 +112,6 @@ public: Vec4 _shadow{0.0f}; Vec4 _control{0.0f, 0.0f, 0.0f, 0.0f}; - - Schema() {} }; const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; } From 74278cad40f34c8f632f335ffc99397e9cd1c09c Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 18 Nov 2015 23:16:44 -0800 Subject: [PATCH 13/25] Fix particle texturing --- libraries/entities-renderer/src/textured_particle.slv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 0027d70da3..718c65a2dc 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -81,7 +81,7 @@ void main(void) { vec4 quadPos = radius * UNIT_QUAD[twoTriID]; // Pass the texcoord and the z texcoord is representing the texture icon - varTexcoord = vec2((quadPos.xy + 1.0) * 0.5); + varTexcoord = vec2((UNIT_QUAD[twoTriID].xy + 1.0) * 0.5); varColor = mixV(particle.color.start, particle.color.finish , age); varColor.w = particle.color.middle.w; From 2cb2ca29e6159cbb32645fd1291c404f28909ef4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 19 Nov 2015 12:10:54 -0800 Subject: [PATCH 14/25] More particle shader work --- .../RenderableParticleEffectEntityItem.cpp | 12 +-- .../src/textured_particle.slv | 84 +++++++++++++++---- 2 files changed, 74 insertions(+), 22 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index c7a2e4893c..ca543d0210 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -179,8 +179,8 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) { updateRenderItem(); } -glm::vec3 toGlm(const rgbColor& color) { - return glm::vec3(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]); +static glm::vec4 toGlm(const xColor& color, float alpha) { + return glm::vec4((float)color.red / 255.0f, (float)color.green / 255.0f, (float)color.blue / 255.0f, alpha); } void RenderableParticleEffectEntityItem::updateRenderItem() { @@ -194,10 +194,10 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { _particleUniforms.radius.finish = getRadiusFinish(); _particleUniforms.radius.spread = getRadiusSpread(); - _particleUniforms.color.start = glm::vec4(toGlm(getColorStart()), getAlphaStart()); - _particleUniforms.color.middle = glm::vec4(toGlm(getColor()), getAlpha()); - _particleUniforms.color.finish = glm::vec4(toGlm(getColorFinish()), getAlphaFinish()); - _particleUniforms.color.spread = glm::vec4(toGlm(getColorSpread()), getAlphaSpread()); + _particleUniforms.color.start = toGlm(getColorStart(), getAlphaStart()); + _particleUniforms.color.middle = toGlm(getXColor(), getAlpha()); + _particleUniforms.color.finish = toGlm(getColorFinish(), getAlphaFinish()); + _particleUniforms.color.spread = toGlm(getColorSpread(), getAlphaSpread()); _particleUniforms.lifespan = getLifespan(); diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 718c65a2dc..7a9c91cb0f 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -37,22 +37,68 @@ uniform particleBuffer { }; in vec3 inPosition; -in vec2 inExtra; +in vec2 inColor; // This is actual Lifetime + Seed out vec4 varColor; out vec2 varTexcoord; -float mix(float start, float finish, float age) { - return start + (finish - start) * age; +float bezierInterpolate(float y1, float y2, float y3, float u) { + // https://en.wikipedia.org/wiki/Bezier_curve + return (1.0 - u) * (1.0 - u) * y1 + 2.0 * (1.0 - u) * u * y2 + u * u * y3; } -vec4 mixV(vec4 start, vec4 finish, float age) { - return vec4(mix(start.x, finish.x, age), - mix(start.y, finish.y, age), - mix(start.z, finish.z, age), - mix(start.w, finish.w, age)); +float interpolate3Floats(float y1, float y2, float y3, float u) { + if ((u <= 0.5 && y1 == y2) || (u >= 0.5 && y2 == y3)) { + // Flat line. + return y2; + } + + if ((y2 >= y1 && y2 >= y3) || (y2 <= y1 && y2 <= y3)) { + // U or inverted-U shape. + // Make the slope at y2 = 0, which means that the control points half way between the value points have the value y2. + if (u <= 0.5) { + return bezierInterpolate(y1, y2, y2, 2.0 * u); + } else { + return bezierInterpolate(y2, y2, y3, 2.0 * u - 1.0); + } + + } else { + // L or inverted and/or mirrored L shape. + // Make the slope at y2 be the slope between y1 and y3, up to a maximum of double the minimum of the slopes between y1 + // and y2, and y2 and y3. Use this slope to calculate the control points half way between the value points. + // Note: The maximum ensures that the control points and therefore the interpolated values stay between y1 and y3. + float slope = y3 - y1; + float slope12 = y2 - y1; + float slope23 = y3 - y2; + if (abs(slope) > abs(2.0 * slope12)) { + slope = 2.0 * slope12; + } else if (abs(slope) > abs(2.0 * slope23)) { + slope = 2.0 * slope23; + } + + if (u <= 0.5) { + return bezierInterpolate(y1, y2 - slope / 2.0, y2, 2.0 * u); + } else { + return bezierInterpolate(y2, y2 + slope / 2.0, y3, 2.0 * u - 1.0); + } + +// float uGreaterHalf = step(0.5, u); +// float uSign = sign(uGreaterHalf - 0.5); +// vec4 y12 = mix(y1, y2, uGreaterHalf) +// vec4 y23 = mix(y2, y3, uGreaterHalf) +// +// return bezierInterpolate(y12, y2 + uSign * slope / 2.0, y23, 2.0 * u - uGreaterHalf); + } } +vec4 interpolate3Vec4(vec4 y1, vec4 y2, vec4 y3, float u) { + return vec4(interpolate3Floats(y1.x, y2.x, y3.x, u), + interpolate3Floats(y1.y, y2.y, y3.y, u), + interpolate3Floats(y1.z, y2.z, y3.z, u), + interpolate3Floats(y1.w, y2.w, y3.w, u)); +} + + void main(void) { const int NUM_VERTICES_PER_PARTICLE = 4; const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE]( @@ -62,12 +108,12 @@ void main(void) { vec4(1.0, 1.0, 0.0, 1.0) ); - float age = inExtra.x / particle.lifespan; - float seed = inExtra.y; + float age = inColor.x / particle.lifespan; + float seed = inColor.y; // anchor point in eye space vec4 anchorPoint = vec4(inPosition.xyz, 1.0); - float radius = mix(particle.radius.start, particle.radius.finish , age); + float radius = interpolate3Floats(particle.radius.start, particle.radius.middle, particle.radius.finish , age); TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); @@ -80,13 +126,19 @@ void main(void) { int twoTriID = gl_VertexID - particleID * NUM_VERTICES_PER_PARTICLE; vec4 quadPos = radius * UNIT_QUAD[twoTriID]; - // Pass the texcoord and the z texcoord is representing the texture icon - varTexcoord = vec2((UNIT_QUAD[twoTriID].xy + 1.0) * 0.5); - varColor = mixV(particle.color.start, particle.color.finish , age); - varColor.w = particle.color.middle.w; - vec4 clipPos; vec4 eyePos = vec4(anchorPoint.xyz + quadPos.xyz, 1.0); <$transformEyeToClip(cam, eyePos, clipPos)$> gl_Position = clipPos; + + + // Pass the texcoord and the z texcoord is representing the texture icon + varTexcoord = vec2((UNIT_QUAD[twoTriID].xy + 1.0) * 0.5); + varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age); + + // if (inColor.x == 0.0) { + // varColor = vec4(0, 1, 0, 1); + // } else { + // varColor = vec4(1, 0, 0, 1); + // } } From 0f316e6ae107eb174cb4ffa0a61c2f38d0f222ab Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Thu, 19 Nov 2015 15:24:36 -0800 Subject: [PATCH 15/25] Remove particles emiter bounds compute --- .../RenderableParticleEffectEntityItem.cpp | 9 ++--- .../entities/src/ParticleEffectEntityItem.cpp | 6 +-- .../entities/src/ParticleEffectEntityItem.h | 40 ++++++++++--------- 3 files changed, 25 insertions(+), 30 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index ca543d0210..e3de0f9555 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -58,7 +58,7 @@ public: void setModelTransform(const Transform& modelTransform) { _modelTransform = modelTransform; } const AABox& getBound() const { return _bound; } - void setBound(AABox& bound) { _bound = bound; } + void setBound(const AABox& bound) { _bound = bound; } BufferPointer getParticleBuffer() { return _particleBuffer; } const BufferPointer& getParticleBuffer() const { return _particleBuffer; } @@ -242,12 +242,9 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { Transform transform; transform.setTranslation(position); transform.setRotation(rotation); + payload.setModelTransform(transform); - - AABox bounds(_particlesBounds); - bounds.rotate(rotation); - bounds.shiftBy(position); - payload.setBound(bounds); + payload.setBound(getAABox()); bool textured = _texture && _texture->isLoaded(); if (textured) { diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 4341dba187..f598426e3c 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -592,20 +592,17 @@ void ParticleEffectEntityItem::integrateParticle(Particle& particle, float delta } void ParticleEffectEntityItem::stepSimulation(float deltaTime) { - _particlesBounds.reset(); - // update particles between head and tail for (Particle& particle : _particles) { particle.lifetime += deltaTime; // if particle has died. - if (particle.lifetime >= _lifespan || _lifespan < EPSILON) { + if (particle.lifetime >= _lifespan) { // move head forward _particles.pop_front(); } else { // Otherwise update it integrateParticle(particle, deltaTime); - _particlesBounds.addPoint(particle.position); } } @@ -628,7 +625,6 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) { // Initialize it integrateParticle(particle, deltaTime); - _particlesBounds.addPoint(particle.position); // Advance in frame timeLeftInFrame -= _timeUntilNextEmit; diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 090c5e3a80..0789f5b95e 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -237,10 +237,7 @@ protected: // Particles container Particles _particles; - // bounding volume - Extents _particlesBounds; - - // the properties of this entity + // Particles properties rgbColor _color; xColor _colorStart = DEFAULT_COLOR; xColor _colorFinish = DEFAULT_COLOR; @@ -249,25 +246,30 @@ protected: float _alphaStart = DEFAULT_ALPHA_START; float _alphaFinish = DEFAULT_ALPHA_FINISH; float _alphaSpread = DEFAULT_ALPHA_SPREAD; - quint32 _maxParticles = DEFAULT_MAX_PARTICLES; - float _lifespan = DEFAULT_LIFESPAN; - float _emitRate = DEFAULT_EMIT_RATE; - float _emitSpeed = DEFAULT_EMIT_SPEED; - float _speedSpread = DEFAULT_SPEED_SPREAD; - glm::quat _emitOrientation = DEFAULT_EMIT_ORIENTATION; - glm::vec3 _emitDimensions = DEFAULT_EMIT_DIMENSIONS; - float _emitRadiusStart = DEFAULT_EMIT_RADIUS_START; - float _polarStart = DEFAULT_POLAR_START; - float _polarFinish = DEFAULT_POLAR_FINISH; - float _azimuthStart = DEFAULT_AZIMUTH_START; - float _azimuthFinish = DEFAULT_AZIMUTH_FINISH; - glm::vec3 _emitAcceleration = DEFAULT_EMIT_ACCELERATION; - glm::vec3 _accelerationSpread = DEFAULT_ACCELERATION_SPREAD; float _particleRadius = DEFAULT_PARTICLE_RADIUS; float _radiusStart = DEFAULT_RADIUS_START; float _radiusFinish = DEFAULT_RADIUS_FINISH; float _radiusSpread = DEFAULT_RADIUS_SPREAD; - + float _lifespan = DEFAULT_LIFESPAN; + + // Emiter properties + quint32 _maxParticles = DEFAULT_MAX_PARTICLES; + + float _emitRate = DEFAULT_EMIT_RATE; + float _emitSpeed = DEFAULT_EMIT_SPEED; + float _speedSpread = DEFAULT_SPEED_SPREAD; + + glm::quat _emitOrientation = DEFAULT_EMIT_ORIENTATION; + glm::vec3 _emitDimensions = DEFAULT_EMIT_DIMENSIONS; + float _emitRadiusStart = DEFAULT_EMIT_RADIUS_START; + glm::vec3 _emitAcceleration = DEFAULT_EMIT_ACCELERATION; + glm::vec3 _accelerationSpread = DEFAULT_ACCELERATION_SPREAD; + + float _polarStart = DEFAULT_POLAR_START; + float _polarFinish = DEFAULT_POLAR_FINISH; + float _azimuthStart = DEFAULT_AZIMUTH_START; + float _azimuthFinish = DEFAULT_AZIMUTH_FINISH; + quint64 _lastSimulated { 0 }; bool _isEmitting { true }; From 9adc43755384684007be5a3d685559222ea8a093 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 20 Nov 2015 15:36:34 -0800 Subject: [PATCH 16/25] Make Particle's Payload/PendingChanges *almost* pointer free --- .../RenderableParticleEffectEntityItem.cpp | 99 ++++++++++++------- .../src/RenderableParticleEffectEntityItem.h | 34 +------ 2 files changed, 64 insertions(+), 69 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index e3de0f9555..5c33d2e01e 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -27,12 +27,30 @@ static const size_t VERTEX_PER_PARTICLE = 4; -class ParticlePayload { +template +struct InterpolationData { + T start; + T middle; + T finish; + T spread; +}; + +class ParticlePayloadData { public: - using Payload = render::Payload; + struct ParticleUniforms { + InterpolationData radius; + InterpolationData color; // rgba + float lifespan; + }; + + struct ParticlePrimitive { + ParticlePrimitive(glm::vec3 xyzIn, glm::vec2 uvIn) : xyz(xyzIn), uv(uvIn) {} + glm::vec3 xyz; // Position + glm::vec2 uv; // Lifetime + seed + }; + + using Payload = render::Payload; using Pointer = Payload::DataPointer; - using ParticlePrimitive = RenderableParticleEffectEntityItem::ParticlePrimitive; - using ParticleUniforms = RenderableParticleEffectEntityItem::ParticleUniforms; using PipelinePointer = gpu::PipelinePointer; using FormatPointer = gpu::Stream::FormatPointer; using BufferPointer = gpu::BufferPointer; @@ -40,8 +58,9 @@ public: using Format = gpu::Stream::Format; using Buffer = gpu::Buffer; using BufferView = gpu::BufferView; - - ParticlePayload(EntityItemPointer entity) : _entity(entity) { + using ParticlePrimitives = std::vector; + + ParticlePayloadData() { ParticleUniforms uniforms; _uniformBuffer = std::make_shared(sizeof(ParticleUniforms), (const gpu::Byte*) &uniforms); @@ -92,7 +111,6 @@ public: } protected: - EntityItemPointer _entity; Transform _modelTransform; AABox _bound; PipelinePointer _pipeline; @@ -105,7 +123,7 @@ protected: namespace render { template <> - const ItemKey payloadGetKey(const ParticlePayload::Pointer& payload) { + const ItemKey payloadGetKey(const ParticlePayloadData::Pointer& payload) { if (payload->getVisibleFlag()) { return ItemKey::Builder::transparentShape(); } else { @@ -114,12 +132,12 @@ namespace render { } template <> - const Item::Bound payloadGetBound(const ParticlePayload::Pointer& payload) { + const Item::Bound payloadGetBound(const ParticlePayloadData::Pointer& payload) { return payload->getBound(); } template <> - void payloadRender(const ParticlePayload::Pointer& payload, RenderArgs* args) { + void payloadRender(const ParticlePayloadData::Pointer& payload, RenderArgs* args) { payload->render(args); } } @@ -145,9 +163,9 @@ bool RenderableParticleEffectEntityItem::addToScene(EntityItemPointer self, _scene = scene; _renderItemId = _scene->allocateID(); - auto particlePayload = std::make_shared(shared_from_this()); - particlePayload->setPipeline(_untexturedPipeline); - auto renderPayload = std::make_shared(particlePayload); + auto particlePayloadData = std::make_shared(); + particlePayloadData->setPipeline(_untexturedPipeline); + auto renderPayload = std::make_shared(particlePayloadData); render::Item::Status::Getters statusGetters; makeEntityItemStatusGetters(shared_from_this(), statusGetters); renderPayload->addStatusGetters(statusGetters); @@ -187,25 +205,29 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { if (!_scene) { return; } + using ParticleUniforms = ParticlePayloadData::ParticleUniforms; + using ParticlePrimitive = ParticlePayloadData::ParticlePrimitive; + using ParticlePrimitives = ParticlePayloadData::ParticlePrimitives; + ParticleUniforms particleUniforms; // Fill in Uniforms structure - _particleUniforms.radius.start = getRadiusStart(); - _particleUniforms.radius.middle = getParticleRadius(); - _particleUniforms.radius.finish = getRadiusFinish(); - _particleUniforms.radius.spread = getRadiusSpread(); + particleUniforms.radius.start = getRadiusStart(); + particleUniforms.radius.middle = getParticleRadius(); + particleUniforms.radius.finish = getRadiusFinish(); + particleUniforms.radius.spread = getRadiusSpread(); - _particleUniforms.color.start = toGlm(getColorStart(), getAlphaStart()); - _particleUniforms.color.middle = toGlm(getXColor(), getAlpha()); - _particleUniforms.color.finish = toGlm(getColorFinish(), getAlphaFinish()); - _particleUniforms.color.spread = toGlm(getColorSpread(), getAlphaSpread()); + particleUniforms.color.start = toGlm(getColorStart(), getAlphaStart()); + particleUniforms.color.middle = toGlm(getXColor(), getAlpha()); + particleUniforms.color.finish = toGlm(getColorFinish(), getAlphaFinish()); + particleUniforms.color.spread = toGlm(getColorSpread(), getAlphaSpread()); - _particleUniforms.lifespan = getLifespan(); + particleUniforms.lifespan = getLifespan(); // Build particle primitives - _particlePrimitives.clear(); // clear primitives - _particlePrimitives.reserve(_particles.size()); // Reserve space + auto particlePrimitives = std::make_shared(); + particlePrimitives->reserve(_particles.size()); // Reserve space for (auto& particle : _particles) { - _particlePrimitives.emplace_back(particle.position, glm::vec2(particle.lifetime, particle.seed)); + particlePrimitives->emplace_back(particle.position, glm::vec2(particle.lifetime, particle.seed)); } // No need to sort if we're doing additive blending @@ -216,35 +238,36 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { // Get direction in the entity space direction = glm::inverse(getRotation()) * direction; - std::sort(_particlePrimitives.begin(), _particlePrimitives.end(), + std::sort(particlePrimitives->begin(), particlePrimitives->end(), [&](const ParticlePrimitive& lhs, const ParticlePrimitive& rhs) { return glm::dot(lhs.xyz, direction) > glm::dot(rhs.xyz, direction); }); } + + auto bounds = getAABox(); + auto position = getPosition(); + auto rotation = getRotation(); + Transform transform; + transform.setTranslation(position); + transform.setRotation(rotation); render::PendingChanges pendingChanges; - pendingChanges.updateItem(_renderItemId, [this](ParticlePayload& payload) { + pendingChanges.updateItem(_renderItemId, [=](ParticlePayloadData& payload) { // Update particle uniforms - memcpy(&payload.editParticleUniforms(), &_particleUniforms, sizeof(ParticleUniforms)); + memcpy(&payload.editParticleUniforms(), &particleUniforms, sizeof(ParticleUniforms)); // Update particle buffer auto particleBuffer = payload.getParticleBuffer(); - size_t numBytes = sizeof(ParticlePrimitive) * _particlePrimitives.size(); + size_t numBytes = sizeof(ParticlePrimitive) * particlePrimitives->size(); particleBuffer->resize(numBytes); if (numBytes == 0) { return; } - memcpy(particleBuffer->editData(), _particlePrimitives.data(), numBytes); + memcpy(particleBuffer->editData(), particlePrimitives->data(), numBytes); - // update transform - glm::vec3 position = getPosition(); - glm::quat rotation = getRotation(); - Transform transform; - transform.setTranslation(position); - transform.setRotation(rotation); - + // Update transform and bounds payload.setModelTransform(transform); - payload.setBound(getAABox()); + payload.setBound(bounds); bool textured = _texture && _texture->isLoaded(); if (textured) { diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 0e1dabb6a6..1fb9674682 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -16,7 +16,7 @@ #include "RenderableEntityItem.h" class RenderableParticleEffectEntityItem : public ParticleEffectEntityItem { - friend class ParticlePayload; + friend class ParticlePayloadData; public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); RenderableParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); @@ -29,42 +29,14 @@ public: virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override; protected: - struct ParticleUniforms { - struct { - float start; - float middle; - float finish; - float spread; - } radius; - - struct { - glm::vec4 start; - glm::vec4 middle; - glm::vec4 finish; - glm::vec4 spread; - } color; - - float lifespan; - }; - - struct ParticlePrimitive { - ParticlePrimitive(glm::vec3 xyzIn, glm::vec2 uvIn) : xyz(xyzIn), uv(uvIn) {} - glm::vec3 xyz; // Position - glm::vec2 uv; // Lifetime + seed - }; - using ParticlePrimitives = std::vector; - void createPipelines(); + render::ScenePointer _scene; render::ItemID _renderItemId; - ParticlePrimitives _particlePrimitives; - ParticleUniforms _particleUniforms; + NetworkTexturePointer _texture; gpu::PipelinePointer _untexturedPipeline; gpu::PipelinePointer _texturedPipeline; - - render::ScenePointer _scene; - NetworkTexturePointer _texture; }; From 28c8cf26f50d403672e7f60c56d1895c4f27c4b4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 23 Nov 2015 15:19:41 -0800 Subject: [PATCH 17/25] Fix shader transform errors --- .../entities-renderer/src/textured_particle.slv | 2 +- libraries/gpu/src/gpu/Transform.slh | 13 ++++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 7a9c91cb0f..72b06e0228 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -128,7 +128,7 @@ void main(void) { vec4 clipPos; vec4 eyePos = vec4(anchorPoint.xyz + quadPos.xyz, 1.0); - <$transformEyeToClip(cam, eyePos, clipPos)$> + <$transformEyeToClipPos(cam, eyePos, clipPos)$> gl_Position = clipPos; diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index de7cdbf7af..5d8be1137d 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -76,11 +76,10 @@ TransformCamera getTransformCamera() { <@func $transformModelToEyePos(cameraTransform, objectTransform, modelPos, eyePos)@> + //return camera._view * object._model * pos; !> { // transformModelToEyePos - vec4 _worldpos = (<$objectTransform$>._model * <$modelPos$>); + vec4 _worldpos = (<$objectTransform$>._model * vec4(<$modelPos$>.xyz, 1.0)); <$eyePos$> = (<$cameraTransform$>._view * _worldpos); - // <$eyePos$> = (<$cameraTransform$>._projectionInverse * <$clipPos$>); } <@endfunc@> @@ -145,13 +144,13 @@ TransformCamera getTransformCamera() { <@func transformClipToEyeDir(cameraTransform, clipPos, eyeDir)@> { // transformClipToEyeDir - <$eyeDir$> = vec3(<$cameraTransform$>._projectionInverse * vec4(<$clipPos$>.xyz, 1.0)); + <$eyeDir$> = vec3(<$cameraTransform$>._projectionInverse * vec4(<$clipPos$>.xyz, 0.0)); } <@endfunc@> -<@func transformEyeToClip(cameraTransform, eyePos, clipPos)@> - { // transformEyeToClip - <$clipPos$> = <$cameraTransform$>._projection * <$eyePos$>; +<@func transformEyeToClipPos(cameraTransform, eyePos, clipPos)@> + { // transformEyeToClipPos + <$clipPos$> = <$cameraTransform$>._projection * vec4(<$eyePos$>.xyz, 1.0); } <@endfunc@> From d08a4d77dc172314e8e25c28f60e54b3c8d0eb9e Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 23 Nov 2015 16:11:23 -0800 Subject: [PATCH 18/25] Shader cleanup --- .../src/textured_particle.slv | 52 ++++++++----------- libraries/gpu/src/gpu/Transform.slh | 18 +++---- 2 files changed, 31 insertions(+), 39 deletions(-) diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 72b06e0228..9289c8f08d 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -42,6 +42,14 @@ in vec2 inColor; // This is actual Lifetime + Seed out vec4 varColor; out vec2 varTexcoord; +const int NUM_VERTICES_PER_PARTICLE = 4; +const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE]( + vec4(-1.0, -1.0, 0.0, 1.0), + vec4(1.0, -1.0, 0.0, 1.0), + vec4(-1.0, 1.0, 0.0, 1.0), + vec4(1.0, 1.0, 0.0, 1.0) +); + float bezierInterpolate(float y1, float y2, float y3, float u) { // https://en.wikipedia.org/wiki/Bezier_curve return (1.0 - u) * (1.0 - u) * y1 + 2.0 * (1.0 - u) * u * y2 + u * u * y3; @@ -100,45 +108,29 @@ vec4 interpolate3Vec4(vec4 y1, vec4 y2, vec4 y3, float u) { void main(void) { - const int NUM_VERTICES_PER_PARTICLE = 4; - const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE]( - vec4(-1.0, -1.0, 0.0, 1.0), - vec4(1.0, -1.0, 0.0, 1.0), - vec4(-1.0, 1.0, 0.0, 1.0), - vec4(1.0, 1.0, 0.0, 1.0) - ); - - float age = inColor.x / particle.lifespan; - float seed = inColor.y; - - // anchor point in eye space - vec4 anchorPoint = vec4(inPosition.xyz, 1.0); - float radius = interpolate3Floats(particle.radius.start, particle.radius.middle, particle.radius.finish , age); - TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - <$transformModelToEyePos(cam, obj, anchorPoint, anchorPoint)$> // Which icon are we dealing with ? int particleID = gl_VertexID / NUM_VERTICES_PER_PARTICLE; - // Which quad vertex pos? int twoTriID = gl_VertexID - particleID * NUM_VERTICES_PER_PARTICLE; - vec4 quadPos = radius * UNIT_QUAD[twoTriID]; - - vec4 clipPos; - vec4 eyePos = vec4(anchorPoint.xyz + quadPos.xyz, 1.0); - <$transformEyeToClipPos(cam, eyePos, clipPos)$> - gl_Position = clipPos; - - + + // Particle properties + float age = inColor.x / particle.lifespan; + float seed = inColor.y; + // Pass the texcoord and the z texcoord is representing the texture icon varTexcoord = vec2((UNIT_QUAD[twoTriID].xy + 1.0) * 0.5); varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age); - // if (inColor.x == 0.0) { - // varColor = vec4(0, 1, 0, 1); - // } else { - // varColor = vec4(1, 0, 0, 1); - // } + // anchor point in eye space + float radius = interpolate3Floats(particle.radius.start, particle.radius.middle, particle.radius.finish , age); + vec4 quadPos = radius * UNIT_QUAD[twoTriID]; + + vec4 anchorPoint; + <$transformModelToEyePos(cam, obj, inPosition, anchorPoint)$> + + vec4 eyePos = anchorPoint + quadPos; + <$transformEyeToClipPos(cam, eyePos, gl_Position)$> } diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 5d8be1137d..9a866ca4d0 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -74,15 +74,6 @@ TransformCamera getTransformCamera() { } <@endfunc@> -<@func $transformModelToEyePos(cameraTransform, objectTransform, modelPos, eyePos)@> - - { // transformModelToEyePos - vec4 _worldpos = (<$objectTransform$>._model * vec4(<$modelPos$>.xyz, 1.0)); - <$eyePos$> = (<$cameraTransform$>._view * _worldpos); - } -<@endfunc@> - <@func $transformInstancedModelToEyeAndClipPos(cameraTransform, objectTransform, modelPos, eyePos, clipPos)@> @@ -148,6 +139,15 @@ TransformCamera getTransformCamera() { } <@endfunc@> +<@func $transformModelToEyePos(cameraTransform, objectTransform, modelPos, eyePos)@> + + { // transformModelToEyePos + vec4 _worldpos = (<$objectTransform$>._model * vec4(<$modelPos$>.xyz, 1.0)); + <$eyePos$> = (<$cameraTransform$>._view * _worldpos); + } +<@endfunc@> + <@func transformEyeToClipPos(cameraTransform, eyePos, clipPos)@> { // transformEyeToClipPos <$clipPos$> = <$cameraTransform$>._projection * vec4(<$eyePos$>.xyz, 1.0); From 4827a96bfa3519673e8fa7d9a59e33878f966cc4 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 23 Nov 2015 17:53:22 -0800 Subject: [PATCH 19/25] Fix vertex shader (nested struct unsupported) --- .../RenderableParticleEffectEntityItem.cpp | 2 +- .../src/textured_particle.slv | 37 ++++++++++--------- 2 files changed, 20 insertions(+), 19 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 5c33d2e01e..f6e8298ec3 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -152,7 +152,7 @@ RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const Ent ParticleEffectEntityItem(entityItemID, properties) { // lazy creation of particle system pipeline - if (!_untexturedPipeline && !_texturedPipeline) { + if (!_untexturedPipeline || !_texturedPipeline) { createPipelines(); } } diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 9289c8f08d..cd5dd75101 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -14,21 +14,22 @@ <$declareStandardTransform()$> +struct Radiuses { + float start; + float middle; + float finish; + float spread; +}; +struct Colors { + vec4 start; + vec4 middle; + vec4 finish; + vec4 spread; +}; + struct ParticleUniforms { - struct { - float start; - float middle; - float finish; - float spread; - } radius; - - struct { - vec4 start; - vec4 middle; - vec4 finish; - vec4 spread; - } color; - + Radiuses radius; + Colors color; float lifespan; }; @@ -44,10 +45,10 @@ out vec2 varTexcoord; const int NUM_VERTICES_PER_PARTICLE = 4; const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE]( - vec4(-1.0, -1.0, 0.0, 1.0), - vec4(1.0, -1.0, 0.0, 1.0), - vec4(-1.0, 1.0, 0.0, 1.0), - vec4(1.0, 1.0, 0.0, 1.0) + vec4(-1.0, -1.0, 0.0, 0.0), + vec4(1.0, -1.0, 0.0, 0.0), + vec4(-1.0, 1.0, 0.0, 0.0), + vec4(1.0, 1.0, 0.0, 0.0) ); float bezierInterpolate(float y1, float y2, float y3, float u) { From 2dd494b5df2a6222a9bf03029f6ee07edfc1bfdc Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Mon, 23 Nov 2015 21:00:54 -0800 Subject: [PATCH 20/25] Remove additive blending option (force it) --- .../RenderableParticleEffectEntityItem.cpp | 50 ++++--------------- .../src/textured_particle_alpha_discard.slf | 25 ---------- 2 files changed, 10 insertions(+), 65 deletions(-) delete mode 100644 libraries/entities-renderer/src/textured_particle_alpha_discard.slf diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index f6e8298ec3..86a0603569 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -23,7 +23,6 @@ #include "untextured_particle_frag.h" #include "textured_particle_vert.h" #include "textured_particle_frag.h" -#include "textured_particle_alpha_discard_frag.h" static const size_t VERTEX_PER_PARTICLE = 4; @@ -229,20 +228,6 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { for (auto& particle : _particles) { particlePrimitives->emplace_back(particle.position, glm::vec2(particle.lifetime, particle.seed)); } - - // No need to sort if we're doing additive blending - if (!_additiveBlending) { - // sort particles back to front - // NOTE: this is view frustum might be one frame out of date. - auto direction = AbstractViewStateInterface::instance()->getCurrentViewFrustum()->getDirection(); - // Get direction in the entity space - direction = glm::inverse(getRotation()) * direction; - - std::sort(particlePrimitives->begin(), particlePrimitives->end(), - [&](const ParticlePrimitive& lhs, const ParticlePrimitive& rhs) { - return glm::dot(lhs.xyz, direction) > glm::dot(rhs.xyz, direction); - }); - } auto bounds = getAABox(); auto position = getPosition(); @@ -283,44 +268,29 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { } void RenderableParticleEffectEntityItem::createPipelines() { - bool writeToDepthBuffer = false; - gpu::State::BlendArg destinationColorBlendArg; - if (_additiveBlending) { - destinationColorBlendArg = gpu::State::ONE; - } else { - destinationColorBlendArg = gpu::State::INV_SRC_ALPHA; - writeToDepthBuffer = true; - } if (!_untexturedPipeline) { auto state = std::make_shared(); state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, writeToDepthBuffer, gpu::LESS_EQUAL); - state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, - destinationColorBlendArg, gpu::State::FACTOR_ALPHA, - gpu::State::BLEND_OP_ADD, gpu::State::ONE); + state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, + 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(); state->setCullMode(gpu::State::CULL_BACK); - + state->setDepthTest(true, false, gpu::LESS_EQUAL); + state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - bool writeToDepthBuffer = !_additiveBlending; - state->setDepthTest(true, writeToDepthBuffer, gpu::LESS_EQUAL); - state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, - destinationColorBlendArg, gpu::State::FACTOR_ALPHA, - gpu::State::BLEND_OP_ADD, gpu::State::ONE); auto vertShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(textured_particle_vert))); - gpu::ShaderPointer fragShader; - if (_additiveBlending) { - fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_frag))); - } else { - //If we are sorting and have no additive blending, we want to discard pixels with low alpha to avoid inter-particle entity artifacts - fragShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(textured_particle_alpha_discard_frag))); - } + 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)); diff --git a/libraries/entities-renderer/src/textured_particle_alpha_discard.slf b/libraries/entities-renderer/src/textured_particle_alpha_discard.slf deleted file mode 100644 index 4d96da943b..0000000000 --- a/libraries/entities-renderer/src/textured_particle_alpha_discard.slf +++ /dev/null @@ -1,25 +0,0 @@ -<@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; - -in vec4 varColor; -in vec2 varTexcoord; - -out vec4 outFragColor; - -void main(void) { - vec4 color = texture(colorMap, varTexcoord); - if (color.a < 0.1) { - discard; - } - outFragColor = color * varColor; -} From 9c5486fb4b407e80a3876422ed04f3c6901f30ad Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 24 Nov 2015 12:58:35 -0800 Subject: [PATCH 21/25] More particle work --- .../RenderableParticleEffectEntityItem.cpp | 24 +++++------ .../src/textured_particle.slv | 40 +------------------ 2 files changed, 12 insertions(+), 52 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 86a0603569..a03d2a9b14 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -26,16 +26,15 @@ static const size_t VERTEX_PER_PARTICLE = 4; -template -struct InterpolationData { - T start; - T middle; - T finish; - T spread; -}; - class ParticlePayloadData { public: + template + struct InterpolationData { + T start; + T middle; + T finish; + T spread; + }; struct ParticleUniforms { InterpolationData radius; InterpolationData color; // rgba @@ -207,19 +206,17 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { using ParticleUniforms = ParticlePayloadData::ParticleUniforms; using ParticlePrimitive = ParticlePayloadData::ParticlePrimitive; using ParticlePrimitives = ParticlePayloadData::ParticlePrimitives; - - ParticleUniforms particleUniforms; + // Fill in Uniforms structure + ParticleUniforms particleUniforms; particleUniforms.radius.start = getRadiusStart(); particleUniforms.radius.middle = getParticleRadius(); particleUniforms.radius.finish = getRadiusFinish(); particleUniforms.radius.spread = getRadiusSpread(); - particleUniforms.color.start = toGlm(getColorStart(), getAlphaStart()); particleUniforms.color.middle = toGlm(getXColor(), getAlpha()); particleUniforms.color.finish = toGlm(getColorFinish(), getAlphaFinish()); particleUniforms.color.spread = toGlm(getColorSpread(), getAlphaSpread()); - particleUniforms.lifespan = getLifespan(); // Build particle primitives @@ -254,8 +251,7 @@ void RenderableParticleEffectEntityItem::updateRenderItem() { payload.setModelTransform(transform); payload.setBound(bounds); - bool textured = _texture && _texture->isLoaded(); - if (textured) { + if (_texture && _texture->isLoaded()) { payload.setTexture(_texture->getGPUTexture()); payload.setPipeline(_texturedPipeline); } else { diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index cd5dd75101..0d915a3468 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -61,43 +61,7 @@ float interpolate3Floats(float y1, float y2, float y3, float u) { // Flat line. return y2; } - - if ((y2 >= y1 && y2 >= y3) || (y2 <= y1 && y2 <= y3)) { - // U or inverted-U shape. - // Make the slope at y2 = 0, which means that the control points half way between the value points have the value y2. - if (u <= 0.5) { - return bezierInterpolate(y1, y2, y2, 2.0 * u); - } else { - return bezierInterpolate(y2, y2, y3, 2.0 * u - 1.0); - } - - } else { - // L or inverted and/or mirrored L shape. - // Make the slope at y2 be the slope between y1 and y3, up to a maximum of double the minimum of the slopes between y1 - // and y2, and y2 and y3. Use this slope to calculate the control points half way between the value points. - // Note: The maximum ensures that the control points and therefore the interpolated values stay between y1 and y3. - float slope = y3 - y1; - float slope12 = y2 - y1; - float slope23 = y3 - y2; - if (abs(slope) > abs(2.0 * slope12)) { - slope = 2.0 * slope12; - } else if (abs(slope) > abs(2.0 * slope23)) { - slope = 2.0 * slope23; - } - - if (u <= 0.5) { - return bezierInterpolate(y1, y2 - slope / 2.0, y2, 2.0 * u); - } else { - return bezierInterpolate(y2, y2 + slope / 2.0, y3, 2.0 * u - 1.0); - } - -// float uGreaterHalf = step(0.5, u); -// float uSign = sign(uGreaterHalf - 0.5); -// vec4 y12 = mix(y1, y2, uGreaterHalf) -// vec4 y23 = mix(y2, y3, uGreaterHalf) -// -// return bezierInterpolate(y12, y2 + uSign * slope / 2.0, y23, 2.0 * u - uGreaterHalf); - } + return bezierInterpolate(y1, y2, y3, u); } vec4 interpolate3Vec4(vec4 y1, vec4 y2, vec4 y3, float u) { @@ -116,7 +80,7 @@ void main(void) { int particleID = gl_VertexID / NUM_VERTICES_PER_PARTICLE; // Which quad vertex pos? int twoTriID = gl_VertexID - particleID * NUM_VERTICES_PER_PARTICLE; - + // Particle properties float age = inColor.x / particle.lifespan; float seed = inColor.y; From bd23a4137ef395231eb7e2776dd63179d15d0897 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Nov 2015 11:11:06 -0800 Subject: [PATCH 22/25] Move toGlm to GLMHelpers --- .../src/RenderableParticleEffectEntityItem.cpp | 7 ++----- libraries/shared/src/GLMHelpers.cpp | 4 ++++ libraries/shared/src/GLMHelpers.h | 1 + 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index a03d2a9b14..cabf616881 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -24,10 +24,11 @@ #include "textured_particle_vert.h" #include "textured_particle_frag.h" -static const size_t VERTEX_PER_PARTICLE = 4; class ParticlePayloadData { public: + static const size_t VERTEX_PER_PARTICLE = 4; + template struct InterpolationData { T start; @@ -195,10 +196,6 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) { updateRenderItem(); } -static glm::vec4 toGlm(const xColor& color, float alpha) { - return glm::vec4((float)color.red / 255.0f, (float)color.green / 255.0f, (float)color.blue / 255.0f, alpha); -} - void RenderableParticleEffectEntityItem::updateRenderItem() { if (!_scene) { return; diff --git a/libraries/shared/src/GLMHelpers.cpp b/libraries/shared/src/GLMHelpers.cpp index fa010a85bd..d89457d761 100644 --- a/libraries/shared/src/GLMHelpers.cpp +++ b/libraries/shared/src/GLMHelpers.cpp @@ -345,6 +345,10 @@ QSize fromGlm(const glm::ivec2 & v) { return QSize(v.x, v.y); } +vec4 toGlm(const xColor& color, float alpha) { + return vec4((float)color.red / 255.0f, (float)color.green / 255.0f, (float)color.blue / 255.0f, alpha); +} + QRectF glmToRect(const glm::vec2 & pos, const glm::vec2 & size) { QRectF result(pos.x, pos.y, size.x, size.y); return result; diff --git a/libraries/shared/src/GLMHelpers.h b/libraries/shared/src/GLMHelpers.h index 8d3410aaf2..d518ab8ae4 100644 --- a/libraries/shared/src/GLMHelpers.h +++ b/libraries/shared/src/GLMHelpers.h @@ -154,6 +154,7 @@ vec2 toGlm(const QPointF& pt); vec3 toGlm(const xColor& color); vec4 toGlm(const QColor& color); ivec4 toGlm(const QRect& rect); +vec4 toGlm(const xColor& color, float alpha); QSize fromGlm(const glm::ivec2 & v); QMatrix4x4 fromGlm(const glm::mat4 & m); From 591025850b91fd1c209b0bac636168c45ae9a508 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Wed, 25 Nov 2015 11:38:59 -0800 Subject: [PATCH 23/25] Fix particle shader --- .../src/textured_particle.slv | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 0d915a3468..8572350de6 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -56,19 +56,11 @@ float bezierInterpolate(float y1, float y2, float y3, float u) { return (1.0 - u) * (1.0 - u) * y1 + 2.0 * (1.0 - u) * u * y2 + u * u * y3; } -float interpolate3Floats(float y1, float y2, float y3, float u) { - if ((u <= 0.5 && y1 == y2) || (u >= 0.5 && y2 == y3)) { - // Flat line. - return y2; - } - return bezierInterpolate(y1, y2, y3, u); -} - vec4 interpolate3Vec4(vec4 y1, vec4 y2, vec4 y3, float u) { - return vec4(interpolate3Floats(y1.x, y2.x, y3.x, u), - interpolate3Floats(y1.y, y2.y, y3.y, u), - interpolate3Floats(y1.z, y2.z, y3.z, u), - interpolate3Floats(y1.w, y2.w, y3.w, u)); + return vec4(bezierInterpolate(y1.x, y2.x, y3.x, u), + bezierInterpolate(y1.y, y2.y, y3.y, u), + bezierInterpolate(y1.z, y2.z, y3.z, u), + bezierInterpolate(y1.w, y2.w, y3.w, u)); } @@ -90,7 +82,7 @@ void main(void) { varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age); // anchor point in eye space - float radius = interpolate3Floats(particle.radius.start, particle.radius.middle, particle.radius.finish , age); + float radius = bezierInterpolate(particle.radius.start, particle.radius.middle, particle.radius.finish , age); vec4 quadPos = radius * UNIT_QUAD[twoTriID]; vec4 anchorPoint; From 180ffcc456132efa5a0dab26f1a8206b95549484 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 15:42:29 -0800 Subject: [PATCH 24/25] Typo (English is weird) --- .../entities-renderer/src/textured_particle.slv | 4 ++-- .../entities/src/ParticleEffectEntityItem.cpp | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index 8572350de6..1e9275ec72 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -14,7 +14,7 @@ <$declareStandardTransform()$> -struct Radiuses { +struct Radii { float start; float middle; float finish; @@ -28,7 +28,7 @@ struct Colors { }; struct ParticleUniforms { - Radiuses radius; + Radii radius; Colors color; float lifespan; }; diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index f598426e3c..27de4766f4 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -678,16 +678,16 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() { radiusScale = 1.0f - std::pow(1.0f - randRadius, 3.0f); } - glm::vec3 radiuses = radiusScale * 0.5f * _emitDimensions; - float x = radiuses.x * glm::cos(elevation) * glm::cos(azimuth); - float y = radiuses.y * glm::cos(elevation) * glm::sin(azimuth); - float z = radiuses.z * glm::sin(elevation); + glm::vec3 radii = radiusScale * 0.5f * _emitDimensions; + float x = radii.x * glm::cos(elevation) * glm::cos(azimuth); + float y = radii.y * glm::cos(elevation) * glm::sin(azimuth); + float z = radii.z * glm::sin(elevation); glm::vec3 emitPosition = glm::vec3(x, y, z); emitDirection = glm::normalize(glm::vec3( - radiuses.x > 0.0f ? x / (radiuses.x * radiuses.x) : 0.0f, - radiuses.y > 0.0f ? y / (radiuses.y * radiuses.y) : 0.0f, - radiuses.z > 0.0f ? z / (radiuses.z * radiuses.z) : 0.0f - )); + radii.x > 0.0f ? x / (radii.x * radii.x) : 0.0f, + radii.y > 0.0f ? y / (radii.y * radii.y) : 0.0f, + radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f + )); particle.position = _emitOrientation * emitPosition; } From c8ab95bb53f12b7f8e03f8b2e81e97ee7ebc8f48 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Tue, 1 Dec 2015 16:25:08 -0800 Subject: [PATCH 25/25] Spacing --- libraries/entities/src/ParticleEffectEntityItem.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index 0789f5b95e..ca6bcf8959 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -229,9 +229,9 @@ protected: struct Particle { float seed { 0.0f }; float lifetime { 0.0f }; - glm::vec3 position { Vectors::ZERO}; - glm::vec3 velocity { Vectors::ZERO}; - glm::vec3 acceleration { Vectors::ZERO}; + glm::vec3 position { Vectors::ZERO }; + glm::vec3 velocity { Vectors::ZERO }; + glm::vec3 acceleration { Vectors::ZERO }; }; // Particles container