mirror of
https://github.com/overte-org/overte.git
synced 2025-08-12 21:29:49 +02:00
Merge pull request #10950 from samcake/hobbes
add custom shape pipeline, use for Polyvox and Particle system entities
This commit is contained in:
commit
01bbd8d89d
12 changed files with 214 additions and 171 deletions
|
@ -13,14 +13,13 @@
|
|||
#include <DependencyManager.h>
|
||||
#include <PerfStat.h>
|
||||
#include <GeometryCache.h>
|
||||
#include <render/ShapePipeline.h>
|
||||
#include <StencilMaskPass.h>
|
||||
#include <AbstractViewStateInterface.h>
|
||||
#include "EntitiesRendererLogging.h"
|
||||
|
||||
#include "RenderableParticleEffectEntityItem.h"
|
||||
|
||||
#include "untextured_particle_vert.h"
|
||||
#include "untextured_particle_frag.h"
|
||||
#include "textured_particle_vert.h"
|
||||
#include "textured_particle_frag.h"
|
||||
|
||||
|
@ -29,6 +28,16 @@ class ParticlePayloadData {
|
|||
public:
|
||||
static const size_t VERTEX_PER_PARTICLE = 4;
|
||||
|
||||
static uint8_t CUSTOM_PIPELINE_NUMBER;
|
||||
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key);
|
||||
static void registerShapePipeline() {
|
||||
if (!CUSTOM_PIPELINE_NUMBER) {
|
||||
CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory);
|
||||
}
|
||||
}
|
||||
|
||||
static std::weak_ptr<gpu::Pipeline> _texturedPipeline;
|
||||
|
||||
template<typename T>
|
||||
struct InterpolationData {
|
||||
T start;
|
||||
|
@ -70,9 +79,6 @@ public:
|
|||
offsetof(ParticlePrimitive, uv), gpu::Stream::PER_INSTANCE);
|
||||
}
|
||||
|
||||
void setPipeline(PipelinePointer pipeline) { _pipeline = pipeline; }
|
||||
const PipelinePointer& getPipeline() const { return _pipeline; }
|
||||
|
||||
const Transform& getModelTransform() const { return _modelTransform; }
|
||||
void setModelTransform(const Transform& modelTransform) { _modelTransform = modelTransform; }
|
||||
|
||||
|
@ -90,15 +96,15 @@ public:
|
|||
|
||||
bool getVisibleFlag() const { return _visibleFlag; }
|
||||
void setVisibleFlag(bool visibleFlag) { _visibleFlag = visibleFlag; }
|
||||
|
||||
|
||||
void render(RenderArgs* args) const {
|
||||
assert(_pipeline);
|
||||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setPipeline(_pipeline);
|
||||
|
||||
if (_texture) {
|
||||
batch.setResourceTexture(0, _texture);
|
||||
} else {
|
||||
batch.setResourceTexture(0, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
}
|
||||
|
||||
batch.setModelTransform(_modelTransform);
|
||||
|
@ -113,7 +119,6 @@ public:
|
|||
protected:
|
||||
Transform _modelTransform;
|
||||
AABox _bound;
|
||||
PipelinePointer _pipeline;
|
||||
FormatPointer _vertexFormat { std::make_shared<Format>() };
|
||||
BufferPointer _particleBuffer { std::make_shared<Buffer>() };
|
||||
BufferView _uniformBuffer;
|
||||
|
@ -142,23 +147,49 @@ namespace render {
|
|||
payload->render(args);
|
||||
}
|
||||
}
|
||||
template <>
|
||||
const ShapeKey shapeGetShapeKey(const ParticlePayloadData::Pointer& payload) {
|
||||
return render::ShapeKey::Builder().withCustom(ParticlePayloadData::CUSTOM_PIPELINE_NUMBER).withTranslucent().build();
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t ParticlePayloadData::CUSTOM_PIPELINE_NUMBER = 0;
|
||||
|
||||
std::weak_ptr<gpu::Pipeline> ParticlePayloadData::_texturedPipeline;
|
||||
|
||||
render::ShapePipelinePointer ParticlePayloadData::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) {
|
||||
auto texturedPipeline = _texturedPipeline.lock();
|
||||
if (!texturedPipeline) {
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert));
|
||||
auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag));
|
||||
|
||||
auto program = gpu::Shader::createProgram(vertShader, fragShader);
|
||||
_texturedPipeline = texturedPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
|
||||
return std::make_shared<render::ShapePipeline>(texturedPipeline, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
EntityItemPointer RenderableParticleEffectEntityItem::factory(const EntityItemID& entityID,
|
||||
const EntityItemProperties& properties) {
|
||||
auto entity = std::make_shared<RenderableParticleEffectEntityItem>(entityID);
|
||||
entity->setProperties(properties);
|
||||
|
||||
// As we create the first ParticuleSystem entity, let s register its special shapePIpeline factory:
|
||||
ParticlePayloadData::registerShapePipeline();
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
RenderableParticleEffectEntityItem::RenderableParticleEffectEntityItem(const EntityItemID& entityItemID) :
|
||||
ParticleEffectEntityItem(entityItemID) {
|
||||
// lazy creation of particle system pipeline
|
||||
if (!_untexturedPipeline || !_texturedPipeline) {
|
||||
createPipelines();
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableParticleEffectEntityItem::addToScene(const EntityItemPointer& self,
|
||||
|
@ -167,7 +198,6 @@ bool RenderableParticleEffectEntityItem::addToScene(const EntityItemPointer& sel
|
|||
_scene = scene;
|
||||
_renderItemId = _scene->allocateID();
|
||||
auto particlePayloadData = std::make_shared<ParticlePayloadData>();
|
||||
particlePayloadData->setPipeline(_untexturedPipeline);
|
||||
auto renderPayload = std::make_shared<ParticlePayloadData::Payload>(particlePayloadData);
|
||||
render::Item::Status::Getters statusGetters;
|
||||
makeEntityItemStatusGetters(getThisPointer(), statusGetters);
|
||||
|
@ -276,47 +306,14 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
|
|||
|
||||
if (_texture && _texture->isLoaded()) {
|
||||
payload.setTexture(_texture->getGPUTexture());
|
||||
payload.setPipeline(_texturedPipeline);
|
||||
} else {
|
||||
payload.setTexture(nullptr);
|
||||
payload.setPipeline(_untexturedPipeline);
|
||||
}
|
||||
});
|
||||
|
||||
_scene->enqueueTransaction(transaction);
|
||||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::createPipelines() {
|
||||
if (!_untexturedPipeline) {
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
auto vertShader = gpu::Shader::createVertex(std::string(untextured_particle_vert));
|
||||
auto fragShader = gpu::Shader::createPixel(std::string(untextured_particle_frag));
|
||||
|
||||
auto program = gpu::Shader::createProgram(vertShader, fragShader);
|
||||
_untexturedPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
if (!_texturedPipeline) {
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, false, gpu::LESS_EQUAL);
|
||||
state->setBlendFunction(true, gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
PrepareStencil::testMask(*state);
|
||||
|
||||
auto vertShader = gpu::Shader::createVertex(std::string(textured_particle_vert));
|
||||
auto fragShader = gpu::Shader::createPixel(std::string(textured_particle_frag));
|
||||
|
||||
auto program = gpu::Shader::createProgram(vertShader, fragShader);
|
||||
_texturedPipeline = gpu::Pipeline::create(program, state);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderableParticleEffectEntityItem::notifyBoundChanged() {
|
||||
if (!render::Item::isValidID(_renderItemId)) {
|
||||
return;
|
||||
|
|
|
@ -34,16 +34,13 @@ protected:
|
|||
virtual void locationChanged(bool tellPhysics = true) override { EntityItem::locationChanged(tellPhysics); notifyBoundChanged(); }
|
||||
virtual void dimensionsChanged() override { EntityItem::dimensionsChanged(); notifyBoundChanged(); }
|
||||
|
||||
void notifyBoundChanged();
|
||||
void notifyBoundChanged();
|
||||
|
||||
void createPipelines();
|
||||
|
||||
render::ScenePointer _scene;
|
||||
render::ItemID _renderItemId{ render::Item::INVALID_ITEM_ID };
|
||||
|
||||
NetworkTexturePointer _texture;
|
||||
gpu::PipelinePointer _untexturedPipeline;
|
||||
gpu::PipelinePointer _texturedPipeline;
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -59,12 +59,8 @@
|
|||
#include "EntityEditPacketSender.h"
|
||||
#include "PhysicalEntitySimulation.h"
|
||||
|
||||
gpu::PipelinePointer RenderablePolyVoxEntityItem::_pipeline = nullptr;
|
||||
gpu::PipelinePointer RenderablePolyVoxEntityItem::_wireframePipeline = nullptr;
|
||||
|
||||
const float MARCHING_CUBE_COLLISION_HULL_OFFSET = 0.5;
|
||||
|
||||
|
||||
/*
|
||||
A PolyVoxEntity has several interdependent parts:
|
||||
|
||||
|
@ -116,6 +112,10 @@ EntityItemPointer RenderablePolyVoxEntityItem::factory(const EntityItemID& entit
|
|||
EntityItemPointer entity{ new RenderablePolyVoxEntityItem(entityID) };
|
||||
entity->setProperties(properties);
|
||||
std::static_pointer_cast<RenderablePolyVoxEntityItem>(entity)->initializePolyVox();
|
||||
|
||||
// As we create the first Polyvox entity, let's register its special shapePipeline factory:
|
||||
PolyVoxPayload::registerShapePipeline();
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
@ -732,35 +732,6 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
!mesh->getIndexBuffer()._buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_pipeline) {
|
||||
gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert));
|
||||
gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag));
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), MATERIAL_GPU_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2));
|
||||
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
|
||||
auto wireframeState = std::make_shared<gpu::State>();
|
||||
wireframeState->setCullMode(gpu::State::CULL_BACK);
|
||||
wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
wireframeState->setFillMode(gpu::State::FILL_LINE);
|
||||
PrepareStencil::testMaskDrawShape(*wireframeState);
|
||||
|
||||
_wireframePipeline = gpu::Pipeline::create(program, wireframeState);
|
||||
}
|
||||
|
||||
if (!_vertexFormat) {
|
||||
auto vf = std::make_shared<gpu::Stream::Format>();
|
||||
|
@ -771,11 +742,6 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
|
||||
// Pick correct Pipeline
|
||||
bool wireframe = (render::ShapeKey(args->_globalShapeKey).isWireframe());
|
||||
auto pipeline = (wireframe ? _wireframePipeline : _pipeline);
|
||||
batch.setPipeline(pipeline);
|
||||
|
||||
Transform transform(voxelToWorldMatrix());
|
||||
batch.setModelTransform(transform);
|
||||
batch.setInputFormat(_vertexFormat);
|
||||
|
@ -817,7 +783,7 @@ void RenderablePolyVoxEntityItem::render(RenderArgs* args) {
|
|||
batch.setResourceTexture(2, DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
}
|
||||
|
||||
int voxelVolumeSizeLocation = pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize");
|
||||
int voxelVolumeSizeLocation = args->_shapePipeline->pipeline->getProgram()->getUniforms().findLocation("voxelVolumeSize");
|
||||
batch._glUniform3f(voxelVolumeSizeLocation, voxelVolumeSize.x, voxelVolumeSize.y, voxelVolumeSize.z);
|
||||
|
||||
batch.drawIndexed(gpu::TRIANGLES, (gpu::uint32)mesh->getNumIndices(), 0);
|
||||
|
@ -848,6 +814,48 @@ void RenderablePolyVoxEntityItem::removeFromScene(const EntityItemPointer& self,
|
|||
render::Item::clearID(_myItem);
|
||||
}
|
||||
|
||||
uint8_t PolyVoxPayload::CUSTOM_PIPELINE_NUMBER = 0;
|
||||
|
||||
std::shared_ptr<gpu::Pipeline> PolyVoxPayload::_pipeline;
|
||||
std::shared_ptr<gpu::Pipeline> PolyVoxPayload::_wireframePipeline;
|
||||
|
||||
render::ShapePipelinePointer PolyVoxPayload::shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key) {
|
||||
if (!_pipeline) {
|
||||
gpu::ShaderPointer vertexShader = gpu::Shader::createVertex(std::string(polyvox_vert));
|
||||
gpu::ShaderPointer pixelShader = gpu::Shader::createPixel(std::string(polyvox_frag));
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), PolyVoxPayload::MATERIAL_GPU_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("xMap"), 0));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("yMap"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("zMap"), 2));
|
||||
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
state->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
PrepareStencil::testMaskDrawShape(*state);
|
||||
|
||||
_pipeline = gpu::Pipeline::create(program, state);
|
||||
|
||||
auto wireframeState = std::make_shared<gpu::State>();
|
||||
wireframeState->setCullMode(gpu::State::CULL_BACK);
|
||||
wireframeState->setDepthTest(true, true, gpu::LESS_EQUAL);
|
||||
wireframeState->setFillMode(gpu::State::FILL_LINE);
|
||||
PrepareStencil::testMaskDrawShape(*wireframeState);
|
||||
|
||||
_wireframePipeline = gpu::Pipeline::create(program, wireframeState);
|
||||
}
|
||||
|
||||
if (key.isWireframe()) {
|
||||
return std::make_shared<render::ShapePipeline>(_wireframePipeline, nullptr, nullptr, nullptr);
|
||||
} else {
|
||||
return std::make_shared<render::ShapePipeline>(_pipeline, nullptr, nullptr, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const PolyVoxPayload::Pointer& payload) {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
|
@ -871,6 +879,10 @@ namespace render {
|
|||
payload->_owner->getRenderableInterface()->render(args);
|
||||
}
|
||||
}
|
||||
|
||||
template <> const ShapeKey shapeGetShapeKey(const PolyVoxPayload::Pointer& payload) {
|
||||
return ShapeKey::Builder().withCustom(PolyVoxPayload::CUSTOM_PIPELINE_NUMBER).build();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1619,7 +1631,7 @@ void RenderablePolyVoxEntityItem::bonkNeighbors() {
|
|||
|
||||
void RenderablePolyVoxEntityItem::locationChanged(bool tellPhysics) {
|
||||
EntityItem::locationChanged(tellPhysics);
|
||||
if (!_pipeline || !render::Item::isValidID(_myItem)) {
|
||||
if (!render::Item::isValidID(_myItem)) {
|
||||
return;
|
||||
}
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
|
|
|
@ -28,6 +28,19 @@
|
|||
|
||||
class PolyVoxPayload {
|
||||
public:
|
||||
|
||||
static uint8_t CUSTOM_PIPELINE_NUMBER;
|
||||
static render::ShapePipelinePointer shapePipelineFactory(const render::ShapePlumber& plumber, const render::ShapeKey& key);
|
||||
static void registerShapePipeline() {
|
||||
if (!CUSTOM_PIPELINE_NUMBER) {
|
||||
CUSTOM_PIPELINE_NUMBER = render::ShapePipeline::registerCustomShapePipelineFactory(shapePipelineFactory);
|
||||
}
|
||||
}
|
||||
|
||||
static const int MATERIAL_GPU_SLOT = 3;
|
||||
static std::shared_ptr<gpu::Pipeline> _pipeline;
|
||||
static std::shared_ptr<gpu::Pipeline> _wireframePipeline;
|
||||
|
||||
PolyVoxPayload(EntityItemPointer owner) : _owner(owner), _bounds(AABox()) { }
|
||||
typedef render::Payload<PolyVoxPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
@ -40,6 +53,7 @@ namespace render {
|
|||
template <> const ItemKey payloadGetKey(const PolyVoxPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const PolyVoxPayload::Pointer& payload);
|
||||
template <> void payloadRender(const PolyVoxPayload::Pointer& payload, RenderArgs* args);
|
||||
template <> const ShapeKey shapeGetShapeKey(const PolyVoxPayload::Pointer& payload);
|
||||
}
|
||||
|
||||
|
||||
|
@ -168,10 +182,7 @@ private:
|
|||
NetworkTexturePointer _yTexture;
|
||||
NetworkTexturePointer _zTexture;
|
||||
|
||||
const int MATERIAL_GPU_SLOT = 3;
|
||||
render::ItemID _myItem{ render::Item::INVALID_ITEM_ID };
|
||||
static gpu::PipelinePointer _pipeline;
|
||||
static gpu::PipelinePointer _wireframePipeline;
|
||||
|
||||
ShapeInfo _shapeInfo;
|
||||
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
// fragment shader
|
||||
//
|
||||
// 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
|
||||
//
|
||||
|
||||
in vec4 _color;
|
||||
|
||||
out vec4 outFragColor;
|
||||
|
||||
void main(void) {
|
||||
outFragColor = _color;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// particle vertex shader
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
<@include gpu/Color.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec4 _color;
|
||||
|
||||
void main(void) {
|
||||
// pass along the color
|
||||
_color = colorToLinearRGBA(inColor);
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
<$transformModelToClipPos(cam, obj, inPosition, gl_Position)$>
|
||||
}
|
|
@ -182,7 +182,6 @@ GLuint compileProgram(const std::vector<GLuint>& glshaders, std::string& error)
|
|||
filestream.close();
|
||||
}
|
||||
*/
|
||||
delete[] temp;
|
||||
|
||||
glDeleteProgram(glprogram);
|
||||
return 0;
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "gpu/StandardShaderLib.h"
|
||||
|
||||
#include "model/TextureMap.h"
|
||||
#include "render/Args.h"
|
||||
|
||||
#include "standardTransformPNTC_vert.h"
|
||||
#include "standardDrawTexture_frag.h"
|
||||
|
@ -459,7 +460,8 @@ _nextID(0) {
|
|||
// Set the defaults needed for a simple program
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
}
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
GeometryCache::_simpleTransparentPipeline =
|
||||
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, true, true, false), nullptr,
|
||||
|
@ -467,11 +469,12 @@ _nextID(0) {
|
|||
// Set the defaults needed for a simple program
|
||||
batch.setResourceTexture(render::ShapePipeline::Slot::MAP::ALBEDO,
|
||||
DependencyManager::get<TextureCache>()->getWhiteTexture());
|
||||
}
|
||||
},
|
||||
nullptr
|
||||
);
|
||||
GeometryCache::_simpleWirePipeline =
|
||||
std::make_shared<render::ShapePipeline>(getSimplePipeline(false, false, true, true), nullptr,
|
||||
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {});
|
||||
[](const render::ShapePipeline&, gpu::Batch& batch, RenderArgs* args) {}, nullptr);
|
||||
}
|
||||
|
||||
GeometryCache::~GeometryCache() {
|
||||
|
|
|
@ -45,8 +45,9 @@ void renderShape(RenderArgs* args, const ShapePlumberPointer& shapeContext, cons
|
|||
if (key.isValid() && !key.hasOwnPipeline()) {
|
||||
args->_shapePipeline = shapeContext->pickPipeline(args, key);
|
||||
if (args->_shapePipeline) {
|
||||
args->_shapePipeline->prepareShapeItem(args, key, item);
|
||||
item.render(args);
|
||||
}
|
||||
}
|
||||
args->_shapePipeline = nullptr;
|
||||
} else if (key.hasOwnPipeline()) {
|
||||
item.render(args);
|
||||
|
@ -110,10 +111,11 @@ void render::renderStateSortShapes(const RenderContextPointer& renderContext,
|
|||
for (auto& pipelineKey : sortedPipelines) {
|
||||
auto& bucket = sortedShapes[pipelineKey];
|
||||
args->_shapePipeline = shapeContext->pickPipeline(args, pipelineKey);
|
||||
if (!args->_shapePipeline) {
|
||||
if (!args->_shapePipeline) {
|
||||
continue;
|
||||
}
|
||||
for (auto& item : bucket) {
|
||||
args->_shapePipeline->prepareShapeItem(args, pipelineKey, item);
|
||||
item.render(args);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,18 +17,34 @@
|
|||
|
||||
using namespace render;
|
||||
|
||||
ShapePipeline::CustomFactoryMap ShapePipeline::_globalCustomFactoryMap;
|
||||
|
||||
ShapePipeline::CustomKey ShapePipeline::registerCustomShapePipelineFactory(CustomFactory factory) {
|
||||
ShapePipeline::CustomKey custom = (ShapePipeline::CustomKey) _globalCustomFactoryMap.size() + 1;
|
||||
_globalCustomFactoryMap[custom] = factory;
|
||||
return custom;
|
||||
}
|
||||
|
||||
|
||||
void ShapePipeline::prepare(gpu::Batch& batch, RenderArgs* args) {
|
||||
if (batchSetter) {
|
||||
batchSetter(*this, batch, args);
|
||||
if (_batchSetter) {
|
||||
_batchSetter(*this, batch, args);
|
||||
}
|
||||
}
|
||||
|
||||
void ShapePipeline::prepareShapeItem(RenderArgs* args, const ShapeKey& key, const Item& shape) {
|
||||
if (_itemSetter) {
|
||||
_itemSetter(*this, args, shape);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ShapeKey::Filter::Builder::Builder() {
|
||||
_mask.set(OWN_PIPELINE);
|
||||
_mask.set(INVALID);
|
||||
}
|
||||
|
||||
void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) {
|
||||
void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit, const PipelinePointer& pipeline) const {
|
||||
// Iterate over all keys
|
||||
if (bit < (int)ShapeKey::FlagBit::NUM_FLAGS) {
|
||||
addPipelineHelper(filter, key, bit + 1, pipeline);
|
||||
|
@ -48,12 +64,12 @@ void ShapePlumber::addPipelineHelper(const Filter& filter, ShapeKey key, int bit
|
|||
}
|
||||
|
||||
void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||
BatchSetter batchSetter) {
|
||||
addPipeline(Filter{key}, program, state, batchSetter);
|
||||
BatchSetter batchSetter, ItemSetter itemSetter) {
|
||||
addPipeline(Filter{key}, program, state, batchSetter, itemSetter);
|
||||
}
|
||||
|
||||
void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||
BatchSetter batchSetter) {
|
||||
BatchSetter batchSetter, ItemSetter itemSetter) {
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightingModelBuffer"), Slot::BUFFER::LIGHTING_MODEL));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::BUFFER::SKINNING));
|
||||
|
@ -90,7 +106,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
|
|||
|
||||
ShapeKey key{filter._flags};
|
||||
auto gpuPipeline = gpu::Pipeline::create(program, state);
|
||||
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter);
|
||||
auto shapePipeline = std::make_shared<Pipeline>(gpuPipeline, locations, batchSetter, itemSetter);
|
||||
addPipelineHelper(filter, key, 0, shapePipeline);
|
||||
}
|
||||
|
||||
|
@ -103,23 +119,34 @@ const ShapePipelinePointer ShapePlumber::pickPipeline(RenderArgs* args, const Ke
|
|||
|
||||
const auto& pipelineIterator = _pipelineMap.find(key);
|
||||
if (pipelineIterator == _pipelineMap.end()) {
|
||||
// The first time we can't find a pipeline, we should log it
|
||||
// The first time we can't find a pipeline, we should try things to solve that
|
||||
if (_missingKeys.find(key) == _missingKeys.end()) {
|
||||
_missingKeys.insert(key);
|
||||
qCDebug(renderlogging) << "Couldn't find a pipeline for" << key;
|
||||
if (key.isCustom()) {
|
||||
auto factoryIt = ShapePipeline::_globalCustomFactoryMap.find(key.getCustom());
|
||||
if ((factoryIt != ShapePipeline::_globalCustomFactoryMap.end()) && (factoryIt)->second) {
|
||||
// found a factory for the custom key, can now generate a shape pipeline for this case:
|
||||
addPipelineHelper(Filter(key), key, 0, (factoryIt)->second(*this, key));
|
||||
|
||||
return pickPipeline(args, key);
|
||||
} else {
|
||||
qCDebug(renderlogging) << "ShapePlumber::Couldn't find a custom pipeline factory for " << key.getCustom() << " key is: " << key;
|
||||
}
|
||||
}
|
||||
|
||||
_missingKeys.insert(key);
|
||||
qCDebug(renderlogging) << "ShapePlumber::Couldn't find a pipeline for" << key;
|
||||
}
|
||||
return PipelinePointer(nullptr);
|
||||
}
|
||||
|
||||
PipelinePointer shapePipeline(pipelineIterator->second);
|
||||
auto& batch = args->_batch;
|
||||
|
||||
// Setup the one pipeline (to rule them all)
|
||||
batch->setPipeline(shapePipeline->pipeline);
|
||||
args->_batch->setPipeline(shapePipeline->pipeline);
|
||||
|
||||
// Run the pipeline's BatchSetter on the passed in batch
|
||||
if (shapePipeline->batchSetter) {
|
||||
shapePipeline->batchSetter(*shapePipeline, *batch, args);
|
||||
if (shapePipeline->_batchSetter) {
|
||||
shapePipeline->_batchSetter(*shapePipeline, *(args->_batch), args);
|
||||
}
|
||||
|
||||
return shapePipeline;
|
||||
|
|
|
@ -19,6 +19,8 @@
|
|||
#include "Args.h"
|
||||
|
||||
namespace render {
|
||||
class Item;
|
||||
class ShapePlumber;
|
||||
|
||||
class ShapeKey {
|
||||
public:
|
||||
|
@ -38,7 +40,19 @@ public:
|
|||
OWN_PIPELINE,
|
||||
INVALID,
|
||||
|
||||
CUSTOM_0,
|
||||
CUSTOM_1,
|
||||
CUSTOM_2,
|
||||
CUSTOM_3,
|
||||
CUSTOM_4,
|
||||
CUSTOM_5,
|
||||
CUSTOM_6,
|
||||
CUSTOM_7,
|
||||
|
||||
NUM_FLAGS, // Not a valid flag
|
||||
|
||||
CUSTOM_MASK = (0xFF << CUSTOM_0),
|
||||
|
||||
};
|
||||
using Flags = std::bitset<NUM_FLAGS>;
|
||||
|
||||
|
@ -73,6 +87,8 @@ public:
|
|||
Builder& withOwnPipeline() { _flags.set(OWN_PIPELINE); return (*this); }
|
||||
Builder& invalidate() { _flags.set(INVALID); return (*this); }
|
||||
|
||||
Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); return (*this); }
|
||||
|
||||
static const ShapeKey ownPipeline() { return Builder().withOwnPipeline(); }
|
||||
static const ShapeKey invalid() { return Builder().invalidate(); }
|
||||
|
||||
|
@ -127,6 +143,9 @@ public:
|
|||
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); }
|
||||
|
||||
Builder& withCustom(uint8_t custom) { _flags &= (~CUSTOM_MASK); _flags |= (custom << CUSTOM_0); _mask |= (CUSTOM_MASK); return (*this); }
|
||||
Builder& withoutCustom() { _flags &= (~CUSTOM_MASK); _mask |= (CUSTOM_MASK); return (*this); }
|
||||
|
||||
protected:
|
||||
friend class Filter;
|
||||
Flags _flags{0};
|
||||
|
@ -155,6 +174,9 @@ public:
|
|||
bool hasOwnPipeline() const { return _flags[OWN_PIPELINE]; }
|
||||
bool isValid() const { return !_flags[INVALID]; }
|
||||
|
||||
uint8_t getCustom() const { return (_flags.to_ulong() & CUSTOM_MASK) >> CUSTOM_0; }
|
||||
bool isCustom() const { return (_flags.to_ulong() & CUSTOM_MASK); }
|
||||
|
||||
// Comparator for use in stl containers
|
||||
class Hash {
|
||||
public:
|
||||
|
@ -240,22 +262,39 @@ public:
|
|||
};
|
||||
using LocationsPointer = std::shared_ptr<Locations>;
|
||||
|
||||
using BatchSetter = std::function<void(const ShapePipeline&, gpu::Batch&, RenderArgs* args)>;
|
||||
using BatchSetter = std::function<void(const ShapePipeline&, gpu::Batch&, render::Args*)>;
|
||||
|
||||
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter) :
|
||||
pipeline(pipeline), locations(locations), batchSetter(batchSetter) {}
|
||||
using ItemSetter = std::function<void(const ShapePipeline&, render::Args*, const render::Item&)>;
|
||||
|
||||
// Normally, a pipeline is accessed thorugh pickPipeline. If it needs to be set manually,
|
||||
ShapePipeline(gpu::PipelinePointer pipeline, LocationsPointer locations, BatchSetter batchSetter, ItemSetter itemSetter) :
|
||||
pipeline(pipeline),
|
||||
locations(locations),
|
||||
_batchSetter(batchSetter),
|
||||
_itemSetter(itemSetter) {}
|
||||
|
||||
// Normally, a pipeline is accessed through 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, RenderArgs* args);
|
||||
void prepare(gpu::Batch& batch, Args* args);
|
||||
|
||||
gpu::PipelinePointer pipeline;
|
||||
std::shared_ptr<Locations> locations;
|
||||
|
||||
void prepareShapeItem(Args* args, const ShapeKey& key, const Item& shape);
|
||||
|
||||
protected:
|
||||
friend class ShapePlumber;
|
||||
|
||||
BatchSetter batchSetter;
|
||||
BatchSetter _batchSetter;
|
||||
ItemSetter _itemSetter;
|
||||
public:
|
||||
using CustomKey = uint8_t;
|
||||
using CustomFactory = std::function<std::shared_ptr<ShapePipeline> (const ShapePlumber& plumber, const ShapeKey& key)>;
|
||||
using CustomFactoryMap = std::map<CustomKey, CustomFactory>;
|
||||
|
||||
static CustomFactoryMap _globalCustomFactoryMap;
|
||||
|
||||
static CustomKey registerCustomShapePipelineFactory(CustomFactory factory);
|
||||
|
||||
};
|
||||
using ShapePipelinePointer = std::shared_ptr<ShapePipeline>;
|
||||
|
||||
|
@ -270,22 +309,24 @@ public:
|
|||
using Locations = Pipeline::Locations;
|
||||
using LocationsPointer = Pipeline::LocationsPointer;
|
||||
using BatchSetter = Pipeline::BatchSetter;
|
||||
using ItemSetter = Pipeline::ItemSetter;
|
||||
|
||||
void addPipeline(const Key& key, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||
BatchSetter batchSetter = nullptr);
|
||||
BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr);
|
||||
void addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
|
||||
BatchSetter batchSetter = nullptr);
|
||||
BatchSetter batchSetter = nullptr, ItemSetter itemSetter = nullptr);
|
||||
|
||||
const PipelinePointer pickPipeline(RenderArgs* args, const Key& key) const;
|
||||
|
||||
protected:
|
||||
void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline);
|
||||
PipelineMap _pipelineMap;
|
||||
void addPipelineHelper(const Filter& filter, Key key, int bit, const PipelinePointer& pipeline) const;
|
||||
mutable PipelineMap _pipelineMap;
|
||||
|
||||
private:
|
||||
mutable std::unordered_set<Key, Key::Hash, Key::KeyEqual> _missingKeys;
|
||||
};
|
||||
|
||||
|
||||
using ShapePlumberPointer = std::shared_ptr<ShapePlumber>;
|
||||
|
||||
}
|
||||
|
|
|
@ -57,8 +57,6 @@
|
|||
#include <render-utils/model_lightmap_specular_map_frag.h>
|
||||
#include <render-utils/model_translucent_frag.h>
|
||||
|
||||
#include <entities-renderer/untextured_particle_frag.h>
|
||||
#include <entities-renderer/untextured_particle_vert.h>
|
||||
#include <entities-renderer/textured_particle_frag.h>
|
||||
#include <entities-renderer/textured_particle_vert.h>
|
||||
|
||||
|
@ -172,7 +170,6 @@ void QTestWindow::draw() {
|
|||
testShaderBuild(skin_model_normal_map_vert, model_translucent_frag);
|
||||
|
||||
testShaderBuild(model_shadow_vert, model_shadow_frag);
|
||||
testShaderBuild(untextured_particle_vert, untextured_particle_frag);
|
||||
testShaderBuild(textured_particle_vert, textured_particle_frag);
|
||||
/* FIXME: Bring back the ssao shader tests
|
||||
testShaderBuild(gaussian_blur_vertical_vert, gaussian_blur_frag);
|
||||
|
|
Loading…
Reference in a new issue