mirror of
https://github.com/lubosz/overte.git
synced 2025-04-10 15:57:39 +02:00
Add TransformNode-based parenting and implement for CollisionPicks
This commit is contained in:
parent
68b86963d4
commit
6e160ad22f
12 changed files with 184 additions and 24 deletions
|
@ -86,7 +86,7 @@ QVariantMap CollisionPickResult::toVariantMap() const {
|
|||
return variantMap;
|
||||
}
|
||||
|
||||
bool CollisionPick::isShapeInfoReady() {
|
||||
bool CollisionPick::getShapeInfoReady() {
|
||||
if (_mathPick.shouldComputeShapeInfo()) {
|
||||
if (_cachedResource && _cachedResource->isLoaded()) {
|
||||
computeShapeInfo(_mathPick, *_mathPick.shapeInfo, _cachedResource);
|
||||
|
@ -95,8 +95,23 @@ bool CollisionPick::isShapeInfoReady() {
|
|||
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
computeShapeInfoDimensionsOnly(_mathPick, *_mathPick.shapeInfo, _cachedResource);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
void CollisionPick::computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource) {
|
||||
ShapeType type = shapeInfo.getType();
|
||||
glm::vec3 dimensions = pick.transform.getScale();
|
||||
QString modelURL = (resource ? resource->getURL().toString() : "");
|
||||
if (type == SHAPE_TYPE_COMPOUND) {
|
||||
shapeInfo.setParams(type, dimensions, modelURL);
|
||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||
shapeInfo.setParams(type, 0.5f * dimensions, modelURL);
|
||||
} else {
|
||||
shapeInfo.setParams(type, 0.5f * dimensions, modelURL);
|
||||
}
|
||||
}
|
||||
|
||||
void CollisionPick::computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource) {
|
||||
|
@ -328,8 +343,23 @@ void CollisionPick::computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo
|
|||
}
|
||||
}
|
||||
|
||||
CollisionPick::CollisionPick(const PickFilter& filter, float maxDistance, bool enabled, CollisionRegion collisionRegion, PhysicsEnginePointer physicsEngine) :
|
||||
Pick(filter, maxDistance, enabled),
|
||||
_mathPick(collisionRegion),
|
||||
_physicsEngine(physicsEngine) {
|
||||
if (collisionRegion.shouldComputeShapeInfo()) {
|
||||
_cachedResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(collisionRegion.modelURL);
|
||||
}
|
||||
}
|
||||
|
||||
CollisionRegion CollisionPick::getMathematicalPick() const {
|
||||
return _mathPick;
|
||||
if (!parentTransform) {
|
||||
return _mathPick;
|
||||
} else {
|
||||
CollisionRegion transformedMathPick = _mathPick;
|
||||
transformedMathPick.transform = parentTransform->getTransform().worldTransform(_mathPick.transform);
|
||||
return transformedMathPick;
|
||||
}
|
||||
}
|
||||
|
||||
void CollisionPick::filterIntersections(std::vector<ContactTestResult>& intersections) const {
|
||||
|
@ -356,7 +386,7 @@ void CollisionPick::filterIntersections(std::vector<ContactTestResult>& intersec
|
|||
}
|
||||
|
||||
PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pick) {
|
||||
if (!isShapeInfoReady()) {
|
||||
if (!getShapeInfoReady()) {
|
||||
// Cannot compute result
|
||||
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
||||
}
|
||||
|
@ -367,13 +397,13 @@ PickResultPointer CollisionPick::getEntityIntersection(const CollisionRegion& pi
|
|||
}
|
||||
|
||||
PickResultPointer CollisionPick::getOverlayIntersection(const CollisionRegion& pick) {
|
||||
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), isShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
||||
return std::make_shared<CollisionPickResult>(pick, getShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
||||
}
|
||||
|
||||
PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pick) {
|
||||
if (!isShapeInfoReady()) {
|
||||
if (!getShapeInfoReady()) {
|
||||
// Cannot compute result
|
||||
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
||||
return std::make_shared<CollisionPickResult>(pick, CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
||||
}
|
||||
|
||||
auto avatarIntersections = _physicsEngine->contactTest(USER_COLLISION_MASK_AVATARS, *pick.shapeInfo, pick.transform);
|
||||
|
@ -382,5 +412,16 @@ PickResultPointer CollisionPick::getAvatarIntersection(const CollisionRegion& pi
|
|||
}
|
||||
|
||||
PickResultPointer CollisionPick::getHUDIntersection(const CollisionRegion& pick) {
|
||||
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), isShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
||||
return std::make_shared<CollisionPickResult>(pick.toVariantMap(), getShapeInfoReady() ? CollisionPickResult::LOAD_STATE_LOADED : CollisionPickResult::LOAD_STATE_NOT_LOADED, std::vector<ContactTestResult>(), std::vector<ContactTestResult>());
|
||||
}
|
||||
|
||||
Transform CollisionPick::getResultTransform() const {
|
||||
PickResultPointer result = getPrevPickResult();
|
||||
if (!result) {
|
||||
return Transform();
|
||||
}
|
||||
|
||||
Transform transform;
|
||||
transform.setTranslation(getMathematicalPick().transform.getTranslation());
|
||||
return transform;
|
||||
}
|
|
@ -11,6 +11,7 @@
|
|||
#include <PhysicsEngine.h>
|
||||
#include <model-networking/ModelCache.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
#include <TransformNode.h>
|
||||
#include <Pick.h>
|
||||
|
||||
class CollisionPickResult : public PickResult {
|
||||
|
@ -24,12 +25,17 @@ public:
|
|||
CollisionPickResult() {}
|
||||
CollisionPickResult(const QVariantMap& pickVariant) : PickResult(pickVariant) {}
|
||||
|
||||
CollisionPickResult(const CollisionRegion& searchRegion, LoadState loadState, const std::vector<ContactTestResult>& entityIntersections, const std::vector<ContactTestResult>& avatarIntersections) :
|
||||
CollisionPickResult(const CollisionRegion& searchRegion,
|
||||
LoadState loadState,
|
||||
const std::vector<ContactTestResult>& entityIntersections,
|
||||
const std::vector<ContactTestResult>& avatarIntersections
|
||||
) :
|
||||
PickResult(searchRegion.toVariantMap()),
|
||||
loadState(loadState),
|
||||
intersects(entityIntersections.size() || avatarIntersections.size()),
|
||||
entityIntersections(entityIntersections),
|
||||
avatarIntersections(avatarIntersections) {
|
||||
avatarIntersections(avatarIntersections)
|
||||
{
|
||||
}
|
||||
|
||||
CollisionPickResult(const CollisionPickResult& collisionPickResult) : PickResult(collisionPickResult.pickVariant) {
|
||||
|
@ -54,14 +60,7 @@ public:
|
|||
|
||||
class CollisionPick : public Pick<CollisionRegion> {
|
||||
public:
|
||||
CollisionPick(const PickFilter& filter, float maxDistance, bool enabled, CollisionRegion collisionRegion, PhysicsEnginePointer physicsEngine) :
|
||||
Pick(filter, maxDistance, enabled),
|
||||
_mathPick(collisionRegion),
|
||||
_physicsEngine(physicsEngine) {
|
||||
if (collisionRegion.shouldComputeShapeInfo()) {
|
||||
_cachedResource = DependencyManager::get<ModelCache>()->getCollisionGeometryResource(collisionRegion.modelURL);
|
||||
}
|
||||
}
|
||||
CollisionPick(const PickFilter& filter, float maxDistance, bool enabled, CollisionRegion collisionRegion, PhysicsEnginePointer physicsEngine);
|
||||
|
||||
CollisionRegion getMathematicalPick() const override;
|
||||
PickResultPointer getDefaultResult(const QVariantMap& pickVariant) const override {
|
||||
|
@ -71,11 +70,12 @@ public:
|
|||
PickResultPointer getOverlayIntersection(const CollisionRegion& pick) override;
|
||||
PickResultPointer getAvatarIntersection(const CollisionRegion& pick) override;
|
||||
PickResultPointer getHUDIntersection(const CollisionRegion& pick) override;
|
||||
|
||||
Transform getResultTransform() const override;
|
||||
protected:
|
||||
// Returns true if pick.shapeInfo is valid. Otherwise, attempts to get the shapeInfo ready for use.
|
||||
bool isShapeInfoReady();
|
||||
bool getShapeInfoReady();
|
||||
void computeShapeInfo(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource);
|
||||
void computeShapeInfoDimensionsOnly(CollisionRegion& pick, ShapeInfo& shapeInfo, QSharedPointer<GeometryResource> resource);
|
||||
void filterIntersections(std::vector<ContactTestResult>& intersections) const;
|
||||
|
||||
CollisionRegion _mathPick;
|
||||
|
|
|
@ -67,4 +67,16 @@ glm::vec3 ParabolaPick::getAcceleration() const {
|
|||
return scale * (DependencyManager::get<AvatarManager>()->getMyAvatar()->getWorldOrientation() * _accelerationAxis);
|
||||
}
|
||||
return scale * _accelerationAxis;
|
||||
}
|
||||
|
||||
Transform ParabolaPick::getResultTransform() const {
|
||||
PickResultPointer result = getPrevPickResult();
|
||||
if (!result) {
|
||||
return Transform();
|
||||
}
|
||||
|
||||
auto parabolaResult = std::static_pointer_cast<ParabolaPickResult>(result);
|
||||
Transform transform;
|
||||
transform.setTranslation(parabolaResult->intersection);
|
||||
return transform;
|
||||
}
|
|
@ -83,6 +83,7 @@ public:
|
|||
PickResultPointer getOverlayIntersection(const PickParabola& pick) override;
|
||||
PickResultPointer getAvatarIntersection(const PickParabola& pick) override;
|
||||
PickResultPointer getHUDIntersection(const PickParabola& pick) override;
|
||||
Transform getResultTransform() const override;
|
||||
|
||||
protected:
|
||||
float _speed;
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
#include "MouseParabolaPick.h"
|
||||
#include "CollisionPick.h"
|
||||
|
||||
#include "SpatialParentFinder.h"
|
||||
#include "NestableTransformNode.h"
|
||||
#include "PickTransformNode.h"
|
||||
#include "MouseTransformNode.h"
|
||||
#include "avatar/MyAvatarHeadTransformNode.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
|
||||
#include <ScriptEngine.h>
|
||||
|
||||
unsigned int PickScriptingInterface::createPick(const PickQuery::PickType type, const QVariant& properties) {
|
||||
|
@ -276,8 +283,10 @@ unsigned int PickScriptingInterface::createCollisionPick(const QVariant& propert
|
|||
}
|
||||
|
||||
CollisionRegion collisionRegion(propMap);
|
||||
auto collisionPick = std::make_shared<CollisionPick>(filter, maxDistance, enabled, collisionRegion, qApp->getPhysicsEngine());
|
||||
collisionPick->parentTransform = createTransformNode(propMap);
|
||||
|
||||
return DependencyManager::get<PickManager>()->addPick(PickQuery::Collision, std::make_shared<CollisionPick>(filter, maxDistance, enabled, collisionRegion, qApp->getPhysicsEngine()));
|
||||
return DependencyManager::get<PickManager>()->addPick(PickQuery::Collision, collisionPick);
|
||||
}
|
||||
|
||||
void PickScriptingInterface::enablePick(unsigned int uid) {
|
||||
|
@ -351,3 +360,42 @@ unsigned int PickScriptingInterface::getPerFrameTimeBudget() const {
|
|||
void PickScriptingInterface::setPerFrameTimeBudget(unsigned int numUsecs) {
|
||||
DependencyManager::get<PickManager>()->setPerFrameTimeBudget(numUsecs);
|
||||
}
|
||||
|
||||
std::shared_ptr<TransformNode> PickScriptingInterface::createTransformNode(const QVariantMap& propMap) {
|
||||
if (propMap["parentID"].isValid()) {
|
||||
QUuid parentUuid = propMap["parentID"].toUuid();
|
||||
if (!parentUuid.isNull()) {
|
||||
// Infer object type from parentID
|
||||
// For now, assume a QUuuid is a SpatiallyNestable. This should change when picks are converted over to QUuids.
|
||||
bool success;
|
||||
std::weak_ptr<SpatiallyNestable> nestablePointer = DependencyManager::get<SpatialParentFinder>()->find(parentUuid, success, nullptr);
|
||||
int parentJointIndex = 0;
|
||||
if (propMap["parentJointIndex"].isValid()) {
|
||||
parentJointIndex = propMap["parentJointIndex"].toInt();
|
||||
}
|
||||
if (success && !nestablePointer.expired()) {
|
||||
return std::make_shared<NestableTransformNode>(nestablePointer, parentJointIndex);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned int pickID = propMap["parentID"].toUInt();
|
||||
if (pickID != 0) {
|
||||
return std::make_shared<PickTransformNode>(pickID);
|
||||
}
|
||||
}
|
||||
|
||||
if (propMap["joint"].isValid()) {
|
||||
QString joint = propMap["joint"].toString();
|
||||
if (joint == "Mouse") {
|
||||
return std::make_shared<MouseTransformNode>();
|
||||
} else if (joint == "Avatar") {
|
||||
return std::make_shared<MyAvatarHeadTransformNode>();
|
||||
} else if (!joint.isNull()) {
|
||||
auto myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
int jointIndex = myAvatar->getJointIndex(joint);
|
||||
return std::make_shared<NestableTransformNode>(myAvatar, jointIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return std::shared_ptr<TransformNode>();
|
||||
}
|
|
@ -320,6 +320,9 @@ public slots:
|
|||
* @returns {number}
|
||||
*/
|
||||
static constexpr unsigned int INTERSECTED_HUD() { return IntersectionType::HUD; }
|
||||
|
||||
protected:
|
||||
static std::shared_ptr<TransformNode> createTransformNode(const QVariantMap& propMap);
|
||||
};
|
||||
|
||||
#endif // hifi_PickScriptingInterface_h
|
||||
|
|
|
@ -50,6 +50,18 @@ PickResultPointer RayPick::getHUDIntersection(const PickRay& pick) {
|
|||
return std::make_shared<RayPickResult>(IntersectionType::HUD, QUuid(), glm::distance(pick.origin, hudRes), hudRes, pick);
|
||||
}
|
||||
|
||||
Transform RayPick::getResultTransform() const {
|
||||
PickResultPointer result = getPrevPickResult();
|
||||
if (!result) {
|
||||
return Transform();
|
||||
}
|
||||
|
||||
auto rayResult = std::static_pointer_cast<RayPickResult>(result);
|
||||
Transform transform;
|
||||
transform.setTranslation(rayResult->intersection);
|
||||
return transform;
|
||||
}
|
||||
|
||||
glm::vec3 RayPick::intersectRayWithXYPlane(const glm::vec3& origin, const glm::vec3& direction, const glm::vec3& point, const glm::quat& rotation, const glm::vec3& registration) {
|
||||
// TODO: take into account registration
|
||||
glm::vec3 n = rotation * Vectors::FRONT;
|
||||
|
|
|
@ -77,6 +77,7 @@ public:
|
|||
PickResultPointer getOverlayIntersection(const PickRay& pick) override;
|
||||
PickResultPointer getAvatarIntersection(const PickRay& pick) override;
|
||||
PickResultPointer getHUDIntersection(const PickRay& pick) override;
|
||||
Transform getResultTransform() const override;
|
||||
|
||||
// These are helper functions for projecting and intersecting rays
|
||||
static glm::vec3 intersectRayWithEntityXYPlane(const QUuid& entityID, const glm::vec3& origin, const glm::vec3& direction);
|
||||
|
|
|
@ -225,4 +225,16 @@ PickResultPointer StylusPick::getAvatarIntersection(const StylusTip& pick) {
|
|||
|
||||
PickResultPointer StylusPick::getHUDIntersection(const StylusTip& pick) {
|
||||
return std::make_shared<StylusPickResult>(pick.toVariantMap());
|
||||
}
|
||||
|
||||
Transform StylusPick::getResultTransform() const {
|
||||
PickResultPointer result = getPrevPickResult();
|
||||
if (!result) {
|
||||
return Transform();
|
||||
}
|
||||
|
||||
auto stylusResult = std::static_pointer_cast<StylusPickResult>(result);
|
||||
Transform transform;
|
||||
transform.setTranslation(stylusResult->intersection);
|
||||
return transform;
|
||||
}
|
|
@ -66,6 +66,7 @@ public:
|
|||
PickResultPointer getOverlayIntersection(const StylusTip& pick) override;
|
||||
PickResultPointer getAvatarIntersection(const StylusTip& pick) override;
|
||||
PickResultPointer getHUDIntersection(const StylusTip& pick) override;
|
||||
Transform getResultTransform() const override;
|
||||
|
||||
bool isLeftHand() const override { return _side == Side::Left; }
|
||||
bool isRightHand() const override { return _side == Side::Right; }
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include <QVariant>
|
||||
|
||||
#include <shared/ReadWriteLockable.h>
|
||||
#include <Transform.h>
|
||||
#include <TransformNode.h>
|
||||
|
||||
enum IntersectionType {
|
||||
NONE = 0,
|
||||
|
@ -214,6 +214,10 @@ public:
|
|||
virtual bool isRightHand() const { return false; }
|
||||
virtual bool isMouse() const { return false; }
|
||||
|
||||
virtual Transform getResultTransform() const = 0;
|
||||
|
||||
std::shared_ptr<TransformNode> parentTransform;
|
||||
|
||||
private:
|
||||
PickFilter _filter;
|
||||
const float _maxDistance;
|
||||
|
|
|
@ -258,8 +258,11 @@ public:
|
|||
|
||||
* @typedef {object} CollisionPick
|
||||
* @property {Shape} shape - The information about the collision region's size and shape.
|
||||
* @property {Vec3} position - The position of the collision region.
|
||||
* @property {Quat} orientation - The orientation of the collision region.
|
||||
* @property {Vec3} position - The position of the collision region, relative to a parent if defined.
|
||||
* @property {Quat} orientation - The orientation of the collision region, relative to a parent if defined.
|
||||
* @property {Uuid} parentID - The ID of the parent, either an avatar, an entity, or an overlay.
|
||||
* @property {number} parentJointIndex - The joint of the parent to parent to, for example, the joints on the model of an avatar. (default = 0, no joint)
|
||||
* @property {string} joint - If "Mouse," parents the pick to the mouse. If "Head," parents the pick to MyAvatar's head. Otherwise, parents to the joint of the given name on MyAvatar.
|
||||
*/
|
||||
class CollisionRegion : public MathPick {
|
||||
public:
|
||||
|
@ -305,6 +308,15 @@ public:
|
|||
if (pickVariant["orientation"].isValid()) {
|
||||
transform.setRotation(quatFromVariant(pickVariant["orientation"]));
|
||||
}
|
||||
if (pickVariant["parentID"].isValid()) {
|
||||
parentID = pickVariant["parentID"].toString();
|
||||
}
|
||||
if (pickVariant["parentJointIndex"].isValid()) {
|
||||
parentJointIndex = pickVariant["parentJointIndex"].toInt();
|
||||
}
|
||||
if (pickVariant["joint"].isValid()) {
|
||||
joint = pickVariant["joint"].toString();
|
||||
}
|
||||
}
|
||||
|
||||
QVariantMap toVariantMap() const override {
|
||||
|
@ -320,6 +332,14 @@ public:
|
|||
collisionRegion["position"] = vec3toVariant(transform.getTranslation());
|
||||
collisionRegion["orientation"] = quatToVariant(transform.getRotation());
|
||||
|
||||
if (!parentID.isNull()) {
|
||||
collisionRegion["parentID"] = parentID;
|
||||
}
|
||||
collisionRegion["parentJointIndex"] = parentJointIndex;
|
||||
if (!joint.isNull()) {
|
||||
collisionRegion["joint"] = joint;
|
||||
}
|
||||
|
||||
return collisionRegion;
|
||||
}
|
||||
|
||||
|
@ -354,6 +374,11 @@ public:
|
|||
// We can't compute the shapeInfo here without loading the model first, so we delegate that responsibility to the owning CollisionPick
|
||||
std::shared_ptr<ShapeInfo> shapeInfo = std::make_shared<ShapeInfo>();
|
||||
Transform transform;
|
||||
|
||||
// Parenting information
|
||||
QUuid parentID;
|
||||
int parentJointIndex = 0;
|
||||
QString joint;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
|
|
Loading…
Reference in a new issue