Add alpha property support to ParticleEffect entities

Add at same "level" as color so that it's available for other entity
types to use in the future.
This commit is contained in:
David Rowe 2015-09-05 10:23:27 -07:00
parent c9cf426dba
commit 12b8a5a1d5
10 changed files with 63 additions and 23 deletions

View file

@ -15,7 +15,7 @@
var box,
particles,
particleExample = -1,
NUM_PARTICLE_EXAMPLES = 6,
NUM_PARTICLE_EXAMPLES = 7,
PARTICLE_RADIUS = 0.04;
function onClickDownOnEntity(entityID) {
@ -24,7 +24,7 @@
switch (particleExample) {
case 0:
print("Simple animation");
print("Simple emitter");
Entities.editEntity(particles, {
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
@ -71,12 +71,24 @@
});
break;
case 5:
print("Stop animation");
print("Alpha 0.5");
Entities.editEntity(particles, {
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
radiusStart: PARTICLE_RADIUS,
radiusFinish: PARTICLE_RADIUS,
alpha: 0.5,
animationIsPlaying: true
});
break;
case 6:
print("Stop emitting");
Entities.editEntity(particles, {
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
radiusStart: PARTICLE_RADIUS,
radiusFinish: PARTICLE_RADIUS,
alpha: 1.0,
animationIsPlaying: false
});
break;

View file

@ -172,16 +172,17 @@ 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 PositionAndRadius {
class ParticleDetails {
public:
PositionAndRadius(glm::vec3 position, float radius) : position(position), radius(radius) { }
ParticleDetails(glm::vec3 position, float radius, uint32_t rgba) : position(position), radius(radius), rgba(rgba) { }
glm::vec3 position;
float radius;
uint32_t rgba;
};
static glm::vec3 zSortAxis;
static bool zSort(const PositionAndRadius& rhs, const PositionAndRadius& lhs) {
static bool zSort(const ParticleDetails& rhs, const ParticleDetails& lhs) {
return glm::dot(rhs.position, ::zSortAxis) > glm::dot(lhs.position, ::zSortAxis);
}
@ -190,22 +191,21 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
return;
}
// make a copy of each particle's details
std::vector<ParticleDetails> particleDetails;
particleDetails.reserve(getLivingParticleCount());
auto xcolor = getXColor();
auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f);
auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha);
// make a copy of each particle position and radius
std::vector<PositionAndRadius> positionsAndRadiuses;
positionsAndRadiuses.reserve(getLivingParticleCount());
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
positionsAndRadiuses.push_back(PositionAndRadius(_particlePositions[i], _particleRadiuses[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));
}
// sort particles back to front
// NOTE: this is view frustum might be one frame out of date.
auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum();
::zSortAxis = frustum->getDirection();
qSort(positionsAndRadiuses.begin(), positionsAndRadiuses.end(), zSort);
qSort(particleDetails.begin(), particleDetails.end(), zSort);
// allocate vertices
_vertices.clear();
@ -213,14 +213,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
// build vertices from particle positions and radiuses
const glm::vec3 up = frustum->getUp();
const glm::vec3 right = frustum->getRight();
for (auto&& particle : positionsAndRadiuses) {
for (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), rgba);
_vertices.emplace_back(particle.position - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba);
_vertices.emplace_back(particle.position - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba);
_vertices.emplace_back(particle.position + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba);
_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);
}
render::PendingChanges pendingChanges;

View file

@ -55,6 +55,7 @@ CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(scriptTimestamp, ENTITY_ITEM_DEFAULT_SCRIPT_TIMESTAMP),
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
CONSTRUCT_PROPERTY(color, ),
CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA),
CONSTRUCT_PROPERTY(modelURL, ""),
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
CONSTRUCT_PROPERTY(animationURL, ""),
@ -331,6 +332,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_SCRIPT_TIMESTAMP, scriptTimestamp);
CHECK_PROPERTY_CHANGE(PROP_COLLISION_SOUND_URL, collisionSoundURL);
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha);
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
@ -445,6 +447,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(angularDamping);
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
COPY_PROPERTY_TO_QSCRIPTVALUE(color);
COPY_PROPERTY_TO_QSCRIPTVALUE(alpha);
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
@ -578,6 +581,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(angularDamping, float, setAngularDamping);
COPY_PROPERTY_FROM_QSCRIPTVALUE(visible, bool, setVisible);
COPY_PROPERTY_FROM_QSCRIPTVALUE(color, xColor, setColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha);
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL);
@ -915,11 +919,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
APPEND_ENTITY_PROPERTY(PROP_STROKE_WIDTHS, properties.getStrokeWidths());
}
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, properties.getMarketplaceID());
APPEND_ENTITY_PROPERTY(PROP_NAME, properties.getName());
APPEND_ENTITY_PROPERTY(PROP_COLLISION_SOUND_URL, properties.getCollisionSoundURL());
APPEND_ENTITY_PROPERTY(PROP_ACTION_DATA, properties.getActionData());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, properties.getAlpha());
}
if (propertyCount > 0) {
int endOfEntityItemData = packetData->getUncompressedByteOffset();
@ -1192,6 +1196,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACTION_DATA, QByteArray, setActionData);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA, float, setAlpha);
return valid;
}
@ -1248,6 +1253,7 @@ void EntityItemProperties::markAllChanged() {
_nameChanged = true;
_visibleChanged = true;
_colorChanged = true;
_alphaChanged = true;
_modelURLChanged = true;
_compoundShapeURLChanged = true;
_animationURLChanged = true;

View file

@ -103,6 +103,7 @@ public:
DEFINE_PROPERTY(PROP_SCRIPT_TIMESTAMP, ScriptTimestamp, scriptTimestamp, quint64);
DEFINE_PROPERTY_REF(PROP_COLLISION_SOUND_URL, CollisionSoundURL, collisionSoundURL, QString);
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float);
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
@ -294,6 +295,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ScriptTimestamp, scriptTimestamp, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionSoundURL, collisionSoundURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");

