Merge pull request #5739 from ctrlaltdavid/20669

CR for 20669 - Add additional particle properties controlling size, colour, and opacity
This commit is contained in:
Eric Levin 2015-09-08 14:51:54 -07:00
commit 69612551e2
11 changed files with 617 additions and 48 deletions

View file

@ -0,0 +1,170 @@
//
// particlesTest.js
// examples/example/entities
//
// Created by David Rowe on 2 Sep 2015.
// Copyright 2015 High Fidelity, Inc.
//
// Click on the box entity to display different particle effects.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
(function () {
var box,
particles,
particleExample = -1,
NUM_PARTICLE_EXAMPLES = 11,
PARTICLE_RADIUS = 0.04;
function onClickDownOnEntity(entityID) {
if (entityID === box || entityID === particles) {
particleExample = (particleExample + 1) % NUM_PARTICLE_EXAMPLES;
switch (particleExample) {
case 0:
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 },
radiusSpread: 0.0,
animationIsPlaying: true
});
break;
case 1:
print("Velocity spread");
Entities.editEntity(particles, {
velocitySpread: { x: 0.1, y: 0.0, z: 0.1 }
});
break;
case 2:
print("Acceleration spread");
Entities.editEntity(particles, {
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
accelerationSpread: { x: 0.0, y: 0.1, z: 0.0 }
});
break;
case 3:
print("Radius spread");
Entities.editEntity(particles, {
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
radiusSpread: 0.035
});
break;
case 4:
print("Radius start and finish");
Entities.editEntity(particles, {
radiusSpread: 0.0,
radiusStart: 0.0,
radiusFinish: 0.0
});
break;
case 5:
print("Alpha 0.5");
Entities.editEntity(particles, {
radiusStart: PARTICLE_RADIUS,
radiusFinish: PARTICLE_RADIUS,
alpha: 0.5
});
break;
case 6:
print("Alpha spread");
Entities.editEntity(particles, {
alpha: 0.5,
alphaSpread: 0.5
});
break;
case 7:
print("Alpha start and finish");
Entities.editEntity(particles, {
alphaSpread: 0.0,
alpha: 1.0,
alphaStart: 0.0,
alphaFinish: 0.0
});
break;
case 8:
print("Color spread");
Entities.editEntity(particles, {
alpha: 1.0,
alphaStart: 1.0,
alphaFinish: 1.0,
color: { red: 128, green: 128, blue: 128 },
colorSpread: { red: 128, green: 0, blue: 0 }
});
break;
case 9:
print("Color start and finish");
Entities.editEntity(particles, {
color: { red: 255, green: 255, blue: 255 },
colorSpread: { red: 0, green: 0, blue: 0 },
colorStart: { red: 255, green: 0, blue: 0 },
colorFinish: { red: 0, green: 255, blue: 0 }
});
break;
case 10:
print("Stop emitting");
Entities.editEntity(particles, {
colorStart: { red: 255, green: 255, blue: 255 },
colorFinish: { red: 255, green: 255, blue: 255 },
animationIsPlaying: false
});
break;
}
}
}
function setUp() {
var spawnPoint = Vec3.sum(MyAvatar.position, Vec3.multiply(4.0, Quat.getFront(Camera.getOrientation()))),
animation = {
fps: 30,
frameIndex: 0,
running: true,
firstFrame: 0,
lastFrame: 30,
loop: true
};
box = Entities.addEntity({
type: "Box",
position: spawnPoint,
dimensions: { x: 0.3, y: 0.3, z: 0.3 },
color: { red: 128, green: 128, blue: 128 },
lifetime: 3600 // 1 hour; just in case
});
particles = Entities.addEntity({
type: "ParticleEffect",
position: spawnPoint,
particleRadius: PARTICLE_RADIUS,
radiusSpread: 0.0,
emitRate: 2.0,
emitVelocity: { x: 0.0, y: 1.0, z: 0.0 },
velocitySpread: { x: 0.0, y: 0.0, z: 0.0 },
emitAcceleration: { x: 0.0, y: -0.3, z: 0.0 },
accelerationSpread: { x: 0.0, y: 0.0, z: 0.0 },
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
color: { red: 255, green: 255, blue: 255 },
lifespan: 5.0,
visible: true,
locked: false,
animationSettings: animation,
animationIsPlaying: false,
lifetime: 3600 // 1 hour; just in case
});
Entities.clickDownOnEntity.connect(onClickDownOnEntity);
print("Click on the box to cycle through particle examples");
}
function tearDown() {
Entities.clickDownOnEntity.disconnect(onClickDownOnEntity);
Entities.deleteEntity(particles);
Entities.deleteEntity(box);
}
setUp();
Script.scriptEnding.connect(tearDown);
}());

