Merge pull request #7251 from sethalves/fix-hulls-for-non-default-registration

fix collisions with non-default registration
This commit is contained in:
Andrew Meadows 2016-03-07 15:46:13 -08:00
commit 592d29fc7c
7 changed files with 78 additions and 29 deletions

View file

@ -336,6 +336,33 @@ bool RenderableModelEntityItem::getAnimationFrame() {
return newFrame;
}
void RenderableModelEntityItem::updateModelBounds() {
if (!hasModel() || !_model) {
return;
}
bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething();
if ((movingOrAnimating ||
_needsInitialSimulation ||
_model->getTranslation() != getPosition() ||
_model->getRotation() != getRotation() ||
_model->getRegistrationPoint() != getRegistrationPoint())
&& _model->isActive() && _dimensionsInitialized) {
_model->setScaleToFit(true, getDimensions());
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
// make sure to simulate so everything gets set up correctly for rendering
{
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsInitialSimulation = false;
}
}
// NOTE: this only renders the "meta" portion of the Model, namely it renders debugging items, and it handles
// the per frame simulation/update that might be required if the models properties changed.
void RenderableModelEntityItem::render(RenderArgs* args) {
@ -414,27 +441,7 @@ void RenderableModelEntityItem::render(RenderArgs* args) {
}
}
});
bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething();
if ((movingOrAnimating ||
_needsInitialSimulation ||
_model->getTranslation() != getPosition() ||
_model->getRotation() != getRotation() ||
_model->getRegistrationPoint() != getRegistrationPoint())
&& _model->isActive() && _dimensionsInitialized) {
_model->setScaleToFit(true, getDimensions());
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation());
_model->setTranslation(getPosition());
// make sure to simulate so everything gets set up correctly for rendering
{
PerformanceTimer perfTimer("_model->simulate");
_model->simulate(0.0f);
}
_needsInitialSimulation = false;
}
updateModelBounds();
}
}
} else {
@ -598,7 +605,9 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
if (type != SHAPE_TYPE_COMPOUND) {
ModelEntityItem::computeShapeInfo(info);
info.setParams(type, 0.5f * getDimensions());
adjustShapeInfoByRegistration(info);
} else {
updateModelBounds();
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
// should never fall in here when collision model not fully loaded
@ -690,10 +699,13 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
AABox box;
for (int i = 0; i < _points.size(); i++) {
for (int j = 0; j < _points[i].size(); j++) {
// compensate for registraion
// compensate for registration
_points[i][j] += _model->getOffset();
// scale so the collision points match the model points
_points[i][j] *= scale;
// this next subtraction is done so we can give info the offset, which will cause
// the shape-key to change.
_points[i][j] -= _model->getOffset();
box += _points[i][j];
}
}
@ -701,6 +713,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
glm::vec3 collisionModelDimensions = box.getDimensions();
info.setParams(type, collisionModelDimensions, _compoundShapeURL);
info.setConvexHulls(_points);
info.setOffset(_model->getOffset());
}
}

View file

@ -49,6 +49,7 @@ public:
virtual void removeFromScene(EntityItemPointer self, std::shared_ptr<render::Scene> scene, render::PendingChanges& pendingChanges) override;
void updateModelBounds();
virtual void render(RenderArgs* args) override;
virtual bool supportsDetailedRayIntersection() const override { return true; }
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,

View file

