Merge pull request #7028 from zzmp/fix/overlay

Add transparency and layering for overlays
sam is doing it
This commit is contained in:
Chris Collins 2016-02-09 09:18:32 -08:00
commit e61636e8a7
46 changed files with 814 additions and 364 deletions

View file

@ -105,7 +105,6 @@ void Circle3DOverlay::render(RenderArgs* args) {
auto transform = _transform;
transform.postScale(glm::vec3(getDimensions(), 1.0f));
batch.setModelTransform(transform);
DependencyManager::get<GeometryCache>()->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);

View file

@ -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);

View file

@ -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<GeometryCache>()->renderSolidCube(*batch, 1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
// }
auto geometryCache = DependencyManager::get<GeometryCache>();
auto pipeline = args->_pipeline;
if (!pipeline) {
pipeline = geometryCache->getShapePipeline();
}
if (_isSolid) {
transform.setScale(dimensions);
batch->setModelTransform(transform);
DependencyManager::get<GeometryCache>()->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>();
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<GeometryCache>()->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);
}

View file

@ -24,6 +24,7 @@ public:
Cube3DOverlay(const Cube3DOverlay* cube3DOverlay);
virtual void render(RenderArgs* args);
virtual const render::ShapeKey getShapeKey() override;
virtual Cube3DOverlay* createClone() const;

View file

@ -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);

View file

@ -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);

View file

@ -95,7 +95,6 @@ void Image3DOverlay::render(RenderArgs* args) {
batch->setModelTransform(transform);
batch->setResourceTexture(0, _texture->getGPUTexture());
DependencyManager::get<GeometryCache>()->bindSimpleProgram(*batch, true, false, _emissive, true);
DependencyManager::get<GeometryCache>()->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);

View file

@ -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; }

View file

@ -53,7 +53,6 @@ void Line3DOverlay::render(RenderArgs* args) {
auto batch = args->_batch;
if (batch) {
batch->setModelTransform(_transform);
DependencyManager::get<GeometryCache>()->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);

View file

@ -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

View file

@ -44,6 +44,8 @@ public:
virtual bool addToScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
virtual void removeFromScene(Overlay::Pointer overlay, std::shared_ptr<render::Scene> 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);
}

View file

@ -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<Base3DOverlay>(overlay)->getDrawOnHUD()) {
if (std::dynamic_pointer_cast<Base3DOverlay>(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();
}
}

View file

@ -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);
}

View file

@ -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;

View file

@ -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<GeometryCache>();
auto pipeline = args->_pipeline;
if (!pipeline) {
pipeline = geometryCache->getShapePipeline();
}
if (_isSolid) {
DependencyManager::get<GeometryCache>()->renderSolidSphereInstance(*batch, sphereColor);
geometryCache->renderSolidSphereInstance(*batch, sphereColor, pipeline);
} else {
DependencyManager::get<GeometryCache>()->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);
}

View file

@ -24,6 +24,7 @@ public:
Sphere3DOverlay(const Sphere3DOverlay* Sphere3DOverlay);
virtual void render(RenderArgs* args);
virtual const render::ShapeKey getShapeKey() override;
virtual Sphere3DOverlay* createClone() const;
};

View file

@ -8,8 +8,10 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
#include "Text3DOverlay.h"
#include <TextureCache.h>
#include <GeometryCache.h>
#include <RegisteredMetaTypes.h>
#include <RenderDeferredTask.h>
@ -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<GeometryCache>()->bindSimpleProgram(batch, false, true, false, true);
DependencyManager::get<GeometryCache>()->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()) {

View file

@ -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

View file

@ -34,7 +34,7 @@ public:
protected:
// Centered local bounding box
AABox _localBoundingBox;
AABox _localBoundingBox{ vec3(0.0f), 1.0f };
};

View file

@ -101,11 +101,18 @@ void Web3DOverlay::render(RenderArgs* args) {
}
batch.setModelTransform(transform);
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, true, false, false, true);
DependencyManager::get<GeometryCache>()->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);

View file

