mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 12:04:18 +02:00
MOving rednering code of Model into ModelRenderPayload.h/cpp
This commit is contained in:
parent
fd232b7d32
commit
9e393ced46
4 changed files with 364 additions and 32 deletions
|
@ -1373,7 +1373,7 @@ AABox Model::getPartBounds(int meshIndex, int partIndex) {
|
|||
return AABox();
|
||||
}
|
||||
|
||||
void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID) {
|
||||
void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID, const MeshPartPayload* payload) {
|
||||
// PROFILE_RANGE(__FUNCTION__);
|
||||
PerformanceTimer perfTimer("Model::renderPart");
|
||||
if (!_readyWhenAdded) {
|
||||
|
@ -1505,6 +1505,7 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
|
|||
|
||||
auto drawPart = drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||
|
||||
/*
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
||||
|
@ -1527,7 +1528,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
|
|||
if (mesh.colors.isEmpty()) {
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
*/
|
||||
payload->bindMesh(batch);
|
||||
|
||||
// guard against partially loaded meshes
|
||||
if (partIndex >= mesh.parts.size()) {
|
||||
return;
|
||||
|
@ -1644,9 +1647,9 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shape
|
|||
|
||||
{
|
||||
PerformanceTimer perfTimer("batch.drawIndexed()");
|
||||
batch.drawIndexed(gpu::TRIANGLES, drawPart._numIndices, drawPart._startIndex);
|
||||
payload->drawCall(batch);
|
||||
}
|
||||
|
||||
|
||||
if (args) {
|
||||
const int INDICES_PER_TRIANGLE = 3;
|
||||
args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||
|
|
|
@ -88,7 +88,7 @@ public:
|
|||
bool isVisible() const { return _isVisible; }
|
||||
|
||||
AABox getPartBounds(int meshIndex, int partIndex);
|
||||
void renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID);
|
||||
void renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID, const MeshPartPayload* payload);
|
||||
|
||||
bool maybeStartBlender();
|
||||
|
||||
|
@ -494,6 +494,7 @@ private:
|
|||
bool _needsReload = true;
|
||||
bool _needsUpdateClusterMatrices = true;
|
||||
|
||||
friend class MeshPartPayload;
|
||||
protected:
|
||||
RigPointer _rig;
|
||||
};
|
||||
|
|
|
@ -13,13 +13,44 @@
|
|||
|
||||
#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);
|
||||
}
|
||||
|
||||
/* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) {
|
||||
return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex);
|
||||
}*/
|
||||
}
|
||||
|
||||
using namespace render;
|
||||
|
||||
MeshPartPayload::MeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex) :
|
||||
model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex), _shapeID(shapeIndex)
|
||||
{
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
|
||||
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
|
||||
_drawMesh = networkMesh._mesh;
|
||||
|
||||
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||
|
||||
}
|
||||
|
||||
|
||||
render::ItemKey MeshPartPayload::getKey() const {
|
||||
if (!model->isVisible()) {
|
||||
return ItemKey::Builder().withInvisible().build();
|
||||
|
@ -50,6 +81,316 @@ render::Item::Bound MeshPartPayload::getBound() const {
|
|||
}
|
||||
|
||||
void MeshPartPayload::render(RenderArgs* args) const {
|
||||
return model->renderPart(args, meshIndex, partIndex, _shapeID);
|
||||
return model->renderPart(args, meshIndex, partIndex, _shapeID, this);
|
||||
}
|
||||
|
||||
void MeshPartPayload::bindMesh(gpu::Batch& batch) const {
|
||||
const FBXGeometry& geometry = model->_geometry->getFBXGeometry();
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = model->_geometry->getMeshes();
|
||||
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
|
||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||
// auto drawMesh = networkMesh._mesh;
|
||||
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
batch.setIndexBuffer(gpu::UINT32, (_drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
||||
batch.setInputFormat((_drawMesh->getVertexFormat()));
|
||||
auto inputStream = _drawMesh->makeBufferStream();
|
||||
|
||||
batch.setInputStream(0, inputStream);
|
||||
} 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));
|
||||
|
||||
auto inputStream = _drawMesh->makeBufferStream().makeRangedStream(2);
|
||||
|
||||
batch.setInputStream(2, inputStream);
|
||||
}
|
||||
|
||||
if (mesh.colors.isEmpty()) {
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::drawCall(gpu::Batch& batch) const {
|
||||
batch.drawIndexed(gpu::TRIANGLES, _drawPart._numIndices, _drawPart._startIndex);
|
||||
}
|
||||
/*
|
||||
void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, int shapeID) {
|
||||
// PROFILE_RANGE(__FUNCTION__);
|
||||
PerformanceTimer perfTimer("Model::renderPart");
|
||||
if (!_readyWhenAdded) {
|
||||
return; // bail asap
|
||||
}
|
||||
|
||||
auto textureCache = DependencyManager::get<TextureCache>();
|
||||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
auto mode = args->_renderMode;
|
||||
|
||||
|
||||
// Capture the view matrix once for the rendering of this model
|
||||
if (_transforms.empty()) {
|
||||
_transforms.push_back(Transform());
|
||||
}
|
||||
|
||||
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||
|
||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _geometry->getMeshes();
|
||||
|
||||
auto networkMaterial = _geometry->getShapeMaterial(shapeID);
|
||||
if (!networkMaterial) {
|
||||
return;
|
||||
};
|
||||
auto material = networkMaterial->_material;
|
||||
if (!material) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: Not yet
|
||||
// auto drawMesh = _geometry->getShapeMesh(shapeID);
|
||||
// auto drawPart = _geometry->getShapePart(shapeID);
|
||||
|
||||
// guard against partially loaded meshes
|
||||
if (meshIndex >= (int)networkMeshes.size() || meshIndex >= (int)geometry.meshes.size() || meshIndex >= (int)_meshStates.size() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
updateClusterMatrices();
|
||||
|
||||
const NetworkMesh& networkMesh = *(networkMeshes.at(meshIndex).get());
|
||||
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||
const MeshState& state = _meshStates.at(meshIndex);
|
||||
|
||||
auto drawMesh = networkMesh._mesh;
|
||||
|
||||
|
||||
auto drawMaterialKey = material->getKey();
|
||||
bool translucentMesh = drawMaterialKey.isTransparent() || drawMaterialKey.isTransparentMap();
|
||||
|
||||
bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
|
||||
bool hasSpecular = drawMaterialKey.isGlossMap(); // !drawMaterial->specularTextureName.isEmpty(); //mesh.hasSpecularTexture();
|
||||
bool hasLightmap = drawMaterialKey.isLightmapMap(); // !drawMaterial->emissiveTextureName.isEmpty(); //mesh.hasEmissiveTexture();
|
||||
bool isSkinned = state.clusterMatrices.size() > 1;
|
||||
bool wireframe = 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;
|
||||
}
|
||||
|
||||
Locations* locations = nullptr;
|
||||
pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||
args, locations);
|
||||
|
||||
// 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()) {
|
||||
_meshGroupsKnown = false; // regenerate these lists next time around.
|
||||
_readyWhenAdded = false; // in case any of our users are using scenes
|
||||
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!
|
||||
}
|
||||
|
||||
// Transform stage
|
||||
if (_transforms.empty()) {
|
||||
_transforms.push_back(Transform());
|
||||
}
|
||||
|
||||
if (isSkinned) {
|
||||
const float* bones;
|
||||
if (_cauterizeBones) {
|
||||
bones = (const float*)state.cauterizedClusterMatrices.constData();
|
||||
} else {
|
||||
bones = (const float*)state.clusterMatrices.constData();
|
||||
}
|
||||
batch._glUniformMatrix4fv(locations->clusterMatrices, state.clusterMatrices.size(), false, bones);
|
||||
_transforms[0] = Transform();
|
||||
_transforms[0].preTranslate(_translation);
|
||||
} else {
|
||||
if (_cauterizeBones) {
|
||||
_transforms[0] = Transform(state.cauterizedClusterMatrices[0]);
|
||||
} else {
|
||||
_transforms[0] = Transform(state.clusterMatrices[0]);
|
||||
}
|
||||
_transforms[0].preTranslate(_translation);
|
||||
}
|
||||
batch.setModelTransform(_transforms[0]);
|
||||
|
||||
auto drawPart = drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||
|
||||
if (mesh.blendshapes.isEmpty()) {
|
||||
batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0);
|
||||
|
||||
batch.setInputFormat((drawMesh->getVertexFormat()));
|
||||
auto inputStream = drawMesh->makeBufferStream();
|
||||
|
||||
batch.setInputStream(0, inputStream);
|
||||
} else {
|
||||
batch.setIndexBuffer(gpu::UINT32, (drawMesh->getIndexBuffer()._buffer), 0);
|
||||
batch.setInputFormat((drawMesh->getVertexFormat()));
|
||||
|
||||
batch.setInputBuffer(0, _blendedVertexBuffers[meshIndex], 0, sizeof(glm::vec3));
|
||||
batch.setInputBuffer(1, _blendedVertexBuffers[meshIndex], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3));
|
||||
|
||||
auto inputStream = drawMesh->makeBufferStream().makeRangedStream(2);
|
||||
|
||||
batch.setInputStream(2, inputStream);
|
||||
}
|
||||
|
||||
if (mesh.colors.isEmpty()) {
|
||||
batch._glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
// guard against partially loaded meshes
|
||||
if (partIndex >= mesh.parts.size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
#ifdef WANT_DEBUG
|
||||
if (material == nullptr) {
|
||||
qCDebug(renderutils) << "WARNING: material == nullptr!!!";
|
||||
}
|
||||
#endif
|
||||
|
||||
{
|
||||
|
||||
// apply material properties
|
||||
if (mode != RenderArgs::SHADOW_RENDER_MODE) {
|
||||
#ifdef WANT_DEBUG
|
||||
qCDebug(renderutils) << "Material Changed ---------------------------------------------";
|
||||
qCDebug(renderutils) << "part INDEX:" << partIndex;
|
||||
qCDebug(renderutils) << "NEW part.materialID:" << part.materialID;
|
||||
#endif //def WANT_DEBUG
|
||||
|
||||
if (locations->materialBufferUnit >= 0) {
|
||||
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
|
||||
}
|
||||
|
||||
auto materialKey = material->getKey();
|
||||
auto textureMaps = material->getTextureMaps();
|
||||
glm::mat4 texcoordTransform[2];
|
||||
|
||||
// Diffuse
|
||||
if (materialKey.isDiffuseMap()) {
|
||||
auto diffuseMap = textureMaps[model::MaterialKey::DIFFUSE_MAP];
|
||||
if (diffuseMap && diffuseMap->isDefined()) {
|
||||
batch.setResourceTexture(DIFFUSE_MAP_SLOT, diffuseMap->getTextureView());
|
||||
|
||||
if (!diffuseMap->getTextureTransform().isIdentity()) {
|
||||
diffuseMap->getTextureTransform().getMatrix(texcoordTransform[0]);
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(DIFFUSE_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
|
||||
// Normal map
|
||||
if ((locations->normalTextureUnit >= 0) && hasTangents) {
|
||||
auto normalMap = textureMaps[model::MaterialKey::NORMAL_MAP];
|
||||
if (normalMap && normalMap->isDefined()) {
|
||||
batch.setResourceTexture(NORMAL_MAP_SLOT, normalMap->getTextureView());
|
||||
|
||||
// texcoord are assumed to be the same has diffuse
|
||||
} else {
|
||||
batch.setResourceTexture(NORMAL_MAP_SLOT, textureCache->getBlueTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(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 ((locations->specularTextureUnit >= 0) && materialKey.isGlossMap()) {
|
||||
auto specularMap = textureMaps[model::MaterialKey::GLOSS_MAP];
|
||||
if (specularMap && specularMap->isDefined()) {
|
||||
batch.setResourceTexture(SPECULAR_MAP_SLOT, specularMap->getTextureView());
|
||||
|
||||
// texcoord are assumed to be the same has diffuse
|
||||
} else {
|
||||
batch.setResourceTexture(SPECULAR_MAP_SLOT, textureCache->getBlackTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(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 ((locations->emissiveTextureUnit >= 0) && materialKey.isLightmapMap()) {
|
||||
auto lightmapMap = textureMaps[model::MaterialKey::LIGHTMAP_MAP];
|
||||
|
||||
if (lightmapMap && lightmapMap->isDefined()) {
|
||||
batch.setResourceTexture(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(LIGHTMAP_MAP_SLOT, textureCache->getGrayTexture());
|
||||
}
|
||||
} else {
|
||||
batch.setResourceTexture(LIGHTMAP_MAP_SLOT, nullptr);
|
||||
}
|
||||
|
||||
// Texcoord transforms ?
|
||||
if (locations->texcoordMatrices >= 0) {
|
||||
batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform);
|
||||
}
|
||||
|
||||
// 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++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (args) {
|
||||
const int INDICES_PER_TRIANGLE = 3;
|
||||
args->_details._trianglesRendered += drawPart._numIndices / INDICES_PER_TRIANGLE;
|
||||
}
|
||||
}
|
||||
*/
|
|
@ -12,9 +12,14 @@
|
|||
#ifndef hifi_ModelRenderPayload_h
|
||||
#define hifi_ModelRenderPayload_h
|
||||
|
||||
#include <render/Scene.h>
|
||||
#include <QUrl>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
|
||||
#include <render/Scene.h>
|
||||
|
||||
#include <model/Geometry.h>
|
||||
|
||||
class Model;
|
||||
|
||||
class MeshPartPayload {
|
||||
|
@ -35,34 +40,16 @@ public:
|
|||
render::Item::Bound getBound() const;
|
||||
void render(RenderArgs* args) const;
|
||||
|
||||
// MeshPartPayload functions to perform render
|
||||
void bindMesh(gpu::Batch& batch) const;
|
||||
void drawCall(gpu::Batch& batch) const;
|
||||
|
||||
model::MeshPointer _drawMesh;
|
||||
model::Mesh::Part _drawPart;
|
||||
model::MaterialPointer _drawMaterial;
|
||||
|
||||
mutable render::Item::Bound _bound;
|
||||
mutable bool _isBoundInvalid = true;
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) {
|
||||
return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
#endif // hifi_ModelRenderPayload_h
|
Loading…
Reference in a new issue