mostly getting attachments working again

This commit is contained in:
ZappoMan 2015-06-10 15:46:54 -07:00
parent aa05d9f67c
commit e06422825a
4 changed files with 43 additions and 132 deletions

View file

@ -582,7 +582,9 @@ void Avatar::simulateAttachments(float deltaTime) {
_skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) { _skeletonModel.getJointCombinedRotation(jointIndex, jointRotation)) {
model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale); model->setTranslation(jointPosition + jointRotation * attachment.translation * _scale);
model->setRotation(jointRotation * attachment.rotation); model->setRotation(jointRotation * attachment.rotation);
model->setScaleToFit(true, _scale * attachment.scale); model->setScaleToFit(true, _scale * attachment.scale, true); // hack to force rescale
model->setSnapModelToCenter(false); // hack to force resnap
model->setSnapModelToCenter(true);
model->simulate(deltaTime); model->simulate(deltaTime);
} }
} }

View file

@ -1196,23 +1196,7 @@ void MyAvatar::renderBody(RenderArgs* renderArgs, ViewFrustum* renderFrustum, bo
} }
scene->enqueuePendingChanges(pendingChanges); scene->enqueuePendingChanges(pendingChanges);
Camera *camera = Application::getInstance()->getCamera(); const glm::vec3 cameraPos = Application::getInstance()->getCamera()->getPosition();
const glm::vec3 cameraPos = camera->getPosition();
// HACK: comment this block which possibly change the near and break the rendering 5/6/2015
// Only tweak the frustum near far if it's not shadow
/* if (renderMode != RenderArgs::SHADOW_RENDER_MODE) {
// Set near clip distance according to skeleton model dimensions if first person and there is no separate head model.
if (shouldRenderHead(cameraPos, renderMode) || !getHead()->getFaceModel().getURL().isEmpty()) {
renderFrustum->setNearClip(DEFAULT_NEAR_CLIP);
} else {
float clipDistance = _skeletonModel.getHeadClipDistance();
clipDistance = glm::length(getEyePosition()
+ camera->getOrientation() * glm::vec3(0.0f, 0.0f, -clipDistance) - cameraPos);
renderFrustum->setNearClip(clipDistance);
}
}*/
// Render head so long as the camera isn't inside it // Render head so long as the camera isn't inside it
if (shouldRenderHead(renderArgs, cameraPos)) { if (shouldRenderHead(renderArgs, cameraPos)) {

View file

@ -435,6 +435,7 @@ bool Model::updateGeometry() {
QSharedPointer<NetworkGeometry> geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis); QSharedPointer<NetworkGeometry> geometry = _geometry->getLODOrFallback(_lodDistance, _lodHysteresis);
if (_geometry != geometry) { if (_geometry != geometry) {
// NOTE: it is theoretically impossible to reach here after passing through the applyNextGeometry() call above. // NOTE: it is theoretically impossible to reach here after passing through the applyNextGeometry() call above.
// Which means we don't need to worry about calling deleteGeometry() below immediately after creating new geometry. // Which means we don't need to worry about calling deleteGeometry() below immediately after creating new geometry.
@ -811,71 +812,41 @@ void Model::renderSetup(RenderArgs* args) {
} }
class TransparentMeshPart { class MeshPartPayload {
public: public:
TransparentMeshPart(Model* model, int meshIndex, int partIndex) : model(model), meshIndex(meshIndex), partIndex(partIndex) { } MeshPartPayload(bool transparent, Model* model, int meshIndex, int partIndex) :
typedef render::Payload<TransparentMeshPart> Payload; transparent(transparent), model(model), url(model->getURL()), meshIndex(meshIndex), partIndex(partIndex) { }
typedef render::Payload<MeshPartPayload> Payload;
typedef Payload::DataPointer Pointer; typedef Payload::DataPointer Pointer;
Model* model; bool transparent;
Model* model;
QUrl url;
int meshIndex; int meshIndex;
int partIndex; int partIndex;
}; };
namespace render { namespace render {
template <> const ItemKey payloadGetKey(const TransparentMeshPart::Pointer& payload) { template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload) {
if (!payload->model->isVisible()) { if (!payload->model->isVisible()) {
return ItemKey::Builder().withInvisible().build(); return ItemKey::Builder().withInvisible().build();
} }
return ItemKey::Builder::transparentShape(); return payload->transparent ? ItemKey::Builder::transparentShape() : ItemKey::Builder::opaqueShape();
} }
template <> const Item::Bound payloadGetBound(const TransparentMeshPart::Pointer& payload) { template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload) {
if (payload) { if (payload) {
return payload->model->getPartBounds(payload->meshIndex, payload->partIndex); return payload->model->getPartBounds(payload->meshIndex, payload->partIndex);
} }
return render::Item::Bound(); return render::Item::Bound();
} }
template <> void payloadRender(const TransparentMeshPart::Pointer& payload, RenderArgs* args) { template <> void payloadRender(const MeshPartPayload::Pointer& payload, RenderArgs* args) {
if (args) { if (args) {
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, true); return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, payload->transparent);
} }
} }
}
class OpaqueMeshPart { /* template <> const model::MaterialKey& shapeGetMaterialKey(const MeshPartPayload::Pointer& payload) {
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) {
if (!payload->model->isVisible()) {
return ItemKey::Builder().withInvisible().build();
}
return ItemKey::Builder::opaqueShape();
}
template <> const Item::Bound payloadGetBound(const OpaqueMeshPart::Pointer& payload) {
if (payload) {
Item::Bound result = payload->model->getPartBounds(payload->meshIndex, payload->partIndex);
//qDebug() << "payloadGetBound(OpaqueMeshPart) " << result;
return result;
}
return render::Item::Bound();
}
template <> void payloadRender(const OpaqueMeshPart::Pointer& payload, RenderArgs* args) {
if (args) {
return payload->model->renderPart(args, payload->meshIndex, payload->partIndex, false);
}
}
/* template <> const model::MaterialKey& shapeGetMaterialKey(const OpaqueMeshPart::Pointer& payload) {
return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex); return payload->model->getPartMaterial(payload->meshIndex, payload->partIndex);
}*/ }*/
} }
@ -902,16 +873,17 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChan
foreach (auto renderItem, _transparentRenderItems) { foreach (auto renderItem, _transparentRenderItems) {
auto item = scene->allocateID(); auto item = scene->allocateID();
auto renderData = TransparentMeshPart::Pointer(renderItem); auto renderData = MeshPartPayload::Pointer(renderItem);
auto renderPayload = render::PayloadPointer(new TransparentMeshPart::Payload(renderData)); auto renderPayload = render::PayloadPointer(new MeshPartPayload::Payload(renderData));
pendingChanges.resetItem(item, renderPayload); pendingChanges.resetItem(item, renderPayload);
_renderItems.insert(item, renderPayload); _renderItems.insert(item, renderPayload);
somethingAdded = true; somethingAdded = true;
} }
foreach (auto renderItem, _opaqueRenderItems) { foreach (auto renderItem, _opaqueRenderItems) {
auto item = scene->allocateID(); auto item = scene->allocateID();
auto renderData = OpaqueMeshPart::Pointer(renderItem); auto renderData = MeshPartPayload::Pointer(renderItem);
auto renderPayload = render::PayloadPointer(new OpaqueMeshPart::Payload(renderData)); auto renderPayload = render::PayloadPointer(new MeshPartPayload::Payload(renderData));
pendingChanges.resetItem(item, renderPayload); pendingChanges.resetItem(item, renderPayload);
_renderItems.insert(item, renderPayload); _renderItems.insert(item, renderPayload);
somethingAdded = true; somethingAdded = true;
@ -1036,12 +1008,12 @@ Extents Model::calculateScaledOffsetExtents(const Extents& extents) const {
Extents translatedExtents = { rotatedExtents.minimum + _translation, Extents translatedExtents = { rotatedExtents.minimum + _translation,
rotatedExtents.maximum + _translation }; rotatedExtents.maximum + _translation };
return translatedExtents; return translatedExtents;
} }
/// Returns the world space equivalent of some box in model space. /// Returns the world space equivalent of some box in model space.
AABox Model::calculateScaledOffsetAABox(const AABox& box) const { AABox Model::calculateScaledOffsetAABox(const AABox& box) const {
return AABox(calculateScaledOffsetExtents(Extents(box))); return AABox(calculateScaledOffsetExtents(Extents(box)));
} }
@ -1110,9 +1082,10 @@ void Model::setURL(const QUrl& url, const QUrl& fallback, bool retainCurrent, bo
if (_url == url && _geometry && _geometry->getURL() == url) { if (_url == url && _geometry && _geometry->getURL() == url) {
return; return;
} }
_readyWhenAdded = false; // reset out render items. _readyWhenAdded = false; // reset out render items.
_needsReload = true; _needsReload = true;
invalidCalculatedMeshBoxes();
_url = url; _url = url;
@ -1301,7 +1274,7 @@ void Model::setScaleToFit(bool scaleToFit, const glm::vec3& dimensions) {
} }
} }
void Model::setScaleToFit(bool scaleToFit, float largestDimension) { void Model::setScaleToFit(bool scaleToFit, float largestDimension, bool forceRescale) {
// NOTE: if the model is not active, then it means we don't actually know the true/natural dimensions of the // NOTE: if the model is not active, then it means we don't actually know the true/natural dimensions of the
// mesh, and so we can't do the needed calculations for scaling to fit to a single largest dimension. In this // mesh, and so we can't do the needed calculations for scaling to fit to a single largest dimension. In this
// case we will record that we do want to do this, but we will stick our desired single dimension into the // case we will record that we do want to do this, but we will stick our desired single dimension into the
@ -1314,7 +1287,7 @@ void Model::setScaleToFit(bool scaleToFit, float largestDimension) {
return; return;
} }
if (_scaleToFit != scaleToFit || glm::length(_scaleToFitDimensions) != largestDimension) { if (forceRescale || _scaleToFit != scaleToFit || glm::length(_scaleToFitDimensions) != largestDimension) {
_scaleToFit = scaleToFit; _scaleToFit = scaleToFit;
// we only need to do this work if we're "turning on" scale to fit. // we only need to do this work if we're "turning on" scale to fit.
@ -1324,7 +1297,7 @@ void Model::setScaleToFit(bool scaleToFit, float largestDimension) {
float maxScale = largestDimension / maxDimension; float maxScale = largestDimension / maxDimension;
glm::vec3 modelMeshDimensions = modelMeshExtents.maximum - modelMeshExtents.minimum; glm::vec3 modelMeshDimensions = modelMeshExtents.maximum - modelMeshExtents.minimum;
glm::vec3 dimensions = modelMeshDimensions * maxScale; glm::vec3 dimensions = modelMeshDimensions * maxScale;
_scaleToFitDimensions = dimensions; _scaleToFitDimensions = dimensions;
_scaledToFit = false; // force rescaling _scaledToFit = false; // force rescaling
} }
@ -1822,7 +1795,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
glm::mat4 scale = glm::scale(partBounds.getDimensions()); glm::mat4 scale = glm::scale(partBounds.getDimensions());
glm::mat4 modelToWorldMatrix = translation * scale; glm::mat4 modelToWorldMatrix = translation * scale;
batch.setModelTransform(modelToWorldMatrix); batch.setModelTransform(modelToWorldMatrix);
//qDebug() << "partBounds:" << partBounds;
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor); DependencyManager::get<DeferredLightingEffect>()->renderWireCube(batch, 1.0f, cubeColor);
} }
#endif //def DEBUG_BOUNDING_PARTS #endif //def DEBUG_BOUNDING_PARTS
@ -1912,16 +1884,18 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
// guard against partially loaded meshes // guard against partially loaded meshes
if (partIndex >= networkMesh.parts.size() || partIndex >= mesh.parts.size()) { if (partIndex >= networkMesh.parts.size() || partIndex >= mesh.parts.size()) {
return; return;
} }
const NetworkMeshPart& networkPart = networkMesh.parts.at(partIndex); const NetworkMeshPart& networkPart = networkMesh.parts.at(partIndex);
const FBXMeshPart& part = mesh.parts.at(partIndex); const FBXMeshPart& part = mesh.parts.at(partIndex);
model::MaterialPointer material = part._material; model::MaterialPointer material = part._material;
#ifdef WANT_DEBUG
if (material == nullptr) { if (material == nullptr) {
// qCDebug(renderutils) << "WARNING: material == nullptr!!!"; qCDebug(renderutils) << "WARNING: material == nullptr!!!";
} }
#endif
if (material != nullptr) { if (material != nullptr) {
@ -2023,8 +1997,6 @@ void Model::renderPart(RenderArgs* args, int meshIndex, int partIndex, bool tran
} }
void Model::segregateMeshGroups() { void Model::segregateMeshGroups() {
_renderBuckets.clear();
const FBXGeometry& geometry = _geometry->getFBXGeometry(); const FBXGeometry& geometry = _geometry->getFBXGeometry();
const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes(); const QVector<NetworkMesh>& networkMeshes = _geometry->getMeshes();
@ -2034,6 +2006,9 @@ void Model::segregateMeshGroups() {
qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet."; qDebug() << "WARNING!!!! Mesh Sizes don't match! We will not segregate mesh groups yet.";
return; return;
} }
_transparentRenderItems.clear();
_opaqueRenderItems.clear();
// Run through all of the meshes, and place them into their segregated, but unsorted buckets // Run through all of the meshes, and place them into their segregated, but unsorted buckets
for (int i = 0; i < networkMeshes.size(); i++) { for (int i = 0; i < networkMeshes.size(); i++) {
@ -2058,43 +2033,12 @@ void Model::segregateMeshGroups() {
for (int partIndex = 0; partIndex < totalParts; partIndex++) { for (int partIndex = 0; partIndex < totalParts; partIndex++) {
// this is a good place to create our renderPayloads // this is a good place to create our renderPayloads
if (translucentMesh) { if (translucentMesh) {
_transparentRenderItems << std::shared_ptr<TransparentMeshPart>(new TransparentMeshPart(this, i, partIndex)); _transparentRenderItems << std::shared_ptr<MeshPartPayload>(new MeshPartPayload(true, this, i, partIndex));
} else { } else {
_opaqueRenderItems << std::shared_ptr<OpaqueMeshPart>(new OpaqueMeshPart(this, i, partIndex)); _opaqueRenderItems << std::shared_ptr<MeshPartPayload>(new MeshPartPayload(false, this, i, partIndex));
} }
} }
QString materialID;
// create a material name from all the parts. If there's one part, this will be a single material and its
// true name. If however the mesh has multiple parts the name will be all the part's materials mashed together
// which will result in those parts being sorted away from single material parts.
QString lastPartMaterialID;
foreach(FBXMeshPart part, mesh.parts) {
if (part.materialID != lastPartMaterialID) {
materialID += part.materialID;
}
lastPartMaterialID = part.materialID;
}
const bool wantDebug = false;
if (wantDebug) {
qCDebug(renderutils) << "materialID:" << materialID << "parts:" << mesh.parts.size();
}
RenderKey key(translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe);
// reuse or create the bucket corresponding to that key and insert the mesh as unsorted
_renderBuckets[key.getRaw()]._unsortedMeshes.insertMulti(materialID, i);
} }
for(auto& b : _renderBuckets) {
foreach(auto i, b.second._unsortedMeshes) {
b.second._meshes.append(i);
}
b.second._unsortedMeshes.clear();
}
_meshGroupsKnown = true; _meshGroupsKnown = true;
} }

View file

@ -51,17 +51,11 @@ namespace render {
class PendingChanges; class PendingChanges;
typedef unsigned int ItemID; typedef unsigned int ItemID;
} }
class OpaqueMeshPart; class MeshPartPayload;
class TransparentMeshPart;
inline uint qHash(const std::shared_ptr<TransparentMeshPart>& a, uint seed) { inline uint qHash(const std::shared_ptr<MeshPartPayload>& a, uint seed) {
return qHash(a.get(), 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 {
@ -77,7 +71,7 @@ public:
virtual ~Model(); virtual ~Model();
/// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension /// enables/disables scale to fit behavior, the model will be automatically scaled to the specified largest dimension
void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f); void setScaleToFit(bool scaleToFit, float largestDimension = 0.0f, bool forceRescale = false);
bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled bool getScaleToFit() const { return _scaleToFit; } /// is scale to fit enabled
bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit bool getIsScaledToFit() const { return _scaledToFit; } /// is model scaled to fit
const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to const glm::vec3& getScaleToFitDimensions() const { return _scaleToFitDimensions; } /// the dimensions model is scaled to
@ -511,24 +505,11 @@ private:
}; };
static RenderPipelineLib _renderPipelineLib; static RenderPipelineLib _renderPipelineLib;
class RenderBucket {
public:
QVector<int> _meshes;
QMap<QString, int> _unsortedMeshes;
};
typedef std::unordered_map<int, RenderBucket> BaseRenderBucketMap;
class RenderBucketMap : public BaseRenderBucketMap {
public:
typedef RenderKey Key;
};
RenderBucketMap _renderBuckets;
bool _renderCollisionHull; bool _renderCollisionHull;
QSet<std::shared_ptr<TransparentMeshPart>> _transparentRenderItems; QSet<std::shared_ptr<MeshPartPayload>> _transparentRenderItems;
QSet<std::shared_ptr<OpaqueMeshPart>> _opaqueRenderItems; QSet<std::shared_ptr<MeshPartPayload>> _opaqueRenderItems;
QMap<render::ItemID, render::PayloadPointer> _renderItems; QMap<render::ItemID, render::PayloadPointer> _renderItems;
bool _readyWhenAdded = false; bool _readyWhenAdded = false;
bool _needsReload = true; bool _needsReload = true;