@ -142,7 +142,7 @@ glm::vec3 RenderablePolyVoxEntityItem::getSurfacePositionAdjustment() const {
glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
glm::vec3 scale = getDimensions() / _voxelVolumeSize; // meters / voxel-units
bool success; // TODO -- Does this actually have to happen in world space?
glm::vec3 center = getCenterPosition(success);
glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes
glm::vec3 position = getPosition(success);
glm::vec3 positionToCenter = center - position;
@ -430,6 +430,13 @@ ShapeType RenderablePolyVoxEntityItem::getShapeType() const {
return SHAPE_TYPE_COMPOUND;
}
void RenderablePolyVoxEntityItem::updateRegistrationPoint(const glm::vec3& value) {
if (value != _registrationPoint) {
_meshDirty = true;
EntityItem::updateRegistrationPoint(value);
}
}
bool RenderablePolyVoxEntityItem::isReadyToComputeShape() {
_meshLock.lockForRead();
if (_meshDirty) {
@ -1224,10 +1231,16 @@ void RenderablePolyVoxEntityItem::computeShapeInfoWorkerAsync() {
}
glm::vec3 collisionModelDimensions = box.getDimensions();
QByteArray b64 = _voxelData.toBase64();
// include the registrationPoint in the shape key, because the offset is already
// included in the points and the shapeManager wont know that the shape has changed.
QString shapeKey = QString(_voxelData.toBase64()) + "," +
QString::number(_registrationPoint.x) + "," +
QString::number(_registrationPoint.y) + "," +
QString::number(_registrationPoint.z);
_shapeInfoLock.lockForWrite();
_shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, QString(b64));
_shapeInfo.setParams(SHAPE_TYPE_COMPOUND, collisionModelDimensions, shapeKey);
_shapeInfo.setConvexHulls(points);
// adjustShapeInfoByRegistration(_shapeInfo);
_shapeInfoLock.unlock();
_meshLock.lockForWrite();

View file

@ -116,6 +116,8 @@ public:
virtual void rebakeMesh();
virtual void updateRegistrationPoint(const glm::vec3& value);
private:
// The PolyVoxEntityItem class has _voxelData which contains dimensions and compressed voxel data. The dimensions
// may not match _voxelVolumeSize.

View file

@ -677,7 +677,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
READ_ENTITY_PROPERTY(PROP_LIFETIME, float, updateLifetime);
READ_ENTITY_PROPERTY(PROP_SCRIPT, QString, setScript);
READ_ENTITY_PROPERTY(PROP_SCRIPT_TIMESTAMP, quint64, setScriptTimestamp);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, setRegistrationPoint);
READ_ENTITY_PROPERTY(PROP_REGISTRATION_POINT, glm::vec3, updateRegistrationPoint);
READ_ENTITY_PROPERTY(PROP_ANGULAR_DAMPING, float, updateAngularDamping);
READ_ENTITY_PROPERTY(PROP_VISIBLE, bool, setVisible);
@ -1120,7 +1120,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) {
// these (along with "position" above) affect tree structure
SET_ENTITY_PROPERTY_FROM_PROPERTIES(dimensions, updateDimensions);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, setRegistrationPoint);
SET_ENTITY_PROPERTY_FROM_PROPERTIES(registrationPoint, updateRegistrationPoint);
// these (along with all properties above) affect the simulation
SET_ENTITY_PROPERTY_FROM_PROPERTIES(density, updateDensity);
@ -1340,6 +1340,15 @@ float EntityItem::getRadius() const {
return 0.5f * glm::length(getDimensions());
}
void EntityItem::adjustShapeInfoByRegistration(ShapeInfo& info) const {
if (_registrationPoint != ENTITY_ITEM_DEFAULT_REGISTRATION_POINT) {
glm::mat4 scale = glm::scale(getDimensions());
glm::mat4 registration = scale * glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
glm::vec3 regTransVec = glm::vec3(registration[3]); // extract position component from matrix
info.setOffset(regTransVec);
}
}
bool EntityItem::contains(const glm::vec3& point) const {
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
bool success;
@ -1348,12 +1357,21 @@ bool EntityItem::contains(const glm::vec3& point) const {
} else {
ShapeInfo info;
info.setParams(getShapeType(), glm::vec3(0.5f));
adjustShapeInfoByRegistration(info);
return info.contains(worldToEntity(point));
}
}
void EntityItem::computeShapeInfo(ShapeInfo& info) {
info.setParams(getShapeType(), 0.5f * getDimensions());
adjustShapeInfoByRegistration(info);
}
void EntityItem::updateRegistrationPoint(const glm::vec3& value) {
if (value != _registrationPoint) {
setRegistrationPoint(value);
_dirtyFlags |= Simulation::DIRTY_SHAPE;
}
}
void EntityItem::updatePosition(const glm::vec3& value) {

View file

@ -305,6 +305,7 @@ public:
// TODO: get rid of users of getRadius()...
float getRadius() const;
virtual void adjustShapeInfoByRegistration(ShapeInfo& info) const;
virtual bool contains(const glm::vec3& point) const;
virtual bool isReadyToComputeShape() { return !isDead(); }
@ -319,6 +320,7 @@ public:
virtual void setRotation(glm::quat orientation) { setOrientation(orientation); }
// updateFoo() methods to be used when changes need to be accumulated in the _dirtyFlags
virtual void updateRegistrationPoint(const glm::vec3& value);
void updatePosition(const glm::vec3& value);
void updatePositionFromNetwork(const glm::vec3& value);
void updateDimensions(const glm::vec3& value);

View file

@ -106,11 +106,11 @@ btCollisionShape* ShapeFactory::createShapeFromInfo(const ShapeInfo& info) {
}
break;
}
if (shape && type != SHAPE_TYPE_COMPOUND) {
if (shape) {
if (glm::length2(info.getOffset()) > MIN_SHAPE_OFFSET * MIN_SHAPE_OFFSET) {
// this shape has an offset, which we support by wrapping the true shape
// in a btCompoundShape with a local transform
auto compound = new btCompoundShape();
auto compound = new btCompoundShape();
btTransform trans;
trans.setIdentity();
trans.setOrigin(glmToBullet(info.getOffset()));