View file

@ -43,7 +43,7 @@
emitVelocity: {x: 0, y: 5, z: 0},
velocitySpread: {x: 2, y: 0, z: 2},
emitAcceleration: {x: 0, y: -9.8, z: 0},
textures: "https://raw.githubusercontent.com/ericrius1/SantasLair/santa/assets/smokeparticle.png",
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
color: color,
lifespan: 1.0,
visible: true,

View file

@ -168,50 +168,59 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) {
updateRenderItem();
}
static glm::vec3 zSortAxis;
static bool zSort(const glm::vec3& rhs, const glm::vec3& lhs) {
return glm::dot(rhs, ::zSortAxis) > glm::dot(lhs, ::zSortAxis);
}
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:
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 ParticleDetails& rhs, const ParticleDetails& lhs) {
return glm::dot(rhs.position, ::zSortAxis) > glm::dot(lhs.position, ::zSortAxis);
}
void RenderableParticleEffectEntityItem::updateRenderItem() {
if (!_scene) {
return;
}
float particleRadius = getParticleRadius();
auto xcolor = getXColor();
auto alpha = (uint8_t)(glm::clamp(getLocalRenderAlpha(), 0.0f, 1.0f) * 255.0f);
auto rgba = toRGBA(xcolor.red, xcolor.green, xcolor.blue, alpha);
// make a copy of each particle position
std::vector<glm::vec3> positions;
positions.reserve(getLivingParticleCount());
// make a copy of each particle's details
std::vector<ParticleDetails> particleDetails;
particleDetails.reserve(getLivingParticleCount());
for (quint32 i = _particleHeadIndex; i != _particleTailIndex; i = (i + 1) % _maxParticles) {
positions.push_back(_particlePositions[i]);
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));
}
// sort particles back to front
// NOTE: this is view frustum might be one frame out of date.
auto frustum = AbstractViewStateInterface::instance()->getCurrentViewFrustum();
::zSortAxis = frustum->getDirection();
qSort(positions.begin(), positions.end(), zSort);
qSort(particleDetails.begin(), particleDetails.end(), zSort);
// allocate vertices
_vertices.clear();
// build vertices from particle positions
const glm::vec3 upOffset = frustum->getUp() * particleRadius;
const glm::vec3 rightOffset = frustum->getRight() * particleRadius;
for (auto&& pos : positions) {
// build vertices from particle positions and radiuses
const glm::vec3 up = frustum->getUp();
const glm::vec3 right = frustum->getRight();
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(pos + rightOffset + upOffset, glm::vec2(1.0f, 1.0f), rgba);
_vertices.emplace_back(pos - rightOffset + upOffset, glm::vec2(0.0f, 1.0f), rgba);
_vertices.emplace_back(pos - rightOffset - upOffset, glm::vec2(0.0f, 0.0f), rgba);
_vertices.emplace_back(pos + rightOffset - upOffset, glm::vec2(1.0f, 0.0f), rgba);
_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,13 @@ 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(colorSpread, ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD),
CONSTRUCT_PROPERTY(colorStart, ParticleEffectEntityItem::DEFAULT_COLOR),
CONSTRUCT_PROPERTY(colorFinish, ParticleEffectEntityItem::DEFAULT_COLOR),
CONSTRUCT_PROPERTY(alpha, ENTITY_ITEM_DEFAULT_ALPHA),
CONSTRUCT_PROPERTY(alphaSpread, ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD),
CONSTRUCT_PROPERTY(alphaStart, ParticleEffectEntityItem::DEFAULT_ALPHA_START),
CONSTRUCT_PROPERTY(alphaFinish, ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH),
CONSTRUCT_PROPERTY(modelURL, ""),
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
CONSTRUCT_PROPERTY(animationURL, ""),
@ -89,6 +96,9 @@ CONSTRUCT_PROPERTY(velocitySpread, ParticleEffectEntityItem::DEFAULT_VELOCITY_SP
CONSTRUCT_PROPERTY(emitAcceleration, ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION),
CONSTRUCT_PROPERTY(accelerationSpread, ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD),
CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS),
CONSTRUCT_PROPERTY(radiusSpread, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD),
CONSTRUCT_PROPERTY(radiusStart, ParticleEffectEntityItem::DEFAULT_RADIUS_START),
CONSTRUCT_PROPERTY(radiusFinish, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH),
CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID),
CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR),
CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY),
@ -328,6 +338,13 @@ 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_COLOR_SPREAD, colorSpread);
CHECK_PROPERTY_CHANGE(PROP_COLOR_START, colorStart);
CHECK_PROPERTY_CHANGE(PROP_COLOR_FINISH, colorFinish);
CHECK_PROPERTY_CHANGE(PROP_ALPHA, alpha);
CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread);
CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart);
CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish);
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
@ -362,6 +379,9 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_EMIT_ACCELERATION, emitAcceleration);
CHECK_PROPERTY_CHANGE(PROP_ACCELERATION_SPREAD, accelerationSpread);
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius);
CHECK_PROPERTY_CHANGE(PROP_RADIUS_SPREAD, radiusSpread);
CHECK_PROPERTY_CHANGE(PROP_RADIUS_START, radiusStart);
CHECK_PROPERTY_CHANGE(PROP_RADIUS_FINISH, radiusFinish);
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
CHECK_PROPERTY_CHANGE(PROP_NAME, name);
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, keyLightColor);
@ -439,6 +459,13 @@ 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(colorSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(colorStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(colorFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(alpha);
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(alphaFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
@ -471,6 +498,9 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(emitAcceleration);
COPY_PROPERTY_TO_QSCRIPTVALUE(accelerationSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusSpread);
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusStart);
COPY_PROPERTY_TO_QSCRIPTVALUE(radiusFinish);
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
COPY_PROPERTY_TO_QSCRIPTVALUE(name);
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL);
@ -569,6 +599,13 @@ 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(colorSpread, xColor, setColorSpread);
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorStart, xColor, setColorStart);
COPY_PROPERTY_FROM_QSCRIPTVALUE(colorFinish, xColor, setColorFinish);
COPY_PROPERTY_FROM_QSCRIPTVALUE(alpha, float, setAlpha);
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread);
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart);
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish);
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(animationURL, QString, setAnimationURL);
@ -600,6 +637,9 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitAcceleration, glmVec3, setEmitAcceleration);
COPY_PROPERTY_FROM_QSCRIPTVALUE(accelerationSpread, glmVec3, setAccelerationSpread);
COPY_PROPERTY_FROM_QSCRIPTVALUE(particleRadius, float, setParticleRadius);
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusSpread, float, setRadiusSpread);
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusStart, float, setRadiusStart);
COPY_PROPERTY_FROM_QSCRIPTVALUE(radiusFinish, float, setRadiusFinish);
COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
@ -850,7 +890,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType::Value command, Ent
APPEND_ENTITY_PROPERTY(PROP_EMIT_ACCELERATION, properties.getEmitAcceleration());
APPEND_ENTITY_PROPERTY(PROP_ACCELERATION_SPREAD, properties.getAccelerationSpread());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius());
APPEND_ENTITY_PROPERTY(PROP_RADIUS_SPREAD, properties.getRadiusSpread());
APPEND_ENTITY_PROPERTY(PROP_RADIUS_START, properties.getRadiusStart());
APPEND_ENTITY_PROPERTY(PROP_RADIUS_FINISH, properties.getRadiusFinish());
APPEND_ENTITY_PROPERTY(PROP_COLOR_SPREAD, properties.getColorSpread());
APPEND_ENTITY_PROPERTY(PROP_COLOR_START, properties.getColorStart());
APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, properties.getColorFinish());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish());
}
if (properties.getType() == EntityTypes::Zone) {
@ -901,11 +949,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();
@ -1126,6 +1174,15 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_ACCELERATION, glm::vec3, setEmitAcceleration);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ACCELERATION_SPREAD, glm::vec3, setAccelerationSpread);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_SPREAD, float, setRadiusSpread);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_START, float, setRadiusStart);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_RADIUS_FINISH, float, setRadiusFinish);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_SPREAD, xColor, setColorSpread);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_START, xColor, setColorStart);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLOR_FINISH, xColor, setColorFinish);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish);
}
if (properties.getType() == EntityTypes::Zone) {
@ -1175,6 +1232,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;
}
@ -1231,6 +1289,7 @@ void EntityItemProperties::markAllChanged() {
_nameChanged = true;
_visibleChanged = true;
_colorChanged = true;
_alphaChanged = true;
_modelURLChanged = true;
_compoundShapeURLChanged = true;
_animationURLChanged = true;
@ -1264,6 +1323,15 @@ void EntityItemProperties::markAllChanged() {
_emitAccelerationChanged = true;
_accelerationSpreadChanged = true;
_particleRadiusChanged = true;
_radiusSpreadChanged = true;
_radiusStartChanged = true;
_radiusFinishChanged = true;
_colorSpreadChanged = true;
_colorStartChanged = true;
_colorFinishChanged = true;
_alphaSpreadChanged = true;
_alphaStartChanged = true;
_alphaFinishChanged = true;
_marketplaceIDChanged = true;

View file

@ -103,6 +103,13 @@ 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_REF(PROP_COLOR_SPREAD, ColorSpread, colorSpread, xColor);
DEFINE_PROPERTY_REF(PROP_COLOR_START, ColorStart, colorStart, xColor);
DEFINE_PROPERTY_REF(PROP_COLOR_FINISH, ColorFinish, colorFinish, xColor);
DEFINE_PROPERTY(PROP_ALPHA, Alpha, alpha, float);
DEFINE_PROPERTY(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float);
DEFINE_PROPERTY(PROP_ALPHA_START, AlphaStart, alphaStart, float);
DEFINE_PROPERTY(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, 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);
@ -136,6 +143,9 @@ public:
DEFINE_PROPERTY(PROP_EMIT_ACCELERATION, EmitAcceleration, emitAcceleration, glm::vec3);
DEFINE_PROPERTY(PROP_ACCELERATION_SPREAD, AccelerationSpread, accelerationSpread, glm::vec3);
DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float);
DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float);
DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float);
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float);
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
@ -291,6 +301,13 @@ 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, ColorSpread, colorSpread, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorStart, colorStart, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ColorFinish, colorFinish, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Alpha, alpha, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaSpread, alphaSpread, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaStart, alphaStart, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AlphaFinish, alphaFinish, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");
@ -322,6 +339,9 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
DEBUG_PROPERTY_IF_CHANGED(debug, properties, EmitAcceleration, emitAcceleration, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AccelerationSpread, accelerationSpread, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ParticleRadius, particleRadius, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusSpread, radiusSpread, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusStart, radiusStart, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, RadiusFinish, radiusFinish, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, MarketplaceID, marketplaceID, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, BackgroundMode, backgroundMode, "");
DEBUG_PROPERTY_IF_CHANGED(debug, properties, VoxelVolumeSize, voxelVolumeSize, "");

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

