diff --git a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp index e2a57840d93..8c885094aeb 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.cpp @@ -21,23 +21,48 @@ using namespace render::entities; static uint8_t CUSTOM_PIPELINE_NUMBER = 0; static gpu::Stream::FormatPointer _vertexFormat; -static std::weak_ptr _texturedPipeline; +// forward, transparent, shadow, wireframe +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); - - auto program = gpu::Shader::createProgram(shader::entities_renderer::program::textured_particle); - _texturedPipeline = texturedPipeline = gpu::Pipeline::create(program, state); + if (_pipelines.empty()) { + using namespace shader::entities_renderer::program; + + // forward, translucent, shadow + static const std::vector> keys = { + std::make_tuple(false, false, false, textured_particle), + std::make_tuple(true, false, false, textured_particle_forward), + std::make_tuple(false, true, false, textured_particle_translucent), + std::make_tuple(true, true, false, textured_particle_translucent_forward), + std::make_tuple(false, false, true, textured_particle_shadow), + // no such thing as shadow and forward/translucent + }; + + for (auto& key : keys) { + for (int i = 0; i < 2; ++i) { + bool transparent = std::get<1>(key); + bool wireframe = i == 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(std::get<3>(key)); + _pipelines[std::make_tuple(std::get<0>(key), transparent, std::get<2>(key), wireframe)] = gpu::Pipeline::create(program, state); + } + } } - return std::make_shared(texturedPipeline, nullptr, nullptr, nullptr); + return std::make_shared(_pipelines[std::make_tuple(args->_renderMethod == Args::RenderMethod::FORWARD, key.isTranslucent(), + args->_renderMode == Args::RenderMode::SHADOW_RENDER_MODE, key.isWireframe())], nullptr, nullptr, nullptr); } struct GpuParticle { @@ -138,26 +163,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()); +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(); +} - if (!_visible) { - builder.withInvisible(); - } +ShapeKey ParticleEffectEntityRenderer::getShapeKey() { + auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER); - if (_cullWithParent) { - builder.withSubMetaCulled(); + if (isTransparent()) { + builder.withTranslucent(); } - return builder.build(); -} - -ShapeKey ParticleEffectEntityRenderer::getShapeKey() { - auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER).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 547d6544866..08d8822d2db 100644 --- a/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h +++ b/libraries/entities-renderer/src/RenderableParticleEffectEntityItem.h @@ -28,7 +28,7 @@ class ParticleEffectEntityRenderer : public TypedEntityRenderer, ShapePipelinePointer> _pipelines; +// forward, shadow, fade, wireframe +static std::map, ShapePipelinePointer> _pipelines; static gpu::Stream::FormatPointer _vertexFormat; ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const ShapeKey& key, RenderArgs* args) { - // FIXME: custom pipelines like this don't handle shadows or renderLayers correctly - if (_pipelines.empty()) { using namespace shader::entities_renderer::program; - static const std::vector> keys = { - std::make_tuple(false, false, polyvox), std::make_tuple(true, false, polyvox_forward) + // forward, shadow, fade + static const std::vector> keys = { + std::make_tuple(false, false, false, polyvox), + std::make_tuple(true, false, false, polyvox_forward), + std::make_tuple(false, true, false, polyvox_shadow), + // no such thing as forward + shadow #ifdef POLYVOX_ENTITY_USE_FADE_EFFECT - , std::make_tuple(false, true, polyvox_fade), std::make_tuple(true, true, polyvox_forward_fade) + std::make_tuple(false, false, true, polyvox_fade), + std::make_tuple(false, true, true, polyvox_shadow_fade), + // no such thing as forward + fade/shadow #else - , std::make_tuple(false, true, polyvox), std::make_tuple(true, true, polyvox_forward) + std::make_tuple(false, false, true, polyvox), + std::make_tuple(false, true, true, polyvox_shadow), + // no such thing as forward + fade/shadow #endif }; for (auto& key : keys) { @@ -1749,19 +1756,19 @@ ShapePipelinePointer shapePipelineFactory(const ShapePlumber& plumber, const Sha state->setFillMode(gpu::State::FILL_LINE); } - auto pipeline = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<2>(key)), state); - if (std::get<1>(key)) { - _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), wireframe)] = std::make_shared(pipeline, nullptr, nullptr, nullptr); + auto pipeline = gpu::Pipeline::create(gpu::Shader::createProgram(std::get<3>(key)), state); + if (!std::get<2>(key)) { + _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key), wireframe)] = std::make_shared(pipeline, nullptr, nullptr, nullptr); } else { const auto& fadeEffect = DependencyManager::get(); - _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), wireframe)] = std::make_shared(pipeline, nullptr, + _pipelines[std::make_tuple(std::get<0>(key), std::get<1>(key), std::get<2>(key), wireframe)] = std::make_shared(pipeline, nullptr, fadeEffect->getBatchSetter(), fadeEffect->getItemUniformSetter()); } } } } - return _pipelines[std::make_tuple(args->_renderMethod == Args::RenderMethod::FORWARD, key.isFaded(), key.isWireframe())]; + return _pipelines[std::make_tuple(args->_renderMethod == Args::RenderMethod::FORWARD, args->_renderMode == Args::RenderMode::SHADOW_RENDER_MODE, key.isFaded(), key.isWireframe())]; } PolyVoxEntityRenderer::PolyVoxEntityRenderer(const EntityItemPointer& entity) : Parent(entity) { @@ -1775,16 +1782,6 @@ PolyVoxEntityRenderer::PolyVoxEntityRenderer(const EntityItemPointer& entity) : _params = std::make_shared(sizeof(glm::vec4), nullptr); } -ItemKey PolyVoxEntityRenderer::getKey() { - auto builder = ItemKey::Builder::opaqueShape().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); - - if (_cullWithParent) { - builder.withSubMetaCulled(); - } - - return builder.build(); -} - ShapeKey PolyVoxEntityRenderer::getShapeKey() { auto builder = ShapeKey::Builder().withCustom(CUSTOM_PIPELINE_NUMBER); if (_primitiveMode == PrimitiveMode::LINES) { @@ -1866,13 +1863,7 @@ void PolyVoxEntityRenderer::doRender(RenderArgs* args) { batch.setModelTransform(transform); batch.setInputFormat(_vertexFormat); - batch.setInputBuffer(gpu::Stream::POSITION, _mesh->getVertexBuffer()._buffer, 0, - sizeof(PolyVox::PositionMaterialNormal)); - - // TODO -- should we be setting this? - // batch.setInputBuffer(gpu::Stream::NORMAL, mesh->getVertexBuffer()._buffer, - // 12, - // sizeof(PolyVox::PositionMaterialNormal)); + batch.setInputBuffer(gpu::Stream::POSITION, _mesh->getVertexBuffer()._buffer, 0, sizeof(PolyVox::PositionMaterialNormal)); batch.setIndexBuffer(gpu::UINT32, _mesh->getIndexBuffer()._buffer, 0); for (size_t i = 0; i < _xyzTextures.size(); ++i) { diff --git a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h index c1c35a21c81..1debeb957c2 100644 --- a/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyVoxEntityItem.h @@ -203,7 +203,6 @@ class PolyVoxEntityRenderer : public TypedEntityRenderer + layout(location=0) out vec4 _fragColor0; +<@else@> + <@include DeferredBufferWrite.slh@> +<@endif@> void main(void) { - outFragColor = texture(colorMap, varTexcoord.xy) * varColor; + vec4 albedo = texture(colorMap, varTexcoord.xy) * varColor; + +<@if HIFI_USE_FORWARD or HIFI_USE_SHADOW@> + <@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@> + +<@if HIFI_USE_FORWARD@> + _fragColor0 = albedo; +<@else@> + _fragColor0 = vec4(1.0); +<@endif@> +<@else@> + vec3 NORMAL = vec3(1.0, 0.0, 0.0); + <@if not HIFI_USE_TRANSLUCENT@> + packDeferredFragmentUnlit(NORMAL, albedo.a, albedo.rgb); + <@else@> + packDeferredFragmentTranslucent(NORMAL, albedo.a, albedo.rgb, DEFAULT_ROUGHNESS); + <@endif@> +<@endif@> } diff --git a/libraries/render-utils/src/RenderCommonTask.cpp b/libraries/render-utils/src/RenderCommonTask.cpp index 7cf7f1129fb..3853d06d31b 100644 --- a/libraries/render-utils/src/RenderCommonTask.cpp +++ b/libraries/render-utils/src/RenderCommonTask.cpp @@ -85,6 +85,8 @@ void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& } if (!inItems.empty()) { + auto deferredLightingEffect = DependencyManager::get(); + // Render the items gpu::doInBatch("DrawLayered3D::main", args->_context, [&](gpu::Batch& batch) { args->_batch = &batch; @@ -108,11 +110,20 @@ void DrawLayered3D::run(const RenderContextPointer& renderContext, const Inputs& batch.setUniformBuffer(graphics::slot::buffer::Buffer::HazeParams, haze->getHazeParametersBuffer()); } + // Set the light + deferredLightingEffect->setupKeyLightBatch(args, batch); + + auto renderMethod = args->_renderMethod; + args->_renderMethod = Args::RenderMethod::FORWARD; if (_opaquePass) { renderStateSortShapes(renderContext, _shapePlumber, inItems, _maxDrawn); } else { renderShapes(renderContext, _shapePlumber, inItems, _maxDrawn); } + + deferredLightingEffect->unsetLocalLightsBatch(batch); + + args->_renderMethod = renderMethod; args->_batch = nullptr; }); } diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index 94e235a1c5d..879b48ce111 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -403,6 +403,7 @@ void initZPassPipelines(ShapePlumber& plumber, gpu::StatePointer state, const re void sortAndRenderZPassShapes(const ShapePlumberPointer& shapePlumber, const render::RenderContextPointer& renderContext, const render::ShapeBounds& inShapes, render::ItemBounds &itemBounds) { std::unordered_map, ShapeKey::Hash, ShapeKey::KeyEqual> sortedShapeKeys; + std::unordered_map, ShapeKey::Hash, ShapeKey::KeyEqual>> sortedCustomShapeKeys; std::unordered_map, ShapeKey::Hash, ShapeKey::KeyEqual> sortedOwnPipelineShapeKeys; for (const auto& items : inShapes) { @@ -444,14 +445,25 @@ void sortAndRenderZPassShapes(const ShapePlumberPointer& shapePlumber, const ren if (items.first.hasOwnPipeline()) { sortedOwnPipelineShapeKeys[variantKey.build()].push_back(items.first); + } else if (items.first.isCustom()) { + const uint8_t custom = items.first.getCustom(); + variantKey.withCustom(custom); + sortedCustomShapeKeys[custom][variantKey.build()].push_back(items.first); } else { sortedShapeKeys[variantKey.build()].push_back(items.first); } } - // Render non-withOwnPipeline things - for (auto& variantAndKeys : sortedShapeKeys) { - if (variantAndKeys.second.size() > 0) { + // Render non-withCustom, non-withOwnPipeline things + for (const auto& variantAndKeys : sortedShapeKeys) { + for (const auto& key : variantAndKeys.second) { + renderShapes(renderContext, shapePlumber, inShapes.at(key)); + } + } + + // Render withCustom things + for (const auto& customAndSortedCustomKeys : sortedCustomShapeKeys) { + for (const auto& variantAndKeys : customAndSortedCustomKeys.second) { for (const auto& key : variantAndKeys.second) { renderShapes(renderContext, shapePlumber, inShapes.at(key)); } @@ -459,11 +471,9 @@ void sortAndRenderZPassShapes(const ShapePlumberPointer& shapePlumber, const ren } // Render withOwnPipeline things - for (auto& variantAndKeys : sortedOwnPipelineShapeKeys) { - if (variantAndKeys.second.size() > 0) { - for (const auto& key : variantAndKeys.second) { - renderShapes(renderContext, shapePlumber, inShapes.at(key)); - } + for (const auto& variantAndKeys : sortedOwnPipelineShapeKeys) { + for (const auto& key : variantAndKeys.second) { + renderShapes(renderContext, shapePlumber, inShapes.at(key)); } } diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index 048e08e959f..4d1682de9a4 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -60,8 +60,8 @@ ShapeKey::Filter::Builder::Builder() { } void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) const { - // Iterate over all keys - if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) { + // Iterate over all non-custom keys + if (bit < (int)ShapeKey::FlagBit::NUM_NON_CUSTOM - 1) { addPipelineHelper(filter, key, bit + 1, pipeline); if (!filter._mask[bit]) { // Toggle bits set as insignificant in filter._mask diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 525572fc44b..fd8b729ffa9 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -54,6 +54,7 @@ class ShapeKey { CUSTOM_7, NUM_FLAGS, // Not a valid flag + NUM_NON_CUSTOM = INVALID, CUSTOM_MASK = (0xFF << CUSTOM_0), @@ -112,7 +113,7 @@ class ShapeKey { Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); } Builder& invalidate() { _flags.set(INVALID); return (*this); } - Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); return (*this); } + Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); return (*this); } static const ShapeKey ownPipeline() { return Builder().withOwnPipeline(); } static const ShapeKey invalid() { return Builder().invalidate(); }