mirror of
https://github.com/overte-org/overte.git
synced 2025-07-23 09:43:51 +02:00
Merge branch 'master' of ssh://github.com/highfidelity/hifi into avatar-interaction
This commit is contained in:
commit
3b3359abce
12 changed files with 149 additions and 26 deletions
BIN
interface/resources/meshes/body.jpg
Normal file
BIN
interface/resources/meshes/body.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 330 KiB |
18
interface/resources/meshes/defaultAvatar_body.fst
Normal file
18
interface/resources/meshes/defaultAvatar_body.fst
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
scale=130
|
||||||
|
joint = jointRoot = jointRoot
|
||||||
|
joint = jointLean = jointSpine
|
||||||
|
joint = jointNeck = jointNeck
|
||||||
|
joint = jointHead = jointHeadtop
|
||||||
|
joint = joint_L_shoulder = joint_L_shoulder
|
||||||
|
freeJoint = joint_L_arm
|
||||||
|
freeJoint = joint_L_elbow
|
||||||
|
joint = jointLeftHand = joint_L_hand
|
||||||
|
joint = joint_R_shoulder = joint_R_shoulder
|
||||||
|
freeJoint = joint_R_arm
|
||||||
|
freeJoint = joint_R_elbow
|
||||||
|
joint = jointRightHand = joint_R_hand
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
45
interface/resources/meshes/defaultAvatar_head.fst
Normal file
45
interface/resources/meshes/defaultAvatar_head.fst
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
# faceshift target mapping file
|
||||||
|
name= defaultAvatar_head
|
||||||
|
filename=../../../Avatars/Jelly/jellyrob_blue.fbx
|
||||||
|
texdir=../../../Avatars/Jelly
|
||||||
|
scale=80
|
||||||
|
rx=0
|
||||||
|
ry=0
|
||||||
|
rz=0
|
||||||
|
tx=0
|
||||||
|
ty=0
|
||||||
|
tz=0
|
||||||
|
joint = jointNeck = jointNeck
|
||||||
|
bs = BrowsD_L = Leye1.BrowsD_L = 0.97
|
||||||
|
bs = BrowsD_R = Reye1.BrowsD_R = 1
|
||||||
|
bs = CheekSquint_L = Leye1.CheekSquint_L = 1
|
||||||
|
bs = CheekSquint_R = Reye1.CheekSquint_R = 1
|
||||||
|
bs = EyeBlink_L = Leye1.EyeBlink_L = 1
|
||||||
|
bs = EyeBlink_R = Reye1.EyeBlink_R = 1
|
||||||
|
bs = EyeDown_L = Leye1.EyeDown_L = 1
|
||||||
|
bs = EyeDown_R = Reye1.EyeDown_R = 0.99
|
||||||
|
bs = EyeIn_L = Leye1.EyeIn_L = 0.92
|
||||||
|
bs = EyeIn_R = Reye1.EyeIn_R = 1
|
||||||
|
bs = EyeOpen_L = Leye1.EyeOpen_L = 1
|
||||||
|
bs = EyeOpen_R = Reye1.EyeOpen_R = 1
|
||||||
|
bs = EyeOut_L = Leye1.EyeOut_L = 0.99
|
||||||
|
bs = EyeOut_R = Reye1.EyeOut_R = 1
|
||||||
|
bs = EyeUp_L = Leye1.EyeUp_L = 0.93
|
||||||
|
bs = EyeUp_R = Reye1.EyeUp_R = 1
|
||||||
|
bs = JawOpen = Mouth.JawOpen = 1
|
||||||
|
bs = LipsFunnel = Mouth.LipsFunnel = 1
|
||||||
|
bs = LipsLowerDown = Mouth.LipsLowerDown = 1
|
||||||
|
bs = LipsPucker = Mouth.LipsPucker = 1
|
||||||
|
bs = LipsStretch_L = Mouth.LipsStretch_L = 0.96
|
||||||
|
bs = LipsStretch_R = Mouth.LipsStretch_R = 1
|
||||||
|
bs = LipsUpperUp = Mouth.LipsUpperUp = 1
|
||||||
|
bs = MouthDimple_L = Mouth.MouthDimple_L = 1
|
||||||
|
bs = MouthDimple_R = Mouth.MouthDimple_R = 1
|
||||||
|
bs = MouthFrown_L = Mouth.MouthFrown_L = 1
|
||||||
|
bs = MouthFrown_R = Mouth.MouthFrown_R = 1
|
||||||
|
bs = MouthLeft = Mouth.MouthLeft = 1
|
||||||
|
bs = MouthRight = Mouth.MouthRight = 1
|
||||||
|
bs = MouthSmile_L = Mouth.MouthSmile_L = 1
|
||||||
|
bs = MouthSmile_R = Mouth.MouthSmile_R = 1
|
||||||
|
bs = Puff = Mouth.Puff = 1
|
||||||
|
bs = Sneer = Mouth.Sneer = 1
|
BIN
interface/resources/meshes/tail.jpg
Normal file
BIN
interface/resources/meshes/tail.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 142 KiB |
BIN
interface/resources/meshes/visor.png
Normal file
BIN
interface/resources/meshes/visor.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.6 KiB |
|
@ -345,12 +345,14 @@ bool Avatar::findSphereCollisionWithSkeleton(const glm::vec3& sphereCenter, floa
|
||||||
|
|
||||||
void Avatar::setFaceModelURL(const QUrl &faceModelURL) {
|
void Avatar::setFaceModelURL(const QUrl &faceModelURL) {
|
||||||
AvatarData::setFaceModelURL(faceModelURL);
|
AvatarData::setFaceModelURL(faceModelURL);
|
||||||
_head.getFaceModel().setURL(_faceModelURL);
|
const QUrl DEFAULT_FACE_MODEL_URL = QUrl::fromLocalFile("resources/meshes/defaultAvatar_head.fbx");
|
||||||
|
_head.getFaceModel().setURL(_faceModelURL, DEFAULT_FACE_MODEL_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setSkeletonModelURL(const QUrl &skeletonModelURL) {
|
void Avatar::setSkeletonModelURL(const QUrl &skeletonModelURL) {
|
||||||
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
AvatarData::setSkeletonModelURL(skeletonModelURL);
|
||||||
_skeletonModel.setURL(_skeletonModelURL);
|
const QUrl DEFAULT_SKELETON_MODEL_URL = QUrl::fromLocalFile("resources/meshes/defaultAvatar_body.fbx");
|
||||||
|
_skeletonModel.setURL(_skeletonModelURL, DEFAULT_SKELETON_MODEL_URL);
|
||||||
}
|
}
|
||||||
|
|
||||||
int Avatar::parseData(const QByteArray& packet) {
|
int Avatar::parseData(const QByteArray& packet) {
|
||||||
|
|
|
@ -58,7 +58,7 @@ void FaceModel::maybeUpdateNeckRotation(const JointState& parentState, const FBX
|
||||||
glm::mat3 axes = glm::mat3_cast(_rotation);
|
glm::mat3 axes = glm::mat3_cast(_rotation);
|
||||||
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
glm::mat3 inverse = glm::mat3(glm::inverse(parentState.transform * glm::translate(state.translation) *
|
||||||
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
joint.preTransform * glm::mat4_cast(joint.preRotation)));
|
||||||
state.rotation = glm::angleAxis(-_owningHead->getRoll(), glm::normalize(inverse * axes[2])) *
|
state.rotation = glm::angleAxis(-_owningHead->getTweakedRoll(), glm::normalize(inverse * axes[2])) *
|
||||||
glm::angleAxis(_owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) *
|
glm::angleAxis(_owningHead->getTweakedYaw(), glm::normalize(inverse * axes[1])) *
|
||||||
glm::angleAxis(-_owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
glm::angleAxis(-_owningHead->getTweakedPitch(), glm::normalize(inverse * axes[0])) * joint.rotation;
|
||||||
}
|
}
|
||||||
|
|
|
@ -834,6 +834,12 @@ QString getTopModelID(const QMultiHash<QString, QString>& parentMap,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString getString(const QVariant& value) {
|
||||||
|
// if it's a list, return the first entry
|
||||||
|
QVariantList list = value.toList();
|
||||||
|
return list.isEmpty() ? value.toString() : list.at(0).toString();
|
||||||
|
}
|
||||||
|
|
||||||
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping) {
|
||||||
QHash<QString, ExtractedMesh> meshes;
|
QHash<QString, ExtractedMesh> meshes;
|
||||||
QVector<ExtractedBlendshape> blendshapes;
|
QVector<ExtractedBlendshape> blendshapes;
|
||||||
|
@ -847,14 +853,14 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
||||||
QHash<QString, QString> bumpTextures;
|
QHash<QString, QString> bumpTextures;
|
||||||
|
|
||||||
QVariantHash joints = mapping.value("joint").toHash();
|
QVariantHash joints = mapping.value("joint").toHash();
|
||||||
QString jointEyeLeftName = processID(joints.value("jointEyeLeft", "jointEyeLeft").toString());
|
QString jointEyeLeftName = processID(getString(joints.value("jointEyeLeft", "jointEyeLeft")));
|
||||||
QString jointEyeRightName = processID(joints.value("jointEyeRight", "jointEyeRight").toString());
|
QString jointEyeRightName = processID(getString(joints.value("jointEyeRight", "jointEyeRight")));
|
||||||
QString jointNeckName = processID(joints.value("jointNeck", "jointNeck").toString());
|
QString jointNeckName = processID(getString(joints.value("jointNeck", "jointNeck")));
|
||||||
QString jointRootName = processID(joints.value("jointRoot", "jointRoot").toString());
|
QString jointRootName = processID(getString(joints.value("jointRoot", "jointRoot")));
|
||||||
QString jointLeanName = processID(joints.value("jointLean", "jointLean").toString());
|
QString jointLeanName = processID(getString(joints.value("jointLean", "jointLean")));
|
||||||
QString jointHeadName = processID(joints.value("jointHead", "jointHead").toString());
|
QString jointHeadName = processID(getString(joints.value("jointHead", "jointHead")));
|
||||||
QString jointLeftHandName = processID(joints.value("jointLeftHand", "jointLeftHand").toString());
|
QString jointLeftHandName = processID(getString(joints.value("jointLeftHand", "jointLeftHand")));
|
||||||
QString jointRightHandName = processID(joints.value("jointRightHand", "jointRightHand").toString());
|
QString jointRightHandName = processID(getString(joints.value("jointRightHand", "jointRightHand")));
|
||||||
QVariantList jointLeftFingerNames = joints.values("jointLeftFinger");
|
QVariantList jointLeftFingerNames = joints.values("jointLeftFinger");
|
||||||
QVariantList jointRightFingerNames = joints.values("jointRightFinger");
|
QVariantList jointRightFingerNames = joints.values("jointRightFinger");
|
||||||
QVariantList jointLeftFingertipNames = joints.values("jointLeftFingertip");
|
QVariantList jointLeftFingertipNames = joints.values("jointLeftFingertip");
|
||||||
|
|
|
@ -290,19 +290,24 @@ void GeometryCache::renderGrid(int xDivisions, int yDivisions) {
|
||||||
buffer.release();
|
buffer.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url) {
|
QSharedPointer<NetworkGeometry> GeometryCache::getGeometry(const QUrl& url, const QUrl& fallback) {
|
||||||
|
if (!url.isValid() && fallback.isValid()) {
|
||||||
|
return getGeometry(fallback);
|
||||||
|
}
|
||||||
QSharedPointer<NetworkGeometry> geometry = _networkGeometry.value(url);
|
QSharedPointer<NetworkGeometry> geometry = _networkGeometry.value(url);
|
||||||
if (geometry.isNull()) {
|
if (geometry.isNull()) {
|
||||||
geometry = QSharedPointer<NetworkGeometry>(new NetworkGeometry(url));
|
geometry = QSharedPointer<NetworkGeometry>(new NetworkGeometry(url, fallback.isValid() ?
|
||||||
|
getGeometry(fallback) : QSharedPointer<NetworkGeometry>()));
|
||||||
_networkGeometry.insert(url, geometry);
|
_networkGeometry.insert(url, geometry);
|
||||||
}
|
}
|
||||||
return geometry;
|
return geometry;
|
||||||
}
|
}
|
||||||
|
|
||||||
NetworkGeometry::NetworkGeometry(const QUrl& url) :
|
NetworkGeometry::NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback) :
|
||||||
_modelRequest(url),
|
_modelRequest(url),
|
||||||
_modelReply(NULL),
|
_modelReply(NULL),
|
||||||
_mappingReply(NULL),
|
_mappingReply(NULL),
|
||||||
|
_fallback(fallback),
|
||||||
_attempts(0)
|
_attempts(0)
|
||||||
{
|
{
|
||||||
if (!url.isValid()) {
|
if (!url.isValid()) {
|
||||||
|
@ -369,18 +374,37 @@ void NetworkGeometry::makeModelRequest() {
|
||||||
void NetworkGeometry::handleModelReplyError() {
|
void NetworkGeometry::handleModelReplyError() {
|
||||||
QDebug debug = qDebug() << _modelReply->errorString();
|
QDebug debug = qDebug() << _modelReply->errorString();
|
||||||
|
|
||||||
|
QNetworkReply::NetworkError error = _modelReply->error();
|
||||||
_modelReply->disconnect(this);
|
_modelReply->disconnect(this);
|
||||||
_modelReply->deleteLater();
|
_modelReply->deleteLater();
|
||||||
_modelReply = NULL;
|
_modelReply = NULL;
|
||||||
|
|
||||||
// retry with increasing delays
|
// retry for certain types of failures
|
||||||
const int MAX_ATTEMPTS = 8;
|
switch (error) {
|
||||||
const int BASE_DELAY_MS = 1000;
|
case QNetworkReply::RemoteHostClosedError:
|
||||||
if (++_attempts < MAX_ATTEMPTS) {
|
case QNetworkReply::TimeoutError:
|
||||||
QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(makeModelRequest()));
|
case QNetworkReply::TemporaryNetworkFailureError:
|
||||||
debug << " -- retrying...";
|
case QNetworkReply::ProxyConnectionClosedError:
|
||||||
|
case QNetworkReply::ProxyTimeoutError:
|
||||||
|
case QNetworkReply::UnknownNetworkError:
|
||||||
|
case QNetworkReply::UnknownProxyError:
|
||||||
|
case QNetworkReply::UnknownContentError:
|
||||||
|
case QNetworkReply::ProtocolFailure: {
|
||||||
|
// retry with increasing delays
|
||||||
|
const int MAX_ATTEMPTS = 8;
|
||||||
|
const int BASE_DELAY_MS = 1000;
|
||||||
|
if (++_attempts < MAX_ATTEMPTS) {
|
||||||
|
QTimer::singleShot(BASE_DELAY_MS * (int)pow(2.0, _attempts), this, SLOT(makeModelRequest()));
|
||||||
|
debug << " -- retrying...";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// fall through to final failure
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
maybeLoadFallback();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void NetworkGeometry::handleMappingReplyError() {
|
void NetworkGeometry::handleMappingReplyError() {
|
||||||
|
@ -415,6 +439,7 @@ void NetworkGeometry::maybeReadModelWithMapping() {
|
||||||
|
|
||||||
} catch (const QString& error) {
|
} catch (const QString& error) {
|
||||||
qDebug() << "Error reading " << url << ": " << error;
|
qDebug() << "Error reading " << url << ": " << error;
|
||||||
|
maybeLoadFallback();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -507,6 +532,24 @@ void NetworkGeometry::maybeReadModelWithMapping() {
|
||||||
|
|
||||||
_meshes.append(networkMesh);
|
_meshes.append(networkMesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
emit loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkGeometry::loadFallback() {
|
||||||
|
_geometry = _fallback->_geometry;
|
||||||
|
_meshes = _fallback->_meshes;
|
||||||
|
emit loaded();
|
||||||
|
}
|
||||||
|
|
||||||
|
void NetworkGeometry::maybeLoadFallback() {
|
||||||
|
if (_fallback) {
|
||||||
|
if (_fallback->isLoaded()) {
|
||||||
|
loadFallback();
|
||||||
|
} else {
|
||||||
|
connect(_fallback.data(), SIGNAL(loaded()), SLOT(loadFallback()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool NetworkMeshPart::isTranslucent() const {
|
bool NetworkMeshPart::isTranslucent() const {
|
||||||
|
|
|
@ -37,7 +37,8 @@ public:
|
||||||
void renderGrid(int xDivisions, int yDivisions);
|
void renderGrid(int xDivisions, int yDivisions);
|
||||||
|
|
||||||
/// Loads geometry from the specified URL.
|
/// Loads geometry from the specified URL.
|
||||||
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url);
|
/// \param fallback a fallback URL to load if the desired one is unavailable
|
||||||
|
QSharedPointer<NetworkGeometry> getGeometry(const QUrl& url, const QUrl& fallback = QUrl());
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -58,7 +59,7 @@ class NetworkGeometry : public QObject {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
NetworkGeometry(const QUrl& url);
|
NetworkGeometry(const QUrl& url, const QSharedPointer<NetworkGeometry>& fallback);
|
||||||
~NetworkGeometry();
|
~NetworkGeometry();
|
||||||
|
|
||||||
bool isLoaded() const { return !_geometry.joints.isEmpty(); }
|
bool isLoaded() const { return !_geometry.joints.isEmpty(); }
|
||||||
|
@ -69,18 +70,26 @@ public:
|
||||||
/// Returns the average color of all meshes in the geometry.
|
/// Returns the average color of all meshes in the geometry.
|
||||||
glm::vec4 computeAverageColor() const;
|
glm::vec4 computeAverageColor() const;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
|
||||||
|
void loaded();
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
|
|
||||||
void makeModelRequest();
|
void makeModelRequest();
|
||||||
void handleModelReplyError();
|
void handleModelReplyError();
|
||||||
void handleMappingReplyError();
|
void handleMappingReplyError();
|
||||||
void maybeReadModelWithMapping();
|
void maybeReadModelWithMapping();
|
||||||
|
void loadFallback();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
void maybeLoadFallback();
|
||||||
|
|
||||||
QNetworkRequest _modelRequest;
|
QNetworkRequest _modelRequest;
|
||||||
QNetworkReply* _modelReply;
|
QNetworkReply* _modelReply;
|
||||||
QNetworkReply* _mappingReply;
|
QNetworkReply* _mappingReply;
|
||||||
|
QSharedPointer<NetworkGeometry> _fallback;
|
||||||
|
|
||||||
int _attempts;
|
int _attempts;
|
||||||
FBXGeometry _geometry;
|
FBXGeometry _geometry;
|
||||||
|
|
|
@ -399,7 +399,7 @@ float Model::getRightArmLength() const {
|
||||||
return getLimbLength(getRightHandJointIndex());
|
return getLimbLength(getRightHandJointIndex());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Model::setURL(const QUrl& url) {
|
void Model::setURL(const QUrl& url, const QUrl& fallback) {
|
||||||
// don't recreate the geometry if it's the same URL
|
// don't recreate the geometry if it's the same URL
|
||||||
if (_url == url) {
|
if (_url == url) {
|
||||||
return;
|
return;
|
||||||
|
@ -410,7 +410,7 @@ void Model::setURL(const QUrl& url) {
|
||||||
deleteGeometry();
|
deleteGeometry();
|
||||||
_dilatedTextures.clear();
|
_dilatedTextures.clear();
|
||||||
|
|
||||||
_geometry = Application::getInstance()->getGeometryCache()->getGeometry(url);
|
_geometry = Application::getInstance()->getGeometryCache()->getGeometry(url, fallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec4 Model::computeAverageColor() const {
|
glm::vec4 Model::computeAverageColor() const {
|
||||||
|
|
|
@ -61,7 +61,7 @@ public:
|
||||||
void simulate(float deltaTime);
|
void simulate(float deltaTime);
|
||||||
bool render(float alpha);
|
bool render(float alpha);
|
||||||
|
|
||||||
Q_INVOKABLE void setURL(const QUrl& url);
|
Q_INVOKABLE void setURL(const QUrl& url, const QUrl& fallback = QUrl());
|
||||||
const QUrl& getURL() const { return _url; }
|
const QUrl& getURL() const { return _url; }
|
||||||
|
|
||||||
/// Returns the extents of the model in its bind pose.
|
/// Returns the extents of the model in its bind pose.
|
||||||
|
|
Loading…
Reference in a new issue