From c1466c2dec03e6e07d1ff341908f5eeae2536dfb Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 17 Mar 2017 10:45:13 -0700 Subject: [PATCH 01/14] Fix a couple sitting bugs --- scripts/tutorials/entity_scripts/sit.js | 33 +++++++++++++++++++------ 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 82afdc8974..82a6ab06a4 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -1,6 +1,16 @@ +// +// sit.js +// +// Created by Clement Brisset on 3/3/17 +// Copyright 2017 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 +// + (function() { Script.include("/~/system/libraries/utils.js"); - + var SETTING_KEY = "com.highfidelity.avatar.isSitting"; var ANIMATION_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/animations/sitting_idle.fbx"; var ANIMATION_FPS = 30; @@ -28,6 +38,7 @@ this.interval = null; this.sitDownSettlePeriod = null; this.lastTimeNoDriveKeys = null; + this.sittingDown = false; this.preload = function(entityID) { this.entityID = entityID; @@ -106,6 +117,7 @@ return; } print("Sitting down (" + this.entityID + ")"); + this.sittingDown = true; var now = Date.now(); this.sitDownSettlePeriod = now + IK_SETTLE_TIME; @@ -121,6 +133,11 @@ for (i in ROLES) { MyAvatar.overrideRoleAnimation(ROLES[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); } + + for (var i in OVERRIDEN_DRIVE_KEYS) { + MyAvatar.disableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); + } + MyAvatar.resetSensorsAndBody(); } @@ -132,22 +149,21 @@ return { headType: 0 }; }, ["headType"]); Script.update.connect(this, this.update); - for (var i in OVERRIDEN_DRIVE_KEYS) { - MyAvatar.disableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); - } } this.standUp = function() { print("Standing up (" + this.entityID + ")"); MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); - for (var i in OVERRIDEN_DRIVE_KEYS) { - MyAvatar.enableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); - } this.setSeatUser(null); if (Settings.getValue(SETTING_KEY) === this.entityID) { Settings.setValue(SETTING_KEY, ""); + + for (var i in OVERRIDEN_DRIVE_KEYS) { + MyAvatar.enableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); + } + var ROLES = MyAvatar.getAnimationRoles(); for (i in ROLES) { MyAvatar.restoreRoleAnimation(ROLES[i]); @@ -165,6 +181,7 @@ MyAvatar.bodyRoll = 0.0; }, SIT_DELAY); } + this.sittingDown = false; } // function called by teleport.js if it detects the appropriate userData @@ -215,7 +232,7 @@ } this.update = function(dt) { - if (MyAvatar.sessionUUID === this.getSeatUser()) { + if (this.sittingDown === true) { var properties = Entities.getEntityProperties(this.entityID); var avatarDistance = Vec3.distance(MyAvatar.position, properties.position); var ikError = MyAvatar.getIKErrorOnLastSolve(); From 4c756808777210af7080c5d2db5d05b19335982b Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 17 Mar 2017 16:10:15 -0700 Subject: [PATCH 02/14] Set teleport target to Cancel if seat in use --- scripts/system/controllers/teleport.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/scripts/system/controllers/teleport.js b/scripts/system/controllers/teleport.js index c058f046db..49bbdb7682 100644 --- a/scripts/system/controllers/teleport.js +++ b/scripts/system/controllers/teleport.js @@ -440,7 +440,12 @@ function getTeleportTargetType(intersection) { var props = Entities.getEntityProperties(intersection.entityID, ['userData', 'visible']); var data = parseJSON(props.userData); if (data !== undefined && data.seat !== undefined) { - return TARGET.SEAT; + var avatarUuid = Uuid.fromString(data.seat.user); + if (Uuid.isNull(avatarUuid) || !AvatarList.getAvatar(avatarUuid)) { + return TARGET.SEAT; + } else { + return TARGET.INVALID; + } } if (!props.visible) { From eccc9ff47c30c7782d51a9ae14a8dbbac0479083 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 17 Mar 2017 16:11:17 -0700 Subject: [PATCH 03/14] Prevent 2 avatars from staying seated in the same chair --- scripts/tutorials/entity_scripts/sit.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 82a6ab06a4..f03bc4fa50 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -156,7 +156,10 @@ MyAvatar.removeAnimationStateHandler(this.animStateHandlerID); Script.update.disconnect(this, this.update); - this.setSeatUser(null); + if (MyAvatar.sessionUUID === this.getSeatUser()) { + this.setSeatUser(null); + } + if (Settings.getValue(SETTING_KEY) === this.entityID) { Settings.setValue(SETTING_KEY, ""); @@ -261,6 +264,9 @@ shouldStandUp = true; } + if (MyAvatar.sessionUUID !== this.getSeatUser()) { + shouldStandUp = true; + } if (shouldStandUp || avatarDistance > RELEASE_DISTANCE) { print("IK error: " + ikError + ", distance from chair: " + avatarDistance); From 1ce4dcc6e5a732dbd1a27a07f59a76fd26f47544 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 17 Mar 2017 16:11:47 -0700 Subject: [PATCH 04/14] Fix attempt for avatar stuck in geometry. --- scripts/tutorials/entity_scripts/sit.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index f03bc4fa50..01c7030a44 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -276,7 +276,11 @@ var offset = { x: 0, y: 1.0, z: -0.5 - properties.dimensions.z * properties.registrationPoint.z }; var position = Vec3.sum(properties.position, Vec3.multiplyQbyV(properties.rotation, offset)); MyAvatar.position = position; - print("Moving Avatar in front of the chair.") + print("Moving Avatar in front of the chair."); + // Delay standing up by 1 cycle. + // This leaves times for the avatar to actually move since a lot + // of the stand up operations are threaded + return; } this.standUp(); From 893a5b1b18fcf32877bf135df0eec1854271816d Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 17 Mar 2017 17:16:08 -0700 Subject: [PATCH 05/14] Only override inAir and flying animation roles --- scripts/tutorials/entity_scripts/sit.js | 26 ++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index 01c7030a44..ae16828c01 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -10,7 +10,13 @@ (function() { Script.include("/~/system/libraries/utils.js"); - + if (!String.prototype.startsWith) { + String.prototype.startsWith = function(searchString, position){ + position = position || 0; + return this.substr(position, searchString.length) === searchString; + }; + } + var SETTING_KEY = "com.highfidelity.avatar.isSitting"; var ANIMATION_URL = "https://s3-us-west-1.amazonaws.com/hifi-content/clement/production/animations/sitting_idle.fbx"; var ANIMATION_FPS = 30; @@ -111,6 +117,12 @@ return seatUser !== null; } + this.rolesToOverride = function() { + return MyAvatar.getAnimationRoles().filter(function(role) { + return role === "fly" || role.startsWith("inAir"); + }); + } + this.sitDown = function() { if (this.checkSeatForAvatar()) { print("Someone is already sitting in that chair."); @@ -129,9 +141,9 @@ if (previousValue === "") { MyAvatar.characterControllerEnabled = false; MyAvatar.hmdLeanRecenterEnabled = false; - var ROLES = MyAvatar.getAnimationRoles(); - for (i in ROLES) { - MyAvatar.overrideRoleAnimation(ROLES[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); + var roles = this.rolesToOverride(); + for (i in roles) { + MyAvatar.overrideRoleAnimation(roles[i], ANIMATION_URL, ANIMATION_FPS, true, ANIMATION_FIRST_FRAME, ANIMATION_LAST_FRAME); } for (var i in OVERRIDEN_DRIVE_KEYS) { @@ -167,9 +179,9 @@ MyAvatar.enableDriveKey(OVERRIDEN_DRIVE_KEYS[i]); } - var ROLES = MyAvatar.getAnimationRoles(); - for (i in ROLES) { - MyAvatar.restoreRoleAnimation(ROLES[i]); + var roles = this.rolesToOverride(); + for (i in roles) { + MyAvatar.restoreRoleAnimation(roles[i]); } MyAvatar.characterControllerEnabled = true; MyAvatar.hmdLeanRecenterEnabled = true; From eab2c314d8cd6cb925f1fb8179a7bccda3b4fcb0 Mon Sep 17 00:00:00 2001 From: Atlante45 Date: Fri, 17 Mar 2017 17:17:05 -0700 Subject: [PATCH 06/14] Preload sitting animation --- scripts/tutorials/entity_scripts/sit.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/scripts/tutorials/entity_scripts/sit.js b/scripts/tutorials/entity_scripts/sit.js index ae16828c01..3d3bc10fb1 100644 --- a/scripts/tutorials/entity_scripts/sit.js +++ b/scripts/tutorials/entity_scripts/sit.js @@ -46,6 +46,9 @@ this.lastTimeNoDriveKeys = null; this.sittingDown = false; + // Preload the animation file + this.animation = AnimationCache.prefetch(ANIMATION_URL); + this.preload = function(entityID) { this.entityID = entityID; } From 60874e6041bd584962bf4e1b85022274061ca694 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 20 Mar 2017 16:31:38 -0700 Subject: [PATCH 07/14] remove unused cruft --- libraries/fbx/src/FBXReader.cpp | 20 +------------------- libraries/fbx/src/FBXReader.h | 2 -- 2 files changed, 1 insertion(+), 21 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index 718793fefa..f4af39fdf4 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1631,13 +1631,11 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS // whether we're skinned depends on how many clusters are attached const FBXCluster& firstFBXCluster = extracted.mesh.clusters.at(0); - int maxJointIndex = firstFBXCluster.jointIndex; glm::mat4 inverseModelTransform = glm::inverse(modelTransform); if (clusterIDs.size() > 1) { // this is a multi-mesh joint extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size()); extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size()); - float maxWeight = 0.0f; for (int i = 0; i < clusterIDs.size(); i++) { QString clusterID = clusterIDs.at(i); const Cluster& cluster = clusters[clusterID]; @@ -1662,11 +1660,9 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform; ShapeVertices& points = shapeVertices.at(jointIndex); - float totalWeight = 0.0f; for (int j = 0; j < cluster.indices.size(); j++) { int oldIndex = cluster.indices.at(j); float weight = cluster.weights.at(j); - totalWeight += weight; for (QMultiHash::const_iterator it = extracted.newIndices.constFind(oldIndex); it != extracted.newIndices.end() && it.key() == oldIndex; it++) { @@ -1701,10 +1697,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } } } - if (totalWeight > maxWeight) { - maxWeight = totalWeight; - maxJointIndex = jointIndex; - } } // normalize the weights if they don't add up to one for (int i = 0; i < extracted.mesh.clusterWeights.size(); i++) { @@ -1716,7 +1708,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } } else { // this is a single-mesh joint - int jointIndex = maxJointIndex; + int jointIndex = firstFBXCluster.jointIndex; FBXJoint& joint = geometry.joints[jointIndex]; // transform cluster vertices to joint-frame and save for later @@ -1736,18 +1728,8 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS } } } - extracted.mesh.isEye = (maxJointIndex == geometry.leftEyeJointIndex || maxJointIndex == geometry.rightEyeJointIndex); - buildModelMesh(extracted.mesh, url); - if (extracted.mesh.isEye) { - if (maxJointIndex == geometry.leftEyeJointIndex) { - geometry.leftEyeSize = extracted.mesh.meshExtents.largestDimension() * offsetScale; - } else { - geometry.rightEyeSize = extracted.mesh.meshExtents.largestDimension() * offsetScale; - } - } - geometry.meshes.append(extracted.mesh); int meshIndex = geometry.meshes.size() - 1; meshIDsToMeshIndices.insert(it.key(), meshIndex); diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index fa047e512f..3e38de74d6 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -219,8 +219,6 @@ public: Extents meshExtents; glm::mat4 modelTransform; - bool isEye; - QVector blendshapes; unsigned int meshIndex; // the order the meshes appeared in the object file From 18544581e6402393383e43282b14f67a60fe0cce Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 21 Mar 2017 15:15:02 -0700 Subject: [PATCH 08/14] remove warnings about implicit float cast --- interface/src/ui/AvatarInputs.cpp | 4 ++-- libraries/entities-renderer/src/EntityTreeRenderer.cpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/interface/src/ui/AvatarInputs.cpp b/interface/src/ui/AvatarInputs.cpp index 944be4bf9e..63e7dcdad9 100644 --- a/interface/src/ui/AvatarInputs.cpp +++ b/interface/src/ui/AvatarInputs.cpp @@ -46,7 +46,7 @@ AvatarInputs::AvatarInputs(QQuickItem* parent) : QQuickItem(parent) { #define AI_UPDATE_FLOAT(name, src, epsilon) \ { \ float val = src; \ - if (fabs(_##name - val) >= epsilon) { \ + if (fabsf(_##name - val) >= epsilon) { \ _##name = val; \ emit name##Changed(); \ } \ @@ -82,7 +82,7 @@ void AvatarInputs::update() { if (audioLevel > 1.0f) { audioLevel = 1.0; } - AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01); + AI_UPDATE_FLOAT(audioLevel, audioLevel, 0.01f); AI_UPDATE(audioClipping, ((audioIO->getTimeSinceLastClip() > 0.0f) && (audioIO->getTimeSinceLastClip() < 1.0f))); AI_UPDATE(audioMuted, audioIO->isMuted()); diff --git a/libraries/entities-renderer/src/EntityTreeRenderer.cpp b/libraries/entities-renderer/src/EntityTreeRenderer.cpp index 31284b2f69..050635a063 100644 --- a/libraries/entities-renderer/src/EntityTreeRenderer.cpp +++ b/libraries/entities-renderer/src/EntityTreeRenderer.cpp @@ -1038,7 +1038,7 @@ void EntityTreeRenderer::playEntityCollisionSound(EntityItemPointer entity, cons // Shift the pitch down by ln(1 + (size / COLLISION_SIZE_FOR_STANDARD_PITCH)) / ln(2) const float COLLISION_SIZE_FOR_STANDARD_PITCH = 0.2f; - const float stretchFactor = log(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / log(2); + const float stretchFactor = logf(1.0f + (minAACube.getLargestDimension() / COLLISION_SIZE_FOR_STANDARD_PITCH)) / logf(2.0f); AudioInjector::playSound(collisionSound, volume, stretchFactor, collision.contactPoint); } From f6d6c62fab7766595ecdf2e0381015f6e1c712b1 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Tue, 21 Mar 2017 15:15:15 -0700 Subject: [PATCH 09/14] move variable closer to context where it is used --- libraries/ui/src/ui/Menu.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/ui/src/ui/Menu.cpp b/libraries/ui/src/ui/Menu.cpp index a793942056..50833e90fc 100644 --- a/libraries/ui/src/ui/Menu.cpp +++ b/libraries/ui/src/ui/Menu.cpp @@ -471,10 +471,10 @@ void Menu::removeSeparator(const QString& menuName, const QString& separatorName int textAt = findPositionOfMenuItem(menu, separatorName); QList menuActions = menu->actions(); if (textAt > 0 && textAt < menuActions.size()) { - QAction* separatorText = menuActions[textAt]; QAction* separatorLine = menuActions[textAt - 1]; if (separatorLine) { if (separatorLine->isSeparator()) { + QAction* separatorText = menuActions[textAt]; menu->removeAction(separatorText); menu->removeAction(separatorLine); separatorRemoved = true; From 60bc76e1c4cf4bbee488e94180bc8f86bc481533 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 24 Mar 2017 10:35:10 -0700 Subject: [PATCH 10/14] store cluster indices and weights in uint16_t --- libraries/fbx/src/FBXReader.cpp | 56 +++++++++++++++++---------- libraries/fbx/src/FBXReader.h | 8 ++-- libraries/fbx/src/FBXReader_Mesh.cpp | 57 ++++++++++++++++++++++++++-- 3 files changed, 94 insertions(+), 27 deletions(-) diff --git a/libraries/fbx/src/FBXReader.cpp b/libraries/fbx/src/FBXReader.cpp index f4af39fdf4..64ee0bc869 100644 --- a/libraries/fbx/src/FBXReader.cpp +++ b/libraries/fbx/src/FBXReader.cpp @@ -1634,8 +1634,12 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS glm::mat4 inverseModelTransform = glm::inverse(modelTransform); if (clusterIDs.size() > 1) { // this is a multi-mesh joint - extracted.mesh.clusterIndices.resize(extracted.mesh.vertices.size()); - extracted.mesh.clusterWeights.resize(extracted.mesh.vertices.size()); + const int WEIGHTS_PER_VERTEX = 4; + int numClusterIndices = extracted.mesh.vertices.size() * WEIGHTS_PER_VERTEX; + extracted.mesh.clusterIndices.fill(0, numClusterIndices); + QVector weightAccumulators; + weightAccumulators.fill(0.0f, numClusterIndices); + for (int i = 0; i < clusterIDs.size(); i++) { QString clusterID = clusterIDs.at(i); const Cluster& cluster = clusters[clusterID]; @@ -1665,45 +1669,59 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS float weight = cluster.weights.at(j); for (QMultiHash::const_iterator it = extracted.newIndices.constFind(oldIndex); it != extracted.newIndices.end() && it.key() == oldIndex; it++) { + int newIndex = it.value(); // remember vertices with at least 1/4 weight const float EXPANSION_WEIGHT_THRESHOLD = 0.99f; if (weight > EXPANSION_WEIGHT_THRESHOLD) { // transform to joint-frame and save for later - const glm::mat4 vertexTransform = meshToJoint * glm::translate(extracted.mesh.vertices.at(it.value())); + const glm::mat4 vertexTransform = meshToJoint * glm::translate(extracted.mesh.vertices.at(newIndex)); points.push_back(extractTranslation(vertexTransform) * clusterScale); } // look for an unused slot in the weights vector - glm::vec4& weights = extracted.mesh.clusterWeights[it.value()]; + int weightIndex = newIndex * WEIGHTS_PER_VERTEX; int lowestIndex = -1; float lowestWeight = FLT_MAX; int k = 0; - for (; k < 4; k++) { - if (weights[k] == 0.0f) { - extracted.mesh.clusterIndices[it.value()][k] = i; - weights[k] = weight; + for (; k < WEIGHTS_PER_VERTEX; k++) { + if (weightAccumulators[weightIndex + k] == 0.0f) { + extracted.mesh.clusterIndices[weightIndex + k] = i; + weightAccumulators[weightIndex + k] = weight; break; } - if (weights[k] < lowestWeight) { + if (weightAccumulators[weightIndex + k] < lowestWeight) { lowestIndex = k; - lowestWeight = weights[k]; + lowestWeight = weightAccumulators[weightIndex + k]; } } - if (k == 4 && weight > lowestWeight) { + if (k == WEIGHTS_PER_VERTEX && weight > lowestWeight) { // no space for an additional weight; we must replace the lowest - weights[lowestIndex] = weight; - extracted.mesh.clusterIndices[it.value()][lowestIndex] = i; + weightAccumulators[weightIndex + lowestIndex] = weight; + extracted.mesh.clusterIndices[weightIndex + lowestIndex] = i; } } } } - // normalize the weights if they don't add up to one - for (int i = 0; i < extracted.mesh.clusterWeights.size(); i++) { - glm::vec4& weights = extracted.mesh.clusterWeights[i]; - float total = weights.x + weights.y + weights.z + weights.w; - if (total != 1.0f && total != 0.0f) { - weights /= total; + + // now that we've accumulated the most relevant weights for each vertex + // normalize and compress to 8-bits + extracted.mesh.clusterWeights.fill(0, numClusterIndices); + int numVertices = extracted.mesh.vertices.size(); + for (int i = 0; i < numVertices; ++i) { + int j = i * WEIGHTS_PER_VERTEX; + + // normalize weights into uint8_t + float totalWeight = weightAccumulators[j]; + for (int k = j + 1; k < j + WEIGHTS_PER_VERTEX; ++k) { + totalWeight += weightAccumulators[k]; + } + if (totalWeight > 0.0f) { + const float ALMOST_HALF = 0.499f; + float weightScalingFactor = (float)(UINT8_MAX) / totalWeight; + for (int k = j; k < j + WEIGHTS_PER_VERTEX; ++k) { + extracted.mesh.clusterWeights[k] = (uint8_t)(weightScalingFactor * weightAccumulators[k] + ALMOST_HALF); + } } } } else { diff --git a/libraries/fbx/src/FBXReader.h b/libraries/fbx/src/FBXReader.h index 3e38de74d6..f73088e7a1 100644 --- a/libraries/fbx/src/FBXReader.h +++ b/libraries/fbx/src/FBXReader.h @@ -202,7 +202,7 @@ public: /// A single mesh (with optional blendshapes) extracted from an FBX document. class FBXMesh { public: - + QVector parts; QVector vertices; @@ -211,9 +211,9 @@ public: QVector colors; QVector texCoords; QVector texCoords1; - QVector clusterIndices; - QVector clusterWeights; - + QVector clusterIndices; + QVector clusterWeights; + QVector clusters; Extents meshExtents; diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 8eb31b0731..9f1ccbbe47 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -422,8 +422,18 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { int colorsSize = fbxMesh.colors.size() * sizeof(glm::vec3); int texCoordsSize = fbxMesh.texCoords.size() * sizeof(glm::vec2); int texCoords1Size = fbxMesh.texCoords1.size() * sizeof(glm::vec2); - int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(glm::vec4); - int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(glm::vec4); +#define UNFORTUNATE_HACK +#ifdef UNFORTUNATE_HACK + // HACK: store clusterIndices in floats rather than short integers + int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(float); +#else // UNFORTUNATE_HACK + int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(uint8_t); + if (fbxMesh.clusters.size() > UINT8_MAX) { + // we need 16 bits instead of just 8 for clusterIndices + clusterIndicesSize *= 2; + } +#endif // UNFORTUNATE_HACK + int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint8_t); int normalsOffset = 0; int tangentsOffset = normalsOffset + normalsSize; @@ -442,7 +452,31 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { attribBuffer->setSubData(colorsOffset, colorsSize, (gpu::Byte*) fbxMesh.colors.constData()); attribBuffer->setSubData(texCoordsOffset, texCoordsSize, (gpu::Byte*) fbxMesh.texCoords.constData()); attribBuffer->setSubData(texCoords1Offset, texCoords1Size, (gpu::Byte*) fbxMesh.texCoords1.constData()); - attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) fbxMesh.clusterIndices.constData()); +#ifdef UNFORTUNATE_HACK + // HACK: copy clusterIndices back into floats to appease render pipeline + QVector clusterIndices; + int32_t numIndices = fbxMesh.clusterIndices.size(); + clusterIndices.resize(numIndices); + for (int32_t i = 0; i < numIndices; ++i) { + assert(fbxMesh.clusterIndices[i] <= UINT8_MAX); + clusterIndices[i] = (float)(fbxMesh.clusterIndices[i]); + } + attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) clusterIndices.constData()); +#else // UNFORTUNATE_HACK + if (fbxMesh.clusters.size() < UINT8_MAX) { + // yay! we can fit the clusterIndices within 8-bits + int32_t numIndices = fbxMesh.clusterIndices.size(); + QVector clusterIndices; + clusterIndices.resize(numIndices); + for (int32_t i = 0; i < numIndices; ++i) { + assert(fbxMesh.clusterIndices[i] <= UINT8_MAX); + clusterIndices[i] = (uint8_t)(fbxMesh.clusterIndices[i]); + } + attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) clusterIndices.constData()); + } else { + attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) fbxMesh.clusterIndices.constData()); + } +#endif // UNFORTUNATE_HACK attribBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (gpu::Byte*) fbxMesh.clusterWeights.constData()); if (normalsSize) { @@ -475,15 +509,30 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); } +#ifdef UNFORTUNATE_HACK + // HACK: cluster indices are submitted to render pipeline in FLOAT format if (clusterIndicesSize) { mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); } +#else // UNFORTUNATE_HACK + if (clusterIndicesSize) { + if (fbxMesh.clusters.size() < UINT8_MAX) { + mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, + model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, + gpu::Element(gpu::VEC4, gpu::UINT8, gpu::XYZW))); + } else { + mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, + model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, + gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW))); + } + } +#endif // UNFORTUNATE_HACK if (clusterWeightsSize) { mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, model::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize, - gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); + gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::XYZW))); } From fcf18cba91e924b23a4d5cf5227d3e141b5b95de Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 24 Mar 2017 10:35:58 -0700 Subject: [PATCH 11/14] render pipeline support for normalized intergers --- libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp | 9 +++++++-- libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp | 7 +++++-- libraries/gpu/src/gpu/Format.h | 12 ++++++------ 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp index 638841b170..51a24563f3 100644 --- a/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl41/GL41BackendInput.cpp @@ -99,8 +99,13 @@ void GL41Backend::updateInput() { GLboolean isNormalized = attrib._element.isNormalized(); for (size_t locNum = 0; locNum < locationCount; ++locNum) { - glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, - reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + if (attrib._element.isInteger()) { + glVertexAttribIPointer(slot + (GLuint)locNum, count, type, stride, + reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + } else { + glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride, + reinterpret_cast(pointer + perLocationStride * (GLuint)locNum)); + } #ifdef GPU_STEREO_DRAWCALL_INSTANCED glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency * (isStereo() ? 2 : 1)); #else diff --git a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp index 01bd2d7bce..ece62e15f1 100644 --- a/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp +++ b/libraries/gpu-gl/src/gpu/gl45/GL45BackendInput.cpp @@ -61,8 +61,11 @@ void GL45Backend::updateInput() { _input._attributeActivation.set(attriNum); glEnableVertexAttribArray(attriNum); } - glVertexAttribFormat(attriNum, count, type, isNormalized, offset + locNum * perLocationSize); - // TODO: Support properly the IAttrib version + if (attrib._element.isInteger()) { + glVertexAttribIFormat(attriNum, count, type, offset + locNum * perLocationSize); + } else { + glVertexAttribFormat(attriNum, count, type, isNormalized, offset + locNum * perLocationSize); + } glVertexAttribBinding(attriNum, attrib._channel); } diff --git a/libraries/gpu/src/gpu/Format.h b/libraries/gpu/src/gpu/Format.h index 493a2de3c2..4114ccb15c 100644 --- a/libraries/gpu/src/gpu/Format.h +++ b/libraries/gpu/src/gpu/Format.h @@ -75,12 +75,12 @@ static const bool TYPE_IS_INTEGER[NUM_TYPES] = { true, // Normalized values - true, - true, - true, - true, - true, - true + false, + false, + false, + false, + false, + false }; // Dimension of an Element From ff2f4da4b25eec2e7a6e30eb25d6557da9b48555 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 27 Mar 2017 15:19:28 -0700 Subject: [PATCH 12/14] final changes as per samcake --- libraries/fbx/src/FBXReader_Mesh.cpp | 29 ++----------------------- libraries/gpu/src/gpu/Inputs.slh | 2 +- libraries/render-utils/src/Skinning.slh | 12 +++++----- 3 files changed, 9 insertions(+), 34 deletions(-) diff --git a/libraries/fbx/src/FBXReader_Mesh.cpp b/libraries/fbx/src/FBXReader_Mesh.cpp index 9f1ccbbe47..4e153dfe3a 100644 --- a/libraries/fbx/src/FBXReader_Mesh.cpp +++ b/libraries/fbx/src/FBXReader_Mesh.cpp @@ -422,17 +422,12 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { int colorsSize = fbxMesh.colors.size() * sizeof(glm::vec3); int texCoordsSize = fbxMesh.texCoords.size() * sizeof(glm::vec2); int texCoords1Size = fbxMesh.texCoords1.size() * sizeof(glm::vec2); -#define UNFORTUNATE_HACK -#ifdef UNFORTUNATE_HACK - // HACK: store clusterIndices in floats rather than short integers - int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(float); -#else // UNFORTUNATE_HACK + int clusterIndicesSize = fbxMesh.clusterIndices.size() * sizeof(uint8_t); if (fbxMesh.clusters.size() > UINT8_MAX) { // we need 16 bits instead of just 8 for clusterIndices clusterIndicesSize *= 2; } -#endif // UNFORTUNATE_HACK int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint8_t); int normalsOffset = 0; @@ -452,17 +447,7 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { attribBuffer->setSubData(colorsOffset, colorsSize, (gpu::Byte*) fbxMesh.colors.constData()); attribBuffer->setSubData(texCoordsOffset, texCoordsSize, (gpu::Byte*) fbxMesh.texCoords.constData()); attribBuffer->setSubData(texCoords1Offset, texCoords1Size, (gpu::Byte*) fbxMesh.texCoords1.constData()); -#ifdef UNFORTUNATE_HACK - // HACK: copy clusterIndices back into floats to appease render pipeline - QVector clusterIndices; - int32_t numIndices = fbxMesh.clusterIndices.size(); - clusterIndices.resize(numIndices); - for (int32_t i = 0; i < numIndices; ++i) { - assert(fbxMesh.clusterIndices[i] <= UINT8_MAX); - clusterIndices[i] = (float)(fbxMesh.clusterIndices[i]); - } - attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) clusterIndices.constData()); -#else // UNFORTUNATE_HACK + if (fbxMesh.clusters.size() < UINT8_MAX) { // yay! we can fit the clusterIndices within 8-bits int32_t numIndices = fbxMesh.clusterIndices.size(); @@ -476,7 +461,6 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { } else { attribBuffer->setSubData(clusterIndicesOffset, clusterIndicesSize, (gpu::Byte*) fbxMesh.clusterIndices.constData()); } -#endif // UNFORTUNATE_HACK attribBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (gpu::Byte*) fbxMesh.clusterWeights.constData()); if (normalsSize) { @@ -509,14 +493,6 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV))); } -#ifdef UNFORTUNATE_HACK - // HACK: cluster indices are submitted to render pipeline in FLOAT format - if (clusterIndicesSize) { - mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, - model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize, - gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW))); - } -#else // UNFORTUNATE_HACK if (clusterIndicesSize) { if (fbxMesh.clusters.size() < UINT8_MAX) { mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX, @@ -528,7 +504,6 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) { gpu::Element(gpu::VEC4, gpu::UINT16, gpu::XYZW))); } } -#endif // UNFORTUNATE_HACK if (clusterWeightsSize) { mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_WEIGHT, model::BufferView(attribBuffer, clusterWeightsOffset, clusterWeightsSize, diff --git a/libraries/gpu/src/gpu/Inputs.slh b/libraries/gpu/src/gpu/Inputs.slh index ce5e4227eb..843d1059f2 100644 --- a/libraries/gpu/src/gpu/Inputs.slh +++ b/libraries/gpu/src/gpu/Inputs.slh @@ -15,7 +15,7 @@ layout(location = 1) in vec4 inNormal; layout(location = 2) in vec4 inColor; layout(location = 3) in vec4 inTexCoord0; layout(location = 4) in vec4 inTangent; -layout(location = 5) in vec4 inSkinClusterIndex; +layout(location = 5) in ivec4 inSkinClusterIndex; layout(location = 6) in vec4 inSkinClusterWeight; layout(location = 7) in vec4 inTexCoord1; <@endif@> diff --git a/libraries/render-utils/src/Skinning.slh b/libraries/render-utils/src/Skinning.slh index 687dab536b..2d1f010029 100644 --- a/libraries/render-utils/src/Skinning.slh +++ b/libraries/render-utils/src/Skinning.slh @@ -18,11 +18,11 @@ layout(std140) uniform skinClusterBuffer { mat4 clusterMatrices[MAX_CLUSTERS]; }; -void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { +void skinPosition(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, out vec4 skinnedPosition) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; newPosition += clusterMatrix * inPosition * clusterWeight; } @@ -30,13 +30,13 @@ void skinPosition(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition skinnedPosition = newPosition; } -void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, +void skinPositionNormal(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, out vec4 skinnedPosition, out vec3 skinnedNormal) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; newPosition += clusterMatrix * inPosition * clusterWeight; newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; @@ -46,14 +46,14 @@ void skinPositionNormal(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPo skinnedNormal = newNormal.xyz; } -void skinPositionNormalTangent(vec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, +void skinPositionNormalTangent(ivec4 skinClusterIndex, vec4 skinClusterWeight, vec4 inPosition, vec3 inNormal, vec3 inTangent, out vec4 skinnedPosition, out vec3 skinnedNormal, out vec3 skinnedTangent) { vec4 newPosition = vec4(0.0, 0.0, 0.0, 0.0); vec4 newNormal = vec4(0.0, 0.0, 0.0, 0.0); vec4 newTangent = vec4(0.0, 0.0, 0.0, 0.0); for (int i = 0; i < INDICES_PER_VERTEX; i++) { - mat4 clusterMatrix = clusterMatrices[int(skinClusterIndex[i])]; + mat4 clusterMatrix = clusterMatrices[(skinClusterIndex[i])]; float clusterWeight = skinClusterWeight[i]; newPosition += clusterMatrix * inPosition * clusterWeight; newNormal += clusterMatrix * vec4(inNormal.xyz, 0.0) * clusterWeight; From 92b41d7a3848b01c4b87a0e4b3c3a3a2db935622 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 27 Mar 2017 15:50:40 -0700 Subject: [PATCH 13/14] fix link error for linux build --- libraries/gpu-gl/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index 65df5ed9dc..e665b7a28e 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -1,6 +1,7 @@ set(TARGET_NAME gpu-gl) setup_hifi_library() link_hifi_libraries(shared gl gpu) +target_link_libraries(${TARGET_NAME} pthread) GroupSources("src") target_opengl() From 5fc1e9716605871eb74b5fe8e1d4e860600c44d4 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Mon, 27 Mar 2017 16:49:43 -0700 Subject: [PATCH 14/14] fix windows build of render-utils-test --- libraries/gpu-gl/CMakeLists.txt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libraries/gpu-gl/CMakeLists.txt b/libraries/gpu-gl/CMakeLists.txt index e665b7a28e..3e3853532a 100644 --- a/libraries/gpu-gl/CMakeLists.txt +++ b/libraries/gpu-gl/CMakeLists.txt @@ -1,7 +1,9 @@ set(TARGET_NAME gpu-gl) setup_hifi_library() link_hifi_libraries(shared gl gpu) -target_link_libraries(${TARGET_NAME} pthread) +if (UNIX) + target_link_libraries(${TARGET_NAME} pthread) +endif(UNIX) GroupSources("src") target_opengl()