From 1c1b68ee6633e26a428eeda0211322fbb602e5a4 Mon Sep 17 00:00:00 2001 From: SamGondelman Date: Wed, 25 Jul 2018 19:04:02 -0700 Subject: [PATCH] emitterShouldTrail fix, review comments, rotateWithEntity --- .../RenderableParticleEffectEntityItem.cpp | 46 +++++++++++-------- .../src/RenderableParticleEffectEntityItem.h | 11 +++-- .../src/textured_particle.slv | 30 +++++++----- .../entities/src/EntityItemProperties.cpp | 23 ++++++++-- libraries/entities/src/EntityItemProperties.h | 3 +- libraries/entities/src/EntityPropertyFlags.h | 1 + .../entities/src/ParticleEffectEntityItem.cpp | 12 +++++ .../entities/src/ParticleEffectEntityItem.h | 6 +++ libraries/gpu/src/gpu/Transform.slh | 2 +- .../particle_explorer/particleExplorer.js | 8 ++++ 10 files changed, 99 insertions(+), 43 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index 89c2f0dccf..73f46245c4 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -101,6 +101,10 @@ void ParticleEffectEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePoi _timeUntilNextEmit = 0; withWriteLock([&]{ _particleProperties = newParticleProperties; + if (!_prevEmitterShouldTrailInitialized) { + _prevEmitterShouldTrailInitialized = true; + _prevEmitterShouldTrail = _particleProperties.emission.shouldTrail; + } }); } _emitting = entity->getIsEmitting(); @@ -149,6 +153,7 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn particleUniforms.spin.finish = _particleProperties.spin.range.finish; particleUniforms.spin.spread = _particleProperties.spin.gradient.spread; particleUniforms.lifespan = _particleProperties.lifespan; + particleUniforms.rotateWithEntity = _particleProperties.rotateWithEntity ? 1 : 0; }); // Update particle uniforms memcpy(&_uniformBuffer.edit(), &particleUniforms, sizeof(ParticleUniforms)); @@ -180,7 +185,7 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa const auto& azimuthFinish = particleProperties.azimuth.finish; const auto& emitDimensions = particleProperties.emission.dimensions; const auto& emitAcceleration = particleProperties.emission.acceleration.target; - auto emitOrientation = particleProperties.emission.orientation; + auto emitOrientation = baseTransform.getRotation() * particleProperties.emission.orientation; const auto& emitRadiusStart = glm::max(particleProperties.radiusStart, EPSILON); // Avoid math complications at center const auto& emitSpeed = particleProperties.emission.speed.target; const auto& speedSpread = particleProperties.emission.speed.spread; @@ -189,10 +194,9 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa particle.seed = randFloatInRange(-1.0f, 1.0f); particle.expiration = now + (uint64_t)(particleProperties.lifespan * USECS_PER_SECOND); - if (particleProperties.emission.shouldTrail) { - particle.position = baseTransform.getTranslation(); - emitOrientation = baseTransform.getRotation() * emitOrientation; - } + + particle.relativePosition = glm::vec3(0.0f); + particle.basePosition = baseTransform.getTranslation(); // Position, velocity, and acceleration if (polarStart == 0.0f && polarFinish == 0.0f && emitDimensions.z == 0.0f) { @@ -241,7 +245,7 @@ ParticleEffectEntityRenderer::CpuParticle ParticleEffectEntityRenderer::createPa 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; + particle.relativePosition += emitOrientation * emitPosition; } particle.velocity = (emitSpeed + randFloatInRange(-1.0f, 1.0f) * speedSpread) * (emitOrientation * emitDirection); @@ -266,8 +270,8 @@ void ParticleEffectEntityRenderer::stepSimulation() { particleProperties = _particleProperties; }); + const auto& modelTransform = getModelTransform(); if (_emitting && particleProperties.emitting()) { - const auto& modelTransform = getModelTransform(); uint64_t emitInterval = particleProperties.emitIntervalUsecs(); if (emitInterval > 0 && interval >= _timeUntilNextEmit) { auto timeRemaining = interval; @@ -292,15 +296,23 @@ void ParticleEffectEntityRenderer::stepSimulation() { const float deltaTime = (float)interval / (float)USECS_PER_SECOND; // update the particles for (auto& particle : _cpuParticles) { + if (_prevEmitterShouldTrail != particleProperties.emission.shouldTrail) { + if (_prevEmitterShouldTrail) { + particle.relativePosition = particle.relativePosition + particle.basePosition - modelTransform.getTranslation(); + } + particle.basePosition = modelTransform.getTranslation(); + } particle.integrate(deltaTime); } + _prevEmitterShouldTrail = particleProperties.emission.shouldTrail; // Build particle primitives static GpuParticles gpuParticles; gpuParticles.clear(); gpuParticles.reserve(_cpuParticles.size()); // Reserve space - std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [](const CpuParticle& particle) { - return GpuParticle(particle.position, glm::vec2(particle.lifetime, particle.seed)); + std::transform(_cpuParticles.begin(), _cpuParticles.end(), std::back_inserter(gpuParticles), [&particleProperties, &modelTransform](const CpuParticle& particle) { + glm::vec3 position = particle.relativePosition + (particleProperties.emission.shouldTrail ? particle.basePosition : modelTransform.getTranslation()); + return GpuParticle(position, glm::vec2(particle.lifetime, particle.seed)); }); // Update particle buffer @@ -328,15 +340,11 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) { } Transform transform; - // In trail mode, the particles are created in world space. - // so we only set a transform if they're not in trail mode - if (!_particleProperties.emission.shouldTrail) { - - withReadLock([&] { - transform = _renderTransform; - }); - transform.setScale(vec3(1)); - } + // The particles are in world space, so the transform is unused, except for the rotation, which we use + // if the particles are marked rotateWithEntity + withReadLock([&] { + transform.setRotation(_renderTransform.getRotation()); + }); batch.setModelTransform(transform); batch.setUniformBuffer(PARTICLE_UNIFORM_SLOT, _uniformBuffer); batch.setInputFormat(_vertexFormat); @@ -345,5 +353,3 @@ void ParticleEffectEntityRenderer::doRender(RenderArgs* args) { auto numParticles = _particleBuffer->getSize() / sizeof(GpuParticle); batch.drawInstanced((gpu::uint32)numParticles, gpu::TRIANGLE_STRIP, (gpu::uint32)VERTEX_PER_PARTICLE); } - - diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index e1e3cd210e..7655918c58 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -49,13 +49,14 @@ private: float seed { 0.0f }; uint64_t expiration { 0 }; float lifetime { 0.0f }; - glm::vec3 position; + glm::vec3 basePosition; + glm::vec3 relativePosition; glm::vec3 velocity; glm::vec3 acceleration; void integrate(float deltaTime) { glm::vec3 atSquared = (0.5f * deltaTime * deltaTime) * acceleration; - position += velocity * deltaTime + atSquared; + relativePosition += velocity * deltaTime + atSquared; velocity += acceleration * deltaTime; lifetime += deltaTime; } @@ -76,14 +77,16 @@ private: InterpolationData color; // rgba InterpolationData spin; float lifespan; - glm::vec3 spare; + int rotateWithEntity; + glm::vec2 spare; }; - static CpuParticle createParticle(uint64_t now, const Transform& baseTransform, const particle::Properties& particleProperties); void stepSimulation(); particle::Properties _particleProperties; + bool _prevEmitterShouldTrail; + bool _prevEmitterShouldTrailInitialized { false }; CpuParticles _cpuParticles; bool _emitting { false }; uint64_t _timeUntilNextEmit { 0 }; diff --git a/libraries/entities-renderer/src/textured_particle.slv b/libraries/entities-renderer/src/textured_particle.slv index bc3ef4fbb0..22254c0ab0 100644 --- a/libraries/entities-renderer/src/textured_particle.slv +++ b/libraries/entities-renderer/src/textured_particle.slv @@ -38,7 +38,9 @@ struct ParticleUniforms { Radii radius; Colors color; Spin spin; - vec4 lifespan; // x is lifespan, 3 spare floats + float lifespan; + int rotateWithEntity; + vec2 spare; }; layout(std140) uniform particleBuffer { @@ -120,7 +122,7 @@ void main(void) { int twoTriID = gl_VertexID - particleID * NUM_VERTICES_PER_PARTICLE; // Particle properties - float age = inColor.x / particle.lifespan.x; + float age = inColor.x / particle.lifespan; float seed = inColor.y; // Pass the texcoord @@ -140,20 +142,24 @@ void main(void) { float radiusSpread = 2.0 * hifi_hash(seed * 6.0) - 1.0; radius = max(radius + radiusSpread * particle.radius.spread, 0.0); - vec4 anchorPoint; - vec4 _inPosition = vec4(inPosition, 1.0); - <$transformModelToEyePos(cam, obj, _inPosition, anchorPoint)$> + // inPosition is in world space + vec4 anchorPoint = cam._view * vec4(inPosition, 1.0); mat3 view3 = mat3(cam._view); - vec3 worldUpEye = normalize(view3 * vec3(0, 1, 0)); - vec3 right = cross(vec3(0, 0, -1), worldUpEye); - vec3 up = cross(right, vec3(0, 0, -1)); + vec3 UP = vec3(0, 1, 0); + vec3 modelUpWorld; + <$transformModelToWorldDir(cam, obj, UP, modelUpWorld)$> + vec3 upWorld = mix(UP, normalize(modelUpWorld), particle.rotateWithEntity); + vec3 upEye = normalize(view3 * upWorld); + vec3 FORWARD = vec3(0, 0, -1); + vec3 particleRight = normalize(cross(FORWARD, upEye)); + vec3 particleUp = cross(particleRight, FORWARD); // don't need to normalize // This ordering ensures that un-rotated particles render upright in the viewer. vec3 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec3[NUM_VERTICES_PER_PARTICLE]( - normalize(-right + up), - normalize(-right - up), - normalize(right + up), - normalize(right - up) + normalize(-particleRight + particleUp), + normalize(-particleRight - particleUp), + normalize(particleRight + particleUp), + normalize(particleRight - particleUp) ); float c = cos(spin); float s = sin(spin); diff --git a/libraries/entities/src/EntityItemProperties.cpp b/libraries/entities/src/EntityItemProperties.cpp index f86c7a18b7..2d0fcd0496 100644 --- a/libraries/entities/src/EntityItemProperties.cpp +++ b/libraries/entities/src/EntityItemProperties.cpp @@ -373,6 +373,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { CHECK_PROPERTY_CHANGE(PROP_SPIN_SPREAD, spinSpread); CHECK_PROPERTY_CHANGE(PROP_SPIN_START, spinStart); CHECK_PROPERTY_CHANGE(PROP_SPIN_FINISH, spinFinish); + CHECK_PROPERTY_CHANGE(PROP_PARTICLE_ROTATE_WITH_ENTITY, rotateWithEntity); // Certifiable Properties CHECK_PROPERTY_CHANGE(PROP_ITEM_NAME, itemName); @@ -913,12 +914,14 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const { * @property {number} alphaSpread=0 - The spread in alpha that each particle is given. If alpha == 0.5 * and alphaSpread == 0.25, each particle will have an alpha in the range 0.250.75. * @property {number} particleSpin=0 - The spin of each particle at the middle of its life. In the range -2*PI2*PI. - * @property {number} spinStart=null - The spin of each particle at the start of its life. In the range -2*PI2*PI. - * If null, the particleSpin value is used. - * @property {number} spinFinish=null - The spin of each particle at the end of its life. In the range -2*PI2*PI. - * If null, the particleSpin value is used. + * @property {number} spinStart=NaN - The spin of each particle at the start of its life. In the range -2*PI2*PI. + * If NaN, the particleSpin value is used. + * @property {number} spinFinish=NaN - The spin of each particle at the end of its life. In the range -2*PI2*PI. + * If NaN, the particleSpin value is used. * @property {number} spinSpread=0 - The spread in spin that each particle is given. In the range 02*PI. If particleSpin == PI * and spinSpread == PI/2, each particle will have a spin in the range PI/23*PI/2. + * @property {boolean} rotateWithEntity=false - Whether or not the particles' spin will rotate with the entity. If false, when particleSpin == 0, the particles will point + * up in the world. If true, they will point towards the entity's up vector, based on its orientation. * * @property {ShapeType} shapeType="none" - Currently not used. Read-only. * @@ -1306,6 +1309,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPIN_SPREAD, spinSpread); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPIN_START, spinStart); COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_SPIN_FINISH, spinFinish); + COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_ROTATE_WITH_ENTITY, rotateWithEntity); } // Models only @@ -1602,6 +1606,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool COPY_PROPERTY_FROM_QSCRIPTVALUE(spinSpread, float, setSpinSpread); COPY_PROPERTY_FROM_QSCRIPTVALUE(spinStart, float, setSpinStart); COPY_PROPERTY_FROM_QSCRIPTVALUE(spinFinish, float, setSpinFinish); + COPY_PROPERTY_FROM_QSCRIPTVALUE(rotateWithEntity, bool, setRotateWithEntity); // Certifiable Properties COPY_PROPERTY_FROM_QSCRIPTVALUE(itemName, QString, setItemName); @@ -1774,6 +1779,7 @@ void EntityItemProperties::merge(const EntityItemProperties& other) { COPY_PROPERTY_IF_CHANGED(spinSpread); COPY_PROPERTY_IF_CHANGED(spinStart); COPY_PROPERTY_IF_CHANGED(spinFinish); + COPY_PROPERTY_IF_CHANGED(rotateWithEntity); // Certifiable Properties COPY_PROPERTY_IF_CHANGED(itemName); @@ -1991,6 +1997,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue ADD_PROPERTY_TO_MAP(PROP_SPIN_SPREAD, SpinSpread, spinSpread, float); ADD_PROPERTY_TO_MAP(PROP_SPIN_START, SpinStart, spinStart, float); ADD_PROPERTY_TO_MAP(PROP_SPIN_FINISH, SpinFinish, spinFinish, float); + ADD_PROPERTY_TO_MAP(PROP_PARTICLE_ROTATE_WITH_ENTITY, RotateWithEntity, rotateWithEntity, float); // Certifiable Properties ADD_PROPERTY_TO_MAP(PROP_ITEM_NAME, ItemName, itemName, QString); @@ -2324,6 +2331,7 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy APPEND_ENTITY_PROPERTY(PROP_SPIN_SPREAD, properties.getSpinSpread()); APPEND_ENTITY_PROPERTY(PROP_SPIN_START, properties.getSpinStart()); APPEND_ENTITY_PROPERTY(PROP_SPIN_FINISH, properties.getSpinFinish()); + APPEND_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, properties.getRotateWithEntity()) } if (properties.getType() == EntityTypes::Zone) { @@ -2703,6 +2711,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPIN_SPREAD, float, setSpinSpread); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPIN_START, float, setSpinStart); READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SPIN_FINISH, float, setSpinFinish); + READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_ROTATE_WITH_ENTITY, bool, setRotateWithEntity); } if (properties.getType() == EntityTypes::Zone) { @@ -2972,7 +2981,7 @@ void EntityItemProperties::markAllChanged() { _shapeTypeChanged = true; _isEmittingChanged = true; - _emitterShouldTrail = true; + _emitterShouldTrailChanged = true; _maxParticlesChanged = true; _lifespanChanged = true; _emitRateChanged = true; @@ -3001,6 +3010,7 @@ void EntityItemProperties::markAllChanged() { _spinStartChanged = true; _spinFinishChanged = true; _spinSpreadChanged = true; + _rotateWithEntityChanged = true; _materialURLChanged = true; _materialMappingModeChanged = true; @@ -3361,6 +3371,9 @@ QList EntityItemProperties::listChangedProperties() { if (spinFinishChanged()) { out += "spinFinish"; } + if (rotateWithEntityChanged()) { + out += "rotateWithEntity"; + } if (materialURLChanged()) { out += "materialURL"; } diff --git a/libraries/entities/src/EntityItemProperties.h b/libraries/entities/src/EntityItemProperties.h index 7799d45b22..04e54c54a5 100644 --- a/libraries/entities/src/EntityItemProperties.h +++ b/libraries/entities/src/EntityItemProperties.h @@ -238,7 +238,8 @@ public: DEFINE_PROPERTY(PROP_PARTICLE_SPIN, ParticleSpin, particleSpin, float, particle::DEFAULT_PARTICLE_SPIN); DEFINE_PROPERTY(PROP_SPIN_SPREAD, SpinSpread, spinSpread, float, particle::DEFAULT_SPIN_SPREAD); DEFINE_PROPERTY(PROP_SPIN_START, SpinStart, spinStart, float, particle::DEFAULT_SPIN_START); - DEFINE_PROPERTY(PROP_SPIN_FINISH, SpinFinish, spinFinish, float, particle::DEFAULT_SPIN_FINISH) + DEFINE_PROPERTY(PROP_SPIN_FINISH, SpinFinish, spinFinish, float, particle::DEFAULT_SPIN_FINISH); + DEFINE_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, RotateWithEntity, rotateWithEntity, bool, particle::DEFAULT_ROTATE_WITH_ENTITY); // Certifiable Properties - related to Proof of Purchase certificates DEFINE_PROPERTY_REF(PROP_ITEM_NAME, ItemName, itemName, QString, ENTITY_ITEM_DEFAULT_ITEM_NAME); diff --git a/libraries/entities/src/EntityPropertyFlags.h b/libraries/entities/src/EntityPropertyFlags.h index bece248fe7..156c5d9dd4 100644 --- a/libraries/entities/src/EntityPropertyFlags.h +++ b/libraries/entities/src/EntityPropertyFlags.h @@ -255,6 +255,7 @@ enum EntityPropertyList { PROP_SPIN_START, PROP_SPIN_FINISH, PROP_SPIN_SPREAD, + PROP_PARTICLE_ROTATE_WITH_ENTITY, //////////////////////////////////////////////////////////////////////////////////////////////////// // ATTENTION: add new properties to end of list just ABOVE this line diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index c1785639e0..238f41b05f 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -92,6 +92,7 @@ bool operator==(const Properties& a, const Properties& b) { (a.alpha == b.alpha) && (a.radius == b.radius) && (a.spin == b.spin) && + (a.rotateWithEntity == b.rotateWithEntity) && (a.radiusStart == b.radiusStart) && (a.lifespan == b.lifespan) && (a.maxParticles == b.maxParticles) && @@ -444,6 +445,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinSpread, getSpinSpread); COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinStart, getSpinStart); COPY_ENTITY_PROPERTY_TO_PROPERTIES(spinFinish, getSpinFinish); + COPY_ENTITY_PROPERTY_TO_PROPERTIES(rotateWithEntity, getRotateWithEntity); return properties; } @@ -485,6 +487,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinSpread, setSpinSpread); SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinStart, setSpinStart); SET_ENTITY_PROPERTY_FROM_PROPERTIES(spinFinish, setSpinFinish); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(rotateWithEntity, setRotateWithEntity); if (somethingChanged) { bool wantDebug = false; @@ -569,6 +572,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch READ_ENTITY_PROPERTY(PROP_SPIN_SPREAD, float, setSpinSpread); READ_ENTITY_PROPERTY(PROP_SPIN_START, float, setSpinStart); READ_ENTITY_PROPERTY(PROP_SPIN_FINISH, float, setSpinFinish); + READ_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, bool, setRotateWithEntity); return bytesRead; } @@ -610,6 +614,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea requestedProperties += PROP_SPIN_SPREAD; requestedProperties += PROP_SPIN_START; requestedProperties += PROP_SPIN_FINISH; + requestedProperties += PROP_PARTICLE_ROTATE_WITH_ENTITY; return requestedProperties; } @@ -657,6 +662,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData, APPEND_ENTITY_PROPERTY(PROP_SPIN_SPREAD, getSpinSpread()); APPEND_ENTITY_PROPERTY(PROP_SPIN_START, getSpinStart()); APPEND_ENTITY_PROPERTY(PROP_SPIN_FINISH, getSpinFinish()); + APPEND_ENTITY_PROPERTY(PROP_PARTICLE_ROTATE_WITH_ENTITY, getRotateWithEntity()); } @@ -728,6 +734,12 @@ void ParticleEffectEntityItem::setEmitterShouldTrail(bool emitterShouldTrail) { }); } +void ParticleEffectEntityItem::setRotateWithEntity(bool rotateWithEntity) { + withWriteLock([&] { + _particleProperties.rotateWithEntity = rotateWithEntity; + }); +} + particle::Properties ParticleEffectEntityItem::getParticleProperties() const { particle::Properties result; withReadLock([&] { diff --git a/libraries/entities/src/ParticleEffectEntityItem.h b/libraries/entities/src/ParticleEffectEntityItem.h index e4120eed63..480b78ffcc 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.h +++ b/libraries/entities/src/ParticleEffectEntityItem.h @@ -77,6 +77,7 @@ namespace particle { static const float MAXIMUM_PARTICLE_SPIN = 2.0f * SCRIPT_MAXIMUM_PI; static const QString DEFAULT_TEXTURES = ""; static const bool DEFAULT_EMITTER_SHOULD_TRAIL = false; + static const bool DEFAULT_ROTATE_WITH_ENTITY = false; template struct Range { @@ -158,6 +159,7 @@ namespace particle { float radiusStart { DEFAULT_EMIT_RADIUS_START }; RangeGradient radius { DEFAULT_PARTICLE_RADIUS, DEFAULT_RADIUS_START, DEFAULT_RADIUS_FINISH, DEFAULT_RADIUS_SPREAD }; RangeGradient spin { DEFAULT_PARTICLE_SPIN, DEFAULT_SPIN_START, DEFAULT_SPIN_FINISH, DEFAULT_SPIN_SPREAD }; + bool rotateWithEntity { DEFAULT_ROTATE_WITH_ENTITY }; float lifespan { DEFAULT_LIFESPAN }; uint32_t maxParticles { DEFAULT_MAX_PARTICLES }; EmitProperties emission; @@ -176,6 +178,7 @@ namespace particle { color = other.color; alpha = other.alpha; spin = other.spin; + rotateWithEntity = other.rotateWithEntity; radius = other.radius; lifespan = other.lifespan; maxParticles = other.maxParticles; @@ -326,6 +329,9 @@ public: void setSpinSpread(float spinSpread); float getSpinSpread() const { return _particleProperties.spin.gradient.spread; } + void setRotateWithEntity(bool rotateWithEntity); + bool getRotateWithEntity() const { return _particleProperties.rotateWithEntity; } + void computeAndUpdateDimensions(); void setTextures(const QString& textures); diff --git a/libraries/gpu/src/gpu/Transform.slh b/libraries/gpu/src/gpu/Transform.slh index 50c0bc13ed..864a106350 100644 --- a/libraries/gpu/src/gpu/Transform.slh +++ b/libraries/gpu/src/gpu/Transform.slh @@ -238,7 +238,7 @@ TransformObject getTransformObject() { <@endfunc@> <@func transformModelToWorldDir(cameraTransform, objectTransform, modelDir, worldDir)@> - { // transformModelToEyeDir + { // transformModelToWorldDir vec3 mr0 = <$objectTransform$>._modelInverse[0].xyz; vec3 mr1 = <$objectTransform$>._modelInverse[1].xyz; vec3 mr2 = <$objectTransform$>._modelInverse[2].xyz; diff --git a/scripts/system/particle_explorer/particleExplorer.js b/scripts/system/particle_explorer/particleExplorer.js index a6cbbc14cb..f1b7c8600f 100644 --- a/scripts/system/particle_explorer/particleExplorer.js +++ b/scripts/system/particle_explorer/particleExplorer.js @@ -398,6 +398,14 @@ min: -360.0, max: 360.0 }, + { + type: "Row" + }, + { + id: "rotateWithEntity", + name: "Rotate with Entity", + type: "Boolean" + }, { type: "Row" }