View file

@ -27,6 +27,7 @@ const QString ENTITY_ITEM_DEFAULT_USER_DATA = QString("");
const QString ENTITY_ITEM_DEFAULT_MARKETPLACE_ID = QString("");
const QUuid ENTITY_ITEM_DEFAULT_SIMULATOR_ID = QUuid();
const float ENTITY_ITEM_DEFAULT_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA = 1.0f;
const float ENTITY_ITEM_DEFAULT_GLOW_LEVEL = 0.0f;
const bool ENTITY_ITEM_DEFAULT_VISIBLE = true;

View file

@ -151,6 +151,8 @@ enum EntityPropertyList {
PROP_RADIUS_START,
PROP_RADIUS_FINISH,
PROP_ALPHA, // Supported by some derived classes
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -85,6 +85,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte
_textures(DEFAULT_TEXTURES),
_texturesChangedFlag(false),
_shapeType(SHAPE_TYPE_NONE),
_alpha(ENTITY_ITEM_DEFAULT_ALPHA),
_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)),
@ -93,6 +94,7 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte
_radiusStarts(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
_radiusMiddles(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
_radiusFinishes(DEFAULT_MAX_PARTICLES, DEFAULT_PARTICLE_RADIUS),
_particleAlphas(DEFAULT_MAX_PARTICLES, ENTITY_ITEM_DEFAULT_ALPHA),
_timeUntilNextEmit(0.0f),
_particleHeadIndex(0),
_particleTailIndex(0),
@ -155,6 +157,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const {
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alpha, getAlpha);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFPS, getAnimationFPS);
@ -181,6 +184,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
bool somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alpha, setAlpha);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFPS, setAnimationFPS);
@ -266,10 +270,11 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
}
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS) {
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES) {
READ_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, float, setRadiusSpread);
READ_ENTITY_PROPERTY(PROP_RADIUS_START, float, setRadiusStart);
READ_ENTITY_PROPERTY(PROP_RADIUS_FINISH, float, setRadiusFinish);
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
}
return bytesRead;
@ -298,6 +303,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
requestedProperties += PROP_RADIUS_SPREAD;
requestedProperties += PROP_RADIUS_START;
requestedProperties += PROP_RADIUS_FINISH;
requestedProperties += PROP_ALPHA;
return requestedProperties;
}
@ -329,6 +335,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, getRadiusSpread());
APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, getRadiusStart());
APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, getRadiusFinish());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
}
bool ParticleEffectEntityItem::isAnimatingSomething() const {
@ -584,6 +591,9 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
integrateParticle(i, timeLeftInFrame);
extendBounds(_particlePositions[i]);
// Alpha
_particleAlphas[i] = _alpha;
_particleTailIndex = (_particleTailIndex + 1) % _maxParticles;
// overflow! move head forward by one.
@ -612,6 +622,7 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
_radiusStarts.resize(_maxParticles);
_radiusMiddles.resize(_maxParticles);
_radiusFinishes.resize(_maxParticles);
_particleAlphas.resize(_maxParticles);
// effectively clear all particles and start emitting new ones from scratch.
_particleHeadIndex = 0;

View file

@ -56,6 +56,9 @@ public:
_color[BLUE_INDEX] = value.blue;
}
void setAlpha(float alpha) { _alpha = alpha; }
float getAlpha() const { return _alpha; }
void updateShapeType(ShapeType type);
virtual ShapeType getShapeType() const { return _shapeType; }
@ -160,6 +163,7 @@ protected:
// the properties of this entity
rgbColor _color;
float _alpha;
quint32 _maxParticles;
float _lifespan;
float _emitRate;
@ -187,6 +191,7 @@ protected:
QVector<float> _radiusStarts;
QVector<float> _radiusMiddles;
QVector<float> _radiusFinishes;
QVector<float> _particleAlphas;
float _timeUntilNextEmit;

View file

@ -67,7 +67,7 @@ PacketVersion versionForPacketType(PacketType::Value packetType) {
case EntityAdd:
case EntityEdit:
case EntityData:
return VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS;
return VERSION_ENTITIES_PARTICLE_ALPHA_PROPERTIES;
case AvatarData:
return 13;
default:

View file

@ -145,6 +145,7 @@ const PacketVersion VERSION_ENTITIES_POLYLINE = 37;
const PacketVersion VERSION_OCTREE_CENTERED_ORIGIN = 38;
const PacketVersion VERSION_ENTITIES_PARTICLE_MODIFICATIONS = 39;
const PacketVersion VERSION_ENTITIES_POLYVOX_NEIGHBORS = 40;
const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_ADDITIONS = 41;
const PacketVersion VERSION_ENTITIES_PARTICLE_RADIUS_PROPERTIES = 41;
const PacketVersion VERSION_ENTITIES_PARTICLE_ALPHA_PROPERTIES = 42;
#endif // hifi_PacketHeaders_h