Start moving update to shader

This commit is contained in:
Atlante45 2015-11-18 23:07:06 -08:00
parent 61511d57bb
commit e25ea122d8
9 changed files with 119 additions and 147 deletions

View file

@ -32,18 +32,23 @@ public:
using Payload = render::Payload<ParticlePayload>;
using Pointer = Payload::DataPointer;
using ParticlePrimitive = RenderableParticleEffectEntityItem::ParticlePrimitive;
using ParticleUniforms = RenderableParticleEffectEntityItem::ParticleUniforms;
using PipelinePointer = gpu::PipelinePointer;
using FormatPointer = gpu::Stream::FormatPointer;
using BufferPointer = gpu::BufferPointer;
using TexturePointer = gpu::TexturePointer;
using Format = gpu::Stream::Format;
using Buffer = gpu::Buffer;
using BufferView = gpu::BufferView;
ParticlePayload(EntityItemPointer entity) : _entity(entity) {
_vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC4F_XYZW,
offsetof(ParticlePrimitive, xyzw), gpu::Stream::PER_INSTANCE);
_vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::COLOR_RGBA_32,
offsetof(ParticlePrimitive, rgba), gpu::Stream::PER_INSTANCE);
ParticleUniforms uniforms;
_uniformBuffer = std::make_shared<Buffer>(sizeof(ParticleUniforms), (const gpu::Byte*) &uniforms);
_vertexFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element::VEC3F_XYZ,
offsetof(ParticlePrimitive, xyz), gpu::Stream::PER_INSTANCE);
_vertexFormat->setAttribute(gpu::Stream::COLOR, 0, gpu::Element::VEC2F_UV,
offsetof(ParticlePrimitive, uv), gpu::Stream::PER_INSTANCE);
}
void setPipeline(PipelinePointer pipeline) { _pipeline = pipeline; }
@ -57,6 +62,9 @@ public:
BufferPointer getParticleBuffer() { return _particleBuffer; }
const BufferPointer& getParticleBuffer() const { return _particleBuffer; }
const ParticleUniforms& getParticleUniforms() const { return _uniformBuffer.get<ParticleUniforms>(); }
ParticleUniforms& editParticleUniforms() { return _uniformBuffer.edit<ParticleUniforms>(); }
void setTexture(TexturePointer texture) { _texture = texture; }
const TexturePointer& getTexture() const { return _texture; }
@ -75,6 +83,7 @@ public:
}
batch.setModelTransform(_modelTransform);
batch.setUniformBuffer(0, _uniformBuffer);
batch.setInputFormat(_vertexFormat);
batch.setInputBuffer(0, _particleBuffer, 0, sizeof(ParticlePrimitive));
@ -89,6 +98,7 @@ protected:
PipelinePointer _pipeline;
FormatPointer _vertexFormat { std::make_shared<Format>() };
BufferPointer _particleBuffer { std::make_shared<Buffer>() };
BufferView _uniformBuffer;
TexturePointer _texture;
bool _visibleFlag = true;
};
@ -169,22 +179,33 @@ void RenderableParticleEffectEntityItem::update(const quint64& now) {
updateRenderItem();
}
uint32_t toRGBA(uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
return ((uint32_t)r | (uint32_t)g << 8 | (uint32_t)b << 16 | (uint32_t)a << 24);
glm::vec3 toGlm(const rgbColor& color) {
return glm::vec3(color[RED_INDEX], color[GREEN_INDEX], color[BLUE_INDEX]);
}
void RenderableParticleEffectEntityItem::updateRenderItem() {
if (!_scene) {
return;
}
// build primitives from particle positions and radiuses
// Fill in Uniforms structure
_particleUniforms.radius.start = getRadiusStart();
_particleUniforms.radius.middle = getParticleRadius();
_particleUniforms.radius.finish = getRadiusFinish();
_particleUniforms.radius.spread = getRadiusSpread();
_particleUniforms.color.start = glm::vec4(toGlm(getColorStart()), getAlphaStart());
_particleUniforms.color.middle = glm::vec4(toGlm(getColor()), getAlpha());
_particleUniforms.color.finish = glm::vec4(toGlm(getColorFinish()), getAlphaFinish());
_particleUniforms.color.spread = glm::vec4(toGlm(getColorSpread()), getAlphaSpread());
_particleUniforms.lifespan = getLifespan();
// Build particle primitives
_particlePrimitives.clear(); // clear primitives
_particlePrimitives.reserve(_particles.size()); // Reserve space
for (auto& particle : _particles) {
auto alpha = glm::clamp(particle.alpha * getLocalRenderAlpha(), 0.0f, 1.0f) * 255;
auto rgba = toRGBA(particle.color.red, particle.color.green, particle.color.blue, alpha);
_particlePrimitives.emplace_back(glm::vec4(particle.position, particle.radius), rgba);
_particlePrimitives.emplace_back(particle.position, glm::vec2(particle.lifetime, particle.seed));
}
// No need to sort if we're doing additive blending
@ -197,13 +218,16 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
std::sort(_particlePrimitives.begin(), _particlePrimitives.end(),
[&](const ParticlePrimitive& lhs, const ParticlePrimitive& rhs) {
return glm::dot(glm::vec3(lhs.xyzw), direction) > glm::dot(glm::vec3(rhs.xyzw), direction);
return glm::dot(lhs.xyz, direction) > glm::dot(rhs.xyz, direction);
});
}
render::PendingChanges pendingChanges;
pendingChanges.updateItem<ParticlePayload>(_renderItemId, [this](ParticlePayload& payload) {
// update particle buffer
// Update particle uniforms
memcpy(&payload.editParticleUniforms(), &_particleUniforms, sizeof(ParticleUniforms));
// Update particle buffer
auto particleBuffer = payload.getParticleBuffer();
size_t numBytes = sizeof(ParticlePrimitive) * _particlePrimitives.size();
particleBuffer->resize(numBytes);
@ -243,8 +267,7 @@ void RenderableParticleEffectEntityItem::createPipelines() {
gpu::State::BlendArg destinationColorBlendArg;
if (_additiveBlending) {
destinationColorBlendArg = gpu::State::ONE;
}
else {
} else {
destinationColorBlendArg = gpu::State::INV_SRC_ALPHA;
writeToDepthBuffer = true;
}

View file

@ -29,18 +29,37 @@ public:
virtual void removeFromScene(EntityItemPointer self, render::ScenePointer scene, render::PendingChanges& pendingChanges) override;
protected:
render::ItemID _renderItemId;
struct ParticleUniforms {
struct {
float start;
float middle;
float finish;
float spread;
} radius;
struct {
glm::vec4 start;
glm::vec4 middle;
glm::vec4 finish;
glm::vec4 spread;
} color;
float lifespan;
};
struct ParticlePrimitive {
ParticlePrimitive(glm::vec4 xyzwIn, uint32_t rgbaIn) : xyzw(xyzwIn), rgba(rgbaIn) {}
glm::vec4 xyzw; // Position + radius
uint32_t rgba; // Color
ParticlePrimitive(glm::vec3 xyzIn, glm::vec2 uvIn) : xyz(xyzIn), uv(uvIn) {}
glm::vec3 xyz; // Position
glm::vec2 uv; // Lifetime + seed
};
using ParticlePrimitives = std::vector<ParticlePrimitive>;
void createPipelines();
render::ItemID _renderItemId;
ParticlePrimitives _particlePrimitives;
ParticleUniforms _particleUniforms;
gpu::PipelinePointer _untexturedPipeline;
gpu::PipelinePointer _texturedPipeline;

View file

@ -9,13 +9,13 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
uniform sampler2D colorMap;
in vec4 varColor;
in vec2 varTexcoord;
out vec4 outFragColor;
uniform sampler2D tex;
void main(void) {
outFragColor = texture(tex, varTexcoord.xy) * varColor;
outFragColor = texture(colorMap, varTexcoord.xy) * varColor;
}

View file

@ -14,12 +14,45 @@
<$declareStandardTransform()$>
in vec4 inPosition;
in vec4 inColor;
struct ParticleUniforms {
struct {
float start;
float middle;
float finish;
float spread;
} radius;
struct {
vec4 start;
vec4 middle;
vec4 finish;
vec4 spread;
} color;
float lifespan;
};
uniform particleBuffer {
ParticleUniforms particle;
};
in vec3 inPosition;
in vec2 inExtra;
out vec4 varColor;
out vec2 varTexcoord;
float mix(float start, float finish, float age) {
return start + (finish - start) * age;
}
vec4 mixV(vec4 start, vec4 finish, float age) {
return vec4(mix(start.x, finish.x, age),
mix(start.y, finish.y, age),
mix(start.z, finish.z, age),
mix(start.w, finish.w, age));
}
void main(void) {
const int NUM_VERTICES_PER_PARTICLE = 4;
const vec4 UNIT_QUAD[NUM_VERTICES_PER_PARTICLE] = vec4[NUM_VERTICES_PER_PARTICLE](
@ -29,9 +62,12 @@ void main(void) {
vec4(1.0, 1.0, 0.0, 1.0)
);
float age = inExtra.x / particle.lifespan;
float seed = inExtra.y;
// anchor point in eye space
vec4 anchorPoint = vec4(inPosition.xyz, 1.0);
float radius = inPosition.w;
float radius = mix(particle.radius.start, particle.radius.finish , age);
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
@ -46,7 +82,8 @@ void main(void) {
// Pass the texcoord and the z texcoord is representing the texture icon
varTexcoord = vec2((quadPos.xy + 1.0) * 0.5);
varColor = inColor;
varColor = mixV(particle.color.start, particle.color.finish , age);
varColor.w = particle.color.middle.w;
vec4 clipPos;
vec4 eyePos = vec4(anchorPoint.xyz + quadPos.xyz, 1.0);

View file

@ -11,15 +11,15 @@
uniform sampler2D colorMap;
in vec4 _color;
in vec2 _texCoord0;
in vec4 varColor;
in vec2 varTexcoord;
out vec4 outFragColor;
void main(void) {
vec4 color = texture(colorMap, _texCoord0);
vec4 color = texture(colorMap, varTexcoord);
if (color.a < 0.1) {
discard;
}
outFragColor = color * _color;
outFragColor = color * varColor;
}

View file

@ -91,7 +91,7 @@ const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f;
const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS;
const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS;
const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = "";
const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = true;
const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = false;
EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
@ -584,25 +584,6 @@ void ParticleEffectEntityItem::updateShapeType(ShapeType type) {
}
}
void ParticleEffectEntityItem::updateRadius(Particle& particle, float age) {
particle.radius = Interpolate::interpolate3Points(particle.radiusStart, particle.radiusMiddle,
particle.radiusFinish, age);
}
void ParticleEffectEntityItem::updateColor(Particle& particle, float age) {
particle.color.red = (int)Interpolate::interpolate3Points(particle.colorStart.red, particle.colorMiddle.red,
particle.colorFinish.red, age);
particle.color.green = (int)Interpolate::interpolate3Points(particle.colorStart.green, particle.colorMiddle.green,
particle.colorFinish.green, age);
particle.color.blue = (int)Interpolate::interpolate3Points(particle.colorStart.blue, particle.colorMiddle.blue,
particle.colorFinish.blue, age);
}
void ParticleEffectEntityItem::updateAlpha(Particle& particle, float age) {
particle.alpha = Interpolate::interpolate3Points(particle.alphaStart, particle.alphaMiddle,
particle.alphaFinish, age);
}
void ParticleEffectEntityItem::integrateParticle(Particle& particle, float deltaTime) {
glm::vec3 atSquared = (0.5f * deltaTime * deltaTime) * particle.acceleration;
glm::vec3 at = particle.acceleration * deltaTime;
@ -610,14 +591,6 @@ void ParticleEffectEntityItem::integrateParticle(Particle& particle, float delta
particle.velocity += at;
}
void ParticleEffectEntityItem::updateParticle(Particle& particle, float deltaTime) {
float age = particle.lifetime / _lifespan; // 0.0 .. 1.0
updateRadius(particle, age);
updateColor(particle, age);
updateAlpha(particle, age);
integrateParticle(particle, deltaTime);
}
void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_particlesBounds.reset();
@ -631,7 +604,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
_particles.pop_front();
} else {
// Otherwise update it
updateParticle(particle, deltaTime);
integrateParticle(particle, deltaTime);
_particlesBounds.addPoint(particle.position);
}
}
@ -654,7 +627,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
particle.lifetime += timeLeftInFrame;
// Initialize it
updateParticle(particle, timeLeftInFrame);
integrateParticle(particle, deltaTime);
_particlesBounds.addPoint(particle.position);
// Advance in frame
@ -669,25 +642,7 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
Particle particle;
// Radius
if (_radiusSpread == 0.0f) {
particle.radiusStart = getRadiusStart();
particle.radiusMiddle = _particleRadius;
particle.radiusFinish = getRadiusFinish();
} else {
float spreadMultiplier;
if (_particleRadius > 0.0f) {
spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _radiusSpread / _particleRadius;
} else {
spreadMultiplier = 1.0f;
}
particle.radiusStart = glm::clamp(spreadMultiplier * getRadiusStart(),
MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
particle.radiusMiddle = glm::clamp(spreadMultiplier * _particleRadius,
MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
particle.radiusFinish = glm::clamp(spreadMultiplier * getRadiusFinish(),
MINIMUM_PARTICLE_RADIUS, MAXIMUM_PARTICLE_RADIUS);
}
particle.seed = randFloatInRange(0.0f, 1.0f);
// Position, velocity, and acceleration
if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) {
@ -745,49 +700,6 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread;
}
// Color
if (_colorSpread == xColor{ 0, 0, 0 }) {
particle.colorStart = getColorStart();
particle.colorMiddle = getXColor();
particle.colorFinish = getColorFinish();
} else {
xColor startColor = getColorStart();
xColor middleColor = getXColor();
xColor finishColor = getColorFinish();
float spread = randFloatInRange(-1.0f, 1.0f);
float spreadMultiplierRed =
middleColor.red > 0 ? 1.0f + spread * (float)_colorSpread.red / (float)middleColor.red : 1.0f;
float spreadMultiplierGreen =
middleColor.green > 0 ? 1.0f + spread * (float)_colorSpread.green / (float)middleColor.green : 1.0f;
float spreadMultiplierBlue =
middleColor.blue > 0 ? 1.0f + spread * (float)_colorSpread.blue / (float)middleColor.blue : 1.0f;
particle.colorStart.red = (int)glm::clamp(spreadMultiplierRed * (float)startColor.red, 0.0f, 255.0f);
particle.colorStart.green = (int)glm::clamp(spreadMultiplierGreen * (float)startColor.green, 0.0f, 255.0f);
particle.colorStart.blue = (int)glm::clamp(spreadMultiplierBlue * (float)startColor.blue, 0.0f, 255.0f);
particle.colorMiddle.red = (int)glm::clamp(spreadMultiplierRed * (float)middleColor.red, 0.0f, 255.0f);
particle.colorMiddle.green = (int)glm::clamp(spreadMultiplierGreen * (float)middleColor.green, 0.0f, 255.0f);
particle.colorMiddle.blue = (int)glm::clamp(spreadMultiplierBlue * (float)middleColor.blue, 0.0f, 255.0f);
particle.colorFinish.red = (int)glm::clamp(spreadMultiplierRed * (float)finishColor.red, 0.0f, 255.0f);
particle.colorFinish.green = (int)glm::clamp(spreadMultiplierGreen * (float)finishColor.green, 0.0f, 255.0f);
particle.colorFinish.blue = (int)glm::clamp(spreadMultiplierBlue * (float)finishColor.blue, 0.0f, 255.0f);
}
// Alpha
if (_alphaSpread == 0.0f) {
particle.alphaStart = getAlphaStart();
particle.alphaMiddle = _alpha;
particle.alphaFinish = getAlphaFinish();
} else {
float spreadMultiplier = 1.0f + randFloatInRange(-1.0f, 1.0f) * _alphaSpread / _alpha;
particle.alphaStart = spreadMultiplier * getAlphaStart();
particle.alphaMiddle = spreadMultiplier * _alpha;
particle.alphaFinish = spreadMultiplier * getAlphaFinish();
}
return particle;
}

View file

@ -211,7 +211,7 @@ public:
static const bool DEFAULT_ADDITIVE_BLENDING;
bool getAdditiveBlending() const { return _additiveBlending; }
void setAdditiveBlending(bool additiveBlending) {
_additiveBlending = true;
_additiveBlending = additiveBlending;
}
virtual bool supportsDetailedRayIntersection() const { return false; }
@ -224,31 +224,14 @@ protected:
Particle createParticle();
void stepSimulation(float deltaTime);
void updateParticle(Particle& particle, float deltaTime);
void updateRadius(Particle& particle, float age);
void updateColor(Particle& particle, float age);
void updateAlpha(Particle& particle, float age);
void integrateParticle(Particle& particle, float deltaTime);
struct Particle {
float seed { 0.0f };
float lifetime { 0.0f };
glm::vec3 position { Vectors::ZERO};
glm::vec3 velocity { Vectors::ZERO};
glm::vec3 acceleration { Vectors::ZERO};
float radius { DEFAULT_PARTICLE_RADIUS };
xColor color = DEFAULT_COLOR;
float alpha { DEFAULT_ALPHA };
float radiusStart { DEFAULT_PARTICLE_RADIUS };
float radiusMiddle { DEFAULT_PARTICLE_RADIUS };
float radiusFinish { DEFAULT_PARTICLE_RADIUS };
xColor colorStart = DEFAULT_COLOR;
xColor colorMiddle = DEFAULT_COLOR;
xColor colorFinish = DEFAULT_COLOR;
float alphaStart { DEFAULT_ALPHA };
float alphaMiddle { DEFAULT_ALPHA };
float alphaFinish { DEFAULT_ALPHA };
};
// Particles container

View file

@ -18,7 +18,7 @@ Light::Light() :
_transform() {
// only if created from nothing shall we create the Buffer to store the properties
Schema schema;
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema));
_schemaBuffer = std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema);
}
Light::Light(const Light& light) :

View file

@ -112,8 +112,6 @@ public:
Vec4 _shadow{0.0f};
Vec4 _control{0.0f, 0.0f, 0.0f, 0.0f};
Schema() {}
};
const UniformBufferView& getSchemaBuffer() const { return _schemaBuffer; }