Change payload interface to return ShapeKey, not MaterialKey

This commit is contained in:
Zach Pomerantz 2016-01-01 17:05:38 -08:00
parent 16bb861046
commit 59a354ea8c
5 changed files with 173 additions and 122 deletions

View file

@ -14,30 +14,36 @@
#include <PerfStat.h>
#include "DeferredLightingEffect.h"
#include "Model.h"
namespace render {
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getKey();
}
// Return opaque for lack of a better idea
return ItemKey::Builder::opaqueShape();
}
using namespace render;
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
}
return render::Item::Bound();
}
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
namespace render {
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getKey();
}
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
}
using namespace render;
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
}
return Item::Bound();
}
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getShapeKey();
}
return ShapeKey::Builder::invalid();
}
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
}
MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::MaterialPointer material, const Transform& transform, const Transform& offsetTransform) {
@ -69,7 +75,7 @@ void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) {
_drawMaterial = drawMaterial;
}
render::ItemKey MeshPartPayload::getKey() const {
ItemKey MeshPartPayload::getKey() const {
ItemKey::Builder builder;
builder.withTypeShape();
@ -83,10 +89,29 @@ render::ItemKey MeshPartPayload::getKey() const {
return builder.build();
}
render::Item::Bound MeshPartPayload::getBound() const {
Item::Bound MeshPartPayload::getBound() const {
return _worldBound;
}
ShapeKey MeshPartPayload::getShapeKey() const {
model::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
}
bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
bool hasTangents = drawMaterialKey.isNormalMap();
bool hasSpecular = drawMaterialKey.isGlossMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
ShapeKey::Builder builder;
if (isTranslucent) { builder.withTranslucent(); }
if (hasTangents) { builder.withTangents(); }
if (hasSpecular) { builder.withSpecular(); }
if (hasLightmap) { builder.withLightmap(); }
return builder.build();
}
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
}
@ -195,27 +220,13 @@ void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locati
void MeshPartPayload::render(RenderArgs* args) const {
PerformanceTimer perfTimer("MeshPartPayload::render");
gpu::Batch& batch = *(args->_batch);
auto mode = args->_renderMode;
model::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
}
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
bool hasTangents = drawMaterialKey.isNormalMap();
bool hasSpecular = drawMaterialKey.isGlossMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isSkinned = false;
bool wireframe = false;
if (wireframe) {
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
}
ShapeKey key = getShapeKey();
ModelRender::Locations* locations = nullptr;
ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
ModelRender::pickPrograms(batch, mode, key.isTranslucent(), key.hasLightmap(), key.hasTangents(), key.hasSpecular(), key.isSkinned(), key.isWireFrame(),
args, locations);
@ -230,7 +241,7 @@ void MeshPartPayload::render(RenderArgs* args) const {
// TODO: We should be able to do that just in the renderTransparentJob
if (translucentMesh && locations->lightBufferUnit >= 0) {
if (key.isTranslucent() && locations->lightBufferUnit >= 0) {
PerformanceTimer perfTimer("DLE->setupTransparent()");
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
@ -251,29 +262,32 @@ void MeshPartPayload::render(RenderArgs* args) const {
}
}
namespace render {
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getKey();
}
// Return opaque for lack of a better idea
return ItemKey::Builder::opaqueShape();
}
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
}
return render::Item::Bound();
}
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getKey();
}
return ItemKey::Builder::opaqueShape(); // for lack of a better idea
}
using namespace render;
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getBound();
}
return Item::Bound();
}
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload) {
if (payload) {
return payload->getShapeKey();
}
return ShapeKey::Builder::invalid();
}
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args) {
return payload->render(args);
}
}
ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
_model(model),
@ -310,7 +324,7 @@ void ModelMeshPartPayload::notifyLocationChanged() {
_model->_needsUpdateClusterMatrices = true;
}
render::ItemKey ModelMeshPartPayload::getKey() const {
ItemKey ModelMeshPartPayload::getKey() const {
ItemKey::Builder builder;
builder.withTypeShape();
@ -332,12 +346,70 @@ render::ItemKey ModelMeshPartPayload::getKey() const {
return builder.build();
}
render::Item::Bound ModelMeshPartPayload::getBound() const {
Item::Bound ModelMeshPartPayload::getBound() const {
// NOTE: we can't cache this bounds because we need to handle the case of a moving
// entity or mesh part.
return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation());
}
ShapeKey ModelMeshPartPayload::getShapeKey() const {
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
// guard against partially loaded meshes
if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size()) {
return ShapeKey::Builder::invalid();
}
// Back to model to update the cluster matrices right now
_model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation());
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
// to false to rebuild out mesh groups.
if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) {
_model->_meshGroupsKnown = false; // regenerate these lists next time around.
_model->_readyWhenAdded = false; // in case any of our users are using scenes
_model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
return ShapeKey::Builder::invalid();
}
int vertexCount = mesh.vertices.size();
if (vertexCount == 0) {
// sanity check
return ShapeKey::Builder::invalid();
}
model::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
}
bool isTranslucent = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
bool hasSpecular = drawMaterialKey.isGlossMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isSkinned = _isSkinned;
bool wireframe = _model->isWireframe();
if (wireframe) {
isTranslucent = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
}
ShapeKey::Builder builder;
if (isTranslucent) { builder.withTranslucent(); }
if (hasTangents) { builder.withTangents(); }
if (hasSpecular) { builder.withSpecular(); }
if (hasLightmap) { builder.withLightmap(); }
if (isSkinned) { builder.withSkinned(); }
if (wireframe) { builder.withWireframe(); }
return builder.build();
}
void ModelMeshPartPayload::bindMesh(gpu::Batch& batch) const {
if (!_isBlendShaped) {
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
@ -387,6 +459,7 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::L
void ModelMeshPartPayload::render(RenderArgs* args) const {
PerformanceTimer perfTimer("ModelMeshPartPayload::render");
if (!_model->_readyWhenAdded || !_model->_isVisible) {
return; // bail asap
}
@ -394,47 +467,11 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
gpu::Batch& batch = *(args->_batch);
auto mode = args->_renderMode;
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
// guard against partially loaded meshes
if (_meshIndex >= (int)networkMeshes.size() || _meshIndex >= (int)geometry.meshes.size() || _meshIndex >= (int)_model->_meshStates.size() ) {
ShapeKey key = getShapeKey();
if (!key.isValid()) {
return;
}
// Back to model to update the cluster matrices right now
_model->updateClusterMatrices(_transform.getTranslation(), _transform.getRotation());
const FBXMesh& mesh = geometry.meshes.at(_meshIndex);
// if our index is ever out of range for either meshes or networkMeshes, then skip it, and set our _meshGroupsKnown
// to false to rebuild out mesh groups.
if (_meshIndex < 0 || _meshIndex >= (int)networkMeshes.size() || _meshIndex > geometry.meshes.size()) {
_model->_meshGroupsKnown = false; // regenerate these lists next time around.
_model->_readyWhenAdded = false; // in case any of our users are using scenes
_model->invalidCalculatedMeshBoxes(); // if we have to reload, we need to assume our mesh boxes are all invalid
return; // FIXME!
}
int vertexCount = mesh.vertices.size();
if (vertexCount == 0) {
// sanity check
return; // FIXME!
}
model::MaterialKey drawMaterialKey;
if (_drawMaterial) {
drawMaterialKey = _drawMaterial->getKey();
}
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
bool hasSpecular = drawMaterialKey.isGlossMap();
bool hasLightmap = drawMaterialKey.isLightmapMap();
bool isSkinned = _isSkinned;
bool wireframe = _model->isWireframe();
// render the part bounding box
#ifdef DEBUG_BOUNDING_PARTS
{
@ -458,12 +495,8 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
}
#endif //def DEBUG_BOUNDING_PARTS
if (wireframe) {
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
}
ModelRender::Locations* locations = nullptr;
ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
ModelRender::pickPrograms(batch, mode, key.isTranslucent(), key.hasLightmap(), key.hasTangents(), key.hasSpecular(), key.isSkinned(), key.isWireFrame(),
args, locations);
if (!locations) { // the pipeline could not be found
@ -481,7 +514,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
// TODO: We should be able to do that just in the renderTransparentJob
if (translucentMesh && locations->lightBufferUnit >= 0) {
if (key.isTranslucent() && locations->lightBufferUnit >= 0) {
PerformanceTimer perfTimer("DLE->setupTransparent()");
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);

View file

@ -40,6 +40,7 @@ public:
// Render Item interface
virtual render::ItemKey getKey() const;
virtual render::Item::Bound getBound() const;
virtual render::ShapeKey getShapeKey() const; // shape interface
virtual void render(RenderArgs* args) const;
// ModelMeshPartPayload functions to perform render
@ -67,10 +68,10 @@ public:
namespace render {
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
template <> const ShapeKey shapeGetShapeKey(const MeshPartPayload::Pointer& payload);
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
}
class ModelMeshPartPayload : public MeshPartPayload {
public:
ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
@ -83,8 +84,9 @@ public:
// Render Item interface
render::ItemKey getKey() const override;
render::Item::Bound getBound() const override;
render::ShapeKey getShapeKey() const override; // shape interface
void render(RenderArgs* args) const override;
// ModelMeshPartPayload functions to perform render
void bindMesh(gpu::Batch& batch) const override;
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const override;

View file

@ -25,6 +25,7 @@
#include <RenderArgs.h>
#include "model/Material.h"
#include "Shape.h"
namespace render {
@ -264,7 +265,7 @@ public:
virtual void render(RenderArgs* args) = 0;
virtual const model::MaterialKey getMaterialKey() const = 0;
virtual const ShapeKey getShapeKey() const = 0;
~PayloadInterface() {}
@ -304,7 +305,7 @@ public:
void render(RenderArgs* args) { _payload->render(args); }
// Shape Type Interface
const model::MaterialKey getMaterialKey() const { return _payload->getMaterialKey(); }
const ShapeKey getShapeKey() const { return _payload->getShapeKey(); }
// Access the status
const StatusPointer& getStatus() const { return _payload->getStatus(); }
@ -346,7 +347,7 @@ template <class T> int payloadGetLayer(const std::shared_ptr<T>& payloadData) {
template <class T> void payloadRender(const std::shared_ptr<T>& payloadData, RenderArgs* args) { }
// Shape type interface
template <class T> const model::MaterialKey shapeGetMaterialKey(const std::shared_ptr<T>& payloadData) { return model::MaterialKey(); }
template <class T> const ShapeKey shapeGetShapeKey(const std::shared_ptr<T>& payloadData) { return ShapeKey::Builder::invalid(); }
template <class T> class Payload : public Item::PayloadInterface {
public:
@ -364,7 +365,7 @@ public:
virtual void render(RenderArgs* args) { payloadRender<T>(_data, args); }
// Shape Type interface
virtual const model::MaterialKey getMaterialKey() const { return shapeGetMaterialKey<T>(_data); }
virtual const ShapeKey getShapeKey() const { return shapeGetShapeKey<T>(_data); }
protected:
DataPointer _data;

View file

@ -31,6 +31,8 @@ public:
SHADOW,
WIREFRAME,
INVALID,
NUM_FLAGS, // Not a valid flag
};
using Flags = std::bitset<NUM_FLAGS>;
@ -59,6 +61,9 @@ public:
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); }
Builder& withShadow() { _flags.set(SHADOW); return (*this); }
Builder& withWireframe() { _flags.set(WIREFRAME); return (*this); }
Builder& invalidate() { _flags.set(INVALID); return (*this); }
static const ShapeKey& invalid() { return Builder().invalidate(); }
};
ShapeKey(const Builder& builder) : ShapeKey(builder._flags) {}
@ -72,6 +77,7 @@ public:
bool isDepthOnly() const { return _flags[DEPTH_ONLY]; }
bool isShadow() const { return _flags[SHADOW]; }
bool isWireFrame() const { return _flags[WIREFRAME]; }
bool isValid() const { return !_flags[INVALID]; }
// Hasher for use in unordered_maps
class Hash {
@ -104,11 +110,9 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& renderKey) {
return debug;
}
// Meta-information (pipeline and locations) to render a shape
class Shape {
// Rendering abstraction over gpu::Pipeline and map locations
class ShapePipeline {
public:
using Key = ShapeKey;
class Slots {
public:
static const int SKINNING_GPU = 2;
@ -135,16 +139,21 @@ public:
int lightBufferUnit;
};
// Rendering abstraction over gpu::Pipeline and map locations
class Pipeline {
public:
gpu::PipelinePointer pipeline;
std::shared_ptr<Locations> locations;
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) {}
};
ShapePipeline() : ShapePipeline(nullptr, nullptr) {}
ShapePipeline(gpu::PipelinePointer pipeline, std::shared_ptr<Locations> locations) :
pipeline(pipeline), locations(locations) {}
};
// Meta-information (pipeline and locations) to render a shape
class Shape {
public:
using Key = ShapeKey;
using Pipeline = ShapePipeline;
using Slots = ShapePipeline::Slots;
using Locations = ShapePipeline::Locations;
using PipelineMap = std::unordered_map<ShapeKey, Pipeline, ShapeKey::Hash, ShapeKey::KeyEqual>;
class PipelineLib : public PipelineMap {
@ -166,4 +175,4 @@ protected:
}
#endif // hifi_render_Shape_h
#endif // hifi_render_Shape_h

View file

@ -20,6 +20,7 @@
class AABox;
class OctreeRenderer;
class ViewFrustum;
namespace gpu {
class Batch;
class Context;
@ -27,6 +28,10 @@ class Texture;
class Framebuffer;
}
namespace render {
class ShapePipeline;
}
class RenderDetails {
public:
enum Type {
@ -103,6 +108,7 @@ public:
std::shared_ptr<gpu::Context> _context = nullptr;
std::shared_ptr<gpu::Framebuffer> _blitFramebuffer = nullptr;
std::shared_ptr<render::ShapePipeline> _pipeline = nullptr;
OctreeRenderer* _renderer = nullptr;
ViewFrustum* _viewFrustum = nullptr;
glm::ivec4 _viewport{ 0, 0, 1, 1 };