mirror of
https://github.com/lubosz/overte.git
synced 2025-04-13 22:26:57 +02:00
WIP: checkpoint
* bug fix in AABox::operator+= * added AABox::emiggen * Avatar now has a default bound for it's skinned mesh. * WIP: AABox tests; NEED MORE * Model: split collision and model mesh render items. Because ModelMeshRenderItems need special handling to update bounds for animated joints. * Model: dynamically update the bound for rigidly bound animated meshes * Rig: added access to geometryToRigTransform * RenderableModelEntityItem: try to update bounds for skinned mesh to be the entity dimentions (this doesn't seem to be working) * Geometry.cpp: removed unused bounds parameter in evalPartBounds * ModelMeshPartPayload: bounds updating * non-animated: use existing _localBound * rigid bound mesh: use _localBound transformed by clusterMatrix joint transform * fully skinned mesh: use _skinnedMeshBound provided by the application.
This commit is contained in:
parent
bb42d84bbd
commit
b4e70d9101
13 changed files with 229 additions and 59 deletions
|
@ -56,6 +56,8 @@ const float DISPLAYNAME_ALPHA = 1.0f;
|
|||
const float DISPLAYNAME_BACKGROUND_ALPHA = 0.4f;
|
||||
const glm::vec3 HAND_TO_PALM_OFFSET(0.0f, 0.12f, 0.08f);
|
||||
|
||||
const AABox DEFAULT_AVATAR_SKINNED_MESH_BOUND(glm::vec3(-1.0, -1.0, -1.0), glm::vec3(2.0f));
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const AvatarSharedPointer& avatar) {
|
||||
return ItemKey::Builder::opaqueShape();
|
||||
|
@ -101,6 +103,7 @@ Avatar::Avatar(RigPointer rig) :
|
|||
_headData = static_cast<HeadData*>(new Head(this));
|
||||
|
||||
_skeletonModel = std::make_shared<SkeletonModel>(this, nullptr, rig);
|
||||
_skeletonModel->setSkinnedMeshBound(DEFAULT_AVATAR_SKINNED_MESH_BOUND);
|
||||
}
|
||||
|
||||
Avatar::~Avatar() {
|
||||
|
|
|
@ -221,6 +221,8 @@ public:
|
|||
|
||||
void setEnableInverseKinematics(bool enable);
|
||||
|
||||
const glm::mat4& getGeometryToRigTransform() const { return _geometryToRigTransform; }
|
||||
|
||||
protected:
|
||||
bool isIndexValid(int index) const { return _animSkeleton && index >= 0 && index < _animSkeleton->getNumJoints(); }
|
||||
void updateAnimationStateHandlers();
|
||||
|
|
|
@ -54,6 +54,8 @@ void RenderableModelEntityItem::setModelURL(const QString& url) {
|
|||
// Here we reset those guards. This doesn't cause the entity values to change -- it just allows the model to match once it comes in.
|
||||
_model->setScaleToFit(false, getDimensions());
|
||||
_model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
|
||||
AABox skinnedMeshBound(getPosition() - getDimensions() * getRegistrationPoint(), getDimensions());
|
||||
_model->setSkinnedMeshBound(skinnedMeshBound);
|
||||
}
|
||||
ModelEntityItem::setModelURL(url);
|
||||
|
||||
|
@ -76,6 +78,8 @@ void RenderableModelEntityItem::loader() {
|
|||
if (_model) {
|
||||
_model->setURL(getParsedModelURL());
|
||||
_model->setCollisionModelURL(QUrl(getCompoundShapeURL()));
|
||||
AABox skinnedMeshBound(getPosition() - getDimensions() * getRegistrationPoint(), getDimensions());
|
||||
_model->setSkinnedMeshBound(skinnedMeshBound);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -111,7 +111,7 @@ Box Mesh::evalPartBound(int partNum) const {
|
|||
return box;
|
||||
}
|
||||
|
||||
Box Mesh::evalPartBounds(int partStart, int partEnd, Boxes& bounds) const {
|
||||
Box Mesh::evalPartBounds(int partStart, int partEnd) const {
|
||||
Box totalBound;
|
||||
auto part = _partBuffer.cbegin<Part>() + partStart;
|
||||
auto partItEnd = _partBuffer.cbegin<Part>() + partEnd;
|
||||
|
|
|
@ -108,9 +108,9 @@ public:
|
|||
|
||||
// evaluate the bounding box of A part
|
||||
Box evalPartBound(int partNum) const;
|
||||
// evaluate the bounding boxes of the parts in the range [start, end[ and fill the bounds parameter
|
||||
// evaluate the bounding boxes of the parts in the range [start, end]
|
||||
// the returned box is the bounding box of ALL the evaluated part bounds.
|
||||
Box evalPartBounds(int partStart, int partEnd, Boxes& bounds) const;
|
||||
Box evalPartBounds(int partStart, int partEnd) const;
|
||||
|
||||
static gpu::Primitive topologyToPrimitive(Topology topo) { return static_cast<gpu::Primitive>(topo); }
|
||||
|
||||
|
|
|
@ -52,17 +52,6 @@ MeshPartPayload::MeshPartPayload(model::MeshPointer mesh, int partIndex, model::
|
|||
updateTransform(transform, offsetTransform);
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) {
|
||||
_drawMesh = drawMesh;
|
||||
if (_drawMesh) {
|
||||
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||
|
||||
_localBound = _drawMesh->evalPartBound(partIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateTransform(const Transform& transform, const Transform& offsetTransform) {
|
||||
_transform = transform;
|
||||
_offsetTransform = offsetTransform;
|
||||
|
@ -71,6 +60,16 @@ void MeshPartPayload::updateTransform(const Transform& transform, const Transfor
|
|||
_worldBound.transform(_drawTransform);
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) {
|
||||
_drawMesh = drawMesh;
|
||||
if (_drawMesh) {
|
||||
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||
_localBound = _drawMesh->evalPartBound(partIndex);
|
||||
}
|
||||
}
|
||||
|
||||
void MeshPartPayload::updateMaterial(model::MaterialPointer drawMaterial) {
|
||||
_drawMaterial = drawMaterial;
|
||||
}
|
||||
|
@ -316,10 +315,13 @@ template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, Ren
|
|||
}
|
||||
}
|
||||
|
||||
ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform) :
|
||||
ModelMeshPartPayload::ModelMeshPartPayload(Model* model, int _meshIndex, int partIndex, int shapeIndex, const Transform& transform,
|
||||
const Transform& offsetTransform, const AABox& skinnedMeshBound) :
|
||||
_model(model),
|
||||
_meshIndex(_meshIndex),
|
||||
_shapeID(shapeIndex) {
|
||||
_shapeID(shapeIndex),
|
||||
_skinnedMeshBound(skinnedMeshBound) {
|
||||
|
||||
auto& modelMesh = _model->_geometry->getMeshes().at(_meshIndex)->_mesh;
|
||||
updateMeshPart(modelMesh, partIndex);
|
||||
|
||||
|
@ -351,6 +353,36 @@ void ModelMeshPartPayload::notifyLocationChanged() {
|
|||
_model->_needsUpdateClusterMatrices = true;
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateTransformForRigidlyBoundMesh(const Transform& transform, const Transform& clusterTransform, const Transform& offsetTransform) {
|
||||
ModelMeshPartPayload::updateTransform(transform, offsetTransform);
|
||||
|
||||
// clusterMatrix has world rotation but not world translation.
|
||||
Transform worldTranslation, geomToWorld;
|
||||
worldTranslation.setTranslation(transform.getTranslation());
|
||||
Transform::mult(geomToWorld, worldTranslation, clusterTransform);
|
||||
|
||||
// transform the localBound into world space
|
||||
_worldBound = _localBound;
|
||||
_worldBound.transform(geomToWorld);
|
||||
}
|
||||
|
||||
void ModelMeshPartPayload::updateMeshPart(model::MeshPointer drawMesh, int partIndex) {
|
||||
_drawMesh = drawMesh;
|
||||
if (_drawMesh) {
|
||||
auto vertexFormat = _drawMesh->getVertexFormat();
|
||||
_hasColorAttrib = vertexFormat->hasAttribute(gpu::Stream::COLOR);
|
||||
_drawPart = _drawMesh->getPartBuffer().get<model::Mesh::Part>(partIndex);
|
||||
|
||||
// this is a skinned mesh..
|
||||
if (vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT) && vertexFormat->hasAttribute(gpu::Stream::SKIN_CLUSTER_INDEX)) {
|
||||
// use the specified skinned bounding box.
|
||||
_localBound = _skinnedMeshBound;
|
||||
} else {
|
||||
_localBound = _drawMesh->evalPartBound(partIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ItemKey ModelMeshPartPayload::getKey() const {
|
||||
ItemKey::Builder builder;
|
||||
builder.withTypeShape();
|
||||
|
@ -373,12 +405,6 @@ ItemKey ModelMeshPartPayload::getKey() const {
|
|||
return builder.build();
|
||||
}
|
||||
|
||||
Item::Bound ModelMeshPartPayload::getBound() const {
|
||||
// NOTE: we can't cache this bounds because we need to handle the case of a moving
|
||||
// entity or mesh part.
|
||||
return _model->getPartBounds(_meshIndex, _partIndex, _transform.getTranslation(), _transform.getRotation());
|
||||
}
|
||||
|
||||
ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
||||
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
|
||||
|
|
|
@ -64,6 +64,7 @@ public:
|
|||
bool _hasColorAttrib = false;
|
||||
};
|
||||
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const MeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const MeshPartPayload::Pointer& payload);
|
||||
|
@ -73,16 +74,18 @@ namespace render {
|
|||
|
||||
class ModelMeshPartPayload : public MeshPartPayload {
|
||||
public:
|
||||
ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform, const Transform& offsetTransform);
|
||||
|
||||
ModelMeshPartPayload(Model* model, int meshIndex, int partIndex, int shapeIndex, const Transform& transform,
|
||||
const Transform& offsetTransform, const AABox& skinnedMeshBound);
|
||||
|
||||
typedef render::Payload<ModelMeshPartPayload> Payload;
|
||||
typedef Payload::DataPointer Pointer;
|
||||
|
||||
void notifyLocationChanged() override;
|
||||
virtual void updateMeshPart(model::MeshPointer drawMesh, int partIndex) override;
|
||||
virtual void notifyLocationChanged() override;
|
||||
void updateTransformForRigidlyBoundMesh(const Transform& transform, const Transform& jointTransform, const Transform& offsetTransform);
|
||||
|
||||
// Render Item interface
|
||||
render::ItemKey getKey() const override;
|
||||
render::Item::Bound getBound() const override;
|
||||
render::ShapeKey getShapeKey() const override; // shape interface
|
||||
void render(RenderArgs* args) const override;
|
||||
|
||||
|
@ -99,6 +102,15 @@ public:
|
|||
|
||||
bool _isSkinned{ false };
|
||||
bool _isBlendShaped{ false };
|
||||
|
||||
AABox _skinnedMeshBound;
|
||||
};
|
||||
|
||||
namespace render {
|
||||
template <> const ItemKey payloadGetKey(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> const Item::Bound payloadGetBound(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> const ShapeKey shapeGetShapeKey(const ModelMeshPartPayload::Pointer& payload);
|
||||
template <> void payloadRender(const ModelMeshPartPayload::Pointer& payload, RenderArgs* args);
|
||||
}
|
||||
|
||||
#endif // hifi_MeshPartPayload_h
|
||||
|
|
|
@ -102,6 +102,7 @@ void Model::setRotation(const glm::quat& rotation) {
|
|||
|
||||
void Model::setScale(const glm::vec3& scale) {
|
||||
setScaleInternal(scale);
|
||||
|
||||
// if anyone sets scale manually, then we are no longer scaled to fit
|
||||
_scaleToFit = false;
|
||||
_scaledToFit = false;
|
||||
|
@ -130,22 +131,46 @@ void Model::setOffset(const glm::vec3& offset) {
|
|||
void Model::enqueueLocationChange() {
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(_translation);
|
||||
transform.setRotation(_rotation);
|
||||
Transform modelTransform;
|
||||
modelTransform.setScale(_scale);
|
||||
modelTransform.setTranslation(_translation);
|
||||
modelTransform.setRotation(_rotation);
|
||||
|
||||
Transform offset;
|
||||
offset.setScale(_scale);
|
||||
offset.postTranslate(_offset);
|
||||
if (_geometry && _geometry->isLoaded()) {
|
||||
offset = Transform(_rig->getGeometryToRigTransform());
|
||||
} else {
|
||||
offset.postTranslate(_offset);
|
||||
}
|
||||
|
||||
render::PendingChanges pendingChanges;
|
||||
foreach (auto itemID, _renderItems.keys()) {
|
||||
pendingChanges.updateItem<MeshPartPayload>(itemID, [transform, offset](MeshPartPayload& data) {
|
||||
data.updateTransform(transform, offset);
|
||||
foreach (auto itemID, _modelMeshRenderItems.keys()) {
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(itemID, [modelTransform, offset](ModelMeshPartPayload& data) {
|
||||
//data._model->updateClusterMatrices(data._transform.getTranslation(), data._transform.getRotation());
|
||||
const Model::MeshState& state = data._model->_meshStates.at(data._meshIndex);
|
||||
if (state.clusterBuffer) {
|
||||
data.updateTransform(modelTransform, offset);
|
||||
} else {
|
||||
// HACK: check for bugs...
|
||||
AnimPose clusterMat(state.clusterMatrices[0]);
|
||||
|
||||
Transform xform;
|
||||
xform.setScale(clusterMat.scale);
|
||||
xform.setRotation(clusterMat.rot);
|
||||
xform.setTranslation(clusterMat.trans);
|
||||
data.updateTransformForRigidlyBoundMesh(modelTransform, xform, offset);
|
||||
}
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
}
|
||||
|
||||
foreach (auto itemID, _collisionRenderItems.keys()) {
|
||||
pendingChanges.updateItem<MeshPartPayload>(itemID, [modelTransform, offset](MeshPartPayload& data) {
|
||||
data.updateTransform(modelTransform, offset);
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
}
|
||||
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
|
||||
|
@ -497,8 +522,11 @@ void Model::setVisibleInScene(bool newValue, std::shared_ptr<render::Scene> scen
|
|||
_isVisible = newValue;
|
||||
|
||||
render::PendingChanges pendingChanges;
|
||||
foreach (auto item, _renderItems.keys()) {
|
||||
pendingChanges.resetItem(item, _renderItems[item]);
|
||||
foreach (auto item, _modelMeshRenderItems.keys()) {
|
||||
pendingChanges.resetItem(item, _modelMeshRenderItems[item]);
|
||||
}
|
||||
foreach (auto item, _collisionRenderItems.keys()) {
|
||||
pendingChanges.resetItem(item, _modelMeshRenderItems[item]);
|
||||
}
|
||||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
|
@ -514,14 +542,25 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene, render::PendingChan
|
|||
|
||||
bool somethingAdded = false;
|
||||
|
||||
foreach (auto renderItem, _renderItemsSet) {
|
||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_modelMeshRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
foreach (auto renderItem, _collisionRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_renderItems.insert(item, renderPayload);
|
||||
_collisionRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
|
@ -541,7 +580,19 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
|||
|
||||
bool somethingAdded = false;
|
||||
|
||||
foreach (auto renderItem, _renderItemsSet) {
|
||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [](ModelMeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_modelMeshRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
foreach (auto renderItem, _collisionRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||
renderPayload->addStatusGetters(statusGetters);
|
||||
|
@ -549,7 +600,7 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
|||
pendingChanges.updateItem<MeshPartPayload>(item, [](MeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
_renderItems.insert(item, renderPayload);
|
||||
_collisionRenderItems.insert(item, renderPayload);
|
||||
somethingAdded = true;
|
||||
}
|
||||
|
||||
|
@ -559,11 +610,16 @@ bool Model::addToScene(std::shared_ptr<render::Scene> scene,
|
|||
}
|
||||
|
||||
void Model::removeFromScene(std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) {
|
||||
foreach (auto item, _renderItems.keys()) {
|
||||
foreach (auto item, _modelMeshRenderItems.keys()) {
|
||||
pendingChanges.removeItem(item);
|
||||
}
|
||||
_renderItems.clear();
|
||||
_renderItemsSet.clear();
|
||||
_modelMeshRenderItems.clear();
|
||||
_modelMeshRenderItemsSet.clear();
|
||||
foreach (auto item, _collisionRenderItems.keys()) {
|
||||
pendingChanges.removeItem(item);
|
||||
}
|
||||
_collisionRenderItems.clear();
|
||||
_collisionRenderItemsSet.clear();
|
||||
_meshGroupsKnown = false;
|
||||
_readyWhenAdded = false;
|
||||
}
|
||||
|
@ -1191,10 +1247,14 @@ void Model::segregateMeshGroups() {
|
|||
return;
|
||||
}
|
||||
|
||||
Q_ASSERT(_renderItems.isEmpty()); // We should not have any existing renderItems if we enter this section of code
|
||||
Q_ASSERT(_renderItemsSet.isEmpty()); // We should not have any existing renderItemsSet if we enter this section of code
|
||||
// We should not have any existing renderItems if we enter this section of code
|
||||
Q_ASSERT(_modelMeshRenderItems.isEmpty());
|
||||
Q_ASSERT(_modelMeshRenderItemsSet.isEmpty());
|
||||
Q_ASSERT(_collisionRenderItems.isEmpty());
|
||||
Q_ASSERT(_collisionRenderItemsSet.isEmpty());
|
||||
|
||||
_renderItemsSet.clear();
|
||||
_modelMeshRenderItemsSet.clear();
|
||||
_collisionRenderItemsSet.clear();
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(_translation);
|
||||
|
@ -1220,9 +1280,14 @@ void Model::segregateMeshGroups() {
|
|||
_collisionHullMaterial->setMetallic(0.02f);
|
||||
_collisionHullMaterial->setRoughness(0.5f);
|
||||
}
|
||||
_renderItemsSet << std::make_shared<MeshPartPayload>(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset);
|
||||
_collisionRenderItemsSet << std::make_shared<MeshPartPayload>(networkMesh._mesh, partIndex, _collisionHullMaterial, transform, offset);
|
||||
} else {
|
||||
_renderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset);
|
||||
AABox geometrySkinnedMeshBound = _skinnedMeshBound;
|
||||
|
||||
// transform bound from model into geometry space.
|
||||
geometrySkinnedMeshBound.transform(Transform(glm::inverse(_rig->getGeometryToRigTransform())));
|
||||
|
||||
_modelMeshRenderItemsSet << std::make_shared<ModelMeshPartPayload>(this, i, partIndex, shapeID, transform, offset, geometrySkinnedMeshBound);
|
||||
}
|
||||
|
||||
shapeID++;
|
||||
|
@ -1245,13 +1310,21 @@ bool Model::initWhenReady(render::ScenePointer scene) {
|
|||
offset.setScale(_scale);
|
||||
offset.postTranslate(_offset);
|
||||
|
||||
foreach (auto renderItem, _renderItemsSet) {
|
||||
foreach (auto renderItem, _modelMeshRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<ModelMeshPartPayload::Payload>(renderItem);
|
||||
_modelMeshRenderItems.insert(item, renderPayload);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<ModelMeshPartPayload>(item, [transform, offset](MeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
}
|
||||
foreach (auto renderItem, _collisionRenderItemsSet) {
|
||||
auto item = scene->allocateID();
|
||||
auto renderPayload = std::make_shared<MeshPartPayload::Payload>(renderItem);
|
||||
_renderItems.insert(item, renderPayload);
|
||||
_collisionRenderItems.insert(item, renderPayload);
|
||||
pendingChanges.resetItem(item, renderPayload);
|
||||
pendingChanges.updateItem<MeshPartPayload>(item, [transform,offset](MeshPartPayload& data) {
|
||||
data.updateTransform(transform, offset);
|
||||
pendingChanges.updateItem<MeshPartPayload>(item, [transform, offset](MeshPartPayload& data) {
|
||||
data.notifyLocationChanged();
|
||||
});
|
||||
}
|
||||
|
|
|
@ -44,6 +44,7 @@ namespace render {
|
|||
typedef unsigned int ItemID;
|
||||
}
|
||||
class MeshPartPayload;
|
||||
class ModelMeshPartPayload;
|
||||
class ModelRenderLocations;
|
||||
|
||||
inline uint qHash(const std::shared_ptr<MeshPartPayload>& a, uint seed) {
|
||||
|
@ -222,6 +223,9 @@ public:
|
|||
|
||||
const glm::vec3& getRegistrationPoint() const { return _registrationPoint; }
|
||||
|
||||
// bounding box used for mesh that is influnced by multiple animated bones.
|
||||
void setSkinnedMeshBound(const AABox& skinnedMeshBound) { _skinnedMeshBound = skinnedMeshBound; }
|
||||
|
||||
protected:
|
||||
|
||||
void setPupilDilation(float dilation) { _pupilDilation = dilation; }
|
||||
|
@ -371,8 +375,12 @@ protected:
|
|||
bool _renderCollisionHull;
|
||||
|
||||
|
||||
QSet<std::shared_ptr<MeshPartPayload>> _renderItemsSet;
|
||||
QMap<render::ItemID, render::PayloadPointer> _renderItems;
|
||||
QSet<std::shared_ptr<MeshPartPayload>> _collisionRenderItemsSet;
|
||||
QMap<render::ItemID, render::PayloadPointer> _collisionRenderItems;
|
||||
|
||||
QSet<std::shared_ptr<ModelMeshPartPayload>> _modelMeshRenderItemsSet;
|
||||
QMap<render::ItemID, render::PayloadPointer> _modelMeshRenderItems;
|
||||
|
||||
bool _readyWhenAdded { false };
|
||||
bool _needsReload { true };
|
||||
bool _needsUpdateClusterMatrices { true };
|
||||
|
@ -382,6 +390,9 @@ protected:
|
|||
|
||||
friend class ModelMeshPartPayload;
|
||||
RigPointer _rig;
|
||||
|
||||
// 2 meter^3 box
|
||||
AABox _skinnedMeshBound { glm::vec3(-1.0, -1.0, -1.0), glm::vec3(2.0f) };
|
||||
};
|
||||
|
||||
Q_DECLARE_METATYPE(ModelPointer)
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
#include "GeometryUtil.h"
|
||||
#include "NumericalConstants.h"
|
||||
|
||||
const glm::vec3 INFINITY_VECTOR(std::numeric_limits<float>::infinity());
|
||||
|
||||
AABox::AABox(const AACube& other) :
|
||||
_corner(other.getCorner()), _scale(other.getScale(), other.getScale(), other.getScale()) {
|
||||
}
|
||||
|
@ -34,7 +36,7 @@ AABox::AABox(const glm::vec3& corner, const glm::vec3& dimensions) :
|
|||
_corner(corner), _scale(dimensions) {
|
||||
};
|
||||
|
||||
AABox::AABox() : _corner(std::numeric_limits<float>::infinity()), _scale(0.0f) {
|
||||
AABox::AABox() : _corner(INFINITY_VECTOR), _scale(0.0f) {
|
||||
};
|
||||
|
||||
glm::vec3 AABox::calcCenter() const {
|
||||
|
@ -475,8 +477,15 @@ AABox AABox::clamp(float min, float max) const {
|
|||
}
|
||||
|
||||
AABox& AABox::operator += (const glm::vec3& point) {
|
||||
_corner = glm::min(_corner, point);
|
||||
_scale = glm::max(_scale, point - _corner);
|
||||
|
||||
if (_corner == INFINITY_VECTOR) {
|
||||
_corner = glm::min(_corner, point);
|
||||
} else {
|
||||
glm::vec3 maximum(_corner + _scale);
|
||||
_corner = glm::min(_corner, point);
|
||||
maximum = glm::max(maximum, point);
|
||||
_scale = maximum - _corner;
|
||||
}
|
||||
|
||||
return (*this);
|
||||
}
|
||||
|
@ -489,11 +498,25 @@ AABox& AABox::operator += (const AABox& box) {
|
|||
return (*this);
|
||||
}
|
||||
|
||||
void AABox::scale(const glm::vec3& scale) {
|
||||
void AABox::embiggen(float scale) {
|
||||
_corner += scale * (-0.5f * _scale);
|
||||
_scale *= scale;
|
||||
}
|
||||
|
||||
void AABox::embiggen(const glm::vec3& scale) {
|
||||
_corner += scale * (-0.5f * _scale);
|
||||
_scale *= scale;
|
||||
}
|
||||
|
||||
void AABox::scale(float scale) {
|
||||
_corner *= scale;
|
||||
_scale *= scale;
|
||||
}
|
||||
|
||||
void AABox::scale(const glm::vec3& scale) {
|
||||
_corner *= scale;
|
||||
_scale *= scale;
|
||||
}
|
||||
|
||||
void AABox::rotate(const glm::quat& rotation) {
|
||||
auto minimum = _corner;
|
||||
|
|
|
@ -58,7 +58,6 @@ public:
|
|||
const glm::vec3& getMinimumPoint() const { return _corner; }
|
||||
glm::vec3 getMaximumPoint() const { return calcTopFarLeft(); }
|
||||
|
||||
|
||||
bool contains(const glm::vec3& point) const;
|
||||
bool contains(const AABox& otherBox) const;
|
||||
bool touches(const AABox& otherBox) const;
|
||||
|
@ -93,6 +92,10 @@ public:
|
|||
void scale(float scale);
|
||||
void scale(const glm::vec3& scale);
|
||||
|
||||
/// make the AABox bigger (scale about it's center)
|
||||
void embiggen(float scale);
|
||||
void embiggen(const glm::vec3& scale);
|
||||
|
||||
// Transform the extents with transform
|
||||
void transform(const Transform& transform);
|
||||
|
||||
|
|
|
@ -151,3 +151,15 @@ void AABoxTests::testTouchesSphere() {
|
|||
}
|
||||
}
|
||||
|
||||
void AABoxTests::testScale() {
|
||||
AABox box(glm::vec3(2.0f), glm::vec3(1.0f));
|
||||
QCOMPARE(box.contains(glm::vec3(0.0f)), false);
|
||||
box.scale(glm::vec3(10.0f));
|
||||
QCOMPARE(box.contains(glm::vec3(0.0f)), false);
|
||||
QCOMPARE(box.contains(glm::vec3(2.0f * 10.0f)), true);
|
||||
|
||||
AABox box(glm::vec3(2.0f), glm::vec3(1.0f));
|
||||
QCOMPARE(box.contains(glm::vec3(0.0f)), false);
|
||||
box.embiggen(glm::vec3(10.0f));
|
||||
QCOMPARE(box.contains(glm::vec3(0.0f)), false);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ private slots:
|
|||
void testCtorsAndSetters();
|
||||
void testContainsPoint();
|
||||
void testTouchesSphere();
|
||||
void testScale();
|
||||
};
|
||||
|
||||
#endif // hifi_AABoxTests_h
|
||||
|
|
Loading…
Reference in a new issue