mirror of
https://github.com/overte-org/overte.git
synced 2025-08-04 04:03:35 +02:00
render models in scene checkpoint
This commit is contained in:
parent
1c3398f27e
commit
eb19b93433
8 changed files with 373 additions and 11 deletions
|
@ -489,6 +489,10 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
||||||
void EntityTreeRenderer::render(RenderArgs* renderArgs) {
|
void EntityTreeRenderer::render(RenderArgs* renderArgs) {
|
||||||
|
|
||||||
if (_tree && !_shuttingDown) {
|
if (_tree && !_shuttingDown) {
|
||||||
|
renderArgs->_renderer = this;
|
||||||
|
|
||||||
|
checkPendingAddToScene(renderArgs);
|
||||||
|
|
||||||
Model::startScene(renderArgs->_renderSide);
|
Model::startScene(renderArgs->_renderSide);
|
||||||
|
|
||||||
ViewFrustum* frustum = (renderArgs->_renderMode == RenderArgs::SHADOW_RENDER_MODE) ?
|
ViewFrustum* frustum = (renderArgs->_renderMode == RenderArgs::SHADOW_RENDER_MODE) ?
|
||||||
|
@ -503,7 +507,6 @@ void EntityTreeRenderer::render(RenderArgs* renderArgs) {
|
||||||
batch.setProjectionTransform(projMat);
|
batch.setProjectionTransform(projMat);
|
||||||
batch.setViewTransform(viewMat);
|
batch.setViewTransform(viewMat);
|
||||||
|
|
||||||
renderArgs->_renderer = this;
|
|
||||||
renderArgs->_batch = &batch;
|
renderArgs->_batch = &batch;
|
||||||
|
|
||||||
_tree->lockForRead();
|
_tree->lockForRead();
|
||||||
|
@ -1081,16 +1084,38 @@ void EntityTreeRenderer::deletingEntity(const EntityItemID& entityID) {
|
||||||
|
|
||||||
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
void EntityTreeRenderer::addingEntity(const EntityItemID& entityID) {
|
||||||
checkAndCallPreload(entityID);
|
checkAndCallPreload(entityID);
|
||||||
|
|
||||||
// here's where we add the entity payload to the scene
|
|
||||||
auto entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
|
auto entity = static_cast<EntityTree*>(_tree)->findEntityByID(entityID);
|
||||||
|
addEntityToScene(entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityTreeRenderer::addEntityToScene(EntityItemPointer entity) {
|
||||||
|
// here's where we add the entity payload to the scene
|
||||||
if (entity && entity->canRenderInScene()) {
|
if (entity && entity->canRenderInScene()) {
|
||||||
render::PendingChanges pendingChanges;
|
if (entity->readyToAddToScene()) {
|
||||||
auto scene = _viewState->getMain3DScene();
|
render::PendingChanges pendingChanges;
|
||||||
if (entity->addToScene(entity, scene, pendingChanges)) {
|
auto scene = _viewState->getMain3DScene();
|
||||||
_entitiesInScene.insert(entity);
|
if (entity->addToScene(entity, scene, pendingChanges)) {
|
||||||
|
_entitiesInScene.insert(entity);
|
||||||
|
}
|
||||||
|
scene->enqueuePendingChanges(pendingChanges);
|
||||||
|
} else {
|
||||||
|
if (!_pendingAddToScene.contains(entity)) {
|
||||||
|
_pendingAddToScene << entity;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
scene->enqueuePendingChanges(pendingChanges);
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void EntityTreeRenderer::checkPendingAddToScene(RenderArgs* renderArgs) {
|
||||||
|
QSet<EntityItemPointer> addedToScene;
|
||||||
|
foreach (auto entity, _pendingAddToScene) {
|
||||||
|
if (entity->readyToAddToScene(renderArgs)) {
|
||||||
|
addEntityToScene(entity);
|
||||||
|
addedToScene << entity;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (auto addedEntity, addedToScene) {
|
||||||
|
_pendingAddToScene.remove(addedEntity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,6 +124,10 @@ protected:
|
||||||
virtual Octree* createTree() { return new EntityTree(true); }
|
virtual Octree* createTree() { return new EntityTree(true); }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void checkPendingAddToScene(RenderArgs* renderArgs);
|
||||||
|
void addEntityToScene(EntityItemPointer entity);
|
||||||
|
QSet<EntityItemPointer> _pendingAddToScene;
|
||||||
|
|
||||||
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
void applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone);
|
||||||
void renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args);
|
void renderElementProxy(EntityTreeElement* entityTreeElement, RenderArgs* args);
|
||||||
void checkAndCallPreload(const EntityItemID& entityID);
|
void checkAndCallPreload(const EntityItemID& entityID);
|
||||||
|
|
|
@ -108,7 +108,35 @@ void RenderableModelEntityItem::remapTextures() {
|
||||||
_currentTextures = _textures;
|
_currentTextures = _textures;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool RenderableModelEntityItem::readyToAddToScene(RenderArgs* renderArgs) {
|
||||||
|
if (!_model && renderArgs) {
|
||||||
|
// TODO: this getModel() appears to be about 3% of model render time. We should optimize
|
||||||
|
PerformanceTimer perfTimer("getModel");
|
||||||
|
EntityTreeRenderer* renderer = static_cast<EntityTreeRenderer*>(renderArgs->_renderer);
|
||||||
|
qDebug() << "RenderableModelEntityItem::readyToAddToScene().... renderer:" << renderer;
|
||||||
|
getModel(renderer);
|
||||||
|
}
|
||||||
|
bool ready = (bool)_model;
|
||||||
|
qDebug() << "RenderableModelEntityItem::readyToAddToScene().... id:" << getEntityItemID()
|
||||||
|
<< "ready:" << ready << "renderArgs:" << renderArgs;
|
||||||
|
return ready;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RenderableModelEntityItem::addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||||
|
render::PendingChanges& pendingChanges) {
|
||||||
|
qDebug() << "RenderableModelEntityItem::addToScene().... id:" << getEntityItemID();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RenderableModelEntityItem::removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||||
|
render::PendingChanges& pendingChanges) {
|
||||||
|
qDebug() << "RenderableModelEntityItem::removeFromScene().... id:" << getEntityItemID();
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void RenderableModelEntityItem::render(RenderArgs* args) {
|
void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
|
qDebug() << "RenderableModelEntityItem::render().... id:" << getEntityItemID();
|
||||||
PerformanceTimer perfTimer("RMEIrender");
|
PerformanceTimer perfTimer("RMEIrender");
|
||||||
assert(getType() == EntityTypes::Model);
|
assert(getType() == EntityTypes::Model);
|
||||||
|
|
||||||
|
@ -199,6 +227,10 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
|
||||||
|
|
||||||
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
||||||
Model* result = NULL;
|
Model* result = NULL;
|
||||||
|
|
||||||
|
if (!renderer) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// make sure our renderer is setup
|
// make sure our renderer is setup
|
||||||
if (!_myRenderer) {
|
if (!_myRenderer) {
|
||||||
|
@ -206,7 +238,7 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
||||||
}
|
}
|
||||||
assert(_myRenderer == renderer); // you should only ever render on one renderer
|
assert(_myRenderer == renderer); // you should only ever render on one renderer
|
||||||
|
|
||||||
if (QThread::currentThread() != _myRenderer->thread()) {
|
if (!_myRenderer || QThread::currentThread() != _myRenderer->thread()) {
|
||||||
return _model;
|
return _model;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -43,7 +43,12 @@ public:
|
||||||
|
|
||||||
virtual void somethingChangedNotification() { _needsInitialSimulation = true; }
|
virtual void somethingChangedNotification() { _needsInitialSimulation = true; }
|
||||||
|
|
||||||
virtual bool canRenderInScene() { return false; } // we don't yet play well with others
|
virtual bool canRenderInScene() { return true; }
|
||||||
|
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr);
|
||||||
|
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||||
|
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||||
|
|
||||||
|
|
||||||
virtual void render(RenderArgs* args);
|
virtual void render(RenderArgs* args);
|
||||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||||
|
|
|
@ -973,7 +973,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void EntityItem::recordCreationTime() {
|
void EntityItem::recordCreationTime() {
|
||||||
assert(_created == UNKNOWN_CREATED_TIME);
|
//assert(_created == UNKNOWN_CREATED_TIME);
|
||||||
_created = usecTimestampNow();
|
_created = usecTimestampNow();
|
||||||
_lastEdited = _created;
|
_lastEdited = _created;
|
||||||
_lastUpdated = _created;
|
_lastUpdated = _created;
|
||||||
|
|
|
@ -158,6 +158,7 @@ public:
|
||||||
{ return 0; }
|
{ return 0; }
|
||||||
|
|
||||||
virtual bool canRenderInScene() { return false; } // does your entity property render using Render Items and Payloads
|
virtual bool canRenderInScene() { return false; } // does your entity property render using Render Items and Payloads
|
||||||
|
virtual bool readyToAddToScene(RenderArgs* renderArgs = nullptr) { return true; } // we assume you're ready to add
|
||||||
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
virtual bool addToScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||||
render::PendingChanges& pendingChanges) { return false; } // by default entity items don't add to scene
|
render::PendingChanges& pendingChanges) { return false; } // by default entity items don't add to scene
|
||||||
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene,
|
||||||
|
|
|
@ -765,6 +765,29 @@ void Model::renderSetup(RenderArgs* args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||||
|
bool somethingAdded = false;
|
||||||
|
// allow the attachments to add to scene
|
||||||
|
foreach (Model* attachment, _attachments) {
|
||||||
|
bool attachementSomethingAdded = attachment->addToScene(scene, pendingChanges);
|
||||||
|
somethingAdded = somethingAdded || attachementSomethingAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO --- need to do something here
|
||||||
|
|
||||||
|
return somethingAdded;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||||
|
// allow the attachments to remove to scene
|
||||||
|
foreach (Model* attachment, _attachments) {
|
||||||
|
attachment->removeFromScene(scene, pendingChanges);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO --- need to do something here
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
bool Model::render(RenderArgs* renderArgs, float alpha) {
|
bool Model::render(RenderArgs* renderArgs, float alpha) {
|
||||||
PROFILE_RANGE(__FUNCTION__);
|
PROFILE_RANGE(__FUNCTION__);
|
||||||
|
|
||||||
|
@ -2068,7 +2091,235 @@ bool Model::renderInScene(float alpha, RenderArgs* args) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class TransparentMeshPart {
|
||||||
|
public:
|
||||||
|
TransparentMeshPart(Model* model, int meshIndex, int partIndex) : model(model), meshIndex(meshIndex), partIndex(partIndex) { }
|
||||||
|
typedef render::Payload<TransparentMeshPart> Payload;
|
||||||
|
typedef Payload::DataPointer Pointer;
|
||||||
|
|
||||||
|
Model* model;
|
||||||
|
int meshIndex;
|
||||||
|
int partIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
template <> const ItemKey payloadGetKey(const TransparentMeshPart::Pointer& payload) {
|
||||||
|
return ItemKey::Builder::transparentShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> const Item::Bound payloadGetBound(const TransparentMeshPart::Pointer& payload) {
|
||||||
|
if (payload) {
|
||||||
|
return payload->model->getPartBounds(payload->meshIndex, payload->partIndex);
|
||||||
|
}
|
||||||
|
return render::Item::Bound();
|
||||||
|
}
|
||||||
|
template <> void payloadRender(const TransparentMeshPart::Pointer& payload, RenderArgs* args) {
|
||||||
|
if (args) {
|
||||||
|
args->_elementsTouched++;
|
||||||
|
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class OpaqueMeshPart {
|
||||||
|
public:
|
||||||
|
OpaqueMeshPart(Model* model, int meshIndex, int partIndex) : model(model), meshIndex(meshIndex), partIndex(partIndex) { }
|
||||||
|
typedef render::Payload<OpaqueMeshPart> Payload;
|
||||||
|
typedef Payload::DataPointer Pointer;
|
||||||
|
|
||||||
|
Model* model;
|
||||||
|
int meshIndex;
|
||||||
|
int partIndex;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
template <> const ItemKey payloadGetKey(const OpaqueMeshPart::Pointer& payload) {
|
||||||
|
return ItemKey::Builder::opaqueShape();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <> const Item::Bound payloadGetBound(const OpaqueMeshPart::Pointer& payload) {
|
||||||
|
if (payload) {
|
||||||
|
return payload->model->getPartBounds(payload->meshIndex, payload->partIndex);
|
||||||
|
}
|
||||||
|
return render::Item::Bound();
|
||||||
|
}
|
||||||
|
template <> void payloadRender(const OpaqueMeshPart::Pointer& payload, RenderArgs* args) {
|
||||||
|
if (args) {
|
||||||
|
args->_elementsTouched++;
|
||||||
|
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AABox Model::getPartBounds(int meshIndex, int partIndex) {
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||||
|
AABox partBox = mesh._mesh.evalPartBound(partIndex);
|
||||||
|
return partBox;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent) {
|
||||||
|
auto textureCache = DependencyManager::get<TextureCache>();
|
||||||
|
|
||||||
|
const float DEFAULT_ALPHA_THRESHOLD = 0.5f;
|
||||||
|
|
||||||
|
int i = meshIndex;
|
||||||
|
int j = partIndex;
|
||||||
|
gpu::Batch& batch = *(args->_batch);
|
||||||
|
auto mode = args->_renderMode;
|
||||||
|
auto alphaThreshold = DEFAULT_ALPHA_THRESHOLD; // FIX ME
|
||||||
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
|
||||||
|
|
||||||
|
const NetworkMesh& networkMesh = networkMeshes.at(meshIndex);
|
||||||
|
const FBXMesh& mesh = geometry.meshes.at(meshIndex);
|
||||||
|
const MeshState& state = _meshStates.at(meshIndex);
|
||||||
|
|
||||||
|
int vertexCount = mesh.vertices.size(); // NOTE: This seems wrong, shouldn't it be the part's vertex count?
|
||||||
|
|
||||||
|
|
||||||
|
bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
|
||||||
|
bool hasTangents = !mesh.tangents.isEmpty();
|
||||||
|
bool hasSpecular = mesh.hasSpecularTexture();
|
||||||
|
bool hasLightmap = mesh.hasEmissiveTexture();
|
||||||
|
bool isSkinned = state.clusterMatrices.size() > 1;
|
||||||
|
bool wireframe = isWireframe();
|
||||||
|
|
||||||
|
if (wireframe) {
|
||||||
|
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Locations* locations = nullptr;
|
||||||
|
pickPrograms(batch, mode, translucent, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||||
|
args, locations);
|
||||||
|
|
||||||
|
if (state.clusterMatrices.size() > 1) {
|
||||||
|
GLBATCH(glUniformMatrix4fv)(locations->clusterMatrices, state.clusterMatrices.size(), false,
|
||||||
|
(const float*)state.clusterMatrices.constData());
|
||||||
|
batch.setModelTransform(Transform());
|
||||||
|
} else {
|
||||||
|
batch.setModelTransform(Transform(state.clusterMatrices[0]));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh.blendshapes.isEmpty()) {
|
||||||
|
batch.setInputFormat(networkMesh._vertexFormat);
|
||||||
|
batch.setInputStream(0, *networkMesh._vertexStream);
|
||||||
|
} else {
|
||||||
|
batch.setInputFormat(networkMesh._vertexFormat);
|
||||||
|
batch.setInputBuffer(0, _blendedVertexBuffers[i], 0, sizeof(glm::vec3));
|
||||||
|
batch.setInputBuffer(1, _blendedVertexBuffers[i], vertexCount * sizeof(glm::vec3), sizeof(glm::vec3));
|
||||||
|
batch.setInputStream(2, *networkMesh._vertexStream);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mesh.colors.isEmpty()) {
|
||||||
|
GLBATCH(glColor4f)(1.0f, 1.0f, 1.0f, 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
qint64 offset = 0;
|
||||||
|
|
||||||
|
const NetworkMeshPart& networkPart = networkMesh.parts.at(j);
|
||||||
|
const FBXMeshPart& part = mesh.parts.at(j);
|
||||||
|
model::MaterialPointer material = part._material;
|
||||||
|
if ((networkPart.isTranslucent() || part.opacity != 1.0f) != translucent) {
|
||||||
|
offset += (part.quadIndices.size() + part.triangleIndices.size()) * sizeof(int);
|
||||||
|
//continue;
|
||||||
|
// FIX ME!!!
|
||||||
|
}
|
||||||
|
|
||||||
|
// apply material properties
|
||||||
|
if (mode == RenderArgs::SHADOW_RENDER_MODE) {
|
||||||
|
/// GLBATCH(glBindTexture)(GL_TEXTURE_2D, 0);
|
||||||
|
} else {
|
||||||
|
const bool wantDebug = false;
|
||||||
|
if (wantDebug) {
|
||||||
|
qCDebug(renderutils) << "Material Changed ---------------------------------------------";
|
||||||
|
qCDebug(renderutils) << "part INDEX:" << j;
|
||||||
|
qCDebug(renderutils) << "NEW part.materialID:" << part.materialID;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locations->materialBufferUnit >= 0) {
|
||||||
|
batch.setUniformBuffer(locations->materialBufferUnit, material->getSchemaBuffer());
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture* diffuseMap = networkPart.diffuseTexture.data();
|
||||||
|
if (mesh.isEye && diffuseMap) {
|
||||||
|
diffuseMap = (_dilatedTextures[i][j] =
|
||||||
|
static_cast<DilatableNetworkTexture*>(diffuseMap)->getDilatedTexture(_pupilDilation)).data();
|
||||||
|
}
|
||||||
|
static bool showDiffuse = true;
|
||||||
|
if (showDiffuse && diffuseMap) {
|
||||||
|
batch.setUniformTexture(0, diffuseMap->getGPUTexture());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
batch.setUniformTexture(0, textureCache->getWhiteTexture());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locations->texcoordMatrices >= 0) {
|
||||||
|
glm::mat4 texcoordTransform[2];
|
||||||
|
if (!part.diffuseTexture.transform.isIdentity()) {
|
||||||
|
part.diffuseTexture.transform.getMatrix(texcoordTransform[0]);
|
||||||
|
}
|
||||||
|
if (!part.emissiveTexture.transform.isIdentity()) {
|
||||||
|
part.emissiveTexture.transform.getMatrix(texcoordTransform[1]);
|
||||||
|
}
|
||||||
|
GLBATCH(glUniformMatrix4fv)(locations->texcoordMatrices, 2, false, (const float*) &texcoordTransform);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!mesh.tangents.isEmpty()) {
|
||||||
|
Texture* normalMap = networkPart.normalTexture.data();
|
||||||
|
batch.setUniformTexture(1, !normalMap ?
|
||||||
|
textureCache->getBlueTexture() : normalMap->getGPUTexture());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (locations->specularTextureUnit >= 0) {
|
||||||
|
Texture* specularMap = networkPart.specularTexture.data();
|
||||||
|
batch.setUniformTexture(locations->specularTextureUnit, !specularMap ?
|
||||||
|
textureCache->getWhiteTexture() : specularMap->getGPUTexture());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args) {
|
||||||
|
args->_materialSwitches++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// HACK: For unkwon reason (yet!) this code that should be assigned only if the material changes need to be called for every
|
||||||
|
// drawcall with an emissive, so let's do it for now.
|
||||||
|
if (locations->emissiveTextureUnit >= 0) {
|
||||||
|
// assert(locations->emissiveParams >= 0); // we should have the emissiveParams defined in the shader
|
||||||
|
float emissiveOffset = part.emissiveParams.x;
|
||||||
|
float emissiveScale = part.emissiveParams.y;
|
||||||
|
GLBATCH(glUniform2f)(locations->emissiveParams, emissiveOffset, emissiveScale);
|
||||||
|
|
||||||
|
Texture* emissiveMap = networkPart.emissiveTexture.data();
|
||||||
|
batch.setUniformTexture(locations->emissiveTextureUnit, !emissiveMap ?
|
||||||
|
textureCache->getWhiteTexture() : emissiveMap->getGPUTexture());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.quadIndices.size() > 0) {
|
||||||
|
batch.drawIndexed(gpu::QUADS, part.quadIndices.size(), offset);
|
||||||
|
offset += part.quadIndices.size() * sizeof(int);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (part.triangleIndices.size() > 0) {
|
||||||
|
batch.drawIndexed(gpu::TRIANGLES, part.triangleIndices.size(), offset);
|
||||||
|
offset += part.triangleIndices.size() * sizeof(int);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args) {
|
||||||
|
const int INDICES_PER_TRIANGLE = 3;
|
||||||
|
const int INDICES_PER_QUAD = 4;
|
||||||
|
args->_trianglesRendered += part.triangleIndices.size() / INDICES_PER_TRIANGLE;
|
||||||
|
args->_quadsRendered += part.quadIndices.size() / INDICES_PER_QUAD;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void Model::segregateMeshGroups() {
|
void Model::segregateMeshGroups() {
|
||||||
|
|
||||||
|
//qDebug() << "Model::segregateMeshGroups() ------------------------------------------------";
|
||||||
|
|
||||||
_renderBuckets.clear();
|
_renderBuckets.clear();
|
||||||
|
|
||||||
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
const FBXGeometry& geometry = _geometry->getFBXGeometry();
|
||||||
|
@ -2086,6 +2337,7 @@ void Model::segregateMeshGroups() {
|
||||||
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
const NetworkMesh& networkMesh = networkMeshes.at(i);
|
||||||
const FBXMesh& mesh = geometry.meshes.at(i);
|
const FBXMesh& mesh = geometry.meshes.at(i);
|
||||||
const MeshState& state = _meshStates.at(i);
|
const MeshState& state = _meshStates.at(i);
|
||||||
|
|
||||||
|
|
||||||
bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
|
bool translucentMesh = networkMesh.getTranslucentPartCount(mesh) == networkMesh.parts.size();
|
||||||
bool hasTangents = !mesh.tangents.isEmpty();
|
bool hasTangents = !mesh.tangents.isEmpty();
|
||||||
|
@ -2097,6 +2349,23 @@ void Model::segregateMeshGroups() {
|
||||||
if (wireframe) {
|
if (wireframe) {
|
||||||
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
translucentMesh = hasTangents = hasSpecular = hasLightmap = isSkinned = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Debug...
|
||||||
|
//qDebug() << "Mesh parts..." << mesh._mesh.getNumParts();
|
||||||
|
int totalParts = mesh._mesh.getNumParts();
|
||||||
|
for (int partIndex = 0; partIndex < totalParts; partIndex++) {
|
||||||
|
AABox boxPart = mesh._mesh.evalPartBound(partIndex);
|
||||||
|
|
||||||
|
// this is a good place to create our renderPayloads
|
||||||
|
if (translucentMesh) {
|
||||||
|
//qDebug() << "Transparent Mesh parts[" << partIndex << "].box=" << boxPart;
|
||||||
|
_transparentRenderItems << std::shared_ptr<TransparentMeshPart>(new TransparentMeshPart(this, i, partIndex));
|
||||||
|
} else {
|
||||||
|
//qDebug() << "Opaque Mesh parts[" << partIndex << "].box=" << boxPart;
|
||||||
|
_opaqueRenderItems << std::shared_ptr<OpaqueMeshPart>(new OpaqueMeshPart(this, i, partIndex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
QString materialID;
|
QString materialID;
|
||||||
|
|
||||||
|
|
|
@ -45,6 +45,21 @@ class Shape;
|
||||||
#include "RenderArgs.h"
|
#include "RenderArgs.h"
|
||||||
class ViewFrustum;
|
class ViewFrustum;
|
||||||
|
|
||||||
|
namespace render {
|
||||||
|
class Scene;
|
||||||
|
class PendingChanges;
|
||||||
|
}
|
||||||
|
class OpaqueMeshPart;
|
||||||
|
class TransparentMeshPart;
|
||||||
|
|
||||||
|
inline uint qHash(const std::shared_ptr<TransparentMeshPart>& a, uint seed) {
|
||||||
|
return qHash(a.get(), seed);
|
||||||
|
}
|
||||||
|
inline uint qHash(const std::shared_ptr<OpaqueMeshPart>& a, uint seed) {
|
||||||
|
return qHash(a.get(), seed);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/// A generic 3D model displaying geometry loaded from a URL.
|
/// A generic 3D model displaying geometry loaded from a URL.
|
||||||
class Model : public QObject, public PhysicsEntity {
|
class Model : public QObject, public PhysicsEntity {
|
||||||
|
@ -105,6 +120,10 @@ public:
|
||||||
bool renderInScene(float alpha = 1.0f, RenderArgs* args = NULL);
|
bool renderInScene(float alpha = 1.0f, RenderArgs* args = NULL);
|
||||||
static void endScene(RenderArgs* args);
|
static void endScene(RenderArgs* args);
|
||||||
|
|
||||||
|
// new Scene/Engine rendering support
|
||||||
|
bool addToScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||||
|
void removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges);
|
||||||
|
|
||||||
/// Sets the URL of the model to render.
|
/// Sets the URL of the model to render.
|
||||||
/// \param fallback the URL of a fallback model to render if the requested model fails to load
|
/// \param fallback the URL of a fallback model to render if the requested model fails to load
|
||||||
/// \param retainCurrent if true, keep rendering the current model until the new one is loaded
|
/// \param retainCurrent if true, keep rendering the current model until the new one is loaded
|
||||||
|
@ -219,6 +238,9 @@ public:
|
||||||
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false);
|
BoxFace& face, QString& extraInfo, bool pickAgainstTriangles = false);
|
||||||
bool convexHullContains(glm::vec3 point);
|
bool convexHullContains(glm::vec3 point);
|
||||||
|
|
||||||
|
AABox getPartBounds(int meshIndex, int partIndex);
|
||||||
|
void renderPart(RenderArgs* args, int meshIndex, int partIndex, bool translucent);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QSharedPointer<NetworkGeometry> _geometry;
|
QSharedPointer<NetworkGeometry> _geometry;
|
||||||
|
|
||||||
|
@ -511,6 +533,10 @@ private:
|
||||||
RenderBucketMap _renderBuckets;
|
RenderBucketMap _renderBuckets;
|
||||||
|
|
||||||
bool _renderCollisionHull;
|
bool _renderCollisionHull;
|
||||||
|
|
||||||
|
|
||||||
|
QSet<std::shared_ptr<TransparentMeshPart>> _transparentRenderItems;
|
||||||
|
QSet<std::shared_ptr<OpaqueMeshPart>> _opaqueRenderItems;
|
||||||
};
|
};
|
||||||
|
|
||||||
Q_DECLARE_METATYPE(QPointer<Model>)
|
Q_DECLARE_METATYPE(QPointer<Model>)
|
||||||
|
|
Loading…
Reference in a new issue