Merge pull request #10035 from sethalves/tablet-ui

Tablet ui - merge from upstream
This commit is contained in:
Seth Alves 2017-03-28 11:42:55 -07:00 committed by GitHub
commit 45e83906e7
15 changed files with 168 additions and 88 deletions

View file

@ -56,7 +56,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(); \
} \
@ -93,7 +93,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());

View file

@ -1045,7 +1045,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);
}

View file

@ -1631,13 +1631,15 @@ 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;
const int WEIGHTS_PER_VERTEX = 4;
int numClusterIndices = extracted.mesh.vertices.size() * WEIGHTS_PER_VERTEX;
extracted.mesh.clusterIndices.fill(0, numClusterIndices);
QVector<float> weightAccumulators;
weightAccumulators.fill(0.0f, numClusterIndices);
for (int i = 0; i < clusterIDs.size(); i++) {
QString clusterID = clusterIDs.at(i);
const Cluster& cluster = clusters[clusterID];
@ -1662,61 +1664,69 @@ 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<int, int>::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;
}
}
}
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++) {
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 {
// 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 +1746,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);

View file

@ -202,7 +202,7 @@ public:
/// A single mesh (with optional blendshapes) extracted from an FBX document.
class FBXMesh {
public:
QVector<FBXMeshPart> parts;
QVector<glm::vec3> vertices;
@ -211,16 +211,14 @@ public:
QVector<glm::vec3> colors;
QVector<glm::vec2> texCoords;
QVector<glm::vec2> texCoords1;
QVector<glm::vec4> clusterIndices;
QVector<glm::vec4> clusterWeights;
QVector<uint16_t> clusterIndices;
QVector<uint8_t> clusterWeights;
QVector<FBXCluster> clusters;
Extents meshExtents;
glm::mat4 modelTransform;
bool isEye;
QVector<FBXBlendshape> blendshapes;
unsigned int meshIndex; // the order the meshes appeared in the object file

View file

@ -422,8 +422,13 @@ 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);
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;
}
int clusterWeightsSize = fbxMesh.clusterWeights.size() * sizeof(uint8_t);
int normalsOffset = 0;
int tangentsOffset = normalsOffset + normalsSize;
@ -442,7 +447,20 @@ 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());
if (fbxMesh.clusters.size() < UINT8_MAX) {
// yay! we can fit the clusterIndices within 8-bits
int32_t numIndices = fbxMesh.clusterIndices.size();
QVector<uint8_t> 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());
}
attribBuffer->setSubData(clusterWeightsOffset, clusterWeightsSize, (gpu::Byte*) fbxMesh.clusterWeights.constData());
if (normalsSize) {
@ -476,14 +494,20 @@ void FBXReader::buildModelMesh(FBXMesh& extractedMesh, const QString& url) {
}
if (clusterIndicesSize) {
mesh->addAttribute(gpu::Stream::SKIN_CLUSTER_INDEX,
model::BufferView(attribBuffer, clusterIndicesOffset, clusterIndicesSize,
gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW)));
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)));
}
}
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)));
}

View file

@ -1,6 +1,9 @@
set(TARGET_NAME gpu-gl)
setup_hifi_library()
link_hifi_libraries(shared gl gpu)
if (UNIX)
target_link_libraries(${TARGET_NAME} pthread)
endif(UNIX)
GroupSources("src")
target_opengl()

View file

@ -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<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
if (attrib._element.isInteger()) {
glVertexAttribIPointer(slot + (GLuint)locNum, count, type, stride,
reinterpret_cast<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
} else {
glVertexAttribPointer(slot + (GLuint)locNum, count, type, isNormalized, stride,
reinterpret_cast<GLvoid*>(pointer + perLocationStride * (GLuint)locNum));
}
#ifdef GPU_STEREO_DRAWCALL_INSTANCED
glVertexAttribDivisor(slot + (GLuint)locNum, attrib._frequency * (isStereo() ? 2 : 1));
#else

View file

@ -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);
}

View file

@ -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

View file

@ -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@>

View file

@ -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;

View file

@ -471,10 +471,10 @@ void Menu::removeSeparator(const QString& menuName, const QString& separatorName
int textAt = findPositionOfMenuItem(menu, separatorName);
QList<QAction*> 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;

View file

@ -1181,7 +1181,7 @@ function MyController(hand) {
this.updateStylusTip();
var DEFAULT_USE_FINGER_AS_STYLUS = false;
var DEFAULT_USE_FINGER_AS_STYLUS = true;
var USE_FINGER_AS_STYLUS = Settings.getValue("preferAvatarFingerOverStylus");
if (USE_FINGER_AS_STYLUS === "") {
USE_FINGER_AS_STYLUS = DEFAULT_USE_FINGER_AS_STYLUS;

View file

@ -441,7 +441,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) {

View file

@ -1,5 +1,21 @@
//
// 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");
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";
@ -28,6 +44,10 @@
this.interval = null;
this.sitDownSettlePeriod = null;
this.lastTimeNoDriveKeys = null;
this.sittingDown = false;
// Preload the animation file
this.animation = AnimationCache.prefetch(ANIMATION_URL);
this.preload = function(entityID) {
this.entityID = entityID;
@ -100,12 +120,19 @@
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.");
return;
}
print("Sitting down (" + this.entityID + ")");
this.sittingDown = true;
var now = Date.now();
this.sitDownSettlePeriod = now + IK_SETTLE_TIME;
@ -117,10 +144,15 @@
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) {
MyAvatar.disableDriveKey(OVERRIDEN_DRIVE_KEYS[i]);
}
MyAvatar.resetSensorsAndBody();
}
@ -132,25 +164,27 @@
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]);
if (MyAvatar.sessionUUID === this.getSeatUser()) {
this.setSeatUser(null);
}
this.setSeatUser(null);
if (Settings.getValue(SETTING_KEY) === this.entityID) {
Settings.setValue(SETTING_KEY, "");
var ROLES = MyAvatar.getAnimationRoles();
for (i in ROLES) {
MyAvatar.restoreRoleAnimation(ROLES[i]);
for (var i in OVERRIDEN_DRIVE_KEYS) {
MyAvatar.enableDriveKey(OVERRIDEN_DRIVE_KEYS[i]);
}
var roles = this.rolesToOverride();
for (i in roles) {
MyAvatar.restoreRoleAnimation(roles[i]);
}
MyAvatar.characterControllerEnabled = true;
MyAvatar.hmdLeanRecenterEnabled = true;
@ -165,6 +199,7 @@
MyAvatar.bodyRoll = 0.0;
}, SIT_DELAY);
}
this.sittingDown = false;
}
// function called by teleport.js if it detects the appropriate userData
@ -215,7 +250,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();
@ -244,6 +279,9 @@
shouldStandUp = true;
}
if (MyAvatar.sessionUUID !== this.getSeatUser()) {
shouldStandUp = true;
}
if (shouldStandUp || avatarDistance > RELEASE_DISTANCE) {
print("IK error: " + ikError + ", distance from chair: " + avatarDistance);
@ -253,7 +291,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();