From 3daa40087ea36d44c28cb165f62f0e2fec3bf169 Mon Sep 17 00:00:00 2001 From: HifiExperiments Date: Fri, 1 Mar 2024 13:04:11 -0800 Subject: [PATCH] support opaque (and black) particles --- .../RenderableParticleEffectEntityItem.cpp | 63 +++++++++++-------- .../src/RenderableParticleEffectEntityItem.h | 2 +- .../entities-renderer/textured_particle.slp | 1 + .../src/textured_particle.slf | 11 +++- 4 files changed, 49 insertions(+), 28 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index e2a57840d9..ff9ba9fb03 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -21,23 +21,35 @@ using namespace render::entities; static uint8_t CUSTOM_PIPELINE_NUMBER = 0; static gpu::Stream::FormatPointer _vertexFormat; -static std::weak_ptr _texturedPipeline; +static std::map, gpu::PipelinePointer> _pipelines; static ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, RenderArgs* args) { - auto texturedPipeline = _texturedPipeline.lock(); - if (!texturedPipeline) { - auto state = std::make_shared(); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, false, gpu::LESS_EQUAL); - state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - PrepareStencil::testMask(*state); + // FIXME: custom pipelines like this don't handle shadows or renderLayers correctly - auto program = gpu::Shader::createProgram(shader::entities_renderer::program::textured_particle); - _texturedPipeline = texturedPipeline = gpu::Pipeline::create(program, state); + if (_pipelines.empty()) { + for (size_t i = 0; i < 4; i++) { + bool transparent = (i % 2 == 0); + bool wireframe = (i / 2) == 0; + + auto state = std::make_shared(); + state->setCullMode(gpu::State::CULL_BACK); + + if (wireframe) { + state->setFillMode(gpu::State::FILL_LINE); + } + + state->setDepthTest(true, !transparent, gpu::LESS_EQUAL); + state->setBlendFunction(transparent, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + transparent ? PrepareStencil::testMask(*state) : PrepareStencil::testMaskDrawShape(*state); + + auto program = gpu::Shader::createProgram(transparent ? shader::entities_renderer::program::textured_particle_translucent : + shader::entities_renderer::program::textured_particle); + _pipelines[std::make_tuple(transparent, wireframe)] = gpu::Pipeline::create(program, state); + } } - return std::make_shared(texturedPipeline, nullptr, nullptr, nullptr); + return std::make_shared(_pipelines[std::make_tuple(key.isTranslucent(), key.isWireframe())], nullptr, nullptr, nullptr); } struct GpuParticle { @@ -138,26 +150,25 @@ void ParticleEffectEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEn _uniformBuffer.edit() = particleUniforms; } -ItemKey ParticleEffectEntityRenderer::getKey() { - // FIXME: implement isTransparent() for particles and an opaque pipeline - auto builder = ItemKey::Builder::transparentShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); - - if (!_visible) { - builder.withInvisible(); - } - - if (_cullWithParent) { - builder.withSubMetaCulled(); - } - - return builder.build(); +bool ParticleEffectEntityRenderer::isTransparent() const { + bool particleTransparent = _particleProperties.getColorStart().a < 1.0f || _particleProperties.getColorMiddle().a < 1.0f || + _particleProperties.getColorFinish().a < 1.0f || _particleProperties.getColorSpread().a > 0.0f || + _pulseProperties.getAlphaMode() != PulseMode::NONE || (_textureLoaded && _networkTexture && _networkTexture->getGPUTexture() && + _networkTexture->getGPUTexture()->getUsage().isAlpha() && !_networkTexture->getGPUTexture()->getUsage().isAlphaMask()); + return particleTransparent || Parent::isTransparent(); } ShapeKey ParticleEffectEntityRenderer::getShapeKey() { - auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER).withTranslucent(); + auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER); + + if (isTransparent()) { + builder.withTranslucent(); + } + if (_primitiveMode == PrimitiveMode::LINES) { builder.withWireframe(); } + return builder.build(); } diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h index 547d654486..08d8822d2d 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -28,7 +28,7 @@ protected: virtual void doRenderUpdateSynchronousTyped(const ScenePointer& scene, Transaction& transaction, const TypedEntityPointer& entity) override; virtual void doRenderUpdateAsynchronousTyped(const TypedEntityPointer& entity) override; - virtual ItemKey getKey() override; + bool isTransparent() const override; virtual ShapeKey getShapeKey() override; virtual Item::Bound getBound(RenderArgs* args) override; virtual void doRender(RenderArgs* args) override; diff --git a/libraries/entities-renderer/src/entities-renderer/textured_particle.slp b/libraries/entities-renderer/src/entities-renderer/textured_particle.slp index e69de29bb2..1348d72a8d 100644 --- a/libraries/entities-renderer/src/entities-renderer/textured_particle.slp +++ b/libraries/entities-renderer/src/entities-renderer/textured_particle.slp @@ -0,0 +1 @@ +DEFINES translucent:f \ No newline at end of file diff --git a/libraries/entities-renderer/src/textured_particle.slf b/libraries/entities-renderer/src/textured_particle.slf index 7dadb6fc49..7c26e036e4 100644 --- a/libraries/entities-renderer/src/textured_particle.slf +++ b/libraries/entities-renderer/src/textured_particle.slf @@ -18,5 +18,14 @@ layout(location=1) in vec2 varTexcoord; layout(location=0) out vec4 outFragColor; void main(void) { - outFragColor = texture(colorMap, varTexcoord.xy) * varColor; + vec4 albedo = texture(colorMap, varTexcoord.xy) * varColor; + + <@if not HIFI_USE_TRANSLUCENT@> + // to reduce texel flickering for floating point error we discard when alpha is "almost one" + if (albedo.a < 0.999999) { + discard; + } + <@endif@> + + outFragColor = albedo; }