mirror of
https://github.com/overte-org/overte.git
synced 2025-08-17 18:33:22 +02:00
Add render::Shape to abstract ModelRender
This commit is contained in:
parent
722fe46a27
commit
16bb861046
2 changed files with 270 additions and 0 deletions
101
libraries/render/src/render/Shape.cpp
Normal file
101
libraries/render/src/render/Shape.cpp
Normal file
|
@ -0,0 +1,101 @@
|
|||
//
|
||||
// Shape.cpp
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Zach Pomerantz on 12/31/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 "Shape.h"
|
||||
|
||||
#include <PerfStat.h>
|
||||
|
||||
using namespace render;
|
||||
|
||||
Shape::PipelineLib _pipelineLip;
|
||||
|
||||
const Shape::Pipeline& Shape::_pickPipeline(RenderArgs* args, const Key& key) {
|
||||
assert(!_pipelineLib.empty());
|
||||
assert(args);
|
||||
assert(args->_batch);
|
||||
|
||||
PerformanceTimer perfTimer("Shape::getPipeline");
|
||||
|
||||
const auto& pipelineIterator = _pipelineLib.find(key);
|
||||
if (pipelineIterator == _pipelineLib.end()) {
|
||||
qDebug() << "Couldn't find a pipeline from ShapeKey ?" << key;
|
||||
return Shape::Pipeline(); // uninitialized _pipeline == nullptr
|
||||
}
|
||||
|
||||
const auto& shapePipeline = pipelineIterator->second;
|
||||
auto& batch = args->_batch;
|
||||
|
||||
// Setup the one pipeline (to rule them all)
|
||||
batch->setPipeline(shapePipeline.pipeline);
|
||||
|
||||
return shapePipeline;
|
||||
}
|
||||
|
||||
void Shape::PipelineLib::addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) {
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Shape::Slots::SKINNING_GPU));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Shape::Slots::MATERIAL_GPU));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), Shape::Slots::DIFFUSE_MAP));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Shape::Slots::NORMAL_MAP));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), Shape::Slots::SPECULAR_MAP));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("emissiveMap"), Shape::Slots::LIGHTMAP_MAP));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), Shape::Slots::LIGHT_BUFFER));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), Shape::Slots::NORMAL_FITTING_MAP));
|
||||
|
||||
gpu::ShaderPointer program = gpu::Shader::createProgram(vertexShader, pixelShader);
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto locations = std::make_shared<Locations>();
|
||||
locations->texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices");
|
||||
locations->emissiveParams = program->getUniforms().findLocation("emissiveParams");
|
||||
locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
|
||||
locations->diffuseTextureUnit = program->getTextures().findLocation("diffuseMap");
|
||||
locations->normalTextureUnit = program->getTextures().findLocation("normalMap");
|
||||
locations->specularTextureUnit = program->getTextures().findLocation("specularMap");
|
||||
locations->emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
|
||||
locations->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer");
|
||||
locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer");
|
||||
locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
|
||||
// Backface on shadow
|
||||
if (key.isShadow()) {
|
||||
state->setCullMode(gpu::State::CULL_FRONT);
|
||||
state->setDepthBias(1.0f);
|
||||
state->setDepthBiasSlopeScale(4.0f);
|
||||
} else {
|
||||
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(),
|
||||
gpu::State::ONE, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, // For transparent only, this keep the highlight intensity
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
// Add the brand new pipeline and cache its location in the lib
|
||||
auto pipeline = gpu::Pipeline::create(program, state);
|
||||
insert(value_type(key, Shape::Pipeline(pipeline, locations)));
|
||||
|
||||
// Add a wireframe version
|
||||
if (!key.isWireFrame()) {
|
||||
ShapeKey wireframeKey(ShapeKey::Builder(key).withWireframe());
|
||||
|
||||
auto wireframeState = std::make_shared<gpu::State>(state->getValues());
|
||||
wireframeState->setFillMode(gpu::State::FILL_LINE);
|
||||
|
||||
auto wireframePipeline = gpu::Pipeline::create(program, wireframeState);
|
||||
insert(value_type(wireframeKey, Shape::Pipeline(wireframePipeline, locations)));
|
||||
}
|
||||
}
|
169
libraries/render/src/render/Shape.h
Normal file
169
libraries/render/src/render/Shape.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
//
|
||||
// Shape.h
|
||||
// render/src/render
|
||||
//
|
||||
// Created by Zach Pomerantz on 12/31/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
|
||||
//
|
||||
|
||||
#ifndef hifi_render_Shape_h
|
||||
#define hifi_render_Shape_h
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <RenderArgs.h>
|
||||
|
||||
namespace render {
|
||||
|
||||
class ShapeKey {
|
||||
public:
|
||||
enum FlagBit {
|
||||
TRANSLUCENT = 0,
|
||||
LIGHTMAP,
|
||||
TANGENTS,
|
||||
SPECULAR,
|
||||
EMISSIVE,
|
||||
SKINNED,
|
||||
STEREO,
|
||||
DEPTH_ONLY,
|
||||
SHADOW,
|
||||
WIREFRAME,
|
||||
|
||||
NUM_FLAGS, // Not a valid flag
|
||||
};
|
||||
using Flags = std::bitset<NUM_FLAGS>;
|
||||
|
||||
Flags _flags;
|
||||
|
||||
ShapeKey() : _flags{ 0 } {}
|
||||
ShapeKey(const Flags& flags) : _flags(flags) {}
|
||||
|
||||
class Builder {
|
||||
friend class ShapeKey;
|
||||
Flags _flags{ 0 };
|
||||
public:
|
||||
Builder() {}
|
||||
Builder(ShapeKey key) : _flags{ key._flags } {}
|
||||
|
||||
ShapeKey build() const { return ShapeKey(_flags); }
|
||||
|
||||
Builder& withTranslucent() { _flags.set(TRANSLUCENT); return (*this); }
|
||||
Builder& withLightmap() { _flags.set(LIGHTMAP); return (*this); }
|
||||
Builder& withTangents() { _flags.set(TANGENTS); return (*this); }
|
||||
Builder& withSpecular() { _flags.set(SPECULAR); return (*this); }
|
||||
Builder& withEmissive() { _flags.set(EMISSIVE); return (*this); }
|
||||
Builder& withSkinned() { _flags.set(SKINNED); return (*this); }
|
||||
Builder& withStereo() { _flags.set(STEREO); return (*this); }
|
||||
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); }
|
||||
Builder& withShadow() { _flags.set(SHADOW); return (*this); }
|
||||
Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); }
|
||||
};
|
||||
ShapeKey(const Builder& builder) : ShapeKey(builder._flags) {}
|
||||
|
||||
bool hasLightmap() const { return _flags[LIGHTMAP]; }
|
||||
bool hasTangents() const { return _flags[TANGENTS]; }
|
||||
bool hasSpecular() const { return _flags[SPECULAR]; }
|
||||
bool hasEmissive() const { return _flags[EMISSIVE]; }
|
||||
bool isTranslucent() const { return _flags[TRANSLUCENT]; }
|
||||
bool isSkinned() const { return _flags[SKINNED]; }
|
||||
bool isStereo() const { return _flags[STEREO]; }
|
||||
bool isDepthOnly() const { return _flags[DEPTH_ONLY]; }
|
||||
bool isShadow() const { return _flags[SHADOW]; }
|
||||
bool isWireFrame() const { return _flags[WIREFRAME]; }
|
||||
|
||||
// Hasher for use in unordered_maps
|
||||
class Hash {
|
||||
public:
|
||||
size_t operator() (const ShapeKey& key) {
|
||||
return std::hash<ShapeKey::Flags>()(key._flags);
|
||||
}
|
||||
};
|
||||
|
||||
// Comparator for use in unordered_maps
|
||||
class KeyEqual {
|
||||
public:
|
||||
bool operator()(const ShapeKey& lhs, const ShapeKey& rhs) const { return lhs._flags == rhs._flags; }
|
||||
};
|
||||
};
|
||||
|
||||
inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) {
|
||||
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()
|
||||
<< "isShadow:" << renderKey.isShadow()
|
||||
<< "isWireFrame:" << renderKey.isWireFrame()
|
||||
<< "]";
|
||||
return debug;
|
||||
}
|
||||
|
||||
// Meta-information (pipeline and locations) to render a shape
|
||||
class Shape {
|
||||
public:
|
||||
using Key = ShapeKey;
|
||||
|
||||
class Slots {
|
||||
public:
|
||||
static const int SKINNING_GPU = 2;
|
||||
static const int MATERIAL_GPU = 3;
|
||||
static const int DIFFUSE_MAP = 0;
|
||||
static const int NORMAL_MAP = 1;
|
||||
static const int SPECULAR_MAP = 2;
|
||||
static const int LIGHTMAP_MAP = 3;
|
||||
static const int LIGHT_BUFFER = 4;
|
||||
static const int NORMAL_FITTING_MAP = 10;
|
||||
};
|
||||
|
||||
class Locations {
|
||||
public:
|
||||
int texcoordMatrices;
|
||||
int diffuseTextureUnit;
|
||||
int normalTextureUnit;
|
||||
int specularTextureUnit;
|
||||
int emissiveTextureUnit;
|
||||
int emissiveParams;
|
||||
int normalFittingMapUnit;
|
||||
int skinClusterBufferUnit;
|
||||
int materialBufferUnit;
|
||||
int lightBufferUnit;
|
||||
};
|
||||
|
||||
// Rendering abstraction over gpu::Pipeline and map locations
|
||||
class Pipeline {
|
||||
public:
|
||||
gpu::PipelinePointer pipeline;
|
||||
std::shared_ptr<Locations> locations;
|
||||
|
||||
Pipeline() : Pipeline(nullptr, nullptr) {}
|
||||
Pipeline(gpu::PipelinePointer pipeline, std::shared_ptr<Locations> locations) :
|
||||
pipeline(pipeline), locations(locations) {}
|
||||
};
|
||||
|
||||
using PipelineMap = std::unordered_map<ShapeKey, Pipeline, ShapeKey::Hash, ShapeKey::KeyEqual>;
|
||||
class PipelineLib : public PipelineMap {
|
||||
public:
|
||||
void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader);
|
||||
};
|
||||
|
||||
static void addPipeline(Key key, gpu::ShaderPointer& vertexShader, gpu::ShaderPointer& pixelShader) {
|
||||
_pipelineLib.addPipeline(key, vertexShader, pixelShader);
|
||||
}
|
||||
virtual const Pipeline& pickPipeline(RenderArgs* args, const Key& key) {
|
||||
return Shape::_pickPipeline(args, key);
|
||||
}
|
||||
|
||||
protected:
|
||||
static const Pipeline& _pickPipeline(RenderArgs* args, const Key& key);
|
||||
static PipelineLib _pipelineLib;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // hifi_render_Shape_h
|
Loading…
Reference in a new issue