mirror of
https://github.com/overte-org/overte.git
synced 2025-04-15 17:20:12 +02:00
Merge pull request #13696 from SamGondelman/particleRot
Particles don't spin with head roll, new spin + rotateWithEntity properties
This commit is contained in:
commit
fc88165e23
13 changed files with 341 additions and 52 deletions
|
@ -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();
|
||||
|
@ -144,7 +148,12 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn
|
|||
particleUniforms.color.middle = _particleProperties.getColorMiddle();
|
||||
particleUniforms.color.finish = _particleProperties.getColorFinish();
|
||||
particleUniforms.color.spread = _particleProperties.getColorSpread();
|
||||
particleUniforms.spin.start = _particleProperties.spin.range.start;
|
||||
particleUniforms.spin.middle = _particleProperties.spin.gradient.target;
|
||||
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>(), &particleUniforms, sizeof(ParticleUniforms));
|
||||
|
@ -176,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;
|
||||
|
@ -185,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) {
|
||||
|
@ -237,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);
|
||||
|
@ -262,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;
|
||||
|
@ -288,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
|
||||
|
@ -324,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);
|
||||
|
@ -341,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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
@ -74,15 +75,18 @@ private:
|
|||
struct ParticleUniforms {
|
||||
InterpolationData<float> radius;
|
||||
InterpolationData<glm::vec4> color; // rgba
|
||||
InterpolationData<float> 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 };
|
||||
|
|
|
@ -27,11 +27,20 @@ struct Colors {
|
|||
vec4 finish;
|
||||
vec4 spread;
|
||||
};
|
||||
struct Spin {
|
||||
float start;
|
||||
float middle;
|
||||
float finish;
|
||||
float spread;
|
||||
};
|
||||
|
||||
struct ParticleUniforms {
|
||||
Radii radius;
|
||||
Colors color;
|
||||
vec4 lifespan; // x is lifespan, 3 spare floats
|
||||
Spin spin;
|
||||
float lifespan;
|
||||
int rotateWithEntity;
|
||||
vec2 spare;
|
||||
};
|
||||
|
||||
layout(std140) uniform particleBuffer {
|
||||
|
@ -44,15 +53,6 @@ layout(location=2) in vec2 inColor; // This is actual Lifetime + Seed
|
|||
out vec4 varColor;
|
||||
out vec2 varTexcoord;
|
||||
|
||||
const int NUM_VERTICES_PER_PARTICLE = 4;
|
||||
// This ordering ensures that un-rotated particles render upright in the viewer.
|
||||
const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE](
|
||||
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) {
|
||||
// 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;
|
||||
|
@ -103,6 +103,15 @@ vec4 interpolate3Vec4(vec4 y1, vec4 y2, vec4 y3, float u) {
|
|||
interpolate3Points(y1.w, y2.w, y3.w, u));
|
||||
}
|
||||
|
||||
const int NUM_VERTICES_PER_PARTICLE = 4;
|
||||
const vec2 TEX_COORDS[NUM_VERTICES_PER_PARTICLE] = vec2[NUM_VERTICES_PER_PARTICLE](
|
||||
vec2(-1.0, 0.0),
|
||||
vec2(-1.0, 1.0),
|
||||
vec2(0.0, 0.0),
|
||||
vec2(0.0, 1.0)
|
||||
);
|
||||
|
||||
|
||||
void main(void) {
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
|
@ -113,28 +122,54 @@ 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 and the z texcoord is representing the texture icon
|
||||
// Offset for corrected vertex ordering.
|
||||
varTexcoord = vec2((UNIT_QUAD[twoTriID].xy -1.0) * vec2(0.5, -0.5));
|
||||
// Pass the texcoord
|
||||
varTexcoord = TEX_COORDS[twoTriID].xy;
|
||||
varColor = interpolate3Vec4(particle.color.start, particle.color.middle, particle.color.finish, age);
|
||||
vec3 colorSpread = 2.0 * vec3(hifi_hash(seed), hifi_hash(seed * 2.0), hifi_hash(seed * 3.0)) - 1.0;
|
||||
varColor.rgb = clamp(varColor.rgb + colorSpread * particle.color.spread.rgb, vec3(0), vec3(1));
|
||||
float alphaSpread = 2.0 * hifi_hash(seed * 4.0) - 1.0;
|
||||
varColor.a = clamp(varColor.a + alphaSpread * particle.color.spread.a, 0.0, 1.0);
|
||||
|
||||
float spin = interpolate3Points(particle.spin.start, particle.spin.middle, particle.spin.finish, age);
|
||||
float spinSpread = 2.0 * hifi_hash(seed * 5.0) - 1.0;
|
||||
spin = spin + spinSpread * particle.spin.spread;
|
||||
|
||||
// anchor point in eye space
|
||||
float radius = interpolate3Points(particle.radius.start, particle.radius.middle, particle.radius.finish, age);
|
||||
float radiusSpread = 2.0 * hifi_hash(seed * 5.0) - 1.0;
|
||||
float radiusSpread = 2.0 * hifi_hash(seed * 6.0) - 1.0;
|
||||
radius = max(radius + radiusSpread * particle.radius.spread, 0.0);
|
||||
vec4 quadPos = radius * UNIT_QUAD[twoTriID];
|
||||
|
||||
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);
|
||||
|
||||
vec4 eyePos = anchorPoint + quadPos;
|
||||
mat3 view3 = mat3(cam._view);
|
||||
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(-particleRight + particleUp),
|
||||
normalize(-particleRight - particleUp),
|
||||
normalize(particleRight + particleUp),
|
||||
normalize(particleRight - particleUp)
|
||||
);
|
||||
float c = cos(spin);
|
||||
float s = sin(spin);
|
||||
mat4 rotation = mat4(
|
||||
c, -s, 0, 0,
|
||||
s, c, 0, 0,
|
||||
0, 0, 1, 0,
|
||||
0, 0, 0, 1
|
||||
);
|
||||
vec4 quadPos = radius * vec4(UNIT_QUAD[twoTriID], 0.0);
|
||||
vec4 eyePos = anchorPoint + rotation * quadPos;
|
||||
<$transformEyeToClipPos(cam, eyePos, gl_Position)$>
|
||||
}
|
||||
|
|
|
@ -369,6 +369,11 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_MAPPING_ROT, materialMappingRot);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MATERIAL_DATA, materialData);
|
||||
CHECK_PROPERTY_CHANGE(PROP_VISIBLE_IN_SECONDARY_CAMERA, isVisibleInSecondaryCamera);
|
||||
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_SPIN, particleSpin);
|
||||
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);
|
||||
|
@ -908,6 +913,15 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
* <code>alpha</code> value is used.
|
||||
* @property {number} alphaSpread=0 - The spread in alpha that each particle is given. If <code>alpha == 0.5</code>
|
||||
* and <code>alphaSpread == 0.25</code>, each particle will have an alpha in the range <code>0.25</code> – <code>0.75</code>.
|
||||
* @property {number} particleSpin=0 - The spin of each particle at the middle of its life. In the range <code>-2*PI</code> – <code>2*PI</code>.
|
||||
* @property {number} spinStart=NaN - The spin of each particle at the start of its life. In the range <code>-2*PI</code> – <code>2*PI</code>.
|
||||
* If <code>NaN</code>, the <code>particleSpin</code> value is used.
|
||||
* @property {number} spinFinish=NaN - The spin of each particle at the end of its life. In the range <code>-2*PI</code> – <code>2*PI</code>.
|
||||
* If <code>NaN</code>, the <code>particleSpin</code> value is used.
|
||||
* @property {number} spinSpread=0 - The spread in spin that each particle is given. In the range <code>0</code> – <code>2*PI</code>. If <code>particleSpin == PI</code>
|
||||
* and <code>spinSpread == PI/2</code>, each particle will have a spin in the range <code>PI/2</code> – <code>3*PI/2</code>.
|
||||
* @property {boolean} rotateWithEntity=false - Whether or not the particles' spin will rotate with the entity. If false, when <code>particleSpin == 0</code>, 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" - <em>Currently not used.</em> <em>Read-only.</em>
|
||||
*
|
||||
|
@ -1291,6 +1305,11 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_PARTICLE_SPIN, particleSpin);
|
||||
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
|
||||
|
@ -1583,6 +1602,11 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialMappingRot, float, setMaterialMappingRot);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(materialData, QString, setMaterialData);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(isVisibleInSecondaryCamera, bool, setIsVisibleInSecondaryCamera);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(particleSpin, float, setParticleSpin);
|
||||
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);
|
||||
|
@ -1751,6 +1775,11 @@ void EntityItemProperties::merge(const EntityItemProperties& other) {
|
|||
COPY_PROPERTY_IF_CHANGED(radiusSpread);
|
||||
COPY_PROPERTY_IF_CHANGED(radiusStart);
|
||||
COPY_PROPERTY_IF_CHANGED(radiusFinish);
|
||||
COPY_PROPERTY_IF_CHANGED(particleSpin);
|
||||
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);
|
||||
|
@ -1964,6 +1993,12 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
|
||||
ADD_PROPERTY_TO_MAP(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool);
|
||||
|
||||
ADD_PROPERTY_TO_MAP(PROP_PARTICLE_SPIN, ParticleSpin, particleSpin, float);
|
||||
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);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString);
|
||||
|
@ -2292,6 +2327,11 @@ OctreeElement::AppendState EntityItemProperties::encodeEntityEditPacket(PacketTy
|
|||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, properties.getEmitterShouldTrail());
|
||||
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, properties.getParticleSpin());
|
||||
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) {
|
||||
|
@ -2667,6 +2707,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_SPIN, float, setParticleSpin);
|
||||
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) {
|
||||
|
@ -2936,7 +2981,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_shapeTypeChanged = true;
|
||||
|
||||
_isEmittingChanged = true;
|
||||
_emitterShouldTrail = true;
|
||||
_emitterShouldTrailChanged = true;
|
||||
_maxParticlesChanged = true;
|
||||
_lifespanChanged = true;
|
||||
_emitRateChanged = true;
|
||||
|
@ -2961,6 +3006,11 @@ void EntityItemProperties::markAllChanged() {
|
|||
_colorFinishChanged = true;
|
||||
_alphaStartChanged = true;
|
||||
_alphaFinishChanged = true;
|
||||
_particleSpinChanged = true;
|
||||
_spinStartChanged = true;
|
||||
_spinFinishChanged = true;
|
||||
_spinSpreadChanged = true;
|
||||
_rotateWithEntityChanged = true;
|
||||
|
||||
_materialURLChanged = true;
|
||||
_materialMappingModeChanged = true;
|
||||
|
@ -3309,6 +3359,21 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (radiusFinishChanged()) {
|
||||
out += "radiusFinish";
|
||||
}
|
||||
if (particleSpinChanged()) {
|
||||
out += "particleSpin";
|
||||
}
|
||||
if (spinSpreadChanged()) {
|
||||
out += "spinSpread";
|
||||
}
|
||||
if (spinStartChanged()) {
|
||||
out += "spinStart";
|
||||
}
|
||||
if (spinFinishChanged()) {
|
||||
out += "spinFinish";
|
||||
}
|
||||
if (rotateWithEntityChanged()) {
|
||||
out += "rotateWithEntity";
|
||||
}
|
||||
if (materialURLChanged()) {
|
||||
out += "materialURL";
|
||||
}
|
||||
|
|
|
@ -235,6 +235,12 @@ public:
|
|||
|
||||
DEFINE_PROPERTY(PROP_VISIBLE_IN_SECONDARY_CAMERA, IsVisibleInSecondaryCamera, isVisibleInSecondaryCamera, bool, ENTITY_ITEM_DEFAULT_VISIBLE_IN_SECONDARY_CAMERA);
|
||||
|
||||
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_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);
|
||||
DEFINE_PROPERTY_REF(PROP_ITEM_DESCRIPTION, ItemDescription, itemDescription, QString, ENTITY_ITEM_DEFAULT_ITEM_DESCRIPTION);
|
||||
|
|
|
@ -251,6 +251,12 @@ enum EntityPropertyList {
|
|||
|
||||
PROP_VISIBLE_IN_SECONDARY_CAMERA, // not sent over the wire, only used locally
|
||||
|
||||
PROP_PARTICLE_SPIN,
|
||||
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
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
|
|
|
@ -91,6 +91,8 @@ bool operator==(const Properties& a, const Properties& b) {
|
|||
(a.color == b.color) &&
|
||||
(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) &&
|
||||
|
@ -130,7 +132,11 @@ bool Properties::valid() const {
|
|||
(radius.gradient.target == glm::clamp(radius.gradient.target, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)) &&
|
||||
(radius.range.start == glm::clamp(radius.range.start, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)) &&
|
||||
(radius.range.finish == glm::clamp(radius.range.finish, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)) &&
|
||||
(radius.gradient.spread == glm::clamp(radius.gradient.spread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS));
|
||||
(radius.gradient.spread == glm::clamp(radius.gradient.spread, MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS)) &&
|
||||
(spin.gradient.target == glm::clamp(spin.gradient.target, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN)) &&
|
||||
(spin.range.start == glm::clamp(spin.range.start, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN)) &&
|
||||
(spin.range.finish == glm::clamp(spin.range.finish, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN)) &&
|
||||
(spin.gradient.spread == glm::clamp(spin.gradient.spread, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN));
|
||||
}
|
||||
|
||||
bool Properties::emitting() const {
|
||||
|
@ -332,6 +338,43 @@ void ParticleEffectEntityItem::setRadiusSpread(float radiusSpread) {
|
|||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setParticleSpin(float particleSpin) {
|
||||
particleSpin = glm::clamp(particleSpin, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN);
|
||||
if (particleSpin != _particleProperties.spin.gradient.target) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.spin.gradient.target = particleSpin;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setSpinStart(float spinStart) {
|
||||
spinStart =
|
||||
glm::isnan(spinStart) ? spinStart : glm::clamp(spinStart, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN);
|
||||
if (spinStart != _particleProperties.spin.range.start) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.spin.range.start = spinStart;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setSpinFinish(float spinFinish) {
|
||||
spinFinish =
|
||||
glm::isnan(spinFinish) ? spinFinish : glm::clamp(spinFinish, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN);
|
||||
if (spinFinish != _particleProperties.spin.range.finish) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.spin.range.finish = spinFinish;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::setSpinSpread(float spinSpread) {
|
||||
spinSpread = glm::clamp(spinSpread, MINIMUM_PARTICLE_SPIN, MAXIMUM_PARTICLE_SPIN);
|
||||
if (spinSpread != _particleProperties.spin.gradient.spread) {
|
||||
withWriteLock([&] {
|
||||
_particleProperties.spin.gradient.spread = spinSpread;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ParticleEffectEntityItem::computeAndUpdateDimensions() {
|
||||
particle::Properties particleProperties;
|
||||
|
@ -398,6 +441,11 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(particleSpin, getParticleSpin);
|
||||
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;
|
||||
}
|
||||
|
@ -435,6 +483,11 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitterShouldTrail, setEmitterShouldTrail);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(particleSpin, setParticleSpin);
|
||||
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;
|
||||
|
@ -515,6 +568,12 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
|
|||
|
||||
READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
|
||||
|
||||
READ_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, float, setParticleSpin);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -551,6 +610,11 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
|
|||
requestedProperties += PROP_AZIMUTH_START;
|
||||
requestedProperties += PROP_AZIMUTH_FINISH;
|
||||
requestedProperties += PROP_EMITTER_SHOULD_TRAIL;
|
||||
requestedProperties += PROP_PARTICLE_SPIN;
|
||||
requestedProperties += PROP_SPIN_SPREAD;
|
||||
requestedProperties += PROP_SPIN_START;
|
||||
requestedProperties += PROP_SPIN_FINISH;
|
||||
requestedProperties += PROP_PARTICLE_ROTATE_WITH_ENTITY;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -594,6 +658,11 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
|
|||
APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail());
|
||||
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_SPIN, getParticleSpin());
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
|
@ -665,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([&] {
|
||||
|
@ -689,6 +764,12 @@ particle::Properties ParticleEffectEntityItem::getParticleProperties() const {
|
|||
if (glm::isnan(result.radius.range.finish)) {
|
||||
result.radius.range.finish = getParticleRadius();
|
||||
}
|
||||
if (glm::isnan(result.spin.range.start)) {
|
||||
result.spin.range.start = getParticleSpin();
|
||||
}
|
||||
if (glm::isnan(result.spin.range.finish)) {
|
||||
result.spin.range.finish = getParticleSpin();
|
||||
}
|
||||
});
|
||||
|
||||
if (!result.valid()) {
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace particle {
|
|||
static const float MINIMUM_EMIT_RATE = 0.0f;
|
||||
static const float MAXIMUM_EMIT_RATE = 100000.0f;
|
||||
static const float DEFAULT_EMIT_SPEED = 5.0f;
|
||||
static const float MINIMUM_EMIT_SPEED = 0.0f;
|
||||
static const float MINIMUM_EMIT_SPEED = -1000.0f;
|
||||
static const float MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3
|
||||
static const float DEFAULT_SPEED_SPREAD = 1.0f;
|
||||
static const glm::quat DEFAULT_EMIT_ORIENTATION = glm::angleAxis(-PI_OVER_TWO, Vectors::UNIT_X); // Vertical
|
||||
|
@ -69,8 +69,15 @@ namespace particle {
|
|||
static const float DEFAULT_RADIUS_SPREAD = 0.0f;
|
||||
static const float DEFAULT_RADIUS_START = UNINITIALIZED;
|
||||
static const float DEFAULT_RADIUS_FINISH = UNINITIALIZED;
|
||||
static const float DEFAULT_PARTICLE_SPIN = 0.0f;
|
||||
static const float DEFAULT_SPIN_START = UNINITIALIZED;
|
||||
static const float DEFAULT_SPIN_FINISH = UNINITIALIZED;
|
||||
static const float DEFAULT_SPIN_SPREAD = 0.0f;
|
||||
static const float MINIMUM_PARTICLE_SPIN = -2.0f * SCRIPT_MAXIMUM_PI;
|
||||
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 <typename T>
|
||||
struct Range {
|
||||
|
@ -151,6 +158,8 @@ namespace particle {
|
|||
RangeGradient<float> alpha { DEFAULT_ALPHA, DEFAULT_ALPHA_START, DEFAULT_ALPHA_FINISH, DEFAULT_ALPHA_SPREAD };
|
||||
float radiusStart { DEFAULT_EMIT_RADIUS_START };
|
||||
RangeGradient<float> radius { DEFAULT_PARTICLE_RADIUS, DEFAULT_RADIUS_START, DEFAULT_RADIUS_FINISH, DEFAULT_RADIUS_SPREAD };
|
||||
RangeGradient<float> 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;
|
||||
|
@ -168,6 +177,8 @@ namespace particle {
|
|||
Properties& operator =(const Properties& other) {
|
||||
color = other.color;
|
||||
alpha = other.alpha;
|
||||
spin = other.spin;
|
||||
rotateWithEntity = other.rotateWithEntity;
|
||||
radius = other.radius;
|
||||
lifespan = other.lifespan;
|
||||
maxParticles = other.maxParticles;
|
||||
|
@ -306,6 +317,21 @@ public:
|
|||
void setRadiusSpread(float radiusSpread);
|
||||
float getRadiusSpread() const { return _particleProperties.radius.gradient.spread; }
|
||||
|
||||
void setParticleSpin(float particleSpin);
|
||||
float getParticleSpin() const { return _particleProperties.spin.gradient.target; }
|
||||
|
||||
void setSpinStart(float spinStart);
|
||||
float getSpinStart() const { return _particleProperties.spin.range.start; }
|
||||
|
||||
void setSpinFinish(float spinFinish);
|
||||
float getSpinFinish() const { return _particleProperties.spin.range.finish; }
|
||||
|
||||
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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -33,7 +33,7 @@ PacketVersion versionForPacketType(PacketType packetType) {
|
|||
case PacketType::EntityEdit:
|
||||
case PacketType::EntityData:
|
||||
case PacketType::EntityPhysics:
|
||||
return static_cast<PacketVersion>(EntityVersion::ParticleEntityFix);
|
||||
return static_cast<PacketVersion>(EntityVersion::ParticleSpin);
|
||||
case PacketType::EntityQuery:
|
||||
return static_cast<PacketVersion>(EntityQueryPacketVersion::ConicalFrustums);
|
||||
case PacketType::AvatarIdentity:
|
||||
|
|
|
@ -238,7 +238,8 @@ enum class EntityVersion : PacketVersion {
|
|||
CloneableData,
|
||||
CollisionMask16Bytes,
|
||||
YieldSimulationOwnership,
|
||||
ParticleEntityFix
|
||||
ParticleEntityFix,
|
||||
ParticleSpin
|
||||
};
|
||||
|
||||
enum class EntityScriptCallMethodVersion : PacketVersion {
|
||||
|
|
|
@ -361,6 +361,55 @@
|
|||
type: "Row"
|
||||
}
|
||||
],
|
||||
Spin: [
|
||||
{
|
||||
id: "particleSpin",
|
||||
name: "Particle Spin",
|
||||
type: "SliderRadian",
|
||||
min: -360.0,
|
||||
max: 360.0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "spinSpread",
|
||||
name: "Spin Spread",
|
||||
type: "SliderRadian",
|
||||
max: 360.0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "spinStart",
|
||||
name: "Spin Start",
|
||||
type: "SliderRadian",
|
||||
min: -360.0,
|
||||
max: 360.0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "spinFinish",
|
||||
name: "Spin Finish",
|
||||
type: "SliderRadian",
|
||||
min: -360.0,
|
||||
max: 360.0
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
},
|
||||
{
|
||||
id: "rotateWithEntity",
|
||||
name: "Rotate with Entity",
|
||||
type: "Boolean"
|
||||
},
|
||||
{
|
||||
type: "Row"
|
||||
}
|
||||
],
|
||||
Polar: [
|
||||
{
|
||||
id: "polarStart",
|
||||
|
|
|
@ -75,6 +75,12 @@ ParticleExplorerTool = function(createToolsWindow) {
|
|||
if (isNaN(properties.colorFinish.red)) {
|
||||
properties.colorFinish = properties.color;
|
||||
}
|
||||
if (isNaN(properties.spinStart)) {
|
||||
properties.spinStart = properties.particleSpin;
|
||||
}
|
||||
if (isNaN(properties.spinFinish)) {
|
||||
properties.spinFinish = properties.particleSpin;
|
||||
}
|
||||
sendParticleProperties(properties);
|
||||
}
|
||||
|
||||
|
@ -88,8 +94,8 @@ ParticleExplorerTool = function(createToolsWindow) {
|
|||
if (data.messageType === "settings_update") {
|
||||
var updatedSettings = data.updatedSettings;
|
||||
|
||||
var optionalProps = ["alphaStart", "alphaFinish", "radiusStart", "radiusFinish", "colorStart", "colorFinish"];
|
||||
var fallbackProps = ["alpha", "particleRadius", "color"];
|
||||
var optionalProps = ["alphaStart", "alphaFinish", "radiusStart", "radiusFinish", "colorStart", "colorFinish", "spinStart", "spinFinish"];
|
||||
var fallbackProps = ["alpha", "particleRadius", "color", "particleSpin"];
|
||||
for (var i = 0; i < optionalProps.length; i++) {
|
||||
var fallbackProp = fallbackProps[Math.floor(i / 2)];
|
||||
var optionalValue = updatedSettings[optionalProps[i]];
|
||||
|
|
Loading…
Reference in a new issue