mirror of
https://github.com/Armored-Dragon/overte.git
synced 2025-03-11 16:13:16 +01:00
Better head vs camera checks for avatar head cauterization
* cameraInsideHead() check now uses detailed avatar collision when possible. * head is now more constantly hidden in first person camera mode * getEyeModelPositions() uses a better estimate when avatar eye joints are missing. * moved findPointKDopDisplacement from Rig.cpp into AnimUtil.cpp * added isPlayingOverrideAnimation() method to Rig class
This commit is contained in:
parent
c902e8392c
commit
02d5769991
7 changed files with 112 additions and 95 deletions
|
@ -3180,17 +3180,40 @@ int MyAvatar::sendAvatarDataPacket(bool sendAll) {
|
|||
return bytesSent;
|
||||
}
|
||||
|
||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.47f;
|
||||
|
||||
bool MyAvatar::cameraInsideHead(const glm::vec3& cameraPosition) const {
|
||||
if (!_skeletonModel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// transform cameraPosition into rig coordinates
|
||||
AnimPose rigToWorld = AnimPose(getWorldOrientation() * Quaternions::Y_180, getWorldPosition());
|
||||
AnimPose worldToRig = rigToWorld.inverse();
|
||||
glm::vec3 rigCameraPosition = worldToRig * cameraPosition;
|
||||
|
||||
// use head k-dop shape to determine if camera is inside head.
|
||||
const Rig& rig = _skeletonModel->getRig();
|
||||
int headJointIndex = rig.indexOfJoint("Head");
|
||||
if (headJointIndex >= 0) {
|
||||
const HFMModel& hfmModel = _skeletonModel->getHFMModel();
|
||||
AnimPose headPose;
|
||||
if (rig.getAbsoluteJointPoseInRigFrame(headJointIndex, headPose)) {
|
||||
glm::vec3 displacement;
|
||||
const HFMJointShapeInfo& headShapeInfo = hfmModel.joints[headJointIndex].shapeInfo;
|
||||
return findPointKDopDisplacement(rigCameraPosition, headPose, headShapeInfo, displacement);
|
||||
}
|
||||
}
|
||||
|
||||
// fall back to simple distance check.
|
||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.47f;
|
||||
return glm::length(cameraPosition - getHeadPosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getModelScale());
|
||||
}
|
||||
|
||||
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||
bool defaultMode = renderArgs->_renderMode == RenderArgs::DEFAULT_RENDER_MODE;
|
||||
bool firstPerson = qApp->getCamera().getMode() == CAMERA_MODE_FIRST_PERSON;
|
||||
bool overrideAnim = _skeletonModel ? _skeletonModel->getRig().isPlayingOverrideAnimation() : false;
|
||||
bool insideHead = cameraInsideHead(renderArgs->getViewFrustum().getPosition());
|
||||
return !defaultMode || !firstPerson || !insideHead;
|
||||
return !defaultMode || (!firstPerson && !insideHead) || (overrideAnim && !insideHead);
|
||||
}
|
||||
|
||||
void MyAvatar::setHasScriptedBlendshapes(bool hasScriptedBlendshapes) {
|
||||
|
|
|
@ -142,3 +142,72 @@ glm::quat computeBodyFacingFromHead(const glm::quat& headRot, const glm::vec3& u
|
|||
|
||||
return glmExtractRotation(bodyMat);
|
||||
}
|
||||
|
||||
|
||||
const float INV_SQRT_3 = 1.0f / sqrtf(3.0f);
|
||||
const int DOP14_COUNT = 14;
|
||||
const glm::vec3 DOP14_NORMALS[DOP14_COUNT] = {
|
||||
Vectors::UNIT_X,
|
||||
-Vectors::UNIT_X,
|
||||
Vectors::UNIT_Y,
|
||||
-Vectors::UNIT_Y,
|
||||
Vectors::UNIT_Z,
|
||||
-Vectors::UNIT_Z,
|
||||
glm::vec3(INV_SQRT_3, INV_SQRT_3, INV_SQRT_3),
|
||||
-glm::vec3(INV_SQRT_3, INV_SQRT_3, INV_SQRT_3),
|
||||
glm::vec3(INV_SQRT_3, -INV_SQRT_3, INV_SQRT_3),
|
||||
-glm::vec3(INV_SQRT_3, -INV_SQRT_3, INV_SQRT_3),
|
||||
glm::vec3(INV_SQRT_3, INV_SQRT_3, -INV_SQRT_3),
|
||||
-glm::vec3(INV_SQRT_3, INV_SQRT_3, -INV_SQRT_3),
|
||||
glm::vec3(INV_SQRT_3, -INV_SQRT_3, -INV_SQRT_3),
|
||||
-glm::vec3(INV_SQRT_3, -INV_SQRT_3, -INV_SQRT_3)
|
||||
};
|
||||
|
||||
// returns true if the given point lies inside of the k-dop, specified by shapeInfo & shapePose.
|
||||
// if the given point does lie within the k-dop, it also returns the amount of displacement necessary to push that point outward
|
||||
// such that it lies on the surface of the kdop.
|
||||
bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& shapePose, const HFMJointShapeInfo& shapeInfo, glm::vec3& displacementOut) {
|
||||
|
||||
// transform point into local space of jointShape.
|
||||
glm::vec3 localPoint = shapePose.inverse().xformPoint(point);
|
||||
|
||||
// Only works for 14-dop shape infos.
|
||||
if (shapeInfo.dots.size() != DOP14_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::vec3 minDisplacement(FLT_MAX);
|
||||
float minDisplacementLen = FLT_MAX;
|
||||
glm::vec3 p = localPoint - shapeInfo.avgPoint;
|
||||
float pLen = glm::length(p);
|
||||
if (pLen > 0.0f) {
|
||||
int slabCount = 0;
|
||||
for (int i = 0; i < DOP14_COUNT; i++) {
|
||||
float dot = glm::dot(p, DOP14_NORMALS[i]);
|
||||
if (dot > 0.0f && dot < shapeInfo.dots[i]) {
|
||||
slabCount++;
|
||||
float distToPlane = pLen * (shapeInfo.dots[i] / dot);
|
||||
float displacementLen = distToPlane - pLen;
|
||||
|
||||
// keep track of the smallest displacement
|
||||
if (displacementLen < minDisplacementLen) {
|
||||
minDisplacementLen = displacementLen;
|
||||
minDisplacement = (p / pLen) * displacementLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (slabCount == (DOP14_COUNT / 2) && minDisplacementLen != FLT_MAX) {
|
||||
// we are within the k-dop so push the point along the minimum displacement found
|
||||
displacementOut = shapePose.xformVectorFast(minDisplacement);
|
||||
return true;
|
||||
} else {
|
||||
// point is outside of kdop
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// point is directly on top of shapeInfo.avgPoint.
|
||||
// push the point out along the x axis.
|
||||
displacementOut = shapePose.xformVectorFast(shapeInfo.points[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,4 +128,10 @@ protected:
|
|||
bool _snapshotValid { false };
|
||||
};
|
||||
|
||||
|
||||
// returns true if the given point lies inside of the k-dop, specified by shapeInfo & shapePose.
|
||||
// if the given point does lie within the k-dop, it also returns the amount of displacement necessary to push that point outward
|
||||
// such that it lies on the surface of the kdop.
|
||||
bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& shapePose, const HFMJointShapeInfo& shapeInfo, glm::vec3& displacementOut);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1521,74 +1521,6 @@ void Rig::updateHead(bool headEnabled, bool hipsEnabled, const AnimPose& headPos
|
|||
}
|
||||
}
|
||||
|
||||
const float INV_SQRT_3 = 1.0f / sqrtf(3.0f);
|
||||
const int DOP14_COUNT = 14;
|
||||
const glm::vec3 DOP14_NORMALS[DOP14_COUNT] = {
|
||||
Vectors::UNIT_X,
|
||||
-Vectors::UNIT_X,
|
||||
Vectors::UNIT_Y,
|
||||
-Vectors::UNIT_Y,
|
||||
Vectors::UNIT_Z,
|
||||
-Vectors::UNIT_Z,
|
||||
glm::vec3(INV_SQRT_3, INV_SQRT_3, INV_SQRT_3),
|
||||
-glm::vec3(INV_SQRT_3, INV_SQRT_3, INV_SQRT_3),
|
||||
glm::vec3(INV_SQRT_3, -INV_SQRT_3, INV_SQRT_3),
|
||||
-glm::vec3(INV_SQRT_3, -INV_SQRT_3, INV_SQRT_3),
|
||||
glm::vec3(INV_SQRT_3, INV_SQRT_3, -INV_SQRT_3),
|
||||
-glm::vec3(INV_SQRT_3, INV_SQRT_3, -INV_SQRT_3),
|
||||
glm::vec3(INV_SQRT_3, -INV_SQRT_3, -INV_SQRT_3),
|
||||
-glm::vec3(INV_SQRT_3, -INV_SQRT_3, -INV_SQRT_3)
|
||||
};
|
||||
|
||||
// returns true if the given point lies inside of the k-dop, specified by shapeInfo & shapePose.
|
||||
// if the given point does lie within the k-dop, it also returns the amount of displacement necessary to push that point outward
|
||||
// such that it lies on the surface of the kdop.
|
||||
static bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& shapePose, const HFMJointShapeInfo& shapeInfo, glm::vec3& displacementOut) {
|
||||
|
||||
// transform point into local space of jointShape.
|
||||
glm::vec3 localPoint = shapePose.inverse().xformPoint(point);
|
||||
|
||||
// Only works for 14-dop shape infos.
|
||||
if (shapeInfo.dots.size() != DOP14_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
||||
glm::vec3 minDisplacement(FLT_MAX);
|
||||
float minDisplacementLen = FLT_MAX;
|
||||
glm::vec3 p = localPoint - shapeInfo.avgPoint;
|
||||
float pLen = glm::length(p);
|
||||
if (pLen > 0.0f) {
|
||||
int slabCount = 0;
|
||||
for (int i = 0; i < DOP14_COUNT; i++) {
|
||||
float dot = glm::dot(p, DOP14_NORMALS[i]);
|
||||
if (dot > 0.0f && dot < shapeInfo.dots[i]) {
|
||||
slabCount++;
|
||||
float distToPlane = pLen * (shapeInfo.dots[i] / dot);
|
||||
float displacementLen = distToPlane - pLen;
|
||||
|
||||
// keep track of the smallest displacement
|
||||
if (displacementLen < minDisplacementLen) {
|
||||
minDisplacementLen = displacementLen;
|
||||
minDisplacement = (p / pLen) * displacementLen;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (slabCount == (DOP14_COUNT / 2) && minDisplacementLen != FLT_MAX) {
|
||||
// we are within the k-dop so push the point along the minimum displacement found
|
||||
displacementOut = shapePose.xformVectorFast(minDisplacement);
|
||||
return true;
|
||||
} else {
|
||||
// point is outside of kdop
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
// point is directly on top of shapeInfo.avgPoint.
|
||||
// push the point out along the x axis.
|
||||
displacementOut = shapePose.xformVectorFast(shapeInfo.points[0]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 Rig::deflectHandFromTorso(const glm::vec3& handPosition, const HFMJointShapeInfo& hipsShapeInfo, const HFMJointShapeInfo& spineShapeInfo,
|
||||
const HFMJointShapeInfo& spine1ShapeInfo, const HFMJointShapeInfo& spine2ShapeInfo) const {
|
||||
glm::vec3 position = handPosition;
|
||||
|
|
|
@ -116,8 +116,9 @@ public:
|
|||
void destroyAnimGraph();
|
||||
|
||||
void overrideAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
bool isPlayingOverrideAnimation() const { return _userAnimState.clipNodeEnum != UserAnimState::None; };
|
||||
void restoreAnimation();
|
||||
|
||||
|
||||
void overrideNetworkAnimation(const QString& url, float fps, bool loop, float firstFrame, float lastFrame);
|
||||
void triggerNetworkRole(const QString& role);
|
||||
void restoreNetworkAnimation();
|
||||
|
@ -333,7 +334,7 @@ protected:
|
|||
RigRole _state { RigRole::Idle };
|
||||
RigRole _desiredState { RigRole::Idle };
|
||||
float _desiredStateAge { 0.0f };
|
||||
|
||||
|
||||
struct NetworkAnimState {
|
||||
enum ClipNodeEnum {
|
||||
None = 0,
|
||||
|
|
|
@ -270,28 +270,13 @@ bool SkeletonModel::getEyeModelPositions(glm::vec3& firstEyePosition, glm::vec3&
|
|||
getJointPosition(_rig.indexOfJoint("RightEye"), secondEyePosition)) {
|
||||
return true;
|
||||
}
|
||||
// no eye joints; try to estimate based on head/neck joints
|
||||
glm::vec3 neckPosition, headPosition;
|
||||
if (getJointPosition(_rig.indexOfJoint("Neck"), neckPosition) &&
|
||||
getJointPosition(_rig.indexOfJoint("Head"), headPosition)) {
|
||||
const float EYE_PROPORTION = 0.6f;
|
||||
glm::vec3 baseEyePosition = glm::mix(neckPosition, headPosition, EYE_PROPORTION);
|
||||
glm::quat headRotation;
|
||||
getJointRotation(_rig.indexOfJoint("Head"), headRotation);
|
||||
const float EYES_FORWARD = 0.25f;
|
||||
const float EYE_SEPARATION = 0.1f;
|
||||
float headHeight = glm::distance(neckPosition, headPosition);
|
||||
firstEyePosition = baseEyePosition + headRotation * glm::vec3(EYE_SEPARATION, 0.0f, EYES_FORWARD) * headHeight;
|
||||
secondEyePosition = baseEyePosition + headRotation * glm::vec3(-EYE_SEPARATION, 0.0f, EYES_FORWARD) * headHeight;
|
||||
return true;
|
||||
} else if (getJointPosition(_rig.indexOfJoint("Head"), headPosition)) {
|
||||
glm::vec3 baseEyePosition = headPosition;
|
||||
glm::quat headRotation;
|
||||
getJointRotation(_rig.indexOfJoint("Head"), headRotation);
|
||||
const float EYES_FORWARD_HEAD_ONLY = 0.30f;
|
||||
const float EYE_SEPARATION = 0.1f;
|
||||
firstEyePosition = baseEyePosition + headRotation * glm::vec3(EYE_SEPARATION, 0.0f, EYES_FORWARD_HEAD_ONLY);
|
||||
secondEyePosition = baseEyePosition + headRotation * glm::vec3(-EYE_SEPARATION, 0.0f, EYES_FORWARD_HEAD_ONLY);
|
||||
|
||||
glm::vec3 headPosition;
|
||||
if (getJointPosition(_rig.indexOfJoint("Head"), headPosition)) {
|
||||
float heightRatio = _rig.getUnscaledEyeHeight() / DEFAULT_AVATAR_EYE_HEIGHT;
|
||||
glm::vec3 ipdOffset = glm::vec3(DEFAULT_AVATAR_IPD / 2.0f, 0.0f, 0.0f);
|
||||
firstEyePosition = headPosition + heightRatio * (DEFAULT_AVATAR_HEAD_TO_MIDDLE_EYE_OFFSET + ipdOffset);
|
||||
secondEyePosition = headPosition + heightRatio * (DEFAULT_AVATAR_HEAD_TO_MIDDLE_EYE_OFFSET - ipdOffset);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -42,6 +42,7 @@ const float DEFAULT_AVATAR_HIPS_MASS = 40.0f;
|
|||
const float DEFAULT_AVATAR_HEAD_MASS = 20.0f;
|
||||
const float DEFAULT_AVATAR_LEFTHAND_MASS = 2.0f;
|
||||
const float DEFAULT_AVATAR_RIGHTHAND_MASS = 2.0f;
|
||||
const float DEFAULT_AVATAR_IPD = 0.064f;
|
||||
|
||||
// Used when avatar is missing joints... (avatar space)
|
||||
const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 };
|
||||
|
|
Loading…
Reference in a new issue