mirror of
https://github.com/overte-org/overte.git
synced 2025-04-20 18:44:01 +02:00
Merge branch 'master' of https://github.com/highfidelity/hifi
This commit is contained in:
commit
9ffd93a167
16 changed files with 121 additions and 183 deletions
|
@ -39,7 +39,7 @@ you to run the full stack of the virtual world.
|
|||
In order to set up your own virtual world, you need to set up and run your own
|
||||
local "domain".
|
||||
|
||||
The domain-server gives a number different types of assignments to the assignment-client for different features: audio, avatars, voxels, particles, and meta-voxels.
|
||||
The domain-server gives a number different types of assignments to the assignment-client for different features: audio, avatars, voxels, particles, meta-voxels and models.
|
||||
|
||||
Follow the instructions in the [build guide](BUILD.md) to build the various components.
|
||||
|
||||
|
@ -57,7 +57,7 @@ Any target can be terminated with Ctrl-C (SIGINT) in the associated Terminal win
|
|||
|
||||
This assignment-client will grab one assignment from the domain-server. You can tell the assignment-client what type you want it to be with the `-t` option. You can also run an assignment-client that forks off *n* assignment-clients with the `-n` option.
|
||||
|
||||
./assignment-client -n 5
|
||||
./assignment-client -n 6
|
||||
|
||||
To test things out you'll want to run the Interface client.
|
||||
|
||||
|
|
|
@ -331,8 +331,9 @@ function ScaleSelector() {
|
|||
});
|
||||
this.setScale = function(scale) {
|
||||
this.scale = scale;
|
||||
this.power = Math.floor(Math.log(scale));
|
||||
this.power = Math.floor(Math.log(scale) / Math.log(2));
|
||||
rescaleImport();
|
||||
this.update();
|
||||
}
|
||||
|
||||
this.show = function(doShow) {
|
||||
|
@ -835,7 +836,6 @@ function showPreviewLines() {
|
|||
|
||||
if (copyScale) {
|
||||
scaleSelector.setScale(intersection.voxel.s);
|
||||
scaleSelector.update();
|
||||
}
|
||||
moveTools();
|
||||
} else {
|
||||
|
|
|
@ -561,42 +561,6 @@ void Application::paintGL() {
|
|||
_myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
|
||||
_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) {
|
||||
_myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
|
||||
_myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition());
|
||||
|
@ -3132,8 +3096,8 @@ void Application::updateWindowTitle(){
|
|||
NodeList* nodeList = NodeList::getInstance();
|
||||
|
||||
QString username = AccountManager::getInstance().getAccountInfo().getUsername();
|
||||
QString title = QString() + (!username.isEmpty() ? username + " " : QString()) + nodeList->getSessionUUID().toString()
|
||||
+ " @ " + nodeList->getDomainHandler().getHostname() + buildVersion;
|
||||
QString title = QString() + (!username.isEmpty() ? username + " @ " : QString())
|
||||
+ nodeList->getDomainHandler().getHostname() + buildVersion;
|
||||
qDebug("Application title set to: %s", title.toStdString().c_str());
|
||||
_window->setWindowTitle(title);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
//
|
||||
|
||||
#include "MainWindow.h"
|
||||
#include "Menu.h"
|
||||
|
||||
#include <QEvent>
|
||||
#include <QMoveEvent>
|
||||
|
@ -56,6 +57,10 @@ void MainWindow::changeEvent(QEvent* event) {
|
|||
} else {
|
||||
emit windowShown(true);
|
||||
}
|
||||
|
||||
if (isFullScreen() != Menu::getInstance()->isOptionChecked(MenuOption::Fullscreen)) {
|
||||
Menu::getInstance()->setIsOptionChecked(MenuOption::Fullscreen, isFullScreen());
|
||||
}
|
||||
} else if (event->type() == QEvent::ActivationChange) {
|
||||
if (isActiveWindow()) {
|
||||
emit windowShown(true);
|
||||
|
|
|
@ -336,7 +336,6 @@ Menu::Menu() :
|
|||
SLOT(setFilter(bool)));
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHands, 0, true);
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::DisplayHandTargets, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::PlaySlaps, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::HandsCollideWithSelf, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::ShowIKConstraints, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(handOptionsMenu, MenuOption::AlignForearmsWithWrists, 0, true);
|
||||
|
|
|
@ -340,7 +340,6 @@ namespace MenuOption {
|
|||
const QString Particles = "Particles";
|
||||
const QString PasteToVoxel = "Paste to Voxel...";
|
||||
const QString PipelineWarnings = "Show Render Pipeline Warnings";
|
||||
const QString PlaySlaps = "Play Slaps";
|
||||
const QString Preferences = "Preferences...";
|
||||
const QString Quit = "Quit";
|
||||
const QString ReloadAllScripts = "Reload All Scripts";
|
||||
|
|
|
@ -153,14 +153,14 @@ bool ModelUploader::zip() {
|
|||
|
||||
// mixamo/autodesk defaults
|
||||
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();
|
||||
if (!joints.contains("jointEyeLeft")) {
|
||||
joints.insert("jointEyeLeft", "LeftEye");
|
||||
joints.insert("jointEyeLeft", geometry.jointIndices.contains("EyeLeft") ? "EyeLeft" : "LeftEye");
|
||||
}
|
||||
if (!joints.contains("jointEyeRight")) {
|
||||
joints.insert("jointEyeRight", "RightEye");
|
||||
joints.insert("jointEyeRight", geometry.jointIndices.contains("EyeRight") ? "EyeRight" : "RightEye");
|
||||
}
|
||||
if (!joints.contains("jointNeck")) {
|
||||
joints.insert("jointNeck", "Neck");
|
||||
|
@ -172,7 +172,8 @@ bool ModelUploader::zip() {
|
|||
joints.insert("jointLean", "Spine");
|
||||
}
|
||||
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")) {
|
||||
joints.insert("jointLeftHand", "LeftHand");
|
||||
|
|
|
@ -29,11 +29,11 @@ void FaceModel::simulate(float deltaTime, bool fullUpdate) {
|
|||
neckPosition = owningAvatar->getPosition();
|
||||
}
|
||||
setTranslation(neckPosition);
|
||||
glm::quat neckRotation;
|
||||
if (!owningAvatar->getSkeletonModel().getNeckRotation(neckRotation)) {
|
||||
neckRotation = owningAvatar->getOrientation();
|
||||
glm::quat neckParentRotation;
|
||||
if (!owningAvatar->getSkeletonModel().getNeckParentRotation(neckParentRotation)) {
|
||||
neckParentRotation = owningAvatar->getOrientation();
|
||||
}
|
||||
setRotation(neckRotation);
|
||||
setRotation(neckParentRotation);
|
||||
const float MODEL_SCALE = 0.0006f;
|
||||
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningHead->getScale() * MODEL_SCALE);
|
||||
|
||||
|
|
|
@ -55,76 +55,10 @@ void Hand::simulate(float deltaTime, bool isMine) {
|
|||
}
|
||||
}
|
||||
|
||||
void Hand::playSlaps(PalmData& palm, Avatar* avatar) {
|
||||
// Check for palm collisions
|
||||
glm::vec3 myPalmPosition = palm.getPosition();
|
||||
float palmCollisionDistance = 0.1f;
|
||||
bool wasColliding = palm.getIsCollidingWithPalm();
|
||||
palm.setIsCollidingWithPalm(false);
|
||||
// If 'Play Slaps' is enabled, look for palm-to-palm collisions and make sound
|
||||
for (size_t j = 0; j < avatar->getHand()->getNumPalms(); j++) {
|
||||
PalmData& otherPalm = avatar->getHand()->getPalms()[j];
|
||||
if (!otherPalm.isActive()) {
|
||||
continue;
|
||||
}
|
||||
glm::vec3 otherPalmPosition = otherPalm.getPosition();
|
||||
if (glm::length(otherPalmPosition - myPalmPosition) < palmCollisionDistance) {
|
||||
palm.setIsCollidingWithPalm(true);
|
||||
if (!wasColliding) {
|
||||
const float PALM_COLLIDE_VOLUME = 1.f;
|
||||
const float PALM_COLLIDE_FREQUENCY = 1000.f;
|
||||
const float PALM_COLLIDE_DURATION_MAX = 0.75f;
|
||||
const float PALM_COLLIDE_DECAY_PER_SAMPLE = 0.01f;
|
||||
Application::getInstance()->getAudio()->startDrumSound(PALM_COLLIDE_VOLUME,
|
||||
PALM_COLLIDE_FREQUENCY,
|
||||
PALM_COLLIDE_DURATION_MAX,
|
||||
PALM_COLLIDE_DECAY_PER_SAMPLE);
|
||||
// If the other person's palm is in motion, move mine downward to show I was hit
|
||||
const float MIN_VELOCITY_FOR_SLAP = 0.05f;
|
||||
if (glm::length(otherPalm.getVelocity()) > MIN_VELOCITY_FOR_SLAP) {
|
||||
// add slapback here
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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::collideAgainstAvatarOld(Avatar* avatar, bool isMyHand) {
|
||||
if (!avatar || avatar == _owningAvatar) {
|
||||
// don't collide with our own hands (that is done elsewhere)
|
||||
return;
|
||||
}
|
||||
float scaledPalmRadius = PALM_COLLISION_RADIUS * _owningAvatar->getScale();
|
||||
for (size_t i = 0; i < getNumPalms(); i++) {
|
||||
PalmData& palm = getPalms()[i];
|
||||
if (!palm.isActive()) {
|
||||
continue;
|
||||
}
|
||||
if (isMyHand && Menu::getInstance()->isOptionChecked(MenuOption::PlaySlaps)) {
|
||||
playSlaps(palm, avatar);
|
||||
}
|
||||
|
||||
glm::vec3 totalPenetration;
|
||||
handCollisions.clear();
|
||||
if (avatar->findSphereCollisions(palm.getPosition(), scaledPalmRadius, handCollisions)) {
|
||||
for (int j = 0; j < handCollisions.size(); ++j) {
|
||||
CollisionInfo* collision = handCollisions.getCollision(j);
|
||||
if (isMyHand) {
|
||||
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (isMyHand) {
|
||||
// resolve penetration
|
||||
palm.addToPosition(-totalPenetration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
|
||||
if (!avatar || avatar == _owningAvatar) {
|
||||
// don't collide hands against ourself (that is done elsewhere)
|
||||
|
|
|
@ -58,7 +58,6 @@ public:
|
|||
const glm::vec3& getLeapFingerTipBallPosition (int ball) const { return _leapFingerTipBalls [ball].position;}
|
||||
const glm::vec3& getLeapFingerRootBallPosition(int ball) const { return _leapFingerRootBalls[ball].position;}
|
||||
|
||||
void collideAgainstAvatarOld(Avatar* avatar, bool isMyHand);
|
||||
void collideAgainstAvatar(Avatar* avatar, bool isMyHand);
|
||||
void collideAgainstOurself();
|
||||
|
||||
|
@ -80,8 +79,6 @@ private:
|
|||
void renderLeapFingerTrails();
|
||||
|
||||
void calculateGeometry();
|
||||
|
||||
void playSlaps(PalmData& palm, Avatar* avatar);
|
||||
};
|
||||
|
||||
#endif // hifi_Hand_h
|
||||
|
|
|
@ -434,6 +434,17 @@ bool Model::getNeckRotation(glm::quat& neckRotation) const {
|
|||
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 {
|
||||
if (!isActive()) {
|
||||
return false;
|
||||
|
|
|
@ -132,6 +132,10 @@ public:
|
|||
/// \return whether or not the neck was found
|
||||
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.
|
||||
/// \return whether or not both eye meshes were found
|
||||
bool getEyePositions(glm::vec3& firstEyePosition, glm::vec3& secondEyePosition) const;
|
||||
|
|
|
@ -19,7 +19,7 @@ ScriptLineNumberArea::ScriptLineNumberArea(ScriptEditBox* scriptEditBox) :
|
|||
_scriptEditBox = scriptEditBox;
|
||||
}
|
||||
|
||||
QSize ScriptLineNumberArea::sizeHint() {
|
||||
QSize ScriptLineNumberArea::sizeHint() const {
|
||||
return QSize(_scriptEditBox->lineNumberAreaWidth(), 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ class ScriptLineNumberArea : public QWidget {
|
|||
|
||||
public:
|
||||
ScriptLineNumberArea(ScriptEditBox* scriptEditBox);
|
||||
QSize sizeHint();
|
||||
QSize sizeHint() const;
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent* event);
|
||||
|
|
|
@ -406,7 +406,7 @@ QVariantHash parseMapping(QIODevice* device) {
|
|||
|
||||
QVector<glm::vec3> createVec3Vector(const QVector<double>& doubleVector) {
|
||||
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 y = *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> 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 t = *it++;
|
||||
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));
|
||||
}
|
||||
|
||||
QVector<int> getIntVector(const QVariantList& properties, int index) {
|
||||
if (index >= properties.size()) {
|
||||
QVector<int> getIntVector(const FBXNode& node) {
|
||||
foreach (const FBXNode& child, node.children) {
|
||||
if (child.name == "a") {
|
||||
return getIntVector(child);
|
||||
}
|
||||
}
|
||||
if (node.properties.isEmpty()) {
|
||||
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()) {
|
||||
return vector;
|
||||
}
|
||||
for (; index < properties.size(); index++) {
|
||||
vector.append(properties.at(index).toInt());
|
||||
for (int i = 0; i < node.properties.size(); i++) {
|
||||
vector.append(node.properties.at(i).toInt());
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
QVector<qlonglong> getLongVector(const QVariantList& properties, int index) {
|
||||
if (index >= properties.size()) {
|
||||
return QVector<qlonglong>();
|
||||
QVector<float> getFloatVector(const FBXNode& node) {
|
||||
foreach (const FBXNode& child, node.children) {
|
||||
if (child.name == "a") {
|
||||
return getFloatVector(child);
|
||||
}
|
||||
}
|
||||
QVector<qlonglong> vector = properties.at(index).value<QVector<qlonglong> >();
|
||||
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()) {
|
||||
if (node.properties.isEmpty()) {
|
||||
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()) {
|
||||
return vector;
|
||||
}
|
||||
for (; index < properties.size(); index++) {
|
||||
vector.append(properties.at(index).toFloat());
|
||||
for (int i = 0; i < node.properties.size(); i++) {
|
||||
vector.append(node.properties.at(i).toFloat());
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
||||
QVector<double> getDoubleVector(const QVariantList& properties, int index) {
|
||||
if (index >= properties.size()) {
|
||||
QVector<double> getDoubleVector(const FBXNode& node) {
|
||||
foreach (const FBXNode& child, node.children) {
|
||||
if (child.name == "a") {
|
||||
return getDoubleVector(child);
|
||||
}
|
||||
}
|
||||
if (node.properties.isEmpty()) {
|
||||
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()) {
|
||||
return vector;
|
||||
}
|
||||
for (; index < properties.size(); index++) {
|
||||
vector.append(properties.at(index).toDouble());
|
||||
for (int i = 0; i < node.properties.size(); i++) {
|
||||
vector.append(node.properties.at(i).toDouble());
|
||||
}
|
||||
return vector;
|
||||
}
|
||||
|
@ -697,21 +698,30 @@ public:
|
|||
};
|
||||
|
||||
void appendIndex(MeshData& data, QVector<int>& indices, int index) {
|
||||
if (index >= data.polygonIndices.size()) {
|
||||
return;
|
||||
}
|
||||
int vertexIndex = data.polygonIndices.at(index);
|
||||
if (vertexIndex < 0) {
|
||||
vertexIndex = -vertexIndex - 1;
|
||||
}
|
||||
|
||||
Vertex vertex;
|
||||
vertex.originalIndex = vertexIndex;
|
||||
|
||||
glm::vec3 position;
|
||||
if (vertexIndex < data.vertices.size()) {
|
||||
position = data.vertices.at(vertexIndex);
|
||||
}
|
||||
|
||||
glm::vec3 normal;
|
||||
if (data.normalIndices.isEmpty()) {
|
||||
normal = data.normals.at(data.normalsByVertex ? vertexIndex : index);
|
||||
|
||||
} else {
|
||||
int normalIndex = data.normalIndices.at(data.normalsByVertex ? vertexIndex : index);
|
||||
if (normalIndex >= 0) {
|
||||
int normalIndex = data.normalsByVertex ? vertexIndex : index;
|
||||
if (data.normalIndices.isEmpty()) {
|
||||
if (normalIndex < data.normals.size()) {
|
||||
normal = data.normals.at(normalIndex);
|
||||
}
|
||||
} else if (normalIndex < data.normalIndices.size()) {
|
||||
normalIndex = data.normalIndices.at(normalIndex);
|
||||
if (normalIndex >= 0 && normalIndex < data.normals.size()) {
|
||||
normal = data.normals.at(normalIndex);
|
||||
}
|
||||
}
|
||||
|
@ -720,9 +730,9 @@ void appendIndex(MeshData& data, QVector<int>& indices, int index) {
|
|||
if (index < data.texCoords.size()) {
|
||||
vertex.texCoord = data.texCoords.at(index);
|
||||
}
|
||||
} else {
|
||||
} else if (index < data.texCoordIndices.size()) {
|
||||
int texCoordIndex = data.texCoordIndices.at(index);
|
||||
if (texCoordIndex >= 0) {
|
||||
if (texCoordIndex >= 0 && texCoordIndex < data.texCoords.size()) {
|
||||
vertex.texCoord = data.texCoords.at(texCoordIndex);
|
||||
}
|
||||
}
|
||||
|
@ -733,7 +743,7 @@ void appendIndex(MeshData& data, QVector<int>& indices, int index) {
|
|||
indices.append(newIndex);
|
||||
data.indices.insert(vertex, 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.texCoords.append(vertex.texCoord);
|
||||
|
||||
|
@ -749,44 +759,51 @@ ExtractedMesh extractMesh(const FBXNode& object) {
|
|||
QVector<int> textures;
|
||||
foreach (const FBXNode& child, object.children) {
|
||||
if (child.name == "Vertices") {
|
||||
data.vertices = createVec3Vector(getDoubleVector(child.properties, 0));
|
||||
data.vertices = createVec3Vector(getDoubleVector(child));
|
||||
|
||||
} else if (child.name == "PolygonVertexIndex") {
|
||||
data.polygonIndices = getIntVector(child.properties, 0);
|
||||
data.polygonIndices = getIntVector(child);
|
||||
|
||||
} else if (child.name == "LayerElementNormal") {
|
||||
data.normalsByVertex = false;
|
||||
bool indexToDirect = false;
|
||||
foreach (const FBXNode& subdata, child.children) {
|
||||
if (subdata.name == "Normals") {
|
||||
data.normals = createVec3Vector(getDoubleVector(subdata.properties, 0));
|
||||
data.normals = createVec3Vector(getDoubleVector(subdata));
|
||||
|
||||
} else if (subdata.name == "NormalsIndex") {
|
||||
data.normalIndices = getIntVector(subdata.properties, 0);
|
||||
data.normalIndices = getIntVector(subdata);
|
||||
|
||||
} else if (subdata.name == "MappingInformationType" &&
|
||||
subdata.properties.at(0) == "ByVertice") {
|
||||
} else if (subdata.name == "MappingInformationType" && subdata.properties.at(0) == "ByVertice") {
|
||||
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) {
|
||||
foreach (const FBXNode& subdata, child.children) {
|
||||
if (subdata.name == "UV") {
|
||||
data.texCoords = createVec2Vector(getDoubleVector(subdata.properties, 0));
|
||||
data.texCoords = createVec2Vector(getDoubleVector(subdata));
|
||||
|
||||
} else if (subdata.name == "UVIndex") {
|
||||
data.texCoordIndices = getIntVector(subdata.properties, 0);
|
||||
data.texCoordIndices = getIntVector(subdata);
|
||||
}
|
||||
}
|
||||
} else if (child.name == "LayerElementMaterial") {
|
||||
foreach (const FBXNode& subdata, child.children) {
|
||||
if (subdata.name == "Materials") {
|
||||
materials = getIntVector(subdata.properties, 0);
|
||||
materials = getIntVector(subdata);
|
||||
}
|
||||
}
|
||||
} else if (child.name == "LayerElementTexture") {
|
||||
foreach (const FBXNode& subdata, child.children) {
|
||||
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;
|
||||
for (int beginIndex = 0; beginIndex < data.polygonIndices.size(); polygonIndex++) {
|
||||
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,
|
||||
(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, nextIndex++);
|
||||
appendIndex(data, part.triangleIndices, nextIndex);
|
||||
if (data.polygonIndices.at(nextIndex) < 0) {
|
||||
if (nextIndex >= data.polygonIndices.size() || data.polygonIndices.at(nextIndex) < 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -835,13 +852,13 @@ FBXBlendshape extractBlendshape(const FBXNode& object) {
|
|||
FBXBlendshape blendshape;
|
||||
foreach (const FBXNode& data, object.children) {
|
||||
if (data.name == "Indexes") {
|
||||
blendshape.indices = getIntVector(data.properties, 0);
|
||||
blendshape.indices = getIntVector(data);
|
||||
|
||||
} else if (data.name == "Vertices") {
|
||||
blendshape.vertices = createVec3Vector(getDoubleVector(data.properties, 0));
|
||||
blendshape.vertices = createVec3Vector(getDoubleVector(data));
|
||||
|
||||
} else if (data.name == "Normals") {
|
||||
blendshape.normals = createVec3Vector(getDoubleVector(data.properties, 0));
|
||||
blendshape.normals = createVec3Vector(getDoubleVector(data));
|
||||
}
|
||||
}
|
||||
return blendshape;
|
||||
|
@ -1016,7 +1033,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
foreach (const FBXNode& object, child.children) {
|
||||
if (object.name == "SceneInfo") {
|
||||
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) {
|
||||
if (subsubobject.name == "P" && subsubobject.properties.size() >= 5 &&
|
||||
subsubobject.properties.at(0) == "Original|ApplicationName") {
|
||||
|
@ -1262,13 +1285,13 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
Cluster cluster;
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
if (subobject.name == "Indexes") {
|
||||
cluster.indices = getIntVector(subobject.properties, 0);
|
||||
cluster.indices = getIntVector(subobject);
|
||||
|
||||
} else if (subobject.name == "Weights") {
|
||||
cluster.weights = getDoubleVector(subobject.properties, 0);
|
||||
cluster.weights = getDoubleVector(subobject);
|
||||
|
||||
} else if (subobject.name == "TransformLink") {
|
||||
QVector<double> values = getDoubleVector(subobject.properties, 0);
|
||||
QVector<double> values = getDoubleVector(subobject);
|
||||
cluster.transformLink = createMat4(values);
|
||||
}
|
||||
}
|
||||
|
@ -1290,7 +1313,7 @@ FBXGeometry extractFBXGeometry(const FBXNode& node, const QVariantHash& mapping)
|
|||
AnimationCurve curve;
|
||||
foreach (const FBXNode& subobject, object.children) {
|
||||
if (subobject.name == "KeyValueFloat") {
|
||||
curve.values = getFloatVector(subobject.properties, 0);
|
||||
curve.values = getFloatVector(subobject);
|
||||
}
|
||||
}
|
||||
animationCurves.insert(getID(object.properties), curve);
|
||||
|
|
|
@ -177,6 +177,7 @@ public:
|
|||
class FBXGeometry {
|
||||
public:
|
||||
|
||||
QString author;
|
||||
QString applicationName; ///< the name of the application that generated the model
|
||||
|
||||
QVector<FBXJoint> joints;
|
||||
|
|
Loading…
Reference in a new issue