@ -146,6 +146,21 @@ enum EntityPropertyList {
PROP_Y_P_NEIGHBOR_ID, // used by PolyVox
PROP_Z_P_NEIGHBOR_ID, // used by PolyVox
// Used by particles
PROP_RADIUS_SPREAD,
PROP_RADIUS_START,
PROP_RADIUS_FINISH,
PROP_ALPHA, // Supported by some derived classes
//Used by particles
PROP_COLOR_SPREAD,
PROP_COLOR_START,
PROP_COLOR_FINISH,
PROP_ALPHA_SPREAD,
PROP_ALPHA_START,
PROP_ALPHA_FINISH,
////////////////////////////////////////////////////////////////////////////////////////////////////
// ATTENTION: add new properties to end of list just ABOVE this line
PROP_AFTER_LAST_ITEM,

View file

@ -43,6 +43,11 @@
#include "ParticleEffectEntityItem.h"
const xColor ParticleEffectEntityItem::DEFAULT_COLOR = { 255, 255, 255 };
const xColor ParticleEffectEntityItem::DEFAULT_COLOR_SPREAD = { 0, 0, 0 };
const float ParticleEffectEntityItem::DEFAULT_ALPHA = 1.0f;
const float ParticleEffectEntityItem::DEFAULT_ALPHA_SPREAD = 0.0f;
const float ParticleEffectEntityItem::DEFAULT_ALPHA_START = DEFAULT_ALPHA;
const float ParticleEffectEntityItem::DEFAULT_ALPHA_FINISH = DEFAULT_ALPHA;
const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f;
const bool ParticleEffectEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
const float ParticleEffectEntityItem::DEFAULT_ANIMATION_FPS = 30.0f;
@ -54,6 +59,9 @@ const glm::vec3 ParticleEffectEntityItem::DEFAULT_VELOCITY_SPREAD(3.0f, 0.0f, 3.
const glm::vec3 ParticleEffectEntityItem::DEFAULT_EMIT_ACCELERATION(0.0f, -9.8f, 0.0f);
const glm::vec3 ParticleEffectEntityItem::DEFAULT_ACCELERATION_SPREAD(0.0f, 0.0f, 0.0f);
const float ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS = 0.025f;
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 = "";
@ -72,16 +80,42 @@ ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityIte
_emitAcceleration(DEFAULT_EMIT_ACCELERATION),
_accelerationSpread(DEFAULT_ACCELERATION_SPREAD),
_particleRadius(DEFAULT_PARTICLE_RADIUS),
_radiusSpread(DEFAULT_RADIUS_SPREAD),
_radiusStart(DEFAULT_RADIUS_START),
_radiusFinish(DEFAULT_RADIUS_FINISH),
_lastAnimated(usecTimestampNow()),
_animationLoop(),
_animationSettings(),
_textures(DEFAULT_TEXTURES),
_texturesChangedFlag(false),
_shapeType(SHAPE_TYPE_NONE),
_colorSpread(DEFAULT_COLOR_SPREAD),
_colorStart(DEFAULT_COLOR),
_colorFinish(DEFAULT_COLOR),
_isColorStartInitialized(false),
_isColorFinishInitialized(false),
_alpha(DEFAULT_ALPHA),
_alphaSpread(DEFAULT_ALPHA_SPREAD),
_alphaStart(DEFAULT_ALPHA_START),
_alphaFinish(DEFAULT_ALPHA_FINISH),
_isAlphaStartInitialized(false),
_isAlphaFinishInitialized(false),
_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)),
_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),
_timeUntilNextEmit(0.0f),
_particleHeadIndex(0),
_particleTailIndex(0),
@ -97,10 +131,6 @@ ParticleEffectEntityItem::~ParticleEffectEntityItem() {
}
void ParticleEffectEntityItem::setLifespan(float lifespan) {
_lifespan = lifespan;
}
void ParticleEffectEntityItem::setEmitVelocity(const glm::vec3& emitVelocity) {
_emitVelocity = emitVelocity;
computeAndUpdateDimensions();
@ -111,7 +141,6 @@ void ParticleEffectEntityItem::setVelocitySpread(const glm::vec3& velocitySpread
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::setEmitAcceleration(const glm::vec3& emitAcceleration) {
_emitAcceleration = emitAcceleration;
computeAndUpdateDimensions();
@ -122,10 +151,6 @@ void ParticleEffectEntityItem::setAccelerationSpread(const glm::vec3& accelerati
computeAndUpdateDimensions();
}
void ParticleEffectEntityItem::setParticleRadius(float particleRadius) {
_particleRadius = particleRadius;
}
void ParticleEffectEntityItem::computeAndUpdateDimensions() {
const float time = _lifespan * 1.1f; // add 10% extra time to account for incremental timer accumulation error
@ -153,6 +178,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);
@ -163,9 +189,19 @@ EntityItemProperties ParticleEffectEntityItem::getProperties() const {
COPY_ENTITY_PROPERTY_TO_PROPERTIES(lifespan, getLifespan);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitRate, getEmitRate);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitVelocity, getEmitVelocity);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(velocitySpread, getVelocitySpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitAcceleration, getEmitAcceleration);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(accelerationSpread, getAccelerationSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleRadius, getParticleRadius);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusSpread, getRadiusSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusStart, getRadiusStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(radiusFinish, getRadiusFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorSpread, getColorSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorStart, getColorStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(colorFinish, getColorFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaSpread, getAlphaSpread);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish);
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
return properties;
@ -175,6 +211,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);
@ -185,11 +222,20 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifespan, setLifespan);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitRate, setEmitRate);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitVelocity, setEmitVelocity);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocitySpread, setVelocitySpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitAcceleration, setEmitAcceleration);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(accelerationSpread, setAccelerationSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleRadius, setParticleRadius);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusSpread, setRadiusSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusStart, setRadiusStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(radiusFinish, setRadiusFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorSpread, setColorSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorStart, setColorStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(colorFinish, setColorFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaSpread, setAlphaSpread);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(velocitySpread, setVelocitySpread);
if (somethingChanged) {
bool wantDebug = false;
@ -257,6 +303,22 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
READ_ENTITY_PROPERTY(PROP_TEXTURES, QString, setTextures);
}
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);
}
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES) {
READ_ENTITY_PROPERTY(PROP_COLOR_SPREAD, xColor, setColorSpread);
READ_ENTITY_PROPERTY(PROP_COLOR_START, xColor, setColorStart);
READ_ENTITY_PROPERTY(PROP_COLOR_FINISH, xColor, setColorFinish);
READ_ENTITY_PROPERTY(PROP_ALPHA, float, setAlpha);
READ_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, float, setAlphaSpread);
READ_ENTITY_PROPERTY(PROP_ALPHA_START, float, setAlphaStart);
READ_ENTITY_PROPERTY(PROP_ALPHA_FINISH, float, setAlphaFinish);
}
return bytesRead;
}
@ -280,6 +342,16 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
requestedProperties += PROP_PARTICLE_RADIUS;
requestedProperties += PROP_TEXTURES;
requestedProperties += PROP_VELOCITY_SPREAD;
requestedProperties += PROP_RADIUS_SPREAD;
requestedProperties += PROP_RADIUS_START;
requestedProperties += PROP_RADIUS_FINISH;
requestedProperties += PROP_COLOR_SPREAD;
requestedProperties += PROP_COLOR_START;
requestedProperties += PROP_COLOR_FINISH;
requestedProperties += PROP_ALPHA;
requestedProperties += PROP_ALPHA_SPREAD;
requestedProperties += PROP_ALPHA_START;
requestedProperties += PROP_ALPHA_FINISH;
return requestedProperties;
}
@ -308,6 +380,16 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, getParticleRadius());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, getTextures());
APPEND_ENTITY_PROPERTY(PROP_VELOCITY_SPREAD, getVelocitySpread());
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_COLOR_SPREAD, getColorSpread());
APPEND_ENTITY_PROPERTY(PROP_COLOR_START, getColorStart());
APPEND_ENTITY_PROPERTY(PROP_COLOR_FINISH, getColorFinish());
APPEND_ENTITY_PROPERTY(PROP_ALPHA, getAlpha());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, getAlphaSpread());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, getAlphaStart());
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, getAlphaFinish());
}
bool ParticleEffectEntityItem::isAnimatingSomething() const {
@ -477,6 +559,27 @@ QString ParticleEffectEntityItem::getAnimationSettings() const {
return jsonByteString;
}
void ParticleEffectEntityItem::updateRadius(quint32 index, float age) {
_particleRadiuses[index] = interpolate(_radiusStarts[index], _radiusMiddles[index], _radiusFinishes[index], age);
}
void ParticleEffectEntityItem::updateColor(quint32 index, float age) {
_particleColors[index].red =
(int)glm::clamp(interpolate(_colorStarts[index].red, _colorMiddles[index].red, _colorFinishes[index].red, age),
0.0f, 255.0f);
_particleColors[index].green =
(int)glm::clamp(interpolate(_colorStarts[index].green, _colorMiddles[index].green, _colorFinishes[index].green, age),
0.0f, 255.0f);
_particleColors[index].blue =
(int)glm::clamp(interpolate(_colorStarts[index].blue, _colorMiddles[index].blue, _colorFinishes[index].blue, age),
0.0f, 255.0f);
}
void ParticleEffectEntityItem::updateAlpha(quint32 index, float age) {
_particleAlphas[index] = glm::clamp(interpolate(_alphaStarts[index], _alphaMiddles[index], _alphaFinishes[index], age),
0.0f, 1.0f);
}
void ParticleEffectEntityItem::extendBounds(const glm::vec3& point) {
_particleMinBound.x = glm::min(_particleMinBound.x, point.x);
_particleMinBound.y = glm::min(_particleMinBound.y, point.y);
@ -509,12 +612,16 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_particleHeadIndex = (_particleHeadIndex + 1) % _maxParticles;
}
else {
float age = (1.0f - _particleLifetimes[i] / _lifespan); // 0.0 .. 1.0
updateRadius(i, age);
updateColor(i, age);
updateAlpha(i, age);
integrateParticle(i, deltaTime);
extendBounds(_particlePositions[i]);
}
}
// emit new particles, but only if animaiton is playing
// emit new particles, but only if animation is playing
if (getAnimationIsPlaying()) {
float timeLeftInFrame = deltaTime;
@ -527,12 +634,24 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
quint32 i = _particleTailIndex;
_particleLifetimes[i] = _lifespan;
// Radius
if (_radiusSpread == 0.0f) {
_radiusStarts[i] = getRadiusStart();
_radiusMiddles[i] =_particleRadius;
_radiusFinishes[i] = getRadiusFinish();
} else {
float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _radiusSpread / _particleRadius;
_radiusStarts[i] = spreadMultiplier * getRadiusStart();
_radiusMiddles[i] = spreadMultiplier * _particleRadius;
_radiusFinishes[i] = spreadMultiplier * getRadiusFinish();
}
updateRadius(i, 0.0f);
// Velocity and acceleration
glm::vec3 spreadOffset;
spreadOffset.x = -_velocitySpread.x + randFloat() * (_velocitySpread.x * 2.0f);
spreadOffset.y = -_velocitySpread.y + randFloat() * (_velocitySpread.y * 2.0f);
spreadOffset.z = -_velocitySpread.z + randFloat() * (_velocitySpread.z * 2.0f);
// set initial conditions
_particlePositions[i] = getPosition();
@ -547,6 +666,48 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
integrateParticle(i, timeLeftInFrame);
extendBounds(_particlePositions[i]);
// Color
if (_colorSpread == xColor{ 0, 0, 0 }) {
_colorStarts[i] = getColorStart();
_colorMiddles[i] = getXColor();
_colorFinishes[i] = getColorFinish();
} else {
xColor startColor = getColorStart();
xColor middleColor = getXColor();
xColor finishColor = getColorFinish();
float spread = 2.0f * randFloat() - 1.0f;
float spreadMultiplierRed = 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red;
float spreadMultiplierGreen = 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green;
float spreadMultiplierBlue = 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue;
_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);
_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);
_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);
}
updateColor(i, 0.0f);
// Alpha
if (_alphaSpread == 0.0f) {
_alphaStarts[i] = getAlphaStart();
_alphaMiddles[i] = _alpha;
_alphaFinishes[i] = getAlphaFinish();
} else {
float spreadMultiplier = 1.0f + (2.0f * randFloat() - 1) * _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.
@ -571,8 +732,20 @@ void ParticleEffectEntityItem::setMaxParticles(quint32 maxParticles) {
_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);
// effectivly clear all particles and start emitting new ones from scratch.
// effectively clear all particles and start emitting new ones from scratch.
_particleHeadIndex = 0;
_particleTailIndex = 0;
_timeUntilNextEmit = 0.0f;
@ -587,3 +760,42 @@ quint32 ParticleEffectEntityItem::getLivingParticleCount() const {
return (_maxParticles - _particleHeadIndex) + _particleTailIndex;
}
}
float ParticleEffectEntityItem::cubicInterpolate(float y0, float y1, float y2, float y3, float u) {
float a0, a1, a2, a3, uu;
uu = u * u;
a0 = y3 - y2 - y0 + y1;
a1 = y0 - y1 - a0;
a2 = y2 - y0;
a3 = y1;
return (a0 * u * uu + a1 * uu + a2 * u + a3);
}
float ParticleEffectEntityItem::interpolate(float start, float middle, float finish, float age) {
float y0, y1, y2, y3, u;
if (age <= 0.5f) {
if (start == middle) {
return middle;
}
y1 = start;
y2 = middle;
y3 = finish;
y0 = 2.0f * y1 - y2;
u = 2.0f * age;
} else {
if (middle == finish) {
return middle;
}
y0 = start;
y1 = middle;
y2 = finish;
y3 = 2.0f * y2 - y1;
u = 2.0f * age - 1.0f;
}
return cubicInterpolate(y0, y1, y2, y3, u);
}

