Merge pull request #2777 from ey6es/master

Fixes for ASCII-encoded FBX models, removed camera pushback entirely from first person camera mode.
This commit is contained in:
Philip Rosedale 2014-05-03 09:53:36 -07:00
commit d1c9032c8f
7 changed files with 108 additions and 104 deletions

View file

@ -561,42 +561,6 @@ void Application::paintGL() {
_myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition()); _myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
_myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation()); _myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
if (Menu::getInstance()->isOptionChecked(MenuOption::CollideWithAvatars)) {
glm::vec3 planeNormal = _myCamera.getTargetRotation() * IDENTITY_FRONT;
const float BASE_PUSHBACK_RADIUS = 0.25f;
float pushbackRadius = _myCamera.getNearClip() + _myAvatar->getScale() * BASE_PUSHBACK_RADIUS;
glm::vec4 plane(planeNormal, -glm::dot(planeNormal, _myCamera.getTargetPosition()) - pushbackRadius);
// push camera out of any intersecting avatars
foreach (const AvatarSharedPointer& avatarData, _avatarManager.getAvatarHash()) {
Avatar* avatar = static_cast<Avatar*>(avatarData.data());
if (avatar->isMyAvatar()) {
continue;
}
if (glm::distance(avatar->getPosition(), _myCamera.getTargetPosition()) >
avatar->getBoundingRadius() + pushbackRadius) {
continue;
}
float angle = angleBetween(avatar->getPosition() - _myCamera.getTargetPosition(), planeNormal);
if (angle > PI_OVER_TWO) {
continue;
}
float scale = 1.0f - angle / PI_OVER_TWO;
scale = qMin(1.0f, scale * 2.5f);
static CollisionList collisions(64);
collisions.clear();
if (!avatar->findPlaneCollisions(plane, collisions)) {
continue;
}
for (int i = 0; i < collisions.size(); i++) {
pushback = qMax(pushback, glm::length(collisions.getCollision(i)->_penetration) * scale);
}
}
const float MAX_PUSHBACK = 0.35f;
pushback = qMin(pushback, MAX_PUSHBACK * _myAvatar->getScale());
const float BASE_PUSHBACK_FOCAL_LENGTH = 0.5f;
pushbackFocalLength = BASE_PUSHBACK_FOCAL_LENGTH * _myAvatar->getScale();
}
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) { } else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
_myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing _myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
_myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition()); _myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition());

View file

@ -153,14 +153,14 @@ bool ModelUploader::zip() {
// mixamo/autodesk defaults // mixamo/autodesk defaults
if (!mapping.contains(SCALE_FIELD)) { if (!mapping.contains(SCALE_FIELD)) {
mapping.insert(SCALE_FIELD, 15.0); mapping.insert(SCALE_FIELD, geometry.author == "www.makehuman.org" ? 150.0 : 15.0);
} }
QVariantHash joints = mapping.value(JOINT_FIELD).toHash(); QVariantHash joints = mapping.value(JOINT_FIELD).toHash();
if (!joints.contains("jointEyeLeft")) { if (!joints.contains("jointEyeLeft")) {
joints.insert("jointEyeLeft", "LeftEye"); joints.insert("jointEyeLeft", geometry.jointIndices.contains("EyeLeft") ? "EyeLeft" : "LeftEye");
} }
if (!joints.contains("jointEyeRight")) { if (!joints.contains("jointEyeRight")) {
joints.insert("jointEyeRight", "RightEye"); joints.insert("jointEyeRight", geometry.jointIndices.contains("EyeRight") ? "EyeRight" : "RightEye");
} }
if (!joints.contains("jointNeck")) { if (!joints.contains("jointNeck")) {
joints.insert("jointNeck", "Neck"); joints.insert("jointNeck", "Neck");
@ -172,7 +172,8 @@ bool ModelUploader::zip() {
joints.insert("jointLean", "Spine"); joints.insert("jointLean", "Spine");
} }
if (!joints.contains("jointHead")) { if (!joints.contains("jointHead")) {
joints.insert("jointHead", geometry.applicationName == "mixamo.com" ? "HeadTop_End" : "HeadEnd"); const char* topName = (geometry.applicationName == "mixamo.com") ? "HeadTop_End" : "HeadEnd";
joints.insert("jointHead", geometry.jointIndices.contains(topName) ? topName : "Head");
} }
if (!joints.contains("jointLeftHand")) { if (!joints.contains("jointLeftHand")) {
joints.insert("jointLeftHand", "LeftHand"); joints.insert("jointLeftHand", "LeftHand");

View file

@ -29,11 +29,11 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
neckPosition = owningAvatar->getPosition(); neckPosition = owningAvatar->getPosition();
} }
setTranslation(neckPosition); setTranslation(neckPosition);
glm::quat neckRotation; glm::quat neckParentRotation;
if (!owningAvatar->getSkeletonModel().getNeckRotation(neckRotation)) { if (!owningAvatar->getSkeletonModel().getNeckParentRotation(neckParentRotation)) {
neckRotation = owningAvatar->getOrientation(); neckParentRotation = owningAvatar->getOrientation();
} }
setRotation(neckRotation); setRotation(neckParentRotation);
const float MODEL_SCALE = 0.0006f; const float MODEL_SCALE = 0.0006f;
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale() * MODEL_SCALE); setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale() * MODEL_SCALE);

