Dispatch classes in their properly named files to appease the coding standard gods

This commit is contained in:
samcake 2015-10-06 09:46:32 -07:00
parent 59afbf1a04
commit c92a6d58ab
6 changed files with 436 additions and 403 deletions

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

View 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

View file

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

View file

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

View file

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

View file

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