diff --git a/libraries/entities-renderer/src/RenderableEntityItem.h b/libraries/entities-renderer/src/RenderableEntityItem.h index c860b849b8..2697d30de4 100644 --- a/libraries/entities-renderer/src/RenderableEntityItem.h +++ b/libraries/entities-renderer/src/RenderableEntityItem.h @@ -101,7 +101,7 @@ protected: virtual void doRender(RenderArgs* args) = 0; virtual bool isFading() const { return _isFading; } - void updateModelTransformAndBound(); + virtual void updateModelTransformAndBound(); virtual bool isTransparent() const { return _isFading ? Interpolate::calculateFadeRatio(_fadeStartTime) < 1.0f : false; } inline bool isValidRenderItem() const { return _renderItemID != Item::INVALID_ITEM_ID; } @@ -124,7 +124,6 @@ signals: protected: template<typename T> std::shared_ptr<T> asTypedEntity() { return std::static_pointer_cast<T>(_entity); } - static void makeStatusGetters(const EntityItemPointer& entity, Item::Status::Getters& statusGetters); const Transform& getModelTransform() const; @@ -153,7 +152,6 @@ protected: quint64 _created; -private: // The base class relies on comparing the model transform to the entity transform in order // to trigger an update, so the member must not be visible to derived classes as a modifiable // transform diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp index 9d2ce6fa28..9a762b3b3a 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.cpp @@ -41,23 +41,55 @@ PolyLineEntityRenderer::PolyLineEntityRenderer(const EntityItemPointer& entity) } } -void PolyLineEntityRenderer::buildPipelines() { - // FIXME: opaque pipelines +void PolyLineEntityRenderer::updateModelTransformAndBound() { + bool success = false; + auto newModelTransform = _entity->getTransformToCenter(success); + if (success) { + _modelTransform = newModelTransform; + auto lineEntity = std::static_pointer_cast<PolyLineEntityItem>(_entity); + AABox bound; + lineEntity->computeTightLocalBoundingBox(bound); + bound.transform(newModelTransform); + _bound = bound; + } +} + +bool PolyLineEntityRenderer::isTransparent() const { + return _glow || (_textureLoaded && _texture->getGPUTexture() && _texture->getGPUTexture()->getUsage().isAlpha()); +} + +void PolyLineEntityRenderer::buildPipelines() { static const std::vector<std::pair<render::Args::RenderMethod, bool>> keys = { { render::Args::DEFERRED, false }, { render::Args::DEFERRED, true }, { render::Args::FORWARD, false }, { render::Args::FORWARD, true }, }; for (auto& key : keys) { - gpu::ShaderPointer program = gpu::Shader::createProgram(key.first == render::Args::DEFERRED ? shader::entities_renderer::program::paintStroke : shader::entities_renderer::program::paintStroke_forward); + gpu::ShaderPointer program; + render::Args::RenderMethod renderMethod = key.first; + bool transparent = key.second; + + if (renderMethod == render::Args::DEFERRED) { + if (transparent) { + program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke_translucent); + } else { + program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke); + } + } else { // render::Args::FORWARD + program = gpu::Shader::createProgram(shader::entities_renderer::program::paintStroke_forward); + } gpu::StatePointer state = gpu::StatePointer(new gpu::State()); state->setCullMode(gpu::State::CullMode::CULL_NONE); - state->setDepthTest(true, !key.second, gpu::LESS_EQUAL); - PrepareStencil::testMask(*state); + state->setDepthTest(true, !transparent, gpu::LESS_EQUAL); + if (transparent) { + PrepareStencil::testMask(*state); + } else { + PrepareStencil::testMaskDrawShape(*state); + } - state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + state->setBlendFunction(transparent, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); _pipelines[key] = gpu::Pipeline::create(program, state); @@ -65,11 +97,16 @@ void PolyLineEntityRenderer::buildPipelines() { } ItemKey PolyLineEntityRenderer::getKey() { - return ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); + return isTransparent() ? + ItemKey::Builder::transparentShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()) : + ItemKey::Builder::opaqueShape().withTypeMeta().withTagBits(getTagMask()).withLayer(getHifiRenderLayer()); } ShapeKey PolyLineEntityRenderer::getShapeKey() { - auto builder = ShapeKey::Builder().withOwnPipeline().withTranslucent().withoutCullFace(); + auto builder = ShapeKey::Builder().withOwnPipeline().withoutCullFace(); + if (isTransparent()) { + builder.withTranslucent(); + } if (_primitiveMode == PrimitiveMode::LINES) { builder.withWireframe(); } @@ -294,7 +331,7 @@ void PolyLineEntityRenderer::doRender(RenderArgs* args) { buildPipelines(); } - batch.setPipeline(_pipelines[{args->_renderMethod, _glow}]); + batch.setPipeline(_pipelines[{args->_renderMethod, isTransparent()}]); batch.setModelTransform(transform); batch.setResourceTexture(0, texture); batch.draw(gpu::TRIANGLE_STRIP, (gpu::uint32)(2 * numVertices), 0); diff --git a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h index 9139c260ea..41b66c0e51 100644 --- a/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h +++ b/libraries/entities-renderer/src/RenderablePolyLineEntityItem.h @@ -25,8 +25,9 @@ class PolyLineEntityRenderer : public TypedEntityRenderer<PolyLineEntityItem> { public: PolyLineEntityRenderer(const EntityItemPointer& entity); - // FIXME: shouldn't always be transparent: take into account texture and glow - virtual bool isTransparent() const override { return true; } + void updateModelTransformAndBound() override; + + virtual bool isTransparent() const override; protected: virtual bool needsRenderUpdate() const override; diff --git a/libraries/entities-renderer/src/entities-renderer/paintStroke.slp b/libraries/entities-renderer/src/entities-renderer/paintStroke.slp index e283f4edcb..acdda4dece 100644 --- a/libraries/entities-renderer/src/entities-renderer/paintStroke.slp +++ b/libraries/entities-renderer/src/entities-renderer/paintStroke.slp @@ -1 +1 @@ -DEFINES forward \ No newline at end of file +DEFINES translucent:f forward diff --git a/libraries/entities-renderer/src/paintStroke.slf b/libraries/entities-renderer/src/paintStroke.slf index 4ae242655c..3d5cc190d0 100644 --- a/libraries/entities-renderer/src/paintStroke.slf +++ b/libraries/entities-renderer/src/paintStroke.slf @@ -34,7 +34,11 @@ void main(void) { texel.a *= mix(1.0, pow(1.0 - min(1.0, abs(_distanceFromCenter)), 10.0), _polylineData.faceCameraGlow.y); <@if not HIFI_USE_FORWARD@> - packDeferredFragmentTranslucent((2.0 * float(gl_FrontFacing) - 1.0) * _normalWS, texel.a, texel.rgb, DEFAULT_ROUGHNESS); + <@if HIFI_USE_TRANSLUCENT@> + packDeferredFragmentTranslucent((2.0 * float(gl_FrontFacing) - 1.0) * _normalWS, texel.a, texel.rgb, DEFAULT_ROUGHNESS); + <@else@> + packDeferredFragmentUnlit((2.0 * float(gl_FrontFacing) - 1.0) * _normalWS, texel.a, texel.rgb); + <@endif@> <@else@> _fragColor0 = texel; <@endif@> diff --git a/libraries/entities/src/PolyLineEntityItem.cpp b/libraries/entities/src/PolyLineEntityItem.cpp index 645d2b39f8..fe14ba6925 100644 --- a/libraries/entities/src/PolyLineEntityItem.cpp +++ b/libraries/entities/src/PolyLineEntityItem.cpp @@ -14,6 +14,7 @@ #include <QDebug> #include <ByteCountCoding.h> +#include <Extents.h> #include "EntitiesLogging.h" #include "EntityItemProperties.h" @@ -85,7 +86,7 @@ void PolyLineEntityItem::setLinePoints(const QVector<glm::vec3>& points) { _points = points; _pointsChanged = true; }); - computeAndUpdateDimensionsAndPosition(); + computeAndUpdateDimensions(); } void PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) { @@ -93,7 +94,7 @@ void PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) { _widths = strokeWidths; _widthsChanged = true; }); - computeAndUpdateDimensionsAndPosition(); + computeAndUpdateDimensions(); } void PolyLineEntityItem::setNormals(const QVector<glm::vec3>& normals) { @@ -110,7 +111,7 @@ void PolyLineEntityItem::setStrokeColors(const QVector<glm::vec3>& strokeColors) }); } -void PolyLineEntityItem::computeAndUpdateDimensionsAndPosition() { +void PolyLineEntityItem::computeAndUpdateDimensions() { QVector<glm::vec3> points; QVector<float> widths; @@ -129,6 +130,32 @@ void PolyLineEntityItem::computeAndUpdateDimensionsAndPosition() { setScaledDimensions(2.0f * (maxHalfDim + maxWidth)); } +void PolyLineEntityItem::computeTightLocalBoundingBox(AABox& localBox) const { + QVector<glm::vec3> points; + QVector<float> widths; + withReadLock([&] { + points = _points; + widths = _widths; + }); + + if (points.size() > 0) { + Extents extents; + float maxWidth = DEFAULT_LINE_WIDTH; + for (int i = 0; i < points.length(); i++) { + extents.addPoint(points[i]); + if (i < widths.size()) { + maxWidth = glm::max(maxWidth, widths[i]); + } + } + extents.addPoint(extents.minimum - maxWidth * Vectors::ONE); + extents.addPoint(extents.maximum + maxWidth * Vectors::ONE); + + localBox.setBox(extents.minimum, extents.maximum - extents.minimum); + } else { + localBox.setBox(glm::vec3(-0.5f * DEFAULT_LINE_WIDTH), glm::vec3(DEFAULT_LINE_WIDTH)); + } +} + int PolyLineEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead, ReadBitstreamToTreeParams& args, EntityPropertyFlags& propertyFlags, bool overwriteLocalData, @@ -267,4 +294,4 @@ void PolyLineEntityItem::setFaceCamera(bool faceCamera) { _needsRenderUpdate = _faceCamera != faceCamera; _faceCamera = faceCamera; }); -} \ No newline at end of file +} diff --git a/libraries/entities/src/PolyLineEntityItem.h b/libraries/entities/src/PolyLineEntityItem.h index fc3b085cf1..e68666d75e 100644 --- a/libraries/entities/src/PolyLineEntityItem.h +++ b/libraries/entities/src/PolyLineEntityItem.h @@ -15,7 +15,7 @@ #include "EntityItem.h" class PolyLineEntityItem : public EntityItem { - public: +public: static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties); PolyLineEntityItem(const EntityItemID& entityItemID); @@ -90,10 +90,12 @@ class PolyLineEntityItem : public EntityItem { BoxFace& face, glm::vec3& surfaceNormal, QVariantMap& extraInfo, bool precisionPicking) const override { return false; } + void computeTightLocalBoundingBox(AABox& box) const; + virtual void debugDump() const override; private: - void computeAndUpdateDimensionsAndPosition(); - + void computeAndUpdateDimensions(); + protected: glm::u8vec3 _color; QVector<glm::vec3> _points; diff --git a/libraries/render-utils/src/DeferredBufferWrite.slh b/libraries/render-utils/src/DeferredBufferWrite.slh index de4581d66e..de3d0a3087 100644 --- a/libraries/render-utils/src/DeferredBufferWrite.slh +++ b/libraries/render-utils/src/DeferredBufferWrite.slh @@ -52,7 +52,8 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float r } void packDeferredFragmentUnlit(vec3 normal, float alpha, vec3 color) { - if (alpha < 1.0) { + // to reduce texel flickering for floating point error we discard when alpha is "almost one" + if (alpha < 0.999999) { discard; } _fragColor0 = vec4(color, packUnlit());