View file

@ -434,6 +434,17 @@ bool Model::getNeckRotation(glm::quat& neckRotation) const {
return isActive() && getJointRotation(_geometry->getFBXGeometry().neckJointIndex, neckRotation); return isActive() && getJointRotation(_geometry->getFBXGeometry().neckJointIndex, neckRotation);
} }
bool Model::getNeckParentRotation(glm::quat& neckParentRotation) const {
if (!isActive()) {
return false;
}
const FBXGeometry& geometry = _geometry->getFBXGeometry();
if (geometry.neckJointIndex == -1) {
return false;
}
return getJointRotation(geometry.joints.at(geometry.neckJointIndex).parentIndex, neckParentRotation);
}
bool Model::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const { bool Model::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const {
if (!isActive()) { if (!isActive()) {
return false; return false;

View file

@ -132,6 +132,10 @@ public:
/// \return whether or not the neck was found /// \return whether or not the neck was found
bool getNeckRotation(glm::quat& neckRotation) const; bool getNeckRotation(glm::quat& neckRotation) const;
/// Returns the rotation of the neck joint's parent.
/// \return whether or not the neck was found
bool getNeckParentRotation(glm::quat& neckRotation) const;
/// Retrieve the positions of up to two eye meshes. /// Retrieve the positions of up to two eye meshes.
/// \return whether or not both eye meshes were found /// \return whether or not both eye meshes were found
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const; bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;

View file

@ -406,7 +406,7 @@ QVariantHash parseMapping(QIODevice* device) {
QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) { QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) {
QVector<glm::vec3> values; QVector<glm::vec3> values;
for (const double* it = doubleVector.constData(), *end = it + doubleVector.size(); it != end; ) { for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 3 * 3); it != end; ) {
float x = *it++; float x = *it++;
float y = *it++; float y = *it++;
float z = *it++; float z = *it++;
@ -417,7 +417,7 @@ QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) {
QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) { QVector<glm::vec2> createVec2Vector(const QVector<double>& doubleVector) {
QVector<glm::vec2> values; QVector<glm::vec2> values;
for (const double* it = doubleVector.constData(), *end = it + doubleVector.size(); it != end; ) { for (const double* it = doubleVector.constData(), *end = it + (doubleVector.size() / 2 * 2); it != end; ) {
float s = *it++; float s = *it++;
float t = *it++; float t = *it++;
values.append(glm::vec2(s, -t)); values.append(glm::vec2(s, -t));
@ -432,58 +432,59 @@ glm::mat4 createMat4(const QVector<double>& doubleVector) {
doubleVector.at(12), doubleVector.at(13), doubleVector.at(14), doubleVector.at(15)); doubleVector.at(12), doubleVector.at(13), doubleVector.at(14), doubleVector.at(15));
} }
QVector<int> getIntVector(const QVariantList& properties, int index) { QVector<int> getIntVector(const FBXNode& node) {
if (index >= properties.size()) { foreach (const FBXNode& child, node.children) {
if (child.name == "a") {
return getIntVector(child);
}
}
if (node.properties.isEmpty()) {
return QVector<int>(); return QVector<int>();
} }
QVector<int> vector = properties.at(index).value<QVector<int> >(); QVector<int> vector = node.properties.at(0).value<QVector<int> >();
if (!vector.isEmpty()) { if (!vector.isEmpty()) {
return vector; return vector;
} }
for (; index < properties.size(); index++) { for (int i = 0; i < node.properties.size(); i++) {
vector.append(properties.at(index).toInt()); vector.append(node.properties.at(i).toInt());
} }
return vector; return vector;
} }
QVector<qlonglong> getLongVector(const QVariantList& properties, int index) { QVector<float> getFloatVector(const FBXNode& node) {
if (index >= properties.size()) { foreach (const FBXNode& child, node.children) {
return QVector<qlonglong>(); if (child.name == "a") {
return getFloatVector(child);
}
} }
QVector<qlonglong> vector = properties.at(index).value<QVector<qlonglong> >(); if (node.properties.isEmpty()) {
if (!vector.isEmpty()) {
return vector;
}
for (; index < properties.size(); index++) {
vector.append(properties.at(index).toLongLong());
}
return vector;
}
QVector<float> getFloatVector(const QVariantList& properties, int index) {
if (index >= properties.size()) {
return QVector<float>(); return QVector<float>();
} }
QVector<float> vector = properties.at(index).value<QVector<float> >(); QVector<float> vector = node.properties.at(0).value<QVector<float> >();
if (!vector.isEmpty()) { if (!vector.isEmpty()) {
return vector; return vector;
} }
for (; index < properties.size(); index++) { for (int i = 0; i < node.properties.size(); i++) {
vector.append(properties.at(index).toFloat()); vector.append(node.properties.at(i).toFloat());
} }
return vector; return vector;
} }
QVector<double> getDoubleVector(const QVariantList& properties, int index) { QVector<double> getDoubleVector(const FBXNode& node) {
if (index >= properties.size()) { foreach (const FBXNode& child, node.children) {
if (child.name == "a") {
return getDoubleVector(child);
}
}
if (node.properties.isEmpty()) {
return QVector<double>(); return QVector<double>();
} }
QVector<double> vector = properties.at(index).value<QVector<double> >(); QVector<double> vector = node.properties.at(0).value<QVector<double> >();
if (!vector.isEmpty()) { if (!vector.isEmpty()) {
return vector; return vector;
} }
for (; index < properties.size(); index++) { for (int i = 0; i < node.properties.size(); i++) {
vector.append(properties.at(index).toDouble()); vector.append(node.properties.at(i).toDouble());
} }
return vector; return vector;
} }
@ -697,21 +698,30 @@ public:
}; };
void appendIndex(MeshData& data, QVector<int>& indices, int index) { void appendIndex(MeshData& data, QVector<int>& indices, int index) {
if (index >= data.polygonIndices.size()) {
return;
}
int vertexIndex = data.polygonIndices.at(index); int vertexIndex = data.polygonIndices.at(index);
if (vertexIndex < 0) { if (vertexIndex < 0) {
vertexIndex = -vertexIndex - 1; vertexIndex = -vertexIndex - 1;
} }
Vertex vertex; Vertex vertex;
vertex.originalIndex = vertexIndex; vertex.originalIndex = vertexIndex;
glm::vec3 position;
if (vertexIndex < data.vertices.size()) {
position = data.vertices.at(vertexIndex);
}
glm::vec3 normal; glm::vec3 normal;
if (data.normalIndices.isEmpty()) { int normalIndex = data.normalsByVertex ? vertexIndex : index;
normal = data.normals.at(data.normalsByVertex ? vertexIndex : index); if (data.normalIndices.isEmpty()) {
if (normalIndex < data.normals.size()) {
} else { normal = data.normals.at(normalIndex);
int normalIndex = data.normalIndices.at(data.normalsByVertex ? vertexIndex : index); }
if (normalIndex >= 0) { } else if (normalIndex < data.normalIndices.size()) {
normalIndex = data.normalIndices.at(normalIndex);
if (normalIndex >= 0 && normalIndex < data.normals.size()) {
normal = data.normals.at(normalIndex); normal = data.normals.at(normalIndex);
} }
} }
@ -720,9 +730,9 @@ void appendIndex(MeshData& data, QVector<int>& indices, int index) {
if (index < data.texCoords.size()) { if (index < data.texCoords.size()) {
vertex.texCoord = data.texCoords.at(index); vertex.texCoord = data.texCoords.at(index);
} }
} else { } else if (index < data.texCoordIndices.size()) {
int texCoordIndex = data.texCoordIndices.at(index); int texCoordIndex = data.texCoordIndices.at(index);
if (texCoordIndex >= 0) { if (texCoordIndex >= 0 && texCoordIndex < data.texCoords.size()) {
vertex.texCoord = data.texCoords.at(texCoordIndex); vertex.texCoord = data.texCoords.at(texCoordIndex);
} }
} }
@ -733,7 +743,7 @@ void appendIndex(MeshData& data, QVector<int>& indices, int index) {
indices.append(newIndex); indices.append(newIndex);
data.indices.insert(vertex, newIndex); data.indices.insert(vertex, newIndex);
data.extracted.newIndices.insert(vertexIndex, newIndex); data.extracted.newIndices.insert(vertexIndex, newIndex);
data.extracted.mesh.vertices.append(data.vertices.at(vertexIndex)); data.extracted.mesh.vertices.append(position);
data.extracted.mesh.normals.append(normal); data.extracted.mesh.normals.append(normal);
data.extracted.mesh.texCoords.append(vertex.texCoord); data.extracted.mesh.texCoords.append(vertex.texCoord);
@ -749,44 +759,51 @@ ExtractedMesh extractMesh(const FBXNode& object) {
QVector<int> textures; QVector<int> textures;
foreach (const FBXNode& child, object.children) { foreach (const FBXNode& child, object.children) {
if (child.name == "Vertices") { if (child.name == "Vertices") {
data.vertices = createVec3Vector(getDoubleVector(child.properties, 0)); data.vertices = createVec3Vector(getDoubleVector(child));
} else if (child.name == "PolygonVertexIndex") { } else if (child.name == "PolygonVertexIndex") {
data.polygonIndices = getIntVector(child.properties, 0); data.polygonIndices = getIntVector(child);
} else if (child.name == "LayerElementNormal") { } else if (child.name == "LayerElementNormal") {
data.normalsByVertex = false; data.normalsByVertex = false;
bool indexToDirect = false;
foreach (const FBXNode& subdata, child.children) { foreach (const FBXNode& subdata, child.children) {
if (subdata.name == "Normals") { if (subdata.name == "Normals") {
data.normals = createVec3Vector(getDoubleVector(subdata.properties, 0)); data.normals = createVec3Vector(getDoubleVector(subdata));
} else if (subdata.name == "NormalsIndex") { } else if (subdata.name == "NormalsIndex") {
data.normalIndices = getIntVector(subdata.properties, 0); data.normalIndices = getIntVector(subdata);
} else if (subdata.name == "MappingInformationType" && } else if (subdata.name == "MappingInformationType" && subdata.properties.at(0) == "ByVertice") {
subdata.properties.at(0) == "ByVertice") {
data.normalsByVertex = true; data.normalsByVertex = true;
} else if (subdata.name == "ReferenceInformationType" && subdata.properties.at(0) == "IndexToDirect") {
indexToDirect = true;
} }
} }
if (indexToDirect && data.normalIndices.isEmpty()) {
// hack to work around wacky Makehuman exports
data.normalsByVertex = true;
}
} else if (child.name == "LayerElementUV" && child.properties.at(0).toInt() == 0) { } else if (child.name == "LayerElementUV" && child.properties.at(0).toInt() == 0) {
foreach (const FBXNode& subdata, child.children) { foreach (const FBXNode& subdata, child.children) {
if (subdata.name == "UV") { if (subdata.name == "UV") {
data.texCoords = createVec2Vector(getDoubleVector(subdata.properties, 0)); data.texCoords = createVec2Vector(getDoubleVector(subdata));
} else if (subdata.name == "UVIndex") { } else if (subdata.name == "UVIndex") {
data.texCoordIndices = getIntVector(subdata.properties, 0); data.texCoordIndices = getIntVector(subdata);
} }
} }
} else if (child.name == "LayerElementMaterial") { } else if (child.name == "LayerElementMaterial") {
foreach (const FBXNode& subdata, child.children) { foreach (const FBXNode& subdata, child.children) {
if (subdata.name == "Materials") { if (subdata.name == "Materials") {
materials = getIntVector(subdata.properties, 0); materials = getIntVector(subdata);
} }
} }
} else if (child.name == "LayerElementTexture") { } else if (child.name == "LayerElementTexture") {
foreach (const FBXNode& subdata, child.children) { foreach (const FBXNode& subdata, child.children) {
if (subdata.name == "TextureId") { if (subdata.name == "TextureId") {
textures = getIntVector(subdata.properties, 0); textures = getIntVector(subdata);
} }
} }
} }
@ -797,7 +814,7 @@ ExtractedMesh extractMesh(const FBXNode& object) {
QHash<QPair<int, int>, int> materialTextureParts; QHash<QPair<int, int>, int> materialTextureParts;
for (int beginIndex = 0; beginIndex < data.polygonIndices.size(); polygonIndex++) { for (int beginIndex = 0; beginIndex < data.polygonIndices.size(); polygonIndex++) {
int endIndex = beginIndex; int endIndex = beginIndex;
while (data.polygonIndices.at(endIndex++) >= 0); while (endIndex < data.polygonIndices.size() && data.polygonIndices.at(endIndex++) >= 0);
QPair<int, int> materialTexture((polygonIndex < materials.size()) ? materials.at(polygonIndex) : 0, QPair<int, int> materialTexture((polygonIndex < materials.size()) ? materials.at(polygonIndex) : 0,
(polygonIndex < textures.size()) ? textures.at(polygonIndex) : 0); (polygonIndex < textures.size()) ? textures.at(polygonIndex) : 0);
@ -820,7 +837,7 @@ ExtractedMesh extractMesh(const FBXNode& object) {
appendIndex(data, part.triangleIndices, beginIndex); appendIndex(data, part.triangleIndices, beginIndex);
appendIndex(data, part.triangleIndices, nextIndex++); appendIndex(data, part.triangleIndices, nextIndex++);
appendIndex(data, part.triangleIndices, nextIndex); appendIndex(data, part.triangleIndices, nextIndex);
if (data.polygonIndices.at(nextIndex) < 0) { if (nextIndex >= data.polygonIndices.size() || data.polygonIndices.at(nextIndex) < 0) {
break; break;
} }
} }
@ -835,13 +852,13 @@ FBXBlendshape extractBlendshape(const FBXNode& object) {
FBXBlendshape blendshape; FBXBlendshape blendshape;
foreach (const FBXNode& data, object.children) { foreach (const FBXNode& data, object.children) {
if (data.name == "Indexes") { if (data.name == "Indexes") {
blendshape.indices = getIntVector(data.properties, 0); blendshape.indices = getIntVector(data);
} else if (data.name == "Vertices") { } else if (data.name == "Vertices") {
blendshape.vertices = createVec3Vector(getDoubleVector(data.properties, 0)); blendshape.vertices = createVec3Vector(getDoubleVector(data));
} else if (data.name == "Normals") { } else if (data.name == "Normals") {
blendshape.normals = createVec3Vector(getDoubleVector(data.properties, 0)); blendshape.normals = createVec3Vector(getDoubleVector(data));
} }
} }
return blendshape; return blendshape;
@ -1016,7 +1033,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
foreach (const FBXNode& object, child.children) { foreach (const FBXNode& object, child.children) {
if (object.name == "SceneInfo") { if (object.name == "SceneInfo") {
foreach (const FBXNode& subobject, object.children) { foreach (const FBXNode& subobject, object.children) {
if (subobject.name == "Properties70") { if (subobject.name == "MetaData") {
foreach (const FBXNode& subsubobject, subobject.children) {
if (subsubobject.name == "Author") {
geometry.author = subsubobject.properties.at(0).toString();
}
}
} else if (subobject.name == "Properties70") {
foreach (const FBXNode& subsubobject, subobject.children) { foreach (const FBXNode& subsubobject, subobject.children) {
if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 && if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 &&
subsubobject.properties.at(0) == "Original|ApplicationName") { subsubobject.properties.at(0) == "Original|ApplicationName") {
@ -1262,13 +1285,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
Cluster cluster; Cluster cluster;
foreach (const FBXNode& subobject, object.children) { foreach (const FBXNode& subobject, object.children) {
if (subobject.name == "Indexes") { if (subobject.name == "Indexes") {
cluster.indices = getIntVector(subobject.properties, 0); cluster.indices = getIntVector(subobject);
} else if (subobject.name == "Weights") { } else if (subobject.name == "Weights") {
cluster.weights = getDoubleVector(subobject.properties, 0); cluster.weights = getDoubleVector(subobject);
} else if (subobject.name == "TransformLink") { } else if (subobject.name == "TransformLink") {
QVector<double> values = getDoubleVector(subobject.properties, 0); QVector<double> values = getDoubleVector(subobject);
cluster.transformLink = createMat4(values); cluster.transformLink = createMat4(values);
} }
} }
@ -1290,7 +1313,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
AnimationCurve curve; AnimationCurve curve;
foreach (const FBXNode& subobject, object.children) { foreach (const FBXNode& subobject, object.children) {
if (subobject.name == "KeyValueFloat") { if (subobject.name == "KeyValueFloat") {
curve.values = getFloatVector(subobject.properties, 0); curve.values = getFloatVector(subobject);
} }
} }
animationCurves.insert(getID(object.properties), curve); animationCurves.insert(getID(object.properties), curve);

View file

@ -177,6 +177,7 @@ public:
class FBXGeometry { class FBXGeometry {
public: public:
QString author;
QString applicationName; ///< the name of the application that generated the model QString applicationName; ///< the name of the application that generated the model
QVector<FBXJoint> joints; QVector<FBXJoint> joints;