View file

@ -56,6 +56,36 @@ public:
_color[BLUE_INDEX] = value.blue;
}
bool _isColorStartInitialized;
void setColorStart(const xColor& colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; }
xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); }
bool _isColorFinishInitialized;
void setColorFinish(const xColor& colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; }
xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); }
static const xColor DEFAULT_COLOR_SPREAD;
void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; }
xColor getColorSpread() const { return _colorSpread; }
static const float DEFAULT_ALPHA;
void setAlpha(float alpha) { _alpha = alpha; }
float getAlpha() const { return _alpha; }
static const float DEFAULT_ALPHA_START;
bool _isAlphaStartInitialized;
void setAlphaStart(float alphaStart) { _alphaStart = alphaStart; _isAlphaStartInitialized = true; }
float getAlphaStart() const { return _isAlphaStartInitialized ? _alphaStart : _alpha; }
static const float DEFAULT_ALPHA_FINISH;
bool _isAlphaFinishInitialized;
void setAlphaFinish(float alphaFinish) { _alphaFinish = alphaFinish; _isAlphaFinishInitialized = true; }
float getAlphaFinish() const { return _isAlphaFinishInitialized ? _alphaFinish : _alpha; }
static const float DEFAULT_ALPHA_SPREAD;
void setAlphaSpread(float alphaSpread) { _alphaSpread = alphaSpread; }
float getAlphaSpread() const { return _alphaSpread; }
void updateShapeType(ShapeType type);
virtual ShapeType getShapeType() const { return _shapeType; }
@ -91,7 +121,7 @@ public:
quint32 getMaxParticles() const { return _maxParticles; }
static const float DEFAULT_LIFESPAN;
void setLifespan(float lifespan);
void setLifespan(float lifespan) { _lifespan = lifespan; }
float getLifespan() const { return _lifespan; }
static const float DEFAULT_EMIT_RATE;
@ -102,12 +132,10 @@ public:
void setEmitVelocity(const glm::vec3& emitVelocity);
const glm::vec3& getEmitVelocity() const { return _emitVelocity; }
static const glm::vec3 DEFAULT_VELOCITY_SPREAD;
void setVelocitySpread(const glm::vec3& velocitySpread);
const glm::vec3& getVelocitySpread() const { return _velocitySpread; }
static const glm::vec3 DEFAULT_EMIT_ACCELERATION;
void setEmitAcceleration(const glm::vec3& emitAcceleration);
const glm::vec3& getEmitAcceleration() const { return _emitAcceleration; }
@ -117,9 +145,23 @@ public:
const glm::vec3& getAccelerationSpread() const { return _accelerationSpread; }
static const float DEFAULT_PARTICLE_RADIUS;
void setParticleRadius(float particleRadius);
void setParticleRadius(float particleRadius) { _particleRadius = particleRadius; }
float getParticleRadius() const { return _particleRadius; }
static const float DEFAULT_RADIUS_START;
bool _isRadiusStartInitialized;
void setRadiusStart(float radiusStart) { _radiusStart = radiusStart; _isRadiusStartInitialized = true; }
float getRadiusStart() const { return _isRadiusStartInitialized ? _radiusStart : _particleRadius; }
static const float DEFAULT_RADIUS_FINISH;
bool _isRadiusFinishInitialized;
void setRadiusFinish(float radiusFinish) { _radiusFinish = radiusFinish; _isRadiusFinishInitialized = true; }
float getRadiusFinish() const { return _isRadiusFinishInitialized ? _radiusFinish : _particleRadius; }
static const float DEFAULT_RADIUS_SPREAD;
void setRadiusSpread(float radiusSpread) { _radiusSpread = radiusSpread; }
float getRadiusSpread() const { return _radiusSpread; }
void computeAndUpdateDimensions();
@ -141,12 +183,22 @@ protected:
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 extendBounds(const glm::vec3& point);
void integrateParticle(quint32 index, float deltaTime);
quint32 getLivingParticleCount() const;
// the properties of this entity
rgbColor _color;
xColor _colorStart;
xColor _colorFinish;
xColor _colorSpread;
float _alpha;
float _alphaStart;
float _alphaFinish;
float _alphaSpread;
quint32 _maxParticles;
float _lifespan;
float _emitRate;
@ -155,6 +207,9 @@ protected:
glm::vec3 _emitAcceleration;
glm::vec3 _accelerationSpread;
float _particleRadius;
float _radiusStart;
float _radiusFinish;
float _radiusSpread;
quint64 _lastAnimated;
AnimationLoop _animationLoop;
QString _animationSettings;
@ -167,9 +222,22 @@ protected:
QVector<glm::vec3> _particlePositions;
QVector<glm::vec3> _particleVelocities;
QVector<glm::vec3> _particleAccelerations;
QVector<float> _particleRadiuses;
QVector<float> _radiusStarts;
QVector<float> _radiusMiddles;
QVector<float> _radiusFinishes;
QVector<xColor> _particleColors;
QVector<xColor> _colorStarts;
QVector<xColor> _colorMiddles;
QVector<xColor> _colorFinishes;
QVector<float> _particleAlphas;
QVector<float> _alphaStarts;
QVector<float> _alphaMiddles;
QVector<float> _alphaFinishes;
float _timeUntilNextEmit;
// particle arrays are a ring buffer, use these indicies
// particle arrays are a ring buffer, use these indices
// to keep track of the living particles.
quint32 _particleHeadIndex;
quint32 _particleTailIndex;
@ -177,6 +245,10 @@ protected:
// bounding volume
glm::vec3 _particleMaxBound;
glm::vec3 _particleMinBound;
private:
float cubicInterpolate(float y0, float y1, float y2, float y3, float u);
float interpolate(float start, float middle, float finish, float age);
};
#endif // hifi_ParticleEffectEntityItem_h

View file

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

View file

@ -145,5 +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_PROPERTIES = 41;
const PacketVersion VERSION_ENTITIES_PARTICLE_COLOR_PROPERTIES = 42;
#endif // hifi_PacketHeaders_h