diff --git a/interface/src/ui/overlays/Circle3DOverlay.cpp b/interface/src/ui/overlays/Circle3DOverlay.cpp index bbb9addc3d..252aacef43 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.cpp +++ b/interface/src/ui/overlays/Circle3DOverlay.cpp @@ -105,7 +105,6 @@ void Circle3DOverlay::render(RenderArgs* args) { auto transform = _transform; transform.postScale(glm::vec3(getDimensions(), 1.0f)); batch.setModelTransform(transform); - DependencyManager::get()->bindSimpleProgram(batch, false, false); // for our overlay, is solid means we draw a ring between the inner and outer radius of the circle, otherwise // we just draw a line... @@ -278,6 +277,14 @@ void Circle3DOverlay::render(RenderArgs* args) { } } +const render::ShapeKey Circle3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder().withoutCullFace(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); +} + void Circle3DOverlay::setProperties(const QScriptValue &properties) { Planar3DOverlay::setProperties(properties); diff --git a/interface/src/ui/overlays/Circle3DOverlay.h b/interface/src/ui/overlays/Circle3DOverlay.h index d03dc2ee2a..7050da3368 100644 --- a/interface/src/ui/overlays/Circle3DOverlay.h +++ b/interface/src/ui/overlays/Circle3DOverlay.h @@ -25,6 +25,7 @@ public: Circle3DOverlay(const Circle3DOverlay* circle3DOverlay); virtual void render(RenderArgs* args); + virtual const render::ShapeKey getShapeKey() override; virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); diff --git a/interface/src/ui/overlays/Cube3DOverlay.cpp b/interface/src/ui/overlays/Cube3DOverlay.cpp index e291882161..8ba29bd336 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.cpp +++ b/interface/src/ui/overlays/Cube3DOverlay.cpp @@ -46,22 +46,17 @@ void Cube3DOverlay::render(RenderArgs* args) { Transform transform; transform.setTranslation(position); transform.setRotation(rotation); - if (_isSolid) { - // if (_borderSize > 0) { - // // Draw a cube at a larger size behind the main cube, creating - // // a border effect. - // // Disable writing to the depth mask so that the "border" cube will not - // // occlude the main cube. This means the border could be covered by - // // overlays that are further back and drawn later, but this is good - // // enough for the use-case. - // transform.setScale(dimensions * _borderSize); - // batch->setModelTransform(transform); - // DependencyManager::get()->renderSolidCube(*batch, 1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha)); - // } + auto geometryCache = DependencyManager::get(); + auto pipeline = args->_pipeline; + if (!pipeline) { + pipeline = geometryCache->getShapePipeline(); + } + + if (_isSolid) { transform.setScale(dimensions); batch->setModelTransform(transform); - DependencyManager::get()->renderSolidCubeInstance(*batch, cubeColor); + geometryCache->renderSolidCubeInstance(*batch, cubeColor, pipeline); } else { if (getIsDashedLine()) { @@ -79,8 +74,6 @@ void Cube3DOverlay::render(RenderArgs* args) { glm::vec3 topLeftFar(-halfDimensions.x, halfDimensions.y, halfDimensions.z); glm::vec3 topRightFar(halfDimensions.x, halfDimensions.y, halfDimensions.z); - auto geometryCache = DependencyManager::get(); - geometryCache->renderDashedLine(*batch, bottomLeftNear, bottomRightNear, cubeColor); geometryCache->renderDashedLine(*batch, bottomRightNear, bottomRightFar, cubeColor); geometryCache->renderDashedLine(*batch, bottomRightFar, bottomLeftFar, cubeColor); @@ -99,12 +92,20 @@ void Cube3DOverlay::render(RenderArgs* args) { } else { transform.setScale(dimensions); batch->setModelTransform(transform); - DependencyManager::get()->renderWireCubeInstance(*batch, cubeColor); + geometryCache->renderWireCubeInstance(*batch, cubeColor, pipeline); } } } } +const render::ShapeKey Cube3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); +} + Cube3DOverlay* Cube3DOverlay::createClone() const { return new Cube3DOverlay(this); } diff --git a/interface/src/ui/overlays/Cube3DOverlay.h b/interface/src/ui/overlays/Cube3DOverlay.h index 6f9026a091..30b6646362 100644 --- a/interface/src/ui/overlays/Cube3DOverlay.h +++ b/interface/src/ui/overlays/Cube3DOverlay.h @@ -24,6 +24,7 @@ public: Cube3DOverlay(const Cube3DOverlay* cube3DOverlay); virtual void render(RenderArgs* args); + virtual const render::ShapeKey getShapeKey() override; virtual Cube3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/Grid3DOverlay.cpp b/interface/src/ui/overlays/Grid3DOverlay.cpp index bfb0d1d9df..fca6a3796a 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.cpp +++ b/interface/src/ui/overlays/Grid3DOverlay.cpp @@ -93,6 +93,14 @@ void Grid3DOverlay::render(RenderArgs* args) { } } +const render::ShapeKey Grid3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); +} + void Grid3DOverlay::setProperties(const QScriptValue& properties) { Planar3DOverlay::setProperties(properties); diff --git a/interface/src/ui/overlays/Grid3DOverlay.h b/interface/src/ui/overlays/Grid3DOverlay.h index 5fb3852905..f9744f3954 100644 --- a/interface/src/ui/overlays/Grid3DOverlay.h +++ b/interface/src/ui/overlays/Grid3DOverlay.h @@ -25,6 +25,7 @@ public: Grid3DOverlay(const Grid3DOverlay* grid3DOverlay); virtual void render(RenderArgs* args); + virtual const render::ShapeKey getShapeKey() override; virtual void setProperties(const QScriptValue& properties); virtual QScriptValue getProperty(const QString& property); diff --git a/interface/src/ui/overlays/Image3DOverlay.cpp b/interface/src/ui/overlays/Image3DOverlay.cpp index 8ce8bf7a5f..66f7143e83 100644 --- a/interface/src/ui/overlays/Image3DOverlay.cpp +++ b/interface/src/ui/overlays/Image3DOverlay.cpp @@ -95,7 +95,6 @@ void Image3DOverlay::render(RenderArgs* args) { batch->setModelTransform(transform); batch->setResourceTexture(0, _texture->getGPUTexture()); - DependencyManager::get()->bindSimpleProgram(*batch, true, false, _emissive, true); DependencyManager::get()->renderQuad( *batch, topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight, glm::vec4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha) @@ -104,6 +103,17 @@ void Image3DOverlay::render(RenderArgs* args) { batch->setResourceTexture(0, args->_whiteTexture); // restore default white color after me } +const render::ShapeKey Image3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); + if (_emissive) { + builder.withEmissive(); + } + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); +} + void Image3DOverlay::setProperties(const QScriptValue &properties) { Billboard3DOverlay::setProperties(properties); diff --git a/interface/src/ui/overlays/Image3DOverlay.h b/interface/src/ui/overlays/Image3DOverlay.h index f2cc3789ee..0b0b245872 100644 --- a/interface/src/ui/overlays/Image3DOverlay.h +++ b/interface/src/ui/overlays/Image3DOverlay.h @@ -31,6 +31,8 @@ public: virtual void update(float deltatime); + virtual const render::ShapeKey getShapeKey() override; + // setters void setURL(const QString& url); void setClipFromSource(const QRect& bounds) { _fromImage = bounds; } diff --git a/interface/src/ui/overlays/Line3DOverlay.cpp b/interface/src/ui/overlays/Line3DOverlay.cpp index ed97b95de0..c0a1c9e282 100644 --- a/interface/src/ui/overlays/Line3DOverlay.cpp +++ b/interface/src/ui/overlays/Line3DOverlay.cpp @@ -53,7 +53,6 @@ void Line3DOverlay::render(RenderArgs* args) { auto batch = args->_batch; if (batch) { batch->setModelTransform(_transform); - DependencyManager::get()->bindSimpleProgram(*batch); if (getIsDashedLine()) { // TODO: add support for color to renderDashedLine() @@ -64,6 +63,14 @@ void Line3DOverlay::render(RenderArgs* args) { } } +const render::ShapeKey Line3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); +} + void Line3DOverlay::setProperties(const QScriptValue& properties) { Base3DOverlay::setProperties(properties); diff --git a/interface/src/ui/overlays/Line3DOverlay.h b/interface/src/ui/overlays/Line3DOverlay.h index 05812709dc..b40ff78231 100644 --- a/interface/src/ui/overlays/Line3DOverlay.h +++ b/interface/src/ui/overlays/Line3DOverlay.h @@ -24,6 +24,7 @@ public: Line3DOverlay(const Line3DOverlay* line3DOverlay); ~Line3DOverlay(); virtual void render(RenderArgs* args); + virtual const render::ShapeKey getShapeKey() override; virtual AABox getBounds() const; // getters diff --git a/interface/src/ui/overlays/Overlay.h b/interface/src/ui/overlays/Overlay.h index 4d3b5ae36f..2343e434ca 100644 --- a/interface/src/ui/overlays/Overlay.h +++ b/interface/src/ui/overlays/Overlay.h @@ -44,6 +44,8 @@ public: virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges); virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr scene, render::PendingChanges& pendingChanges); + virtual const render::ShapeKey getShapeKey() { return render::ShapeKey::Builder::ownPipeline(); } + // getters virtual QString getType() const = 0; virtual bool is3D() const = 0; @@ -119,6 +121,7 @@ namespace render { template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay); template <> int payloadGetLayer(const Overlay::Pointer& overlay); template <> void payloadRender(const Overlay::Pointer& overlay, RenderArgs* args); + template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay); } diff --git a/interface/src/ui/overlays/OverlaysPayload.cpp b/interface/src/ui/overlays/OverlaysPayload.cpp index 753106fa0a..bf625503c0 100644 --- a/interface/src/ui/overlays/OverlaysPayload.cpp +++ b/interface/src/ui/overlays/OverlaysPayload.cpp @@ -35,15 +35,18 @@ namespace render { template <> const ItemKey payloadGetKey(const Overlay::Pointer& overlay) { + auto builder = ItemKey::Builder().withTypeShape(); if (overlay->is3D() && !std::dynamic_pointer_cast(overlay)->getDrawOnHUD()) { if (std::dynamic_pointer_cast(overlay)->getDrawInFront()) { - return ItemKey::Builder().withTypeShape().withLayered().build(); - } else { - return ItemKey::Builder::opaqueShape(); + builder.withLayered(); + } + if (overlay->getAlpha() != 1.0f) { + builder.withTransparent(); } } else { - return ItemKey::Builder().withTypeShape().withViewSpace().build(); + builder.withViewSpace(); } + return builder.build(); } template <> const Item::Bound payloadGetBound(const Overlay::Pointer& overlay) { return overlay->getBounds(); @@ -80,4 +83,7 @@ namespace render { } } } + template <> const ShapeKey shapeGetShapeKey(const Overlay::Pointer& overlay) { + return overlay->getShapeKey(); + } } diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.cpp b/interface/src/ui/overlays/Rectangle3DOverlay.cpp index 64c5e4c819..cee924c44c 100644 --- a/interface/src/ui/overlays/Rectangle3DOverlay.cpp +++ b/interface/src/ui/overlays/Rectangle3DOverlay.cpp @@ -88,6 +88,14 @@ void Rectangle3DOverlay::render(RenderArgs* args) { } } +const render::ShapeKey Rectangle3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); +} + void Rectangle3DOverlay::setProperties(const QScriptValue &properties) { Planar3DOverlay::setProperties(properties); } diff --git a/interface/src/ui/overlays/Rectangle3DOverlay.h b/interface/src/ui/overlays/Rectangle3DOverlay.h index e5eba8bce8..cde4ad2f53 100644 --- a/interface/src/ui/overlays/Rectangle3DOverlay.h +++ b/interface/src/ui/overlays/Rectangle3DOverlay.h @@ -24,6 +24,7 @@ public: Rectangle3DOverlay(const Rectangle3DOverlay* rectangle3DOverlay); ~Rectangle3DOverlay(); virtual void render(RenderArgs* args); + virtual const render::ShapeKey getShapeKey() override; virtual void setProperties(const QScriptValue& properties); virtual Rectangle3DOverlay* createClone() const; diff --git a/interface/src/ui/overlays/Sphere3DOverlay.cpp b/interface/src/ui/overlays/Sphere3DOverlay.cpp index dcd1460ff4..d50f2f7285 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.cpp +++ b/interface/src/ui/overlays/Sphere3DOverlay.cpp @@ -42,14 +42,29 @@ void Sphere3DOverlay::render(RenderArgs* args) { Transform transform = _transform; transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE); batch->setModelTransform(transform); + + auto geometryCache = DependencyManager::get(); + auto pipeline = args->_pipeline; + if (!pipeline) { + pipeline = geometryCache->getShapePipeline(); + } + if (_isSolid) { - DependencyManager::get()->renderSolidSphereInstance(*batch, sphereColor); + geometryCache->renderSolidSphereInstance(*batch, sphereColor, pipeline); } else { - DependencyManager::get()->renderWireSphereInstance(*batch, sphereColor); + geometryCache->renderWireSphereInstance(*batch, sphereColor, pipeline); } } } +const render::ShapeKey Sphere3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); +} + Sphere3DOverlay* Sphere3DOverlay::createClone() const { return new Sphere3DOverlay(this); } diff --git a/interface/src/ui/overlays/Sphere3DOverlay.h b/interface/src/ui/overlays/Sphere3DOverlay.h index d371077502..ec2efa9f04 100644 --- a/interface/src/ui/overlays/Sphere3DOverlay.h +++ b/interface/src/ui/overlays/Sphere3DOverlay.h @@ -24,6 +24,7 @@ public: Sphere3DOverlay(const Sphere3DOverlay* Sphere3DOverlay); virtual void render(RenderArgs* args); + virtual const render::ShapeKey getShapeKey() override; virtual Sphere3DOverlay* createClone() const; }; diff --git a/interface/src/ui/overlays/Text3DOverlay.cpp b/interface/src/ui/overlays/Text3DOverlay.cpp index 2e5110951d..c8ffa5243d 100644 --- a/interface/src/ui/overlays/Text3DOverlay.cpp +++ b/interface/src/ui/overlays/Text3DOverlay.cpp @@ -8,8 +8,10 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + #include "Text3DOverlay.h" +#include #include #include #include @@ -34,6 +36,7 @@ Text3DOverlay::Text3DOverlay() : _bottomMargin(DEFAULT_MARGIN) { _textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); + _alpha = _backgroundAlpha; } Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) : @@ -47,7 +50,8 @@ Text3DOverlay::Text3DOverlay(const Text3DOverlay* text3DOverlay) : _rightMargin(text3DOverlay->_rightMargin), _bottomMargin(text3DOverlay->_bottomMargin) { - _textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); + _textRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, FIXED_FONT_POINT_SIZE); + _alpha = _backgroundAlpha; } Text3DOverlay::~Text3DOverlay() { @@ -100,7 +104,6 @@ void Text3DOverlay::render(RenderArgs* args) { glm::vec3 topLeft(-halfDimensions.x, -halfDimensions.y, SLIGHTLY_BEHIND); glm::vec3 bottomRight(halfDimensions.x, halfDimensions.y, SLIGHTLY_BEHIND); - DependencyManager::get()->bindSimpleProgram(batch, false, true, false, true); DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); // Same font properties as textSize() @@ -120,7 +123,15 @@ void Text3DOverlay::render(RenderArgs* args) { glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, getAlpha() }; - _textRenderer->draw(batch, 0, 0, _text, textColor); + _textRenderer->draw(batch, 0, 0, _text, textColor, glm::vec2(-1.0f), getDrawInFront()); +} + +const render::ShapeKey Text3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); } void Text3DOverlay::setProperties(const QScriptValue& properties) { @@ -145,6 +156,7 @@ void Text3DOverlay::setProperties(const QScriptValue& properties) { if (properties.property("backgroundAlpha").isValid()) { _backgroundAlpha = properties.property("backgroundAlpha").toVariant().toFloat(); + _alpha = _backgroundAlpha; } if (properties.property("lineHeight").isValid()) { diff --git a/interface/src/ui/overlays/Text3DOverlay.h b/interface/src/ui/overlays/Text3DOverlay.h index 5bd87e766a..f8ca134aa9 100644 --- a/interface/src/ui/overlays/Text3DOverlay.h +++ b/interface/src/ui/overlays/Text3DOverlay.h @@ -31,6 +31,8 @@ public: virtual void update(float deltatime); + virtual const render::ShapeKey getShapeKey() override; + // getters const QString& getText() const { return _text; } float getLineHeight() const { return _lineHeight; } @@ -72,5 +74,4 @@ private: float _bottomMargin; }; - #endif // hifi_Text3DOverlay_h diff --git a/interface/src/ui/overlays/Volume3DOverlay.h b/interface/src/ui/overlays/Volume3DOverlay.h index 1608e99b35..5756b6549a 100644 --- a/interface/src/ui/overlays/Volume3DOverlay.h +++ b/interface/src/ui/overlays/Volume3DOverlay.h @@ -34,7 +34,7 @@ public: protected: // Centered local bounding box - AABox _localBoundingBox; + AABox _localBoundingBox{ vec3(0.0f), 1.0f }; }; diff --git a/interface/src/ui/overlays/Web3DOverlay.cpp b/interface/src/ui/overlays/Web3DOverlay.cpp index 1ec502139b..7ceff81dd2 100644 --- a/interface/src/ui/overlays/Web3DOverlay.cpp +++ b/interface/src/ui/overlays/Web3DOverlay.cpp @@ -101,11 +101,18 @@ void Web3DOverlay::render(RenderArgs* args) { } batch.setModelTransform(transform); - DependencyManager::get()->bindSimpleProgram(batch, true, false, false, true); DependencyManager::get()->renderQuad(batch, halfSize * -1.0f, halfSize, vec2(0), vec2(1), color); batch.setResourceTexture(0, args->_whiteTexture); // restore default white color after me } +const render::ShapeKey Web3DOverlay::getShapeKey() { + auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias(); + if (getAlpha() != 1.0f) { + builder.withTranslucent(); + } + return builder.build(); +} + void Web3DOverlay::setProperties(const QScriptValue &properties) { Billboard3DOverlay::setProperties(properties); diff --git a/interface/src/ui/overlays/Web3DOverlay.h b/interface/src/ui/overlays/Web3DOverlay.h index bab2a1b55a..b1715dff46 100644 --- a/interface/src/ui/overlays/Web3DOverlay.h +++ b/interface/src/ui/overlays/Web3DOverlay.h @@ -25,6 +25,7 @@ public: virtual ~Web3DOverlay(); virtual void render(RenderArgs* args); + virtual const render::ShapeKey getShapeKey() override; virtual void update(float deltatime); diff --git a/libraries/render-utils/src/DeferredLightingEffect.cpp b/libraries/render-utils/src/DeferredLightingEffect.cpp index f81ac2efd1..003c309740 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.cpp +++ b/libraries/render-utils/src/DeferredLightingEffect.cpp @@ -511,9 +511,10 @@ void DeferredLightingEffect::render(const render::RenderContextPointer& renderCo } } -void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) { +void DeferredLightingEffect::setupBatch(gpu::Batch& batch, int lightBufferUnit) { + PerformanceTimer perfTimer("DLE->setupBatch()"); auto globalLight = _allocatedLights[_globalLights.front()]; - args->_batch->setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer()); + batch.setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer()); } static void loadLightProgram(const char* vertSource, const char* fragSource, bool lightVolume, gpu::PipelinePointer& pipeline, LightLocationsPtr& locations) { diff --git a/libraries/render-utils/src/DeferredLightingEffect.h b/libraries/render-utils/src/DeferredLightingEffect.h index ee4eeb445e..6ef5794d95 100644 --- a/libraries/render-utils/src/DeferredLightingEffect.h +++ b/libraries/render-utils/src/DeferredLightingEffect.h @@ -46,7 +46,7 @@ public: void prepare(RenderArgs* args); void render(const render::RenderContextPointer& renderContext); - void setupTransparent(RenderArgs* args, int lightBufferUnit); + void setupBatch(gpu::Batch& batch, int lightBufferUnit); // update global lighting void setAmbientLightMode(int preset); diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index aa82232524..ed6b8f2f5b 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -494,10 +494,22 @@ gpu::Stream::FormatPointer& getInstancedSolidStreamFormat() { return INSTANCED_SOLID_STREAM_FORMAT; } +render::ShapePipelinePointer GeometryCache::_simplePipeline; + GeometryCache::GeometryCache() : _nextID(0) { buildShapes(); + GeometryCache::_simplePipeline = + std::make_shared(getSimplePipeline(), nullptr, + [](const render::ShapePipeline&, gpu::Batch& batch) { + // Set the defaults needed for a simple program + batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP, + DependencyManager::get()->getWhiteTexture()); + batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, + DependencyManager::get()->getNormalFittingTexture()); + } + ); } GeometryCache::~GeometryCache() { @@ -536,14 +548,6 @@ void GeometryCache::renderWireShapeInstances(gpu::Batch& batch, Shape shape, siz _shapes[shape].drawWireInstances(batch, count); } -void GeometryCache::renderCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer colorBuffer) { - renderShapeInstances(batch, Cube, count, colorBuffer); -} - -void GeometryCache::renderWireCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer colorBuffer) { - renderWireShapeInstances(batch, Cube, count, colorBuffer); -} - void GeometryCache::renderCube(gpu::Batch& batch) { renderShape(batch, Cube); } @@ -552,10 +556,6 @@ void GeometryCache::renderWireCube(gpu::Batch& batch) { renderWireShape(batch, Cube); } -void GeometryCache::renderSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer colorBuffer) { - renderShapeInstances(batch, Sphere, count, colorBuffer); -} - void GeometryCache::renderSphere(gpu::Batch& batch) { renderShape(batch, Sphere); } @@ -756,7 +756,9 @@ void GeometryCache::updateVertices(int id, const QVector& points, con #endif // def WANT_DEBUG } - const int FLOATS_PER_VERTEX = 2; + const int FLOATS_PER_VERTEX = 2 + 3; // vertices + normals + const int NUM_POS_COORDS = 2; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); details.isCreated = true; details.vertices = points.size(); details.vertexSize = FLOATS_PER_VERTEX; @@ -772,6 +774,7 @@ void GeometryCache::updateVertices(int id, const QVector& points, con details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); @@ -791,9 +794,13 @@ void GeometryCache::updateVertices(int id, const QVector& points, con int* colorData = new int[details.vertices]; int* colorDataAt = colorData; + const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); foreach (const glm::vec2& point, points) { *(vertex++) = point.x; *(vertex++) = point.y; + *(vertex++) = NORMAL.x; + *(vertex++) = NORMAL.y; + *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; } @@ -817,7 +824,9 @@ void GeometryCache::updateVertices(int id, const QVector& points, con #endif // def WANT_DEBUG } - const int FLOATS_PER_VERTEX = 3; + const int FLOATS_PER_VERTEX = 3 + 3; // vertices + normals + const int NUM_POS_COORDS = 3; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); details.isCreated = true; details.vertices = points.size(); details.vertexSize = FLOATS_PER_VERTEX; @@ -833,6 +842,7 @@ void GeometryCache::updateVertices(int id, const QVector& points, con details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); @@ -852,10 +862,14 @@ void GeometryCache::updateVertices(int id, const QVector& points, con int* colorData = new int[details.vertices]; int* colorDataAt = colorData; + const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); foreach (const glm::vec3& point, points) { *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; + *(vertex++) = NORMAL.x; + *(vertex++) = NORMAL.y; + *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; } @@ -880,7 +894,11 @@ void GeometryCache::updateVertices(int id, const QVector& points, con #endif // def WANT_DEBUG } - const int FLOATS_PER_VERTEX = 5; + const int FLOATS_PER_VERTEX = 3 + 3 + 2; // vertices + normals + tex coords + const int NUM_POS_COORDS = 3; + const int NUM_NORMAL_COORDS = 3; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); + const int VERTEX_TEX_OFFSET = VERTEX_NORMAL_OFFSET + NUM_NORMAL_COORDS * sizeof(float); details.isCreated = true; details.vertices = points.size(); details.vertexSize = FLOATS_PER_VERTEX; @@ -896,7 +914,8 @@ void GeometryCache::updateVertices(int id, const QVector& points, con details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); - details.streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), 3 * sizeof(float)); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); + details.streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEX_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); @@ -918,12 +937,16 @@ void GeometryCache::updateVertices(int id, const QVector& points, con int* colorData = new int[details.vertices]; int* colorDataAt = colorData; + const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); for (int i = 0; i < points.size(); i++) { glm::vec3 point = points[i]; glm::vec2 texCoord = texCoords[i]; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; + *(vertex++) = NORMAL.x; + *(vertex++) = NORMAL.y; + *(vertex++) = NORMAL.z; *(vertex++) = texCoord.x; *(vertex++) = texCoord.y; @@ -1073,8 +1096,10 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co #endif // def WANT_DEBUG } - const int FLOATS_PER_VERTEX = 2; // vertices + const int FLOATS_PER_VERTEX = 2 + 3; // vertices + normals const int VERTICES = 4; // 1 quad = 4 vertices + const int NUM_POS_COORDS = 2; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); if (!details.isCreated) { @@ -1093,17 +1118,19 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); + const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); float vertexBuffer[VERTICES * FLOATS_PER_VERTEX] = { - minCorner.x, minCorner.y, - maxCorner.x, minCorner.y, - minCorner.x, maxCorner.y, - maxCorner.x, maxCorner.y, + minCorner.x, minCorner.y, NORMAL.x, NORMAL.y, NORMAL.z, + maxCorner.x, minCorner.y, NORMAL.x, NORMAL.y, NORMAL.z, + minCorner.x, maxCorner.y, NORMAL.x, NORMAL.y, NORMAL.z, + maxCorner.x, maxCorner.y, NORMAL.x, NORMAL.y, NORMAL.z, }; const int NUM_COLOR_SCALARS_PER_QUAD = 4; @@ -1158,10 +1185,12 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co #endif // def WANT_DEBUG } - const int FLOATS_PER_VERTEX = 2 * 2; // text coords & vertices + const int FLOATS_PER_VERTEX = 2 + 3 + 2; // vertices + normals + tex coords const int VERTICES = 4; // 1 quad = 4 vertices const int NUM_POS_COORDS = 2; - const int VERTEX_TEXCOORD_OFFSET = NUM_POS_COORDS * sizeof(float); + const int NUM_NORMAL_COORDS = 3; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); + const int VERTEX_TEXCOORD_OFFSET = VERTEX_NORMAL_OFFSET + NUM_NORMAL_COORDS * sizeof(float); if (!details.isCreated) { @@ -1181,7 +1210,9 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co details.streamFormat = streamFormat; details.stream = stream; + // zzmp: fix the normal across all renderQuad details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); @@ -1189,11 +1220,12 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec2& minCorner, co details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); + const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); float vertexBuffer[VERTICES * FLOATS_PER_VERTEX] = { - minCorner.x, minCorner.y, texCoordMinCorner.x, texCoordMinCorner.y, - maxCorner.x, minCorner.y, texCoordMaxCorner.x, texCoordMinCorner.y, - minCorner.x, maxCorner.y, texCoordMinCorner.x, texCoordMaxCorner.y, - maxCorner.x, maxCorner.y, texCoordMaxCorner.x, texCoordMaxCorner.y, + minCorner.x, minCorner.y, NORMAL.x, NORMAL.y, NORMAL.z, texCoordMinCorner.x, texCoordMinCorner.y, + maxCorner.x, minCorner.y, NORMAL.x, NORMAL.y, NORMAL.z, texCoordMaxCorner.x, texCoordMinCorner.y, + minCorner.x, maxCorner.y, NORMAL.x, NORMAL.y, NORMAL.z, texCoordMinCorner.x, texCoordMaxCorner.y, + maxCorner.x, maxCorner.y, NORMAL.x, NORMAL.y, NORMAL.z, texCoordMaxCorner.x, texCoordMaxCorner.y, }; @@ -1235,8 +1267,10 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, co #endif // def WANT_DEBUG } - const int FLOATS_PER_VERTEX = 3; // vertices + const int FLOATS_PER_VERTEX = 3 + 3; // vertices + normals const int VERTICES = 4; // 1 quad = 4 vertices + const int NUM_POS_COORDS = 3; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); if (!details.isCreated) { @@ -1257,17 +1291,19 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& minCorner, co details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); + const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); float vertexBuffer[VERTICES * FLOATS_PER_VERTEX] = { - minCorner.x, minCorner.y, minCorner.z, - maxCorner.x, minCorner.y, minCorner.z, - minCorner.x, maxCorner.y, maxCorner.z, - maxCorner.x, maxCorner.y, maxCorner.z, + minCorner.x, minCorner.y, minCorner.z, NORMAL.x, NORMAL.y, NORMAL.z, + maxCorner.x, minCorner.y, minCorner.z, NORMAL.x, NORMAL.y, NORMAL.z, + minCorner.x, maxCorner.y, maxCorner.z, NORMAL.x, NORMAL.y, NORMAL.z, + maxCorner.x, maxCorner.y, maxCorner.z, NORMAL.x, NORMAL.y, NORMAL.z, }; const int NUM_COLOR_SCALARS_PER_QUAD = 4; @@ -1327,10 +1363,13 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& topLeft, cons #endif // def WANT_DEBUG } - const int FLOATS_PER_VERTEX = 3 + 2; // 3d vertices + text coords + const int FLOATS_PER_VERTEX = 3 + 3 + 2; // vertices + normals + tex coords const int VERTICES = 4; // 1 quad = 4 vertices const int NUM_POS_COORDS = 3; - const int VERTEX_TEXCOORD_OFFSET = NUM_POS_COORDS * sizeof(float); + const int NUM_NORMAL_COORDS = 3; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); + const int VERTEX_TEXCOORD_OFFSET = VERTEX_NORMAL_OFFSET + NUM_NORMAL_COORDS * sizeof(float); + if (!details.isCreated) { @@ -1349,6 +1388,7 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& topLeft, cons details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), VERTEX_TEXCOORD_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); @@ -1356,12 +1396,13 @@ void GeometryCache::renderQuad(gpu::Batch& batch, const glm::vec3& topLeft, cons details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); + const glm::vec3 NORMAL(0.0f, 0.0f, 1.0f); float vertexBuffer[VERTICES * FLOATS_PER_VERTEX] = { - bottomLeft.x, bottomLeft.y, bottomLeft.z, texCoordBottomLeft.x, texCoordBottomLeft.y, - bottomRight.x, bottomRight.y, bottomRight.z, texCoordBottomRight.x, texCoordBottomRight.y, - topLeft.x, topLeft.y, topLeft.z, texCoordTopLeft.x, texCoordTopLeft.y, - topRight.x, topRight.y, topRight.z, texCoordTopRight.x, texCoordTopRight.y, - }; + bottomLeft.x, bottomLeft.y, bottomLeft.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordBottomLeft.x, texCoordBottomLeft.y, + bottomRight.x, bottomRight.y, bottomRight.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordBottomRight.x, texCoordBottomRight.y, + topLeft.x, topLeft.y, topLeft.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordTopLeft.x, texCoordTopLeft.y, + topRight.x, topRight.y, topRight.z, NORMAL.x, NORMAL.y, NORMAL.z, texCoordTopRight.x, texCoordTopRight.y, + }; const int NUM_COLOR_SCALARS_PER_QUAD = 4; int compactColor = ((int(color.x * 255.0f) & 0xFF)) | @@ -1414,7 +1455,9 @@ void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start, glm::vec3 dashVector = segmentVector / SEGMENT_LENGTH * dash_length; glm::vec3 gapVector = segmentVector / SEGMENT_LENGTH * gap_length; - const int FLOATS_PER_VERTEX = 3; + const int FLOATS_PER_VERTEX = 3 + 3; // vertices + normals + const int NUM_POS_COORDS = 3; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); details.vertices = (segmentCountFloor + 1) * 2; details.vertexSize = FLOATS_PER_VERTEX; details.isCreated = true; @@ -1430,6 +1473,7 @@ void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start, details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); @@ -1441,10 +1485,14 @@ void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start, float* vertexData = new float[details.vertices * FLOATS_PER_VERTEX]; float* vertex = vertexData; + const glm::vec3 NORMAL(1.0f, 0.0f, 0.0f); glm::vec3 point = start; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; + *(vertex++) = NORMAL.x; + *(vertex++) = NORMAL.y; + *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; for (int i = 0; i < segmentCountFloor; i++) { @@ -1452,17 +1500,26 @@ void GeometryCache::renderDashedLine(gpu::Batch& batch, const glm::vec3& start, *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; + *(vertex++) = NORMAL.x; + *(vertex++) = NORMAL.y; + *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; point += gapVector; *(vertex++) = point.x; *(vertex++) = point.y; *(vertex++) = point.z; + *(vertex++) = NORMAL.x; + *(vertex++) = NORMAL.y; + *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; } *(vertex++) = end.x; *(vertex++) = end.y; *(vertex++) = end.z; + *(vertex++) = NORMAL.x; + *(vertex++) = NORMAL.y; + *(vertex++) = NORMAL.z; *(colorDataAt++) = compactColor; details.verticesBuffer->append(sizeof(float) * FLOATS_PER_VERTEX * details.vertices, (gpu::Byte*) vertexData); @@ -1569,7 +1626,9 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm #endif // def WANT_DEBUG } - const int FLOATS_PER_VERTEX = 3; + const int FLOATS_PER_VERTEX = 3 + 3; // vertices + normals + const int NUM_POS_COORDS = 3; + const int VERTEX_NORMAL_OFFSET = NUM_POS_COORDS * sizeof(float); const int vertices = 2; if (!details.isCreated) { @@ -1588,13 +1647,16 @@ void GeometryCache::renderLine(gpu::Batch& batch, const glm::vec3& p1, const glm details.stream = stream; details.streamFormat->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), 0); + details.streamFormat->setAttribute(gpu::Stream::NORMAL, 0, gpu::Element(gpu::VEC3, gpu::FLOAT, gpu::XYZ), VERTEX_NORMAL_OFFSET); details.streamFormat->setAttribute(gpu::Stream::COLOR, 1, gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA)); details.stream->addBuffer(details.verticesBuffer, 0, details.streamFormat->getChannels().at(0)._stride); details.stream->addBuffer(details.colorBuffer, 0, details.streamFormat->getChannels().at(1)._stride); - - float vertexBuffer[vertices * FLOATS_PER_VERTEX] = { p1.x, p1.y, p1.z, p2.x, p2.y, p2.z }; + const glm::vec3 NORMAL(1.0f, 0.0f, 0.0f); + float vertexBuffer[vertices * FLOATS_PER_VERTEX] = { + p1.x, p1.y, p1.z, NORMAL.x, NORMAL.y, NORMAL.z, + p2.x, p2.y, p2.z, NORMAL.x, NORMAL.y, NORMAL.z}; const int NUM_COLOR_SCALARS = 2; int colors[NUM_COLOR_SCALARS] = { compactColor1, compactColor2 }; @@ -1781,7 +1843,23 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) { return a.getRaw() == b.getRaw(); } -gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) { +void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool emissive, bool depthBiased) { + batch.setPipeline(getSimplePipeline(textured, culled, emissive, depthBiased)); + + // If not textured, set a default diffuse map + if (!textured) { + batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP, + DependencyManager::get()->getWhiteTexture()); + } + // Set a default normal map + batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, + DependencyManager::get()->getNormalFittingTexture()); +} + +gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool culled, bool emissive, bool depthBiased) { + SimpleProgramKey config{textured, culled, emissive, depthBiased}; + + // Compile the shaders static std::once_flag once; std::call_once(once, [&]() { auto VS = gpu::Shader::createVertex(std::string(simple_vert)); @@ -1796,13 +1874,14 @@ gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) { gpu::Shader::makeProgram(*_simpleShader, slotBindings); gpu::Shader::makeProgram(*_emissiveShader, slotBindings); }); - - + + // If the pipeline already exists, return it auto it = _simplePrograms.find(config); if (it != _simplePrograms.end()) { return it.value(); } - + + // If the pipeline did not exist, make it auto state = std::make_shared(); if (config.isCulled()) { state->setCullMode(gpu::State::CULL_BACK); @@ -1815,33 +1894,15 @@ gpu::PipelinePointer GeometryCache::getPipeline(SimpleProgramKey config) { state->setDepthBiasSlopeScale(1.0f); } state->setBlendFunction(false, - 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); - + 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); + gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state); _simplePrograms.insert(config, pipeline); return pipeline; } -gpu::PipelinePointer GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, - bool emissive, bool depthBias) { - SimpleProgramKey config{textured, culled, emissive, depthBias}; - gpu::PipelinePointer pipeline = getPipeline(config); - batch.setPipeline(pipeline); - - gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader; - - if (!config.isTextured()) { - // If it is not textured, bind white texture and keep using textured pipeline - batch.setResourceTexture(0, DependencyManager::get()->getWhiteTexture()); - } - - batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, - DependencyManager::get()->getNormalFittingTexture()); - return pipeline; -} - uint32_t toCompactColor(const glm::vec4& color) { uint32_t compactColor = ((int(color.x * 255.0f) & 0xFF)) | ((int(color.y * 255.0f) & 0xFF) << 8) | @@ -1852,46 +1913,51 @@ uint32_t toCompactColor(const glm::vec4& color) { static const size_t INSTANCE_COLOR_BUFFER = 0; -template -void renderInstances(const std::string& name, gpu::Batch& batch, const glm::vec4& color, F f) { +void renderInstances(const std::string& name, gpu::Batch& batch, const glm::vec4& color, bool isWire, + const render::ShapePipelinePointer& pipeline, GeometryCache::Shape shape) { + // Add pipeline to name + std::string instanceName = name + std::to_string(std::hash()(pipeline)); + + // Add color to named buffer { - gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(name, INSTANCE_COLOR_BUFFER); + gpu::BufferPointer instanceColorBuffer = batch.getNamedBuffer(instanceName, INSTANCE_COLOR_BUFFER); auto compactColor = toCompactColor(color); instanceColorBuffer->append(compactColor); } - - batch.setupNamedCalls(name, [f](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->bindSimpleProgram(batch); - f(batch, data); + + // Add call to named buffer + batch.setupNamedCalls(instanceName, [isWire, pipeline, shape](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + batch.setPipeline(pipeline->pipeline); + pipeline->prepare(batch); + + if (isWire) { + DependencyManager::get()->renderWireShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]); + } else { + DependencyManager::get()->renderShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]); + } }); } -void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color) { +void GeometryCache::renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderShapeInstances(batch, GeometryCache::Sphere, data.count(), - data.buffers[INSTANCE_COLOR_BUFFER]); - }); + renderInstances(INSTANCE_NAME, batch, color, false, pipeline, GeometryCache::Sphere); } -void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color) { +void GeometryCache::renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderWireShapeInstances(batch, GeometryCache::Sphere, data.count(), - data.buffers[INSTANCE_COLOR_BUFFER]); - }); + renderInstances(INSTANCE_NAME, batch, color, true, pipeline, GeometryCache::Sphere); } // Enable this in a debug build to cause 'box' entities to iterate through all the // available shape types, both solid and wireframes //#define DEBUG_SHAPES -void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color) { +void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { static const std::string INSTANCE_NAME = __FUNCTION__; #ifdef DEBUG_SHAPES static auto startTime = usecTimestampNow(); - renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { + renderInstances(INSTANCE_NAME, batch, color, pipeline, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { auto usecs = usecTimestampNow(); usecs -= startTime; @@ -1916,26 +1982,17 @@ void GeometryCache::renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& // For the first half second for a given shape, show the wireframe, for the second half, show the solid. if (fractionalSeconds > 0.5f) { - DependencyManager::get()->renderShapeInstances(batch, shape, data.count(), - data.buffers[INSTANCE_COLOR_BUFFER]); + renderInstances(INSTANCE_NAME, batch, color, true, pipeline, shape); } else { - DependencyManager::get()->renderWireShapeInstances(batch, shape, data.count(), - data.buffers[INSTANCE_COLOR_BUFFER]); + renderInstances(INSTANCE_NAME, batch, color, false, pipeline, shape); } }); #else - renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderCubeInstances(batch, data.count(), - data.buffers[INSTANCE_COLOR_BUFFER]); - }); + renderInstances(INSTANCE_NAME, batch, color, false, pipeline, GeometryCache::Cube); #endif } -void GeometryCache::renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color) { +void GeometryCache::renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color, const render::ShapePipelinePointer& pipeline) { static const std::string INSTANCE_NAME = __FUNCTION__; - renderInstances(INSTANCE_NAME, batch, color, [](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) { - DependencyManager::get()->renderWireCubeInstances(batch, data.count(), - data.buffers[INSTANCE_COLOR_BUFFER]); - }); + renderInstances(INSTANCE_NAME, batch, color, true, pipeline, GeometryCache::Cube); } - diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 81b8dfb325..32cdec56bf 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -150,45 +150,55 @@ public: static const int UNKNOWN_ID; - /// Sets up the state necessary to render static untextured geometry with the simple program. - gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, - bool emissive = false, bool depthBias = false); + // Bind the pipeline and get the state to render static geometry + void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true, + bool emissive = false, bool depthBias = false); + // Get the pipeline to render static geometry + gpu::PipelinePointer getSimplePipeline(bool textured = false, bool culled = true, + bool emissive = false, bool depthBias = false); + render::ShapePipelinePointer getShapePipeline() { return GeometryCache::_simplePipeline; } - void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color); - void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color) { - renderSolidSphereInstance(batch, glm::vec4(color, 1.0)); - } - - void renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color); - void renderWireSphereInstance(gpu::Batch& batch, const glm::vec3& color) { - renderWireSphereInstance(batch, glm::vec4(color, 1.0)); - } - - void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color); - void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec3& color) { - renderSolidCubeInstance(batch, glm::vec4(color, 1.0)); - } - - void renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color); - void renderWireCubeInstance(gpu::Batch& batch, const glm::vec3& color) { - renderWireCubeInstance(batch, glm::vec4(color, 1.0)); - } - - + // Static (instanced) geometry void renderShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer); void renderWireShapeInstances(gpu::Batch& batch, Shape shape, size_t count, gpu::BufferPointer& colorBuffer); + + void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec4& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline); + void renderSolidSphereInstance(gpu::Batch& batch, const glm::vec3& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline) { + renderSolidSphereInstance(batch, glm::vec4(color, 1.0f), pipeline); + } + + void renderWireSphereInstance(gpu::Batch& batch, const glm::vec4& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline); + void renderWireSphereInstance(gpu::Batch& batch, const glm::vec3& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline) { + renderWireSphereInstance(batch, glm::vec4(color, 1.0f), pipeline); + } + + void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec4& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline); + void renderSolidCubeInstance(gpu::Batch& batch, const glm::vec3& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline) { + renderSolidCubeInstance(batch, glm::vec4(color, 1.0f), pipeline); + } + + void renderWireCubeInstance(gpu::Batch& batch, const glm::vec4& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline); + void renderWireCubeInstance(gpu::Batch& batch, const glm::vec3& color, + const render::ShapePipelinePointer& pipeline = _simplePipeline) { + renderWireCubeInstance(batch, glm::vec4(color, 1.0f), pipeline); + } + + // Dynamic geometry void renderShape(gpu::Batch& batch, Shape shape); void renderWireShape(gpu::Batch& batch, Shape shape); size_t getShapeTriangleCount(Shape shape); - void renderCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer colorBuffer); - void renderWireCubeInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer colorBuffer); void renderCube(gpu::Batch& batch); void renderWireCube(gpu::Batch& batch); size_t getCubeTriangleCount(); - void renderSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer colorBuffer); - void renderWireSphereInstances(gpu::Batch& batch, size_t count, gpu::BufferPointer colorBuffer); void renderSphere(gpu::Batch& batch); void renderWireSphere(gpu::Batch& batch); size_t getSphereTriangleCount(); @@ -364,11 +374,9 @@ private: QHash > _networkGeometry; - - gpu::PipelinePointer getPipeline(SimpleProgramKey config); - gpu::ShaderPointer _simpleShader; gpu::ShaderPointer _emissiveShader; + static render::ShapePipelinePointer _simplePipeline; QHash _simplePrograms; }; diff --git a/libraries/render-utils/src/MeshPartPayload.cpp b/libraries/render-utils/src/MeshPartPayload.cpp index d5ee1434bb..c0003219a0 100644 --- a/libraries/render-utils/src/MeshPartPayload.cpp +++ b/libraries/render-utils/src/MeshPartPayload.cpp @@ -225,8 +225,6 @@ void MeshPartPayload::render(RenderArgs* args) const { gpu::Batch& batch = *(args->_batch); - ShapeKey key = getShapeKey(); - auto locations = args->_pipeline->locations; assert(locations); @@ -239,13 +237,6 @@ void MeshPartPayload::render(RenderArgs* args) const { // apply material properties bindMaterial(batch, locations); - - // TODO: We should be able to do that just in the renderTransparentJob - if (key.isTranslucent() && locations->lightBufferUnit >= 0) { - PerformanceTimer perfTimer("DLE->setupTransparent()"); - - DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); - } if (args) { args->_details._materialSwitches++; } @@ -475,8 +466,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { gpu::Batch& batch = *(args->_batch); - ShapeKey key = getShapeKey(); - if (!key.isValid()) { + if (!getShapeKey().isValid()) { return; } @@ -517,13 +507,6 @@ void ModelMeshPartPayload::render(RenderArgs* args) const { // apply material properties bindMaterial(batch, locations); - - // TODO: We should be able to do that just in the renderTransparentJob - if (key.isTranslucent() && locations->lightBufferUnit >= 0) { - PerformanceTimer perfTimer("DLE->setupTransparent()"); - - DependencyManager::get()->setupTransparent(args, locations->lightBufferUnit); - } if (args) { args->_details._materialSwitches++; } diff --git a/libraries/render-utils/src/RenderDeferredTask.cpp b/libraries/render-utils/src/RenderDeferredTask.cpp index e21b8ce799..d3aeb23a50 100755 --- a/libraries/render-utils/src/RenderDeferredTask.cpp +++ b/libraries/render-utils/src/RenderDeferredTask.cpp @@ -104,7 +104,8 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) { addJob("DrawStatus", opaques, DrawStatus(statusIconMap)); } - addJob("DrawOverlay3D"); + addJob("DrawOverlay3DOpaque", ItemFilter::Builder::opaqueShape().withLayered()); + addJob("DrawOverlay3DTransparent", ItemFilter::Builder::transparentShape().withLayered()); addJob("HitEffect"); @@ -156,7 +157,7 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont }); } -DrawOverlay3D::DrawOverlay3D() : _shapePlumber{ std::make_shared() } { +DrawOverlay3D::DrawOverlay3D(ItemFilter filter) : _filter{ filter }, _shapePlumber{ std::make_shared() } { initOverlay3DPipelines(*_shapePlumber); } @@ -166,7 +167,7 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon // render backgrounds auto& scene = sceneContext->_scene; - auto& items = scene->getMasterBucket().at(ItemFilter::Builder::opaqueShape().withLayered()); + auto& items = scene->getMasterBucket().at(_filter); auto config = std::static_pointer_cast(renderContext->jobConfig); @@ -179,7 +180,6 @@ void DrawOverlay3D::run(const SceneContextPointer& sceneContext, const RenderCon } } config->numItems = (int)inItems.size(); - config->numDrawn = (int)inItems.size(); if (!inItems.empty()) { RenderArgs* args = renderContext->args; diff --git a/libraries/render-utils/src/RenderDeferredTask.h b/libraries/render-utils/src/RenderDeferredTask.h index 0be2e0e808..5d97de3905 100755 --- a/libraries/render-utils/src/RenderDeferredTask.h +++ b/libraries/render-utils/src/RenderDeferredTask.h @@ -87,14 +87,11 @@ public: class DrawOverlay3DConfig : public render::Job::Config { Q_OBJECT Q_PROPERTY(int numItems READ getNumItems) - Q_PROPERTY(int numDrawn READ getNumDrawn) Q_PROPERTY(int maxDrawn MEMBER maxDrawn NOTIFY dirty) public: int getNumItems() { return numItems; } - int getNumDrawn() { return numDrawn; } int numItems{ 0 }; - int numDrawn{ 0 }; int maxDrawn{ -1 }; signals: void dirty(); @@ -105,12 +102,13 @@ public: using Config = DrawOverlay3DConfig; using JobModel = render::Job::Model; - DrawOverlay3D(); + DrawOverlay3D(render::ItemFilter filter); void configure(const Config& config) { _maxDrawn = config.maxDrawn; } void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext); protected: + render::ItemFilter _filter; render::ShapePlumberPointer _shapePlumber; int _maxDrawn; // initialized by Config }; diff --git a/libraries/render-utils/src/RenderPipelines.cpp b/libraries/render-utils/src/RenderPipelines.cpp index d2e880aea3..fce9ce1c28 100644 --- a/libraries/render-utils/src/RenderPipelines.cpp +++ b/libraries/render-utils/src/RenderPipelines.cpp @@ -13,6 +13,7 @@ #include #include +#include "DeferredLightingEffect.h" #include "TextureCache.h" #include "render/DrawTask.h" @@ -26,6 +27,7 @@ #include "skin_model_normal_map_vert.h" #include "model_frag.h" +#include "model_emissive_frag.h" #include "model_shadow_frag.h" #include "model_normal_map_frag.h" #include "model_normal_specular_map_frag.h" @@ -35,9 +37,13 @@ #include "model_lightmap_normal_specular_map_frag.h" #include "model_lightmap_specular_map_frag.h" #include "model_translucent_frag.h" +#include "model_translucent_emissive_frag.h" #include "overlay3D_vert.h" #include "overlay3D_frag.h" +#include "overlay3D_translucent_frag.h" +#include "overlay3D_emissive_frag.h" +#include "overlay3D_translucent_emissive_frag.h" #include "drawOpaqueStencil_frag.h" @@ -58,22 +64,85 @@ void initStencilPipeline(gpu::PipelinePointer& pipeline) { pipeline = gpu::Pipeline::create(program, state); } -void initOverlay3DPipelines(ShapePlumber& plumber) { - auto vs = gpu::Shader::createVertex(std::string(overlay3D_vert)); - auto ps = gpu::Shader::createPixel(std::string(overlay3D_frag)); - auto program = gpu::Shader::createProgram(vs, ps); - - auto opaqueState = std::make_shared(); - opaqueState->setDepthTest(false); - opaqueState->setBlendFunction(false); - - plumber.addPipeline(ShapeKey::Filter::Builder().withOpaque(), program, opaqueState); +gpu::BufferView getDefaultMaterialBuffer() { + model::Material::Schema schema; + schema._diffuse = vec3(1.0f); + schema._opacity = 1.0f; + schema._metallic = vec3(0.1f); + schema._gloss = 10.0f; + return gpu::BufferView(std::make_shared(sizeof(model::Material::Schema), (const gpu::Byte*) &schema)); } -void pipelineBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { - if (pipeline.locations->normalFittingMapUnit > -1) { - batch.setResourceTexture(pipeline.locations->normalFittingMapUnit, - DependencyManager::get()->getNormalFittingTexture()); +void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { + // Set a default diffuse map + batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP, + DependencyManager::get()->getWhiteTexture()); + // Set a default normal map + batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, + DependencyManager::get()->getNormalFittingTexture()); + // Set default coordinates + if (pipeline.locations->texcoordMatrices >= 0) { + static const glm::mat4 TEX_COORDS[2]; + batch._glUniformMatrix4fv(pipeline.locations->texcoordMatrices, 2, false, (const float*)&TEX_COORDS); + } + // Set a default material + if (pipeline.locations->materialBufferUnit >= 0) { + static const gpu::BufferView OPAQUE_SCHEMA_BUFFER = getDefaultMaterialBuffer(); + batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_GPU, OPAQUE_SCHEMA_BUFFER); + } +} + +void lightBatchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) { + batchSetter(pipeline, batch); + // Set the light + if (pipeline.locations->lightBufferUnit >= 0) { + DependencyManager::get()->setupBatch(batch, pipeline.locations->lightBufferUnit); + } +} + +void initOverlay3DPipelines(ShapePlumber& plumber) { + auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert)); + auto pixel = gpu::Shader::createPixel(std::string(overlay3D_frag)); + auto pixelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_translucent_frag)); + auto pixelEmissive = gpu::Shader::createPixel(std::string(overlay3D_emissive_frag)); + auto pixelTranslucentEmissive = gpu::Shader::createPixel(std::string(overlay3D_translucent_emissive_frag)); + + auto opaqueProgram = gpu::Shader::createProgram(vertex, pixel); + auto translucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucent); + auto emissiveOpaqueProgram = gpu::Shader::createProgram(vertex, pixelEmissive); + auto emissiveTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentEmissive); + + for (int i = 0; i < 8; i++) { + bool isCulled = (i & 1); + bool isBiased = (i & 2); + bool isOpaque = (i & 4); + + auto state = std::make_shared(); + state->setDepthTest(false); + state->setCullMode(isCulled ? gpu::State::CULL_BACK : gpu::State::CULL_NONE); + if (isBiased) { + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(1.0f); + } + if (isOpaque) { + // Soft edges + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA); + } else { + state->setBlendFunction(true, + 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); + } + + ShapeKey::Filter::Builder builder; + isCulled ? builder.withCullFace() : builder.withoutCullFace(); + isBiased ? builder.withDepthBias() : builder.withoutDepthBias(); + isOpaque ? builder.withOpaque() : builder.withTranslucent(); + + auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram; + auto emissiveProgram = isOpaque ? emissiveOpaqueProgram : emissiveTranslucentProgram; + plumber.addPipeline(builder.withoutEmissive().build(), simpleProgram, state, &lightBatchSetter); + plumber.addPipeline(builder.withEmissive().build(), emissiveProgram, state, &batchSetter); } } @@ -82,31 +151,43 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { using ShaderPointer = gpu::ShaderPointer; auto addPipeline = [&plumber](const Key& key, const ShaderPointer& vertexShader, const ShaderPointer& pixelShader) { - auto state = std::make_shared(); - - // Cull backface - state->setCullMode(gpu::State::CULL_BACK); - - // Z test depends on transparency - state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); - - // Blend if transparent - state->setBlendFunction(key.isTranslucent(), - // For transparency, keep the highlight intensity - gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + // These keyvalues' pipelines will be added by this lamdba in addition to the key passed + assert(!key.isWireFrame()); + assert(!key.isDepthBiased()); + assert(key.isCullFace()); ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader); - plumber.addPipeline(key, program, state, &pipelineBatchSetter); - // Add a wireframe version - if (!key.isWireFrame()) { - auto wireFrameKey = Key::Builder(key).withWireframe(); - auto wireFrameState = std::make_shared(state->getValues()); + for (int i = 0; i < 8; i++) { + bool isCulled = (i & 1); + bool isBiased = (i & 2); + bool isWireframed = (i & 4); - wireFrameState->setFillMode(gpu::State::FILL_LINE); + ShapeKey::Builder builder(key); + auto state = std::make_shared(); - plumber.addPipeline(wireFrameKey, program, wireFrameState, &pipelineBatchSetter); + // Depth test depends on transparency + state->setDepthTest(true, !key.isTranslucent(), gpu::LESS_EQUAL); + state->setBlendFunction(key.isTranslucent(), + 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); + + if (!isCulled) { + builder.withoutCullFace(); + } + state->setCullMode(isCulled ? gpu::State::CULL_BACK : gpu::State::CULL_NONE); + if (isWireframed) { + builder.withWireframe(); + state->setFillMode(gpu::State::FILL_LINE); + } + if (isBiased) { + builder.withDepthBias(); + state->setDepthBias(1.0f); + state->setDepthBiasSlopeScale(1.0f); + } + + plumber.addPipeline(builder.build(), program, state, + key.isTranslucent() ? &lightBatchSetter : &batchSetter); } }; @@ -122,113 +203,99 @@ void initDeferredPipelines(render::ShapePlumber& plumber) { // Pixel shaders auto modelPixel = gpu::Shader::createPixel(std::string(model_frag)); + auto modelEmissivePixel = gpu::Shader::createPixel(std::string(model_emissive_frag)); auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag)); auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag)); auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag)); auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag)); + auto modelTranslucentEmissivePixel = gpu::Shader::createPixel(std::string(model_translucent_emissive_frag)); auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag)); auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag)); auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag)); auto modelLightmapSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_specular_map_frag)); auto modelLightmapNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_specular_map_frag)); - // Fill the pipelineLib + // TODO: Refactor this to use a filter + // Opaques addPipeline( Key::Builder(), modelVertex, modelPixel); - + addPipeline( + Key::Builder().withEmissive(), + modelVertex, modelEmissivePixel); addPipeline( Key::Builder().withTangents(), modelNormalMapVertex, modelNormalMapPixel); - addPipeline( Key::Builder().withSpecular(), modelVertex, modelSpecularMapPixel); - addPipeline( Key::Builder().withTangents().withSpecular(), modelNormalMapVertex, modelNormalSpecularMapPixel); - - + // Translucents addPipeline( Key::Builder().withTranslucent(), modelVertex, modelTranslucentPixel); - // FIXME Ignore lightmap for translucents meshpart addPipeline( + Key::Builder().withTranslucent().withEmissive(), + modelVertex, modelTranslucentEmissivePixel); + addPipeline( + Key::Builder().withTranslucent().withTangents(), + modelNormalMapVertex, modelTranslucentPixel); + addPipeline( + Key::Builder().withTranslucent().withSpecular(), + modelVertex, modelTranslucentPixel); + addPipeline( + Key::Builder().withTranslucent().withTangents().withSpecular(), + modelNormalMapVertex, modelTranslucentPixel); + addPipeline( + // FIXME: Ignore lightmap for translucents meshpart Key::Builder().withTranslucent().withLightmap(), modelVertex, modelTranslucentPixel); - - addPipeline( - Key::Builder().withTangents().withTranslucent(), - modelNormalMapVertex, modelTranslucentPixel); - - addPipeline( - Key::Builder().withSpecular().withTranslucent(), - modelVertex, modelTranslucentPixel); - - addPipeline( - Key::Builder().withTangents().withSpecular().withTranslucent(), - modelNormalMapVertex, modelTranslucentPixel); - - + // Lightmapped addPipeline( Key::Builder().withLightmap(), modelLightmapVertex, modelLightmapPixel); - addPipeline( Key::Builder().withLightmap().withTangents(), modelLightmapNormalMapVertex, modelLightmapNormalMapPixel); - addPipeline( Key::Builder().withLightmap().withSpecular(), modelLightmapVertex, modelLightmapSpecularMapPixel); - addPipeline( Key::Builder().withLightmap().withTangents().withSpecular(), modelLightmapNormalMapVertex, modelLightmapNormalSpecularMapPixel); - - + // Skinned addPipeline( Key::Builder().withSkinned(), skinModelVertex, modelPixel); - addPipeline( Key::Builder().withSkinned().withTangents(), skinModelNormalMapVertex, modelNormalMapPixel); - addPipeline( Key::Builder().withSkinned().withSpecular(), skinModelVertex, modelSpecularMapPixel); - addPipeline( Key::Builder().withSkinned().withTangents().withSpecular(), skinModelNormalMapVertex, modelNormalSpecularMapPixel); - - + // Skinned and Translucent addPipeline( Key::Builder().withSkinned().withTranslucent(), skinModelVertex, modelTranslucentPixel); - addPipeline( - Key::Builder().withSkinned().withTangents().withTranslucent(), + Key::Builder().withSkinned().withTranslucent().withTangents(), skinModelNormalMapVertex, modelTranslucentPixel); - addPipeline( - Key::Builder().withSkinned().withSpecular().withTranslucent(), + Key::Builder().withSkinned().withTranslucent().withSpecular(), skinModelVertex, modelTranslucentPixel); - addPipeline( - Key::Builder().withSkinned().withTangents().withSpecular().withTranslucent(), + Key::Builder().withSkinned().withTranslucent().withTangents().withSpecular(), skinModelNormalMapVertex, modelTranslucentPixel); - - + // Depth-only addPipeline( Key::Builder().withDepthOnly(), modelShadowVertex, modelShadowPixel); - - addPipeline( Key::Builder().withSkinned().withDepthOnly(), skinModelShadowVertex, modelShadowPixel); } - diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 6d10ed7069..81e9378815 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -72,12 +72,12 @@ float TextRenderer3D::getFontSize() const { } void TextRenderer3D::draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color, - const glm::vec2& bounds) { + const glm::vec2& bounds, bool layered) { // The font does all the OpenGL work if (_font) { // Cache color so that the pointer stays valid. _color = color; - _font->drawString(batch, x, y, str, &_color, _effectType, bounds); + _font->drawString(batch, x, y, str, &_color, _effectType, bounds, layered); } } diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index ea230016f2..9d48ca1a6c 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -40,7 +40,7 @@ public: float getFontSize() const; // Pixel size void draw(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4& color = glm::vec4(1.0f), - const glm::vec2& bounds = glm::vec2(-1.0f)); + const glm::vec2& bounds = glm::vec2(-1.0f), bool layered = false); private: TextRenderer3D(const char* family, float pointSize, int weight = -1, bool italic = false, diff --git a/libraries/render-utils/src/model.slv b/libraries/render-utils/src/model.slv index 47de20a5d9..0507f1c6c5 100755 --- a/libraries/render-utils/src/model.slv +++ b/libraries/render-utils/src/model.slv @@ -1,7 +1,7 @@ <@include gpu/Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> -// model.vert +// model.slv // vertex shader // // Created by Andrzej Kapolka on 10/14/13. @@ -17,19 +17,18 @@ <$declareStandardTransform()$> const int MAX_TEXCOORDS = 2; - uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; +out vec3 _color; +out float _alpha; +out vec2 _texCoord0; out vec4 _position; out vec3 _normal; -out vec3 _color; -out vec2 _texCoord0; void main(void) { - // pass along the diffuse color in linear space _color = colorToLinearRGB(inColor.xyz); + _alpha = inColor.w; - // and the texture coordinates _texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; // standard transform diff --git a/libraries/render-utils/src/model_emissive.slf b/libraries/render-utils/src/model_emissive.slf new file mode 100644 index 0000000000..25239691cd --- /dev/null +++ b/libraries/render-utils/src/model_emissive.slf @@ -0,0 +1,38 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_emissive.frag +// fragment shader +// +// Created by Zach Pomerantz on 2/3/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include DeferredBufferWrite.slh@> +<@include model/Material.slh@> + +uniform sampler2D diffuseMap; + +in vec2 _texCoord0; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +void main(void) { + vec4 texel = texture(diffuseMap, _texCoord0); + + Material mat = getMaterial(); + vec3 fragColor = getMaterialDiffuse(mat) * texel.rgb * _color; + + packDeferredFragmentLightmap( + normalize(_normal), + texel.a, + vec3(1.0), + getMaterialSpecular(mat), + getMaterialShininess(mat), + fragColor); +} diff --git a/libraries/render-utils/src/model_translucent.slf b/libraries/render-utils/src/model_translucent.slf index 1a17258408..c6f745ed0f 100755 --- a/libraries/render-utils/src/model_translucent.slf +++ b/libraries/render-utils/src/model_translucent.slf @@ -11,39 +11,14 @@ // Distributed under the Apache License, Version 2.0. // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // + <@include model/Material.slh@> -// Everything about global lighting - <@include DeferredLighting.slh@> -<@include gpu/Transform.slh@> -<$declareStandardCameraTransform()$> - - -// Everything about light <@include model/Light.slh@> -// The view Matrix -//uniform mat4 invViewMat; - -vec4 evalNormalColor(vec3 dir, float opacity) { - bool isX = (abs(dir.x) > 0.99); - bool isY = (abs(dir.y) > 0.99); - bool isZ = (abs(dir.z) > 0.99); - if (isX || isY || isZ) { - bool negX = (dir.x < -0.995); - bool negY = (dir.y < -0.995); - bool negZ = (dir.z < -0.995); - - if (negX || negY || negZ) { - return vec4(float(isX), float(isY), float(isZ), 0.2); - } else { - return vec4(float(isX), float(isY), float(isZ), 1.0); - } - } - - return vec4(0.5 * dir + vec3(0.5), opacity); -} +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss, float opacity) { @@ -60,42 +35,37 @@ vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 d vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); - color += vec3(opacity * diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + color += vec3(diffuse * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); - //return vec4(color, opacity); return vec4(color, opacity); - //return vec4(diffuse.rgb, opacity); - //return evalNormalColor(fragEyeDir, opacity); } -// the diffuse texture uniform sampler2D diffuseMap; -in vec4 _position; in vec2 _texCoord0; +in vec4 _position; in vec3 _normal; in vec3 _color; +in float _alpha; out vec4 _fragColor; void main(void) { - vec3 fragPosition = _position.xyz; - - // Fetch diffuse map vec4 diffuse = texture(diffuseMap, _texCoord0); Material mat = getMaterial(); + vec3 fragPosition = _position.xyz; vec3 fragNormal = normalize(_normal); - float fragOpacity = getMaterialOpacity(mat) * diffuse.a; vec3 fragDiffuse = getMaterialDiffuse(mat) * diffuse.rgb * _color; vec3 fragSpecular = getMaterialSpecular(mat); - float fragGloss = getMaterialShininess(mat); + float fragGloss = getMaterialShininess(mat) / 128; + float fragOpacity = getMaterialOpacity(mat) * diffuse.a * _alpha; _fragColor = evalGlobalColor(1.0, - fragPosition, - fragNormal, - fragDiffuse, - fragSpecular, - fragGloss, - fragOpacity); + fragPosition, + fragNormal, + fragDiffuse, + fragSpecular, + fragGloss, + fragOpacity); } diff --git a/libraries/render-utils/src/model_translucent_emissive.slf b/libraries/render-utils/src/model_translucent_emissive.slf new file mode 100644 index 0000000000..a2c7186f6f --- /dev/null +++ b/libraries/render-utils/src/model_translucent_emissive.slf @@ -0,0 +1,33 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// model_translucent_emissive.frag +// fragment shader +// +// Created by Zach Pomerantz on 2/3/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include model/Material.slh@> + +uniform sampler2D diffuseMap; + +in vec2 _texCoord0; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; + +void main(void) { + vec4 diffuse = texture(diffuseMap, _texCoord0); + + Material mat = getMaterial(); + vec3 fragColor = getMaterialDiffuse(mat) * diffuse.rgb * _color; + float fragOpacity = getMaterialOpacity(mat) * diffuse.a * _alpha; + + _fragColor = vec4(fragColor, fragOpacity); +} diff --git a/libraries/render-utils/src/overlay3D.slf b/libraries/render-utils/src/overlay3D.slf index 7b8a8d85f4..66a48e95f4 100644 --- a/libraries/render-utils/src/overlay3D.slf +++ b/libraries/render-utils/src/overlay3D.slf @@ -1,7 +1,7 @@ <@include gpu/Config.slh@> <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> -// model.frag +// overlay3D.slf // fragment shader // // Created by Sam Gateau on 6/16/15. @@ -11,20 +11,64 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -uniform sampler2D diffuseMap; +<@include DeferredLighting.slh@> +<@include model/Light.slh@> -in vec2 varTexcoord; +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> -in vec3 varEyeNormal; +vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss, float opacity) { -in vec4 varColor; -out vec4 outFragColor; + // Need the light now + Light light = getLight(); + TransformCamera cam = getTransformCamera(); + vec3 fragNormal; + <$transformEyeToWorldDir(cam, normal, fragNormal)$> + vec3 fragEyeVectorView = normalize(-position); + vec3 fragEyeDir; + <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> + vec3 color = opacity * diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); + + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + + color += vec3(diffuse * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + + return vec4(color, opacity); +} + +uniform sampler2D originalTexture; + +in vec2 _texCoord0; +in vec4 _position; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; void main(void) { - vec4 diffuse = texture(diffuseMap, varTexcoord.st); - if (diffuse.a < 0.5) { + vec4 diffuse = texture(originalTexture, _texCoord0); + + vec3 fragPosition = _position.xyz; + vec3 fragNormal = normalize(_normal); + vec3 fragDiffuse = diffuse.rgb * _color; + vec3 fragSpecular = vec3(0.1); + float fragGloss = 10.0 / 128.0; + float fragOpacity = diffuse.a; + + if (fragOpacity <= 0.1) { discard; } - outFragColor = vec4(varColor * diffuse); + + vec4 color = evalGlobalColor(1.0, + fragPosition, + fragNormal, + fragDiffuse, + fragSpecular, + fragGloss, + fragOpacity); + + // Apply standard tone mapping + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); } diff --git a/libraries/render-utils/src/overlay3D.slv b/libraries/render-utils/src/overlay3D.slv index 74416f0c1f..d39e5a2f01 100644 --- a/libraries/render-utils/src/overlay3D.slv +++ b/libraries/render-utils/src/overlay3D.slv @@ -2,6 +2,7 @@ <$VERSION_HEADER$> // Generated on <$_SCRIBE_DATE$> // overlay3D.slv +// vertex shader // // Created by Sam Gateau on 6/16/15. // Copyright 2015 High Fidelity, Inc. @@ -15,25 +16,21 @@ <@include gpu/Transform.slh@> <$declareStandardTransform()$> -out vec2 varTexcoord; - -// interpolated eye position -out vec4 varEyePosition; - -// the interpolated normal -out vec3 varEyeNormal; - -out vec4 varColor; +out vec3 _color; +out float _alpha; +out vec2 _texCoord0; +out vec4 _position; +out vec3 _normal; void main(void) { - varTexcoord = inTexCoord0.xy; + _color = colorToLinearRGB(inColor.xyz); + _alpha = inColor.w; - // pass along the color - varColor = colorToLinearRGBA(inColor); + _texCoord0 = inTexCoord0.st; // standard transform TransformCamera cam = getTransformCamera(); TransformObject obj = getTransformObject(); - <$transformModelToEyeAndClipPos(cam, obj, inPosition, varEyePosition, gl_Position)$> - <$transformModelToEyeDir(cam, obj, inNormal.xyz, varEyeNormal.xyz)$> + <$transformModelToEyeAndClipPos(cam, obj, inPosition, _position, gl_Position)$> + <$transformModelToEyeDir(cam, obj, inNormal.xyz, _normal)$> } diff --git a/libraries/render-utils/src/overlay3D_emissive.slf b/libraries/render-utils/src/overlay3D_emissive.slf new file mode 100644 index 0000000000..ad689baf91 --- /dev/null +++ b/libraries/render-utils/src/overlay3D_emissive.slf @@ -0,0 +1,32 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// overlay3D_emissive.frag +// fragment shader +// +// Created by Zach Pomerantz on 2/2/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +uniform sampler2D originalTexture; + +in vec2 _texCoord0; +in vec3 _color; + +out vec4 _fragColor; + +void main(void) { + vec4 diffuse = texture(originalTexture, _texCoord0); + + if (diffuse.a <= 0.1) { + discard; + } + vec4 color = vec4(diffuse.rgb * _color, diffuse.a); + + // Apply standard tone mapping + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); +} diff --git a/libraries/render-utils/src/overlay3D_translucent.slf b/libraries/render-utils/src/overlay3D_translucent.slf new file mode 100644 index 0000000000..dcc15ba25b --- /dev/null +++ b/libraries/render-utils/src/overlay3D_translucent.slf @@ -0,0 +1,71 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// overlay3D_translucent.slf +// fragment shader +// +// Created by Sam Gateau on 6/16/15. +// Copyright 2015 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +<@include DeferredLighting.slh@> +<@include model/Light.slh@> + +<@include gpu/Transform.slh@> +<$declareStandardCameraTransform()$> + +vec4 evalGlobalColor(float shadowAttenuation, vec3 position, vec3 normal, vec3 diffuse, vec3 specular, float gloss, float opacity) { + + // Need the light now + Light light = getLight(); + TransformCamera cam = getTransformCamera(); + vec3 fragNormal; + <$transformEyeToWorldDir(cam, normal, fragNormal)$> + vec3 fragEyeVectorView = normalize(-position); + vec3 fragEyeDir; + <$transformEyeToWorldDir(cam, fragEyeVectorView, fragEyeDir)$> + + vec3 color = opacity * diffuse.rgb * getLightColor(light) * getLightAmbientIntensity(light); + + vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss); + + color += vec3(diffuse * shading.w * opacity + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light); + + return vec4(color, opacity); +} + +uniform sampler2D originalTexture; + +in vec2 _texCoord0; +in vec4 _position; +in vec3 _normal; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; + +void main(void) { + vec4 diffuse = texture(originalTexture, _texCoord0); + + vec3 fragPosition = _position.xyz; + vec3 fragNormal = normalize(_normal); + vec3 fragDiffuse = diffuse.rgb * _color; + vec3 fragSpecular = vec3(0.1); + float fragGloss = 10.0 / 128.0; + float fragOpacity = diffuse.a * _alpha; + + vec4 color = evalGlobalColor(1.0, + fragPosition, + fragNormal, + fragDiffuse, + fragSpecular, + fragGloss, + fragOpacity); + + // Apply standard tone mapping + _fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w); +} diff --git a/libraries/render-utils/src/overlay3D_translucent_emissive.slf b/libraries/render-utils/src/overlay3D_translucent_emissive.slf new file mode 100644 index 0000000000..bcfec7d588 --- /dev/null +++ b/libraries/render-utils/src/overlay3D_translucent_emissive.slf @@ -0,0 +1,27 @@ +<@include gpu/Config.slh@> +<$VERSION_HEADER$> +// Generated on <$_SCRIBE_DATE$> +// +// overlay3D_translucent_emissive.frag +// fragment shader +// +// Created by Zach Pomerantz on 2/2/2016. +// Copyright 2016 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +uniform sampler2D originalTexture; + +in vec2 _texCoord0; +in vec3 _color; +in float _alpha; + +out vec4 _fragColor; + +void main(void) { + vec4 diffuse = texture(originalTexture, _texCoord0); + + _fragColor = vec4(diffuse.rgb * _color, diffuse.a * _alpha); +} diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 43202c29c2..2e86d09fe0 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -234,6 +234,10 @@ void Font::setupGPU() { 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); _pipeline = gpu::Pipeline::create(program, state); + + auto layeredState = std::make_shared(state->getValues()); + layeredState->setDepthTest(false); + _layeredPipeline = gpu::Pipeline::create(program, layeredState); } // Sanity checks @@ -336,7 +340,7 @@ void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2 } void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, - EffectType effectType, const glm::vec2& bounds) { + EffectType effectType, const glm::vec2& bounds, bool layered) { if (str == "") { return; } @@ -347,7 +351,7 @@ void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, c setupGPU(); - batch.setPipeline(_pipeline); + batch.setPipeline(layered ? _layeredPipeline : _pipeline); batch.setResourceTexture(_fontLoc, _texture); batch._glUniform1i(_outlineLoc, (effectType == OUTLINE_EFFECT)); batch._glUniform4fv(_colorLoc, 1, (const float*)color); diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index e10360d45f..351bc63163 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -27,7 +27,7 @@ public: // Render string to batch void drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, EffectType effectType, - const glm::vec2& bound); + const glm::vec2& bound, bool layered = false); static Font* load(QIODevice& fontFile); static Font* load(const QString& family); @@ -61,6 +61,7 @@ private: // gpu structures gpu::PipelinePointer _pipeline; + gpu::PipelinePointer _layeredPipeline; gpu::TexturePointer _texture; gpu::Stream::FormatPointer _format; gpu::BufferPointer _verticesBuffer; diff --git a/libraries/render/src/render/DrawTask.cpp b/libraries/render/src/render/DrawTask.cpp index 455a420355..bb31792c4b 100755 --- a/libraries/render/src/render/DrawTask.cpp +++ b/libraries/render/src/render/DrawTask.cpp @@ -143,6 +143,7 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons if (args->_pipeline) { item.render(args); } + args->_pipeline = nullptr; } else if (key.hasOwnPipeline()) { item.render(args); } else { diff --git a/libraries/render/src/render/ShapePipeline.cpp b/libraries/render/src/render/ShapePipeline.cpp index c83f16c456..b77c9c3451 100644 --- a/libraries/render/src/render/ShapePipeline.cpp +++ b/libraries/render/src/render/ShapePipeline.cpp @@ -17,6 +17,12 @@ using namespace render; +void ShapePipeline::prepare(gpu::Batch& batch) { + if (batchSetter) { + batchSetter(*this, batch); + } +} + ShapeKey::Filter::Builder::Builder() { _mask.set(OWN_PIPELINE); _mask.set(INVALID); @@ -90,13 +96,13 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke PipelinePointer shapePipeline(pipelineIterator->second); auto& batch = args->_batch; + // Setup the one pipeline (to rule them all) + batch->setPipeline(shapePipeline->pipeline); + // Run the pipeline's BatchSetter on the passed in batch if (shapePipeline->batchSetter) { shapePipeline->batchSetter(*shapePipeline, *batch); } - // Setup the one pipeline (to rule them all) - batch->setPipeline(shapePipeline->pipeline); - return shapePipeline; } diff --git a/libraries/render/src/render/ShapePipeline.h b/libraries/render/src/render/ShapePipeline.h index 1a6837efa3..4fd1dc22c5 100644 --- a/libraries/render/src/render/ShapePipeline.h +++ b/libraries/render/src/render/ShapePipeline.h @@ -28,7 +28,9 @@ public: SKINNED, STEREO, DEPTH_ONLY, + DEPTH_BIAS, WIREFRAME, + NO_CULL_FACE, OWN_PIPELINE, INVALID, @@ -39,7 +41,7 @@ public: Flags _flags; - ShapeKey() : _flags{0} {} + ShapeKey() : _flags{ 0 } {} ShapeKey(const Flags& flags) : _flags{flags} {} class Builder { @@ -57,7 +59,9 @@ public: Builder& withSkinned() { _flags.set(SKINNED); return (*this); } Builder& withStereo() { _flags.set(STEREO); return (*this); } Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); } + Builder& withDepthBias() { _flags.set(DEPTH_BIAS); return (*this); } Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); } + Builder& withoutCullFace() { _flags.set(NO_CULL_FACE); return (*this); } Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); } Builder& invalidate() { _flags.set(INVALID); return (*this); } @@ -107,9 +111,15 @@ public: Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } Builder& withoutDepthOnly() { _flags.reset(DEPTH_ONLY); _mask.set(DEPTH_ONLY); return (*this); } + Builder& withDepthBias() { _flags.set(DEPTH_BIAS); _mask.set(DEPTH_BIAS); return (*this); } + Builder& withoutDepthBias() { _flags.reset(DEPTH_BIAS); _mask.set(DEPTH_BIAS); return (*this); } + Builder& withWireframe() { _flags.set(WIREFRAME); _mask.set(WIREFRAME); return (*this); } Builder& withoutWireframe() { _flags.reset(WIREFRAME); _mask.set(WIREFRAME); return (*this); } + Builder& withCullFace() { _flags.reset(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); } + Builder& withoutCullFace() { _flags.set(NO_CULL_FACE); _mask.set(NO_CULL_FACE); return (*this); } + protected: friend class Filter; Flags _flags{0}; @@ -130,7 +140,9 @@ public: bool isSkinned() const { return _flags[SKINNED]; } bool isStereo() const { return _flags[STEREO]; } bool isDepthOnly() const { return _flags[DEPTH_ONLY]; } + bool isDepthBiased() const { return _flags[DEPTH_BIAS]; } bool isWireFrame() const { return _flags[WIREFRAME]; } + bool isCullFace() const { return !_flags[NO_CULL_FACE]; } bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; } bool isValid() const { return !_flags[INVALID]; } @@ -150,21 +162,23 @@ public: }; }; -inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) { - if (renderKey.isValid()) { - if (renderKey.hasOwnPipeline()) { +inline QDebug operator<<(QDebug debug, const ShapeKey& key) { + if (key.isValid()) { + if (key.hasOwnPipeline()) { debug << "[ShapeKey: OWN_PIPELINE]"; } else { debug << "[ShapeKey:" - << "hasLightmap:" << renderKey.hasLightmap() - << "hasTangents:" << renderKey.hasTangents() - << "hasSpecular:" << renderKey.hasSpecular() - << "hasEmissive:" << renderKey.hasEmissive() - << "isTranslucent:" << renderKey.isTranslucent() - << "isSkinned:" << renderKey.isSkinned() - << "isStereo:" << renderKey.isStereo() - << "isDepthOnly:" << renderKey.isDepthOnly() - << "isWireFrame:" << renderKey.isWireFrame() + << "hasLightmap:" << key.hasLightmap() + << "hasTangents:" << key.hasTangents() + << "hasSpecular:" << key.hasSpecular() + << "hasEmissive:" << key.hasEmissive() + << "isTranslucent:" << key.isTranslucent() + << "isSkinned:" << key.isSkinned() + << "isStereo:" << key.isStereo() + << "isDepthOnly:" << key.isDepthOnly() + << "isDepthBiased:" << key.isDepthBiased() + << "isWireFrame:" << key.isWireFrame() + << "isCullFace:" << key.isCullFace() << "]"; } } else { @@ -209,6 +223,10 @@ public: ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) : pipeline(pipeline), locations(locations), batchSetter(batchSetter) {} + // Normally, a pipeline is accessed thorugh pickPipeline. If it needs to be set manually, + // after calling setPipeline this method should be called to prepare the pipeline with default buffers. + void prepare(gpu::Batch& batch); + gpu::PipelinePointer pipeline; std::shared_ptr locations; diff --git a/tests/gpu-test/src/main.cpp b/tests/gpu-test/src/main.cpp index b1ca3d0448..87ce2d7622 100644 --- a/tests/gpu-test/src/main.cpp +++ b/tests/gpu-test/src/main.cpp @@ -239,6 +239,7 @@ public: } } + auto pipeline = geometryCache->getSimplePipeline(); for (auto& transform : transforms) { batch.setModelTransform(transform); batch.setupNamedCalls(GRID_INSTANCE, [=](gpu::Batch& batch, gpu::Batch::NamedBatchData& data) {