mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 17:14:59 +02:00
Dispatch classes in their properly named files to appease the coding standard gods
This commit is contained in:
parent
59afbf1a04
commit
c92a6d58ab
6 changed files with 436 additions and 403 deletions
349
libraries/render-utils/src/MeshPartPayload.cpp
Normal file
349
libraries/render-utils/src/MeshPartPayload.cpp
Normal file
|
@ -0,0 +1,349 @@
|
|||
//
|
||||
// MeshPartPayload.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Sam Gateau on 10/3/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 "MeshPartPayload.h"
|
||||
|
||||
#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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
using namespace render;
|
||||
|
||||
MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) :
|
||||
model(model), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex)
|
||||
{
|
||||
initCache();
|
||||
}
|
||||
|
||||
void MeshPartPayload::initCache() {
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
|
||||
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
|
||||
_drawMesh = networkMesh._mesh;
|
||||
|
||||
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
|
||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||
_hasColorAttrib = !mesh.colors.isEmpty();
|
||||
_isBlendShaped = !mesh.blendshapes.isEmpty();
|
||||
_isSkinned = !mesh.clusterIndices.isEmpty();
|
||||
|
||||
|
||||
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||
|
||||
auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID);
|
||||
if (networkMaterial) {
|
||||
_drawMaterial = networkMaterial->_material;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
render::ItemKey MeshPartPayload::getKey() const {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape();
|
||||
|
||||
if (!model->isVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
if (_isBlendShaped || _isSkinned) {
|
||||
builder.withDeformed();
|
||||
}
|
||||
|
||||
if (_drawMaterial) {
|
||||
auto matKey = _drawMaterial->getKey();
|
||||
if (matKey.isTransparent() || matKey.isTransparentMap()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
render::Item::Bound MeshPartPayload::getBound() const {
|
||||
if (_isBoundInvalid) {
|
||||
model->getPartBounds(meshIndex, partIndex);
|
||||
_isBoundInvalid = false;
|
||||
}
|
||||
return _bound;
|
||||
}
|
||||
|
||||
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||
if (!_isBlendShaped) {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
|
||||
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||
} else {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
|
||||
batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
|
||||
batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
|
||||
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
||||
}
|
||||
|
||||
// TODO: Get rid of that extra call
|
||||
if (!_hasColorAttrib) {
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
||||
if (!_drawMaterial) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer());
|
||||
|
||||
auto materialKey = _drawMaterial->getKey();
|
||||
auto textureMaps = _drawMaterial->getTextureMaps();
|
||||
glm::mat4 texcoordTransform[2];
|
||||
|
||||
// Diffuse
|
||||
if (materialKey.isDiffuseMap()) {
|
||||
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
|
||||
if (diffuseMap && diffuseMap->isDefined()) {
|
||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
|
||||
|
||||
if (!diffuseMap->getTextureTransform().isIdentity()) {
|
||||
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
|
||||
// Normal map
|
||||
if (materialKey.isNormalMap()) {
|
||||
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
|
||||
if (normalMap && normalMap->isDefined()) {
|
||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView());
|
||||
|
||||
// texcoord are assumed to be the same has diffuse
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr);
|
||||
}
|
||||
|
||||
// TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that
|
||||
if (materialKey.isGlossMap()) {
|
||||
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
|
||||
if (specularMap && specularMap->isDefined()) {
|
||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView());
|
||||
|
||||
// texcoord are assumed to be the same has diffuse
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr);
|
||||
}
|
||||
|
||||
// TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too
|
||||
if (materialKey.isLightmapMap()) {
|
||||
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
|
||||
|
||||
if (lightmapMap && lightmapMap->isDefined()) {
|
||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView());
|
||||
|
||||
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
|
||||
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
|
||||
|
||||
if (!lightmapMap->getTextureTransform().isIdentity()) {
|
||||
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr);
|
||||
}
|
||||
|
||||
// Texcoord transforms ?
|
||||
if (locations->texcoordMatrices >= 0) {
|
||||
batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
||||
// Still relying on the raw data from the model
|
||||
const Model::MeshState& state = model->_meshStates.at(meshIndex);
|
||||
|
||||
Transform transform;
|
||||
if (state.clusterBuffer) {
|
||||
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer);
|
||||
} else {
|
||||
if (model->_cauterizeBones) {
|
||||
transform = Transform(state.cauterizedClusterMatrices[0]);
|
||||
} else {
|
||||
transform = Transform(state.clusterMatrices[0]);
|
||||
}
|
||||
}
|
||||
transform.preTranslate(model->_translation);
|
||||
batch.setModelTransform(transform);
|
||||
}
|
||||
|
||||
|
||||
void MeshPartPayload::render(RenderArgs* args) const {
|
||||
PerformanceTimer perfTimer("MeshPartPayload::render");
|
||||
if (!model->_readyWhenAdded) {
|
||||
return; // bail asap
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
auto mode = args->_renderMode;
|
||||
|
||||
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Back to model to update the cluster matrices right now
|
||||
model->updateClusterMatrices();
|
||||
|
||||
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!
|
||||
}
|
||||
|
||||
|
||||
// guard against partially loaded meshes
|
||||
if (partIndex >= mesh.parts.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
AABox partBounds = getPartBounds(meshIndex, partIndex);
|
||||
bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE;
|
||||
|
||||
glm::vec4 cubeColor;
|
||||
if (isSkinned) {
|
||||
cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f);
|
||||
} else if (inView) {
|
||||
cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f);
|
||||
} else {
|
||||
cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(partBounds.calcCenter());
|
||||
transform.setScale(partBounds.getDimensions());
|
||||
batch.setModelTransform(transform);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor);
|
||||
}
|
||||
#endif //def DEBUG_BOUNDING_PARTS
|
||||
|
||||
if (wireframe) {
|
||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||
}
|
||||
|
||||
ModelRender::Locations* locations = nullptr;
|
||||
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||
args, locations);
|
||||
|
||||
|
||||
// Bind the model transform and the skinCLusterMatrices if needed
|
||||
bindTransform(batch, locations);
|
||||
|
||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||
bindMesh(batch);
|
||||
|
||||
// apply material properties
|
||||
bindMaterial(batch, locations);
|
||||
|
||||
|
||||
// TODO: We should be able to do that just in the renderTransparentJob
|
||||
if (translucentMesh && locations->lightBufferUnit >= 0) {
|
||||
PerformanceTimer perfTimer("DLE->setupTransparent()");
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
||||
}
|
||||
if (args) {
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
// Draw!
|
||||
{
|
||||
PerformanceTimer perfTimer("batch.drawIndexed()");
|
||||
drawCall(batch);
|
||||
}
|
||||
|
||||
if (args) {
|
||||
const int INDICES_PER_TRIANGLE = 3;
|
||||
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||
}
|
||||
}
|
||||
|
69
libraries/render-utils/src/MeshPartPayload.h
Normal file
69
libraries/render-utils/src/MeshPartPayload.h
Normal file
|
@ -0,0 +1,69 @@
|
|||
//
|
||||
// MeshPartPayload.h
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Sam Gateau on 10/3/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_MeshPartPayload_h
|
||||
#define hifi_MeshPartPayload_h
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include <model/Geometry.h>
|
||||
|
||||
#include "ModelRender.h"
|
||||
|
||||
class Model;
|
||||
|
||||
class MeshPartPayload {
|
||||
public:
|
||||
MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex);
|
||||
|
||||
typedef render::Payload<MeshPartPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
Model* model;
|
||||
int meshIndex;
|
||||
int partIndex;
|
||||
int _shapeID;
|
||||
|
||||
// Render Item interface
|
||||
render::ItemKey getKey() const;
|
||||
render::Item::Bound getBound() const;
|
||||
void render(RenderArgs* args) const;
|
||||
|
||||
// MeshPartPayload functions to perform render
|
||||
void drawCall(gpu::Batch& batch) const;
|
||||
void bindMesh(gpu::Batch& batch) const;
|
||||
void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
||||
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
||||
|
||||
|
||||
void initCache();
|
||||
|
||||
// Payload resource cached values
|
||||
model::MeshPointer _drawMesh;
|
||||
model::Mesh::Part _drawPart;
|
||||
model::MaterialPointer _drawMaterial;
|
||||
bool _hasColorAttrib = false;
|
||||
bool _isSkinned = false;
|
||||
bool _isBlendShaped = false;
|
||||
|
||||
mutable render::Item::Bound _bound;
|
||||
mutable bool _isBoundInvalid = true;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
|
||||
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
#endif // hifi_MeshPartPayload_h
|
|
@ -23,9 +23,8 @@
|
|||
|
||||
#include "AbstractViewStateInterface.h"
|
||||
#include "AnimationHandle.h"
|
||||
#include "DeferredLightingEffect.h"
|
||||
#include "Model.h"
|
||||
#include "ModelRenderItem.h"
|
||||
#include "MeshPartPayload.h"
|
||||
|
||||
#include "RenderUtilsLogging.h"
|
||||
|
||||
|
|
|
@ -24,9 +24,7 @@
|
|||
#include <AABox.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryUtil.h>
|
||||
#include <gpu/Stream.h>
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Pipeline.h>
|
||||
#include <render/Scene.h>
|
||||
#include <Transform.h>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// ModelRenderItem.cpp
|
||||
// ModelRender.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Sam Gateau on 10/3/15.
|
||||
|
@ -9,14 +9,12 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ModelRenderItem.h"
|
||||
#include "ModelRender.h"
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <model-networking/TextureCache.h>
|
||||
|
||||
#include "DeferredLightingEffect.h"
|
||||
|
||||
#include "Model.h"
|
||||
|
||||
#include "model_vert.h"
|
||||
#include "model_shadow_vert.h"
|
||||
#include "model_normal_map_vert.h"
|
||||
|
@ -172,8 +170,6 @@ void ModelRender::RenderPipelineLib::addRenderPipeline(ModelRender::RenderKey ke
|
|||
gpu::ShaderPointer& pixelShader) {
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), ModelRender::SKINNING_GPU_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), ModelRender::MATERIAL_GPU_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("diffuseMap"), ModelRender::DIFFUSE_MAP_SLOT));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), ModelRender::NORMAL_MAP_SLOT));
|
||||
|
@ -262,7 +258,9 @@ void ModelRender::RenderPipelineLib::initLocations(gpu::ShaderPointer& program,
|
|||
locations.emissiveTextureUnit = program->getTextures().findLocation("emissiveMap");
|
||||
locations.materialBufferUnit = program->getBuffers().findLocation("materialBuffer");
|
||||
locations.lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
|
||||
locations.skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer");
|
||||
locations.clusterMatrices = program->getUniforms().findLocation("clusterMatrices");
|
||||
locations.clusterIndices = program->getInputs().findLocation("inSkinClusterIndex");
|
||||
locations.clusterWeights = program->getInputs().findLocation("inSkinClusterWeight");
|
||||
}
|
||||
|
||||
|
||||
|
@ -270,7 +268,7 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b
|
|||
bool hasLightmap, bool hasTangents, bool hasSpecular, bool isSkinned, bool isWireframe, RenderArgs* args,
|
||||
Locations*& locations) {
|
||||
|
||||
PerformanceTimer perfTimer("ModelRender::pickPrograms");
|
||||
// PerformanceTimer perfTimer("Model::pickPrograms");
|
||||
getRenderPipelineLib();
|
||||
|
||||
RenderKey key(mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, isWireframe);
|
||||
|
@ -305,334 +303,3 @@ void ModelRender::pickPrograms(gpu::Batch& batch, RenderArgs::RenderMode mode, b
|
|||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
using namespace render;
|
||||
|
||||
MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) :
|
||||
model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex)
|
||||
{
|
||||
initCache();
|
||||
}
|
||||
|
||||
void MeshPartPayload::initCache() {
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
|
||||
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
|
||||
_drawMesh = networkMesh._mesh;
|
||||
|
||||
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
|
||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||
_hasColorAttrib = !mesh.colors.isEmpty();
|
||||
_isBlendShaped = !mesh.blendshapes.isEmpty();
|
||||
_isSkinned = !mesh.clusterIndices.isEmpty();
|
||||
|
||||
|
||||
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||
|
||||
auto networkMaterial = model->_geometry->getShapeMaterial(_shapeID);
|
||||
if (networkMaterial) {
|
||||
_drawMaterial = networkMaterial->_material;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
render::ItemKey MeshPartPayload::getKey() const {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape();
|
||||
|
||||
if (!model->isVisible()) {
|
||||
builder.withInvisible();
|
||||
}
|
||||
|
||||
if (_isBlendShaped || _isSkinned) {
|
||||
builder.withDeformed();
|
||||
}
|
||||
|
||||
if (_drawMaterial) {
|
||||
auto matKey = _drawMaterial->getKey();
|
||||
if (matKey.isTransparent() || matKey.isTransparentMap()) {
|
||||
builder.withTransparent();
|
||||
}
|
||||
}
|
||||
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
render::Item::Bound MeshPartPayload::getBound() const {
|
||||
if (_isBoundInvalid) {
|
||||
model->getPartBounds(meshIndex, partIndex);
|
||||
_isBoundInvalid = false;
|
||||
}
|
||||
return _bound;
|
||||
}
|
||||
|
||||
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||
if (!_isBlendShaped) {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
|
||||
batch.setInputStream(0, _drawMesh->getVertexStream());
|
||||
} else {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
|
||||
batch.setInputBuffer(0, model->_blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
|
||||
batch.setInputBuffer(1, model->_blendedVertexBuffers[meshIndex], _drawMesh->getNumVertices() * sizeof(glm::vec3), sizeof(glm::vec3));
|
||||
batch.setInputStream(2, _drawMesh->getVertexStream().makeRangedStream(2));
|
||||
}
|
||||
|
||||
// TODO: Get rid of that extra call
|
||||
if (!_hasColorAttrib) {
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
||||
if (!_drawMaterial) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
batch.setUniformBuffer(ModelRender::MATERIAL_GPU_SLOT, _drawMaterial->getSchemaBuffer());
|
||||
|
||||
auto materialKey = _drawMaterial->getKey();
|
||||
auto textureMaps = _drawMaterial->getTextureMaps();
|
||||
glm::mat4 texcoordTransform[2];
|
||||
|
||||
// Diffuse
|
||||
if (materialKey.isDiffuseMap()) {
|
||||
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
|
||||
if (diffuseMap && diffuseMap->isDefined()) {
|
||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
|
||||
|
||||
if (!diffuseMap->getTextureTransform().isIdentity()) {
|
||||
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
|
||||
// Normal map
|
||||
if (materialKey.isNormalMap()) {
|
||||
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
|
||||
if (normalMap && normalMap->isDefined()) {
|
||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, normalMap->getTextureView());
|
||||
|
||||
// texcoord are assumed to be the same has diffuse
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, textureCache->getBlueTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::NORMAL_MAP_SLOT, nullptr);
|
||||
}
|
||||
|
||||
// TODO: For now gloss map is used as the "specular map in the shading, we ll need to fix that
|
||||
if (materialKey.isGlossMap()) {
|
||||
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
|
||||
if (specularMap && specularMap->isDefined()) {
|
||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, specularMap->getTextureView());
|
||||
|
||||
// texcoord are assumed to be the same has diffuse
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::SPECULAR_MAP_SLOT, nullptr);
|
||||
}
|
||||
|
||||
// TODO: For now lightmaop is piped into the emissive map unit, we need to fix that and support for real emissive too
|
||||
if (materialKey.isLightmapMap()) {
|
||||
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
|
||||
|
||||
if (lightmapMap && lightmapMap->isDefined()) {
|
||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, lightmapMap->getTextureView());
|
||||
|
||||
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
|
||||
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
|
||||
|
||||
if (!lightmapMap->getTextureTransform().isIdentity()) {
|
||||
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(ModelRender::LIGHTMAP_MAP_SLOT, nullptr);
|
||||
}
|
||||
|
||||
// Texcoord transforms ?
|
||||
if (locations->texcoordMatrices >= 0) {
|
||||
batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const {
|
||||
// Still relying on the raw data from the model
|
||||
const Model::MeshState& state = model->_meshStates.at(meshIndex);
|
||||
|
||||
Transform transform;
|
||||
if (state.clusterBuffer) {
|
||||
batch.setUniformBuffer(ModelRender::SKINNING_GPU_SLOT, state.clusterBuffer);
|
||||
} else {
|
||||
if (model->_cauterizeBones) {
|
||||
transform = Transform(state.cauterizedClusterMatrices[0]);
|
||||
} else {
|
||||
transform = Transform(state.clusterMatrices[0]);
|
||||
}
|
||||
}
|
||||
transform.preTranslate(model->_translation);
|
||||
batch.setModelTransform(transform);
|
||||
}
|
||||
|
||||
|
||||
void MeshPartPayload::render(RenderArgs* args) const {
|
||||
PerformanceTimer perfTimer("MeshPartPayload::render");
|
||||
if (!model->_readyWhenAdded) {
|
||||
return; // bail asap
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
auto mode = args->_renderMode;
|
||||
|
||||
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// Back to model to update the cluster matrices right now
|
||||
model->updateClusterMatrices();
|
||||
|
||||
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!
|
||||
}
|
||||
|
||||
|
||||
// guard against partially loaded meshes
|
||||
if (partIndex >= mesh.parts.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
AABox partBounds = getPartBounds(meshIndex, partIndex);
|
||||
bool inView = args->_viewFrustum->boxInFrustum(partBounds) != ViewFrustum::OUTSIDE;
|
||||
|
||||
glm::vec4 cubeColor;
|
||||
if (isSkinned) {
|
||||
cubeColor = glm::vec4(0.0f, 1.0f, 1.0f, 1.0f);
|
||||
} else if (inView) {
|
||||
cubeColor = glm::vec4(1.0f, 0.0f, 1.0f, 1.0f);
|
||||
} else {
|
||||
cubeColor = glm::vec4(1.0f, 1.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(partBounds.calcCenter());
|
||||
transform.setScale(partBounds.getDimensions());
|
||||
batch.setModelTransform(transform);
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor);
|
||||
}
|
||||
#endif //def DEBUG_BOUNDING_PARTS
|
||||
|
||||
if (wireframe) {
|
||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||
}
|
||||
|
||||
ModelRender::Locations* locations = nullptr;
|
||||
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||
args, locations);
|
||||
|
||||
|
||||
// Bind the model transform and the skinCLusterMatrices if needed
|
||||
bindTransform(batch, locations);
|
||||
|
||||
//Bind the index buffer and vertex buffer and Blend shapes if needed
|
||||
bindMesh(batch);
|
||||
|
||||
// apply material properties
|
||||
bindMaterial(batch, locations);
|
||||
|
||||
|
||||
// TODO: We should be able to do that just in the renderTransparentJob
|
||||
if (translucentMesh && locations->lightBufferUnit >= 0) {
|
||||
PerformanceTimer perfTimer("DLE->setupTransparent()");
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->setupTransparent(args, locations->lightBufferUnit);
|
||||
}
|
||||
if (args) {
|
||||
args->_details._materialSwitches++;
|
||||
}
|
||||
|
||||
// Draw!
|
||||
{
|
||||
PerformanceTimer perfTimer("batch.drawIndexed()");
|
||||
drawCall(batch);
|
||||
}
|
||||
|
||||
if (args) {
|
||||
const int INDICES_PER_TRIANGLE = 3;
|
||||
args->_details._trianglesRendered += _drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// ModelRenderItem.h
|
||||
// ModelRender.h
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Sam Gateau on 10/3/15.
|
||||
|
@ -9,22 +9,16 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ModelRenderPayload_h
|
||||
#define hifi_ModelRenderPayload_h
|
||||
|
||||
#include <QUrl>
|
||||
#ifndef hifi_ModelRender_h
|
||||
#define hifi_ModelRender_h
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include <model/Geometry.h>
|
||||
|
||||
class Model;
|
||||
|
||||
class ModelRender {
|
||||
public:
|
||||
|
||||
|
||||
static const int SKINNING_GPU_SLOT = 2;
|
||||
static const int MATERIAL_GPU_SLOT = 3;
|
||||
static const int DIFFUSE_MAP_SLOT = 0;
|
||||
|
@ -35,6 +29,7 @@ public:
|
|||
|
||||
class Locations {
|
||||
public:
|
||||
int tangent;
|
||||
int alphaThreshold;
|
||||
int texcoordMatrices;
|
||||
int diffuseTextureUnit;
|
||||
|
@ -45,7 +40,9 @@ public:
|
|||
int glowIntensity;
|
||||
int normalFittingMapUnit;
|
||||
int materialBufferUnit;
|
||||
int skinClusterBufferUnit;
|
||||
int clusterMatrices;
|
||||
int clusterIndices;
|
||||
int clusterWeights;
|
||||
int lightBufferUnit;
|
||||
};
|
||||
|
||||
|
@ -157,54 +154,8 @@ public:
|
|||
};
|
||||
static RenderPipelineLib _renderPipelineLib;
|
||||
|
||||
static const RenderPipelineLib& getRenderPipelineLib();
|
||||
static const ModelRender::RenderPipelineLib& ModelRender::getRenderPipelineLib();
|
||||
|
||||
};
|
||||
|
||||
|
||||
class MeshPartPayload {
|
||||
public:
|
||||
MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex);
|
||||
|
||||
typedef render::Payload<MeshPartPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
Model* model;
|
||||
QUrl url;
|
||||
int meshIndex;
|
||||
int partIndex;
|
||||
int _shapeID;
|
||||
|
||||
// Render Item interface
|
||||
render::ItemKey getKey() const;
|
||||
render::Item::Bound getBound() const;
|
||||
void render(RenderArgs* args) const;
|
||||
|
||||
// MeshPartPayload functions to perform render
|
||||
void drawCall(gpu::Batch& batch) const;
|
||||
void bindMesh(gpu::Batch& batch) const;
|
||||
void bindMaterial(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
||||
void bindTransform(gpu::Batch& batch, const ModelRender::Locations* locations) const;
|
||||
|
||||
|
||||
void initCache();
|
||||
|
||||
// Payload resource cached values
|
||||
model::MeshPointer _drawMesh;
|
||||
model::Mesh::Part _drawPart;
|
||||
model::MaterialPointer _drawMaterial;
|
||||
bool _hasColorAttrib = false;
|
||||
bool _isSkinned = false;
|
||||
bool _isBlendShaped = false;
|
||||
|
||||
mutable render::Item::Bound _bound;
|
||||
mutable bool _isBoundInvalid = true;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
|
||||
template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
#endif // hifi_ModelRenderPayload_h
|
||||
#endif // hifi_ModelRender_h
|
Loading…
Reference in a new issue