mirror of
https://github.com/overte-org/overte.git
synced 2025-06-17 15:00:26 +02:00
192 lines
6.5 KiB
C++
192 lines
6.5 KiB
C++
//
|
|
// Hand.cpp
|
|
// interface/src/avatar
|
|
//
|
|
// Copyright 2013 High Fidelity, Inc.
|
|
//
|
|
// Distributed under the Apache License, Version 2.0.
|
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
|
//
|
|
|
|
#include <QImage>
|
|
|
|
#include <NodeList.h>
|
|
|
|
#include <GeometryUtil.h>
|
|
|
|
#include "Application.h"
|
|
#include "Avatar.h"
|
|
#include "Hand.h"
|
|
#include "Menu.h"
|
|
#include "Util.h"
|
|
#include "renderer/ProgramObject.h"
|
|
|
|
using namespace std;
|
|
|
|
const float PALM_COLLISION_RADIUS = 0.03f;
|
|
|
|
|
|
Hand::Hand(Avatar* owningAvatar) :
|
|
HandData((AvatarData*)owningAvatar),
|
|
_owningAvatar(owningAvatar)
|
|
{
|
|
}
|
|
|
|
void Hand::simulate(float deltaTime, bool isMine) {
|
|
if (isMine) {
|
|
// Iterate hand controllers, take actions as needed
|
|
for (size_t i = 0; i < getNumPalms(); ++i) {
|
|
PalmData& palm = getPalms()[i];
|
|
palm.setLastControllerButtons(palm.getControllerButtons());
|
|
}
|
|
}
|
|
}
|
|
|
|
// We create a static CollisionList that is recycled for each collision test.
|
|
const float MAX_COLLISIONS_PER_AVATAR = 32;
|
|
static CollisionList handCollisions(MAX_COLLISIONS_PER_AVATAR);
|
|
|
|
void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
|
|
if (!avatar || avatar == _owningAvatar) {
|
|
// don't collide hands against ourself (that is done elsewhere)
|
|
return;
|
|
}
|
|
|
|
const SkeletonModel& skeletonModel = _owningAvatar->getSkeletonModel();
|
|
int jointIndices[2];
|
|
jointIndices[0] = skeletonModel.getLeftHandJointIndex();
|
|
jointIndices[1] = skeletonModel.getRightHandJointIndex();
|
|
|
|
for (size_t i = 0; i < 2; i++) {
|
|
int jointIndex = jointIndices[i];
|
|
if (jointIndex < 0) {
|
|
continue;
|
|
}
|
|
|
|
handCollisions.clear();
|
|
QVector<const Shape*> shapes;
|
|
skeletonModel.getHandShapes(jointIndex, shapes);
|
|
|
|
if (avatar->findCollisions(shapes, handCollisions)) {
|
|
glm::vec3 totalPenetration(0.f);
|
|
glm::vec3 averageContactPoint;
|
|
for (int j = 0; j < handCollisions.size(); ++j) {
|
|
CollisionInfo* collision = handCollisions.getCollision(j);
|
|
totalPenetration += collision->_penetration;
|
|
averageContactPoint += collision->_contactPoint;
|
|
}
|
|
if (isMyHand) {
|
|
// our hand against other avatar
|
|
// TODO: resolve this penetration when we don't think the other avatar will yield
|
|
//palm.addToPenetration(averagePenetration);
|
|
} else {
|
|
// someone else's hand against MyAvatar
|
|
// TODO: submit collision info to MyAvatar which should lean accordingly
|
|
averageContactPoint /= (float)handCollisions.size();
|
|
avatar->applyCollision(averageContactPoint, totalPenetration);
|
|
|
|
CollisionInfo collision;
|
|
collision._penetration = totalPenetration;
|
|
collision._contactPoint = averageContactPoint;
|
|
emit avatar->collisionWithAvatar(avatar->getSessionUUID(), _owningAvatar->getSessionUUID(), collision);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Hand::resolvePenetrations() {
|
|
for (size_t i = 0; i < getNumPalms(); ++i) {
|
|
PalmData& palm = getPalms()[i];
|
|
palm.resolvePenetrations();
|
|
}
|
|
}
|
|
|
|
void Hand::render(bool isMine, Model::RenderMode renderMode) {
|
|
if (renderMode != Model::SHADOW_RENDER_MODE &&
|
|
Menu::getInstance()->isOptionChecked(MenuOption::RenderSkeletonCollisionShapes)) {
|
|
// draw a green sphere at hand joint location, which is actually near the wrist)
|
|
for (size_t i = 0; i < getNumPalms(); i++) {
|
|
PalmData& palm = getPalms()[i];
|
|
if (!palm.isActive()) {
|
|
continue;
|
|
}
|
|
glm::vec3 position = palm.getPosition();
|
|
glPushMatrix();
|
|
glTranslatef(position.x, position.y, position.z);
|
|
glColor3f(0.0f, 1.0f, 0.0f);
|
|
glutSolidSphere(PALM_COLLISION_RADIUS * _owningAvatar->getScale(), 10, 10);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
|
|
if (renderMode != Model::SHADOW_RENDER_MODE && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHands)) {
|
|
renderHandTargets(isMine);
|
|
}
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
glEnable(GL_RESCALE_NORMAL);
|
|
}
|
|
|
|
void Hand::renderHandTargets(bool isMine) {
|
|
glPushMatrix();
|
|
|
|
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
|
const float avatarScale = Application::getInstance()->getAvatar()->getScale();
|
|
|
|
const float alpha = 1.0f;
|
|
const glm::vec3 handColor(1.0, 0.0, 0.0); // Color the hand targets red to be different than skin
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthMask(GL_TRUE);
|
|
|
|
if (isMine && Menu::getInstance()->isOptionChecked(MenuOption::DisplayHandTargets)) {
|
|
for (size_t i = 0; i < getNumPalms(); ++i) {
|
|
PalmData& palm = getPalms()[i];
|
|
if (!palm.isActive()) {
|
|
continue;
|
|
}
|
|
glm::vec3 targetPosition = palm.getTipPosition();
|
|
glPushMatrix();
|
|
glTranslatef(targetPosition.x, targetPosition.y, targetPosition.z);
|
|
|
|
const float collisionRadius = 0.05f;
|
|
glColor4f(0.5f,0.5f,0.5f, alpha);
|
|
glutWireSphere(collisionRadius, 10.f, 10.f);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
|
|
const float PALM_BALL_RADIUS = 0.03f * avatarScale;
|
|
const float PALM_DISK_RADIUS = 0.06f * avatarScale;
|
|
const float PALM_DISK_THICKNESS = 0.01f * avatarScale;
|
|
const float PALM_FINGER_ROD_RADIUS = 0.003f * avatarScale;
|
|
|
|
// Draw the palm ball and disk
|
|
for (size_t i = 0; i < getNumPalms(); ++i) {
|
|
PalmData& palm = getPalms()[i];
|
|
if (palm.isActive()) {
|
|
glColor4f(handColor.r, handColor.g, handColor.b, alpha);
|
|
glm::vec3 tip = palm.getTipPosition();
|
|
glm::vec3 root = palm.getPosition();
|
|
|
|
//Scale the positions based on avatar scale
|
|
myAvatar->scaleVectorRelativeToPosition(tip);
|
|
myAvatar->scaleVectorRelativeToPosition(root);
|
|
|
|
Avatar::renderJointConnectingCone(root, tip, PALM_FINGER_ROD_RADIUS, PALM_FINGER_ROD_RADIUS);
|
|
// Render sphere at palm/finger root
|
|
glm::vec3 offsetFromPalm = root + palm.getNormal() * PALM_DISK_THICKNESS;
|
|
Avatar::renderJointConnectingCone(root, offsetFromPalm, PALM_DISK_RADIUS, 0.0f);
|
|
glPushMatrix();
|
|
glTranslatef(root.x, root.y, root.z);
|
|
glutSolidSphere(PALM_BALL_RADIUS, 20.0f, 20.0f);
|
|
glPopMatrix();
|
|
}
|
|
}
|
|
|
|
glDepthMask(GL_TRUE);
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glPopMatrix();
|
|
}
|
|
|