@ -25,6 +25,7 @@ public:
virtual ~Web3DOverlay();
virtual void render(RenderArgs* args);
virtual const render::ShapeKey getShapeKey() override;
virtual void update(float deltatime);

View file

@ -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) {

View file

@ -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);

View file

@ -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<render::ShapePipeline>(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<TextureCache>()->getWhiteTexture());
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->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<glm::vec2>& 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<glm::vec2>& 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<glm::vec2>& 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<glm::vec3>& 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<glm::vec3>& 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<glm::vec3>& 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<glm::vec3>& 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<glm::vec3>& 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<glm::vec3>& 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<TextureCache>()->getWhiteTexture());
}
// Set a default normal map
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->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<gpu::State>();
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<TextureCache>()->getWhiteTexture());
}
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->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 <typename F>
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<render::ShapePipelinePointer>()(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<GeometryCache>()->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<GeometryCache>()->renderWireShapeInstances(batch, shape, data.count(), data.buffers[INSTANCE_COLOR_BUFFER]);
} else {
DependencyManager::get<GeometryCache>()->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<GeometryCache>()->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<GeometryCache>()->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<GeometryCache>()->renderShapeInstances(batch, shape, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]);
renderInstances(INSTANCE_NAME, batch, color, true, pipeline, shape);
} else {
DependencyManager::get<GeometryCache>()->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<GeometryCache>()->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<GeometryCache>()->renderWireCubeInstances(batch, data.count(),
data.buffers[INSTANCE_COLOR_BUFFER]);
});
renderInstances(INSTANCE_NAME, batch, color, true, pipeline, GeometryCache::Cube);
}

View file

@ -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<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
gpu::PipelinePointer getPipeline(SimpleProgramKey config);
gpu::ShaderPointer _simpleShader;
gpu::ShaderPointer _emissiveShader;
static render::ShapePipelinePointer _simplePipeline;
QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
};

View file

@ -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<DeferredLightingEffect>()->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<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
}
if (args) {
args->_details._materialSwitches++;
}

View file

@ -104,7 +104,8 @@ RenderDeferredTask::RenderDeferredTask(CullFunctor cullFunctor) {
addJob<DrawStatus>("DrawStatus", opaques, DrawStatus(statusIconMap));
}
addJob<DrawOverlay3D>("DrawOverlay3D");
addJob<DrawOverlay3D>("DrawOverlay3DOpaque", ItemFilter::Builder::opaqueShape().withLayered());
addJob<DrawOverlay3D>("DrawOverlay3DTransparent", ItemFilter::Builder::transparentShape().withLayered());
addJob<HitEffect>("HitEffect");
@ -156,7 +157,7 @@ void DrawDeferred::run(const SceneContextPointer& sceneContext, const RenderCont
});
}
DrawOverlay3D::DrawOverlay3D() : _shapePlumber{ std::make_shared<ShapePlumber>() } {
DrawOverlay3D::DrawOverlay3D(ItemFilter filter) : _filter{ filter }, _shapePlumber{ std::make_shared<ShapePlumber>() } {
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<Config>(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;

View file

@ -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, Config>;
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
};

View file

@ -13,6 +13,7 @@
#include <gpu/Context.h>
#include <gpu/StandardShaderLib.h>
#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<gpu::State>();
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<gpu::Buffer>(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<TextureCache>()->getNormalFittingTexture());
void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
// Set a default diffuse map
batch.setResourceTexture(render::ShapePipeline::Slot::DIFFUSE_MAP,
DependencyManager::get<TextureCache>()->getWhiteTexture());
// Set a default normal map
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->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<DeferredLightingEffect>()->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<gpu::State>();
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<gpu::State>();
// 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<gpu::State>(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<gpu::State>();
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);
}

View file

@ -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);
}
}

View file

@ -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,

View file

@ -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

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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)$>
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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);
}

View file

@ -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<gpu::State>(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);

View file

@ -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;

View file

@ -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 {

View file

@ -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;
}

View file

@ -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> locations;

View file

@ -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) {