mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-08-09 23:01:47 +02:00
Merge branch 'master' into android_new
This commit is contained in:
commit
bc4193f276
67 changed files with 967 additions and 530 deletions
|
@ -170,9 +170,9 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
||||||
|
|
||||||
// Define the minimum bubble size
|
// Define the minimum bubble size
|
||||||
static const glm::vec3 minBubbleSize = glm::vec3(0.3f, 1.3f, 0.3f);
|
static const glm::vec3 minBubbleSize = avatar.getSensorToWorldScale() * glm::vec3(0.3f, 1.3f, 0.3f);
|
||||||
// Define the scale of the box for the current node
|
// Define the scale of the box for the current node
|
||||||
glm::vec3 nodeBoxScale = (nodeData->getPosition() - nodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
glm::vec3 nodeBoxScale = (nodeData->getPosition() - nodeData->getGlobalBoundingBoxCorner()) * 2.0f * avatar.getSensorToWorldScale();
|
||||||
// Set up the bounding box for the current node
|
// Set up the bounding box for the current node
|
||||||
AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale);
|
AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale);
|
||||||
// Clamp the size of the bounding box to a minimum scale
|
// Clamp the size of the bounding box to a minimum scale
|
||||||
|
@ -209,7 +209,7 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map
|
assert(avatarNode); // we can't have gotten here without the avatarData being a valid key in the map
|
||||||
return nodeData->getLastBroadcastTime(avatarNode->getUUID());
|
return nodeData->getLastBroadcastTime(avatarNode->getUUID());
|
||||||
}, [&](AvatarSharedPointer avatar)->float{
|
}, [&](AvatarSharedPointer avatar)->float{
|
||||||
glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner());
|
glm::vec3 nodeBoxHalfScale = (avatar->getPosition() - avatar->getGlobalBoundingBoxCorner() * avatar->getSensorToWorldScale());
|
||||||
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
return glm::max(nodeBoxHalfScale.x, glm::max(nodeBoxHalfScale.y, nodeBoxHalfScale.z));
|
||||||
}, [&](AvatarSharedPointer avatar)->bool {
|
}, [&](AvatarSharedPointer avatar)->bool {
|
||||||
if (avatar == thisAvatar) {
|
if (avatar == thisAvatar) {
|
||||||
|
@ -244,9 +244,9 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
// Check to see if the space bubble is enabled
|
// Check to see if the space bubble is enabled
|
||||||
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
// Don't bother with these checks if the other avatar has their bubble enabled and we're gettingAnyIgnored
|
||||||
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
||||||
|
float sensorToWorldScale = avatarNodeData->getAvatarSharedPointer()->getSensorToWorldScale();
|
||||||
// Define the scale of the box for the current other node
|
// Define the scale of the box for the current other node
|
||||||
glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
glm::vec3 otherNodeBoxScale = (avatarNodeData->getPosition() - avatarNodeData->getGlobalBoundingBoxCorner()) * 2.0f * sensorToWorldScale;
|
||||||
// Set up the bounding box for the current other node
|
// Set up the bounding box for the current other node
|
||||||
AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||||
// Clamp the size of the bounding box to a minimum scale
|
// Clamp the size of the bounding box to a minimum scale
|
||||||
|
@ -334,8 +334,9 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
||||||
|
|
||||||
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
glm::vec3 otherPosition = otherAvatar->getClientGlobalPosition();
|
||||||
|
|
||||||
|
|
||||||
// determine if avatar is in view, to determine how much data to include...
|
// determine if avatar is in view, to determine how much data to include...
|
||||||
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f;
|
glm::vec3 otherNodeBoxScale = (otherPosition - otherNodeData->getGlobalBoundingBoxCorner()) * 2.0f * otherAvatar->getSensorToWorldScale();
|
||||||
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
AABox otherNodeBox(otherNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||||
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
||||||
|
|
||||||
|
|
|
@ -2413,10 +2413,18 @@ void Application::paintGL() {
|
||||||
auto lodManager = DependencyManager::get<LODManager>();
|
auto lodManager = DependencyManager::get<LODManager>();
|
||||||
|
|
||||||
RenderArgs renderArgs;
|
RenderArgs renderArgs;
|
||||||
|
|
||||||
|
float sensorToWorldScale = getMyAvatar()->getSensorToWorldScale();
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(render, "/buildFrustrumAndArgs");
|
PROFILE_RANGE(render, "/buildFrustrumAndArgs");
|
||||||
{
|
{
|
||||||
QMutexLocker viewLocker(&_viewMutex);
|
QMutexLocker viewLocker(&_viewMutex);
|
||||||
|
// adjust near clip plane to account for sensor scaling.
|
||||||
|
auto adjustedProjection = glm::perspective(_viewFrustum.getFieldOfView(),
|
||||||
|
_viewFrustum.getAspectRatio(),
|
||||||
|
DEFAULT_NEAR_CLIP * sensorToWorldScale,
|
||||||
|
_viewFrustum.getFarClip());
|
||||||
|
_viewFrustum.setProjection(adjustedProjection);
|
||||||
_viewFrustum.calculate();
|
_viewFrustum.calculate();
|
||||||
}
|
}
|
||||||
renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(),
|
renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(),
|
||||||
|
@ -2464,7 +2472,7 @@ void Application::paintGL() {
|
||||||
PerformanceTimer perfTimer("CameraUpdates");
|
PerformanceTimer perfTimer("CameraUpdates");
|
||||||
|
|
||||||
auto myAvatar = getMyAvatar();
|
auto myAvatar = getMyAvatar();
|
||||||
boomOffset = myAvatar->getScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
|
boomOffset = myAvatar->getModelScale() * myAvatar->getBoomLength() * -IDENTITY_FORWARD;
|
||||||
|
|
||||||
// The render mode is default or mirror if the camera is in mirror mode, assigned further below
|
// The render mode is default or mirror if the camera is in mirror mode, assigned further below
|
||||||
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||||
|
@ -2476,7 +2484,7 @@ void Application::paintGL() {
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||||
_myCamera.setPosition(extractTranslation(camMat));
|
_myCamera.setPosition(extractTranslation(camMat));
|
||||||
_myCamera.setOrientation(glm::quat_cast(camMat));
|
_myCamera.setOrientation(glmExtractRotation(camMat));
|
||||||
} else {
|
} else {
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
|
||||||
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
|
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
|
||||||
|
@ -2484,7 +2492,7 @@ void Application::paintGL() {
|
||||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||||
if (isHMDMode()) {
|
if (isHMDMode()) {
|
||||||
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||||
_myCamera.setOrientation(glm::normalize(glm::quat_cast(hmdWorldMat)));
|
_myCamera.setOrientation(glm::normalize(glmExtractRotation(hmdWorldMat)));
|
||||||
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
|
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
|
||||||
myAvatar->getOrientation() * boomOffset);
|
myAvatar->getOrientation() * boomOffset);
|
||||||
} else {
|
} else {
|
||||||
|
@ -2517,14 +2525,14 @@ void Application::paintGL() {
|
||||||
hmdOffset.x = -hmdOffset.x;
|
hmdOffset.x = -hmdOffset.x;
|
||||||
|
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
|
+ glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0)
|
||||||
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
|
+ mirrorBodyOrientation * glm::vec3(0.0f, 0.0f, 1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror
|
||||||
+ mirrorBodyOrientation * hmdOffset);
|
+ mirrorBodyOrientation * hmdOffset);
|
||||||
} else {
|
} else {
|
||||||
_myCamera.setOrientation(myAvatar->getOrientation()
|
_myCamera.setOrientation(myAvatar->getOrientation()
|
||||||
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
||||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
_myCamera.setPosition(myAvatar->getDefaultEyePosition()
|
||||||
+ glm::vec3(0, _raiseMirror * myAvatar->getUniformScale(), 0)
|
+ glm::vec3(0, _raiseMirror * myAvatar->getModelScale(), 0)
|
||||||
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
+ (myAvatar->getOrientation() * glm::quat(glm::vec3(0.0f, _rotateMirror, 0.0f))) *
|
||||||
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
||||||
}
|
}
|
||||||
|
@ -2552,7 +2560,7 @@ void Application::paintGL() {
|
||||||
|
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(render, "/updateCompositor");
|
PROFILE_RANGE(render, "/updateCompositor");
|
||||||
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform());
|
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform(), getMyAvatar()->getSensorToWorldMatrix());
|
||||||
}
|
}
|
||||||
|
|
||||||
gpu::FramebufferPointer finalFramebuffer;
|
gpu::FramebufferPointer finalFramebuffer;
|
||||||
|
@ -2566,6 +2574,12 @@ void Application::paintGL() {
|
||||||
finalFramebuffer = framebufferCache->getFramebuffer();
|
finalFramebuffer = framebufferCache->getFramebuffer();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||||
|
float ipdScale = hmdInterface->getIPDScale();
|
||||||
|
|
||||||
|
// scale IPD by sensorToWorldScale, to make the world seem larger or smaller accordingly.
|
||||||
|
ipdScale *= sensorToWorldScale;
|
||||||
|
|
||||||
mat4 eyeProjections[2];
|
mat4 eyeProjections[2];
|
||||||
{
|
{
|
||||||
PROFILE_RANGE(render, "/mainRender");
|
PROFILE_RANGE(render, "/mainRender");
|
||||||
|
@ -2575,6 +2589,7 @@ void Application::paintGL() {
|
||||||
// in the overlay render?
|
// in the overlay render?
|
||||||
// Viewport is assigned to the size of the framebuffer
|
// Viewport is assigned to the size of the framebuffer
|
||||||
renderArgs._viewport = ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height());
|
renderArgs._viewport = ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height());
|
||||||
|
auto baseProjection = renderArgs.getViewFrustum().getProjection();
|
||||||
if (displayPlugin->isStereo()) {
|
if (displayPlugin->isStereo()) {
|
||||||
// Stereo modes will typically have a larger projection matrix overall,
|
// Stereo modes will typically have a larger projection matrix overall,
|
||||||
// so we ask for the 'mono' projection matrix, which for stereo and HMD
|
// so we ask for the 'mono' projection matrix, which for stereo and HMD
|
||||||
|
@ -2585,12 +2600,10 @@ void Application::paintGL() {
|
||||||
// just relying on the left FOV in each case and hoping that the
|
// just relying on the left FOV in each case and hoping that the
|
||||||
// overall culling margin of error doesn't cause popping in the
|
// overall culling margin of error doesn't cause popping in the
|
||||||
// right eye. There are FIXMEs in the relevant plugins
|
// right eye. There are FIXMEs in the relevant plugins
|
||||||
_myCamera.setProjection(displayPlugin->getCullingProjection(_myCamera.getProjection()));
|
_myCamera.setProjection(displayPlugin->getCullingProjection(baseProjection));
|
||||||
renderArgs._context->enableStereo(true);
|
renderArgs._context->enableStereo(true);
|
||||||
mat4 eyeOffsets[2];
|
mat4 eyeOffsets[2];
|
||||||
auto baseProjection = renderArgs.getViewFrustum().getProjection();
|
mat4 eyeProjections[2];
|
||||||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
|
||||||
float IPDScale = hmdInterface->getIPDScale();
|
|
||||||
|
|
||||||
// FIXME we probably don't need to set the projection matrix every frame,
|
// FIXME we probably don't need to set the projection matrix every frame,
|
||||||
// only when the display plugin changes (or in non-HMD modes when the user
|
// only when the display plugin changes (or in non-HMD modes when the user
|
||||||
|
@ -2604,7 +2617,7 @@ void Application::paintGL() {
|
||||||
// Grab the translation
|
// Grab the translation
|
||||||
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
||||||
// Apply IPD scaling
|
// Apply IPD scaling
|
||||||
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
|
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * ipdScale);
|
||||||
eyeOffsets[eye] = eyeOffsetTransform;
|
eyeOffsets[eye] = eyeOffsetTransform;
|
||||||
eyeProjections[eye] = displayPlugin->getEyeProjection(eye, baseProjection);
|
eyeProjections[eye] = displayPlugin->getEyeProjection(eye, baseProjection);
|
||||||
});
|
});
|
||||||
|
@ -2624,8 +2637,14 @@ void Application::paintGL() {
|
||||||
PerformanceTimer perfTimer("postComposite");
|
PerformanceTimer perfTimer("postComposite");
|
||||||
renderArgs._batch = &postCompositeBatch;
|
renderArgs._batch = &postCompositeBatch;
|
||||||
renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height()));
|
renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height()));
|
||||||
renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView());
|
|
||||||
for_each_eye([&](Eye eye) {
|
for_each_eye([&](Eye eye) {
|
||||||
|
|
||||||
|
// apply eye offset and IPD scale to the view matrix
|
||||||
|
mat4 eyeToHead = displayPlugin->getEyeToHeadTransform(eye);
|
||||||
|
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
||||||
|
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * ipdScale);
|
||||||
|
renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView() * eyeOffsetTransform);
|
||||||
|
|
||||||
renderArgs._batch->setProjectionTransform(eyeProjections[eye]);
|
renderArgs._batch->setProjectionTransform(eyeProjections[eye]);
|
||||||
_overlays.render3DHUDOverlays(&renderArgs);
|
_overlays.render3DHUDOverlays(&renderArgs);
|
||||||
});
|
});
|
||||||
|
@ -6411,7 +6430,12 @@ void Application::addAssetToWorldFromURL(QString url) {
|
||||||
}
|
}
|
||||||
if (url.contains("vr.google.com/downloads")) {
|
if (url.contains("vr.google.com/downloads")) {
|
||||||
filename = url.section('/', -1);
|
filename = url.section('/', -1);
|
||||||
filename.remove(".zip");
|
if (url.contains("noDownload")) {
|
||||||
|
filename.remove(".zip?noDownload=false");
|
||||||
|
} else {
|
||||||
|
filename.remove(".zip");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
|
if (!DependencyManager::get<NodeList>()->getThisNodeCanWriteAssets()) {
|
||||||
|
@ -6441,7 +6465,11 @@ void Application::addAssetToWorldFromURLRequestFinished() {
|
||||||
}
|
}
|
||||||
if (url.contains("vr.google.com/downloads")) {
|
if (url.contains("vr.google.com/downloads")) {
|
||||||
filename = url.section('/', -1);
|
filename = url.section('/', -1);
|
||||||
filename.remove(".zip");
|
if (url.contains("noDownload")) {
|
||||||
|
filename.remove(".zip?noDownload=false");
|
||||||
|
} else {
|
||||||
|
filename.remove(".zip");
|
||||||
|
}
|
||||||
isBlocks = true;
|
isBlocks = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -6608,7 +6636,9 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) {
|
||||||
properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND);
|
properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND);
|
||||||
properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar.
|
properties.setCollisionless(true); // Temporarily set so that doesn't collide with avatar.
|
||||||
properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions.
|
properties.setVisible(false); // Temporarily set so that don't see at large unresized dimensions.
|
||||||
properties.setPosition(getMyAvatar()->getPosition() + getMyAvatar()->getOrientation() * glm::vec3(0.0f, 0.0f, -2.0f));
|
glm::vec3 positionOffset = getMyAvatar()->getOrientation() * (getMyAvatar()->getSensorToWorldScale() * glm::vec3(0.0f, 0.0f, -2.0f));
|
||||||
|
properties.setPosition(getMyAvatar()->getPosition() + positionOffset);
|
||||||
|
properties.setRotation(getMyAvatar()->getOrientation());
|
||||||
properties.setGravity(glm::vec3(0.0f, 0.0f, 0.0f));
|
properties.setGravity(glm::vec3(0.0f, 0.0f, 0.0f));
|
||||||
auto entityID = DependencyManager::get<EntityScriptingInterface>()->addEntity(properties);
|
auto entityID = DependencyManager::get<EntityScriptingInterface>()->addEntity(properties);
|
||||||
|
|
||||||
|
@ -6655,7 +6685,7 @@ void Application::addAssetToWorldCheckModelSize() {
|
||||||
if (dimensions != DEFAULT_DIMENSIONS) {
|
if (dimensions != DEFAULT_DIMENSIONS) {
|
||||||
|
|
||||||
// Scale model so that its maximum is exactly specific size.
|
// Scale model so that its maximum is exactly specific size.
|
||||||
const float MAXIMUM_DIMENSION = 1.0f;
|
const float MAXIMUM_DIMENSION = 1.0f * getMyAvatar()->getSensorToWorldScale();
|
||||||
auto previousDimensions = dimensions;
|
auto previousDimensions = dimensions;
|
||||||
auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y,
|
auto scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y,
|
||||||
MAXIMUM_DIMENSION / dimensions.z));
|
MAXIMUM_DIMENSION / dimensions.z));
|
||||||
|
|
|
@ -165,7 +165,7 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
||||||
|
|
||||||
Transform avatarTransform;
|
Transform avatarTransform;
|
||||||
avatarTransform = myAvatar->getTransform();
|
avatarTransform = myAvatar->getTransform();
|
||||||
palmPosition = avatarTransform.transform(camRelPos / myAvatar->getDomainLimitedScale());
|
palmPosition = avatarTransform.transform(camRelPos);
|
||||||
palmRotation = avatarTransform.getRotation() * camRelRot;
|
palmRotation = avatarTransform.getRotation() * camRelRot;
|
||||||
} else {
|
} else {
|
||||||
glm::vec3 avatarRigidBodyPosition;
|
glm::vec3 avatarRigidBodyPosition;
|
||||||
|
|
|
@ -64,18 +64,13 @@ using namespace std;
|
||||||
|
|
||||||
const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f;
|
const float DEFAULT_REAL_WORLD_FIELD_OF_VIEW_DEGREES = 30.0f;
|
||||||
|
|
||||||
const float MAX_WALKING_SPEED = 2.6f; // human walking speed
|
|
||||||
const float MAX_BOOST_SPEED = 0.5f * MAX_WALKING_SPEED; // action motor gets additive boost below this speed
|
|
||||||
const float MIN_AVATAR_SPEED = 0.05f;
|
|
||||||
const float MIN_AVATAR_SPEED_SQUARED = MIN_AVATAR_SPEED * MIN_AVATAR_SPEED; // speed is set to zero below this
|
|
||||||
|
|
||||||
const float YAW_SPEED_DEFAULT = 100.0f; // degrees/sec
|
const float YAW_SPEED_DEFAULT = 100.0f; // degrees/sec
|
||||||
const float PITCH_SPEED_DEFAULT = 75.0f; // degrees/sec
|
const float PITCH_SPEED_DEFAULT = 75.0f; // degrees/sec
|
||||||
|
|
||||||
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
|
const float MAX_BOOST_SPEED = 0.5f * DEFAULT_AVATAR_MAX_WALKING_SPEED; // action motor gets additive boost below this speed
|
||||||
// to properly follow avatar size.
|
const float MIN_AVATAR_SPEED = 0.05f;
|
||||||
float MAX_AVATAR_SPEED = 30.0f;
|
const float MIN_AVATAR_SPEED_SQUARED = MIN_AVATAR_SPEED * MIN_AVATAR_SPEED; // speed is set to zero below this
|
||||||
float MAX_ACTION_MOTOR_SPEED = MAX_AVATAR_SPEED;
|
|
||||||
float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;
|
float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;
|
||||||
float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;
|
float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;
|
||||||
const int SCRIPTED_MOTOR_CAMERA_FRAME = 0;
|
const int SCRIPTED_MOTOR_CAMERA_FRAME = 0;
|
||||||
|
@ -87,29 +82,6 @@ const float MyAvatar::ZOOM_MIN = 0.5f;
|
||||||
const float MyAvatar::ZOOM_MAX = 25.0f;
|
const float MyAvatar::ZOOM_MAX = 25.0f;
|
||||||
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
const float MyAvatar::ZOOM_DEFAULT = 1.5f;
|
||||||
|
|
||||||
// default values, used when avatar is missing joints... (avatar space)
|
|
||||||
static const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_MIDDLE_EYE_POS { 0.0f, 0.6f, 0.0f };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_HEAD_POS { 0.0f, 0.53f, 0.0f };
|
|
||||||
static const glm::quat DEFAULT_AVATAR_HEAD_ROT { Quaternions::Y_180 };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_RIGHTARM_POS { -0.134824f, 0.396348f, -0.0515777f };
|
|
||||||
static const glm::quat DEFAULT_AVATAR_RIGHTARM_ROT { -0.536241f, 0.536241f, -0.460918f, -0.460918f };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_LEFTARM_POS { 0.134795f, 0.396349f, -0.0515881f };
|
|
||||||
static const glm::quat DEFAULT_AVATAR_LEFTARM_ROT { 0.536257f, 0.536258f, -0.460899f, 0.4609f };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_RIGHTHAND_POS { -0.72768f, 0.396349f, -0.0515779f };
|
|
||||||
static const glm::quat DEFAULT_AVATAR_RIGHTHAND_ROT { 0.479184f, -0.520013f, 0.522537f, 0.476365f};
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_LEFTHAND_POS { 0.727588f, 0.39635f, -0.0515878f };
|
|
||||||
static const glm::quat DEFAULT_AVATAR_LEFTHAND_ROT { -0.479181f, -0.52001f, 0.52254f, -0.476369f };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_NECK_POS { 0.0f, 0.445f, 0.025f };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_SPINE2_POS { 0.0f, 0.32f, 0.02f };
|
|
||||||
static const glm::quat DEFAULT_AVATAR_SPINE2_ROT { Quaternions::Y_180 };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_HIPS_POS { 0.0f, 0.0f, 0.0f };
|
|
||||||
static const glm::quat DEFAULT_AVATAR_HIPS_ROT { Quaternions::Y_180 };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_LEFTFOOT_POS { -0.08f, -0.96f, 0.029f};
|
|
||||||
static const glm::quat DEFAULT_AVATAR_LEFTFOOT_ROT { -0.40167322754859924f, 0.9154590368270874f, -0.005437685176730156f, -0.023744143545627594f };
|
|
||||||
static const glm::vec3 DEFAULT_AVATAR_RIGHTFOOT_POS { 0.08f, -0.96f, 0.029f };
|
|
||||||
static const glm::quat DEFAULT_AVATAR_RIGHTFOOT_ROT { -0.4016716778278351f, 0.9154615998268127f, 0.0053307069465518f, 0.023696165531873703f };
|
|
||||||
|
|
||||||
MyAvatar::MyAvatar(QThread* thread) :
|
MyAvatar::MyAvatar(QThread* thread) :
|
||||||
Avatar(thread),
|
Avatar(thread),
|
||||||
_yawSpeed(YAW_SPEED_DEFAULT),
|
_yawSpeed(YAW_SPEED_DEFAULT),
|
||||||
|
@ -344,7 +316,7 @@ void MyAvatar::centerBody() {
|
||||||
// transform this body into world space
|
// transform this body into world space
|
||||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||||
auto worldBodyPos = extractTranslation(worldBodyMatrix);
|
auto worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||||
auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
auto worldBodyRot = glmExtractRotation(worldBodyMatrix);
|
||||||
|
|
||||||
if (_characterController.getState() == CharacterController::State::Ground) {
|
if (_characterController.getState() == CharacterController::State::Ground) {
|
||||||
// the avatar's physical aspect thinks it is standing on something
|
// the avatar's physical aspect thinks it is standing on something
|
||||||
|
@ -397,7 +369,7 @@ void MyAvatar::reset(bool andRecenter, bool andReload, bool andHead) {
|
||||||
// transform this body into world space
|
// transform this body into world space
|
||||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||||
auto worldBodyPos = extractTranslation(worldBodyMatrix);
|
auto worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||||
auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
auto worldBodyRot = glmExtractRotation(worldBodyMatrix);
|
||||||
|
|
||||||
// this will become our new position.
|
// this will become our new position.
|
||||||
setPosition(worldBodyPos);
|
setPosition(worldBodyPos);
|
||||||
|
@ -586,7 +558,7 @@ void MyAvatar::simulate(float deltaTime) {
|
||||||
headPosition = getPosition();
|
headPosition = getPosition();
|
||||||
}
|
}
|
||||||
head->setPosition(headPosition);
|
head->setPosition(headPosition);
|
||||||
head->setScale(getUniformScale());
|
head->setScale(getModelScale());
|
||||||
head->simulate(deltaTime);
|
head->simulate(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +636,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
_hmdSensorPosition = newHmdSensorPosition;
|
_hmdSensorPosition = newHmdSensorPosition;
|
||||||
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
_hmdSensorOrientation = glmExtractRotation(hmdSensorMatrix);
|
||||||
auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||||
if (headPose.isValid()) {
|
if (headPose.isValid()) {
|
||||||
_headControllerFacing = getFacingDir2D(headPose.rotation);
|
_headControllerFacing = getFacingDir2D(headPose.rotation);
|
||||||
|
@ -688,9 +660,11 @@ void MyAvatar::updateJointFromController(controller::Action poseKey, ThreadSafeV
|
||||||
// update sensor to world matrix from current body position and hmd sensor.
|
// update sensor to world matrix from current body position and hmd sensor.
|
||||||
// This is so the correct camera can be used for rendering.
|
// This is so the correct camera can be used for rendering.
|
||||||
void MyAvatar::updateSensorToWorldMatrix() {
|
void MyAvatar::updateSensorToWorldMatrix() {
|
||||||
|
|
||||||
// update the sensor mat so that the body position will end up in the desired
|
// update the sensor mat so that the body position will end up in the desired
|
||||||
// position when driven from the head.
|
// position when driven from the head.
|
||||||
glm::mat4 desiredMat = createMatFromQuatAndPos(getOrientation(), getPosition());
|
float sensorToWorldScale = getEyeHeight() / getUserEyeHeight();
|
||||||
|
glm::mat4 desiredMat = createMatFromScaleQuatAndPos(glm::vec3(sensorToWorldScale), getOrientation(), getPosition());
|
||||||
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
_sensorToWorldMatrix = desiredMat * glm::inverse(_bodySensorMatrix);
|
||||||
|
|
||||||
lateUpdatePalms();
|
lateUpdatePalms();
|
||||||
|
@ -1002,6 +976,7 @@ void MyAvatar::saveData() {
|
||||||
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||||
settings.setValue("useSnapTurn", _useSnapTurn);
|
settings.setValue("useSnapTurn", _useSnapTurn);
|
||||||
settings.setValue("clearOverlayWhenMoving", _clearOverlayWhenMoving);
|
settings.setValue("clearOverlayWhenMoving", _clearOverlayWhenMoving);
|
||||||
|
settings.setValue("userHeight", getUserHeight());
|
||||||
|
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
@ -1142,6 +1117,7 @@ void MyAvatar::loadData() {
|
||||||
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
||||||
setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool());
|
setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool());
|
||||||
setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower());
|
setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower());
|
||||||
|
setUserHeight(settings.value("userHeight", DEFAULT_AVATAR_HEIGHT).toDouble());
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
|
|
||||||
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));
|
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));
|
||||||
|
@ -1247,7 +1223,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
||||||
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
|
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
|
||||||
avatar->setIsLookAtTarget(false);
|
avatar->setIsLookAtTarget(false);
|
||||||
if (!avatar->isMyAvatar() && avatar->isInitialized() &&
|
if (!avatar->isMyAvatar() && avatar->isInitialized() &&
|
||||||
(distanceTo < GREATEST_LOOKING_AT_DISTANCE * getUniformScale())) {
|
(distanceTo < GREATEST_LOOKING_AT_DISTANCE * getModelScale())) {
|
||||||
float radius = glm::length(avatar->getHead()->getEyePosition() - avatar->getHead()->getRightEyePosition());
|
float radius = glm::length(avatar->getHead()->getEyePosition() - avatar->getHead()->getRightEyePosition());
|
||||||
float angleTo = coneSphereAngle(getHead()->getEyePosition(), lookForward, avatar->getHead()->getEyePosition(), radius);
|
float angleTo = coneSphereAngle(getHead()->getEyePosition(), lookForward, avatar->getHead()->getEyePosition(), radius);
|
||||||
if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) {
|
if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) {
|
||||||
|
@ -1489,7 +1465,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const {
|
||||||
|
|
||||||
void MyAvatar::rebuildCollisionShape() {
|
void MyAvatar::rebuildCollisionShape() {
|
||||||
// compute localAABox
|
// compute localAABox
|
||||||
float scale = getUniformScale();
|
float scale = getModelScale();
|
||||||
float radius = scale * _skeletonModel->getBoundingCapsuleRadius();
|
float radius = scale * _skeletonModel->getBoundingCapsuleRadius();
|
||||||
float height = scale * _skeletonModel->getBoundingCapsuleHeight() + 2.0f * radius;
|
float height = scale * _skeletonModel->getBoundingCapsuleHeight() + 2.0f * radius;
|
||||||
glm::vec3 corner(-radius, -0.5f * height, -radius);
|
glm::vec3 corner(-radius, -0.5f * height, -radius);
|
||||||
|
@ -1595,6 +1571,7 @@ void MyAvatar::prepareForPhysicsSimulation() {
|
||||||
}
|
}
|
||||||
_characterController.handleChangedCollisionGroup();
|
_characterController.handleChangedCollisionGroup();
|
||||||
_characterController.setParentVelocity(parentVelocity);
|
_characterController.setParentVelocity(parentVelocity);
|
||||||
|
_characterController.setScaleFactor(getSensorToWorldScale());
|
||||||
|
|
||||||
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
||||||
auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||||
|
@ -1930,7 +1907,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
||||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.3f;
|
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.3f;
|
||||||
|
|
||||||
bool MyAvatar::cameraInsideHead(const glm::vec3& cameraPosition) const {
|
bool MyAvatar::cameraInsideHead(const glm::vec3& cameraPosition) const {
|
||||||
return glm::length(cameraPosition - getHeadPosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getUniformScale());
|
return glm::length(cameraPosition - getHeadPosition()) < (RENDER_HEAD_CUTOFF_DISTANCE * getModelScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
bool MyAvatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||||
|
@ -1978,38 +1955,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
||||||
snapTurn = true;
|
snapTurn = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// use head/HMD orientation to turn while flying
|
// Use head/HMD roll to turn while flying, but not when standing still.
|
||||||
if (getCharacterController()->getState() == CharacterController::State::Hover) {
|
if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover && _hmdRollControlEnabled && hasDriveInput()) {
|
||||||
|
|
||||||
// This is the direction the user desires to fly in.
|
|
||||||
glm::vec3 desiredFacing = getMyHead()->getHeadOrientation() * Vectors::UNIT_Z;
|
|
||||||
desiredFacing.y = 0.0f;
|
|
||||||
|
|
||||||
// This is our reference frame, it is captured when the user begins to move.
|
|
||||||
glm::vec3 referenceFacing = transformVectorFast(_sensorToWorldMatrix, _hoverReferenceCameraFacing);
|
|
||||||
referenceFacing.y = 0.0f;
|
|
||||||
referenceFacing = glm::normalize(referenceFacing);
|
|
||||||
glm::vec3 referenceRight(referenceFacing.z, 0.0f, -referenceFacing.x);
|
|
||||||
const float HOVER_FLY_ROTATION_PERIOD = 0.5f;
|
|
||||||
float tau = glm::clamp(deltaTime / HOVER_FLY_ROTATION_PERIOD, 0.0f, 1.0f);
|
|
||||||
|
|
||||||
// new facing is a linear interpolation between the desired and reference vectors.
|
|
||||||
glm::vec3 newFacing = glm::normalize((1.0f - tau) * referenceFacing + tau * desiredFacing);
|
|
||||||
|
|
||||||
// calcualte the signed delta yaw angle to apply so that we match our newFacing.
|
|
||||||
float sign = copysignf(1.0f, glm::dot(desiredFacing, referenceRight));
|
|
||||||
float deltaAngle = sign * acosf(glm::clamp(glm::dot(referenceFacing, newFacing), -1.0f, 1.0f));
|
|
||||||
|
|
||||||
// speedFactor is 0 when we are at rest adn 1.0 when we are at max flying speed.
|
|
||||||
const float MAX_FLYING_SPEED = 30.0f;
|
|
||||||
float speedFactor = glm::min(glm::length(getVelocity()) / MAX_FLYING_SPEED, 1.0f);
|
|
||||||
|
|
||||||
// apply our delta, but scale it by the speed factor, so we turn faster when we are flying faster.
|
|
||||||
totalBodyYaw += (speedFactor * deltaAngle * (180.0f / PI));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Use head/HMD roll to turn while walking or flying, but not when standing still
|
|
||||||
if (qApp->isHMDMode() && _hmdRollControlEnabled && hasDriveInput()) {
|
|
||||||
// Turn with head roll.
|
// Turn with head roll.
|
||||||
const float MIN_CONTROL_SPEED = 0.01f;
|
const float MIN_CONTROL_SPEED = 0.01f;
|
||||||
float speed = glm::length(getVelocity());
|
float speed = glm::length(getVelocity());
|
||||||
|
@ -2103,17 +2050,17 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
||||||
if (state == CharacterController::State::Hover) {
|
if (state == CharacterController::State::Hover) {
|
||||||
// we're flying --> complex acceleration curve that builds on top of current motor speed and caps at some max speed
|
// we're flying --> complex acceleration curve that builds on top of current motor speed and caps at some max speed
|
||||||
float motorSpeed = glm::length(_actionMotorVelocity);
|
float motorSpeed = glm::length(_actionMotorVelocity);
|
||||||
float finalMaxMotorSpeed = getUniformScale() * MAX_ACTION_MOTOR_SPEED;
|
float finalMaxMotorSpeed = getSensorToWorldScale() * DEFAULT_AVATAR_MAX_FLYING_SPEED;
|
||||||
float speedGrowthTimescale = 2.0f;
|
float speedGrowthTimescale = 2.0f;
|
||||||
float speedIncreaseFactor = 1.8f;
|
float speedIncreaseFactor = 1.8f;
|
||||||
motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale, 0.0f, 1.0f) * speedIncreaseFactor;
|
motorSpeed *= 1.0f + glm::clamp(deltaTime / speedGrowthTimescale, 0.0f, 1.0f) * speedIncreaseFactor;
|
||||||
const float maxBoostSpeed = getUniformScale() * MAX_BOOST_SPEED;
|
const float maxBoostSpeed = getSensorToWorldScale() * MAX_BOOST_SPEED;
|
||||||
|
|
||||||
if (_isPushing) {
|
if (_isPushing) {
|
||||||
if (motorSpeed < maxBoostSpeed) {
|
if (motorSpeed < maxBoostSpeed) {
|
||||||
// an active action motor should never be slower than this
|
// an active action motor should never be slower than this
|
||||||
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;
|
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;
|
||||||
motorSpeed += MIN_AVATAR_SPEED * boostCoefficient;
|
motorSpeed += getSensorToWorldScale() * MIN_AVATAR_SPEED * boostCoefficient;
|
||||||
} else if (motorSpeed > finalMaxMotorSpeed) {
|
} else if (motorSpeed > finalMaxMotorSpeed) {
|
||||||
motorSpeed = finalMaxMotorSpeed;
|
motorSpeed = finalMaxMotorSpeed;
|
||||||
}
|
}
|
||||||
|
@ -2121,7 +2068,7 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
||||||
_actionMotorVelocity = motorSpeed * direction;
|
_actionMotorVelocity = motorSpeed * direction;
|
||||||
} else {
|
} else {
|
||||||
// we're interacting with a floor --> simple horizontal speed and exponential decay
|
// we're interacting with a floor --> simple horizontal speed and exponential decay
|
||||||
_actionMotorVelocity = MAX_WALKING_SPEED * direction;
|
_actionMotorVelocity = getSensorToWorldScale() * DEFAULT_AVATAR_MAX_WALKING_SPEED * direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
float boomChange = getDriveKey(ZOOM);
|
float boomChange = getDriveKey(ZOOM);
|
||||||
|
@ -2135,22 +2082,24 @@ void MyAvatar::updatePosition(float deltaTime) {
|
||||||
}
|
}
|
||||||
|
|
||||||
vec3 velocity = getVelocity();
|
vec3 velocity = getVelocity();
|
||||||
|
float sensorToWorldScale = getSensorToWorldScale();
|
||||||
|
float sensorToWorldScale2 = sensorToWorldScale * sensorToWorldScale;
|
||||||
const float MOVING_SPEED_THRESHOLD_SQUARED = 0.0001f; // 0.01 m/s
|
const float MOVING_SPEED_THRESHOLD_SQUARED = 0.0001f; // 0.01 m/s
|
||||||
if (!_characterController.isEnabledAndReady()) {
|
if (!_characterController.isEnabledAndReady()) {
|
||||||
// _characterController is not in physics simulation but it can still compute its target velocity
|
// _characterController is not in physics simulation but it can still compute its target velocity
|
||||||
updateMotors();
|
updateMotors();
|
||||||
_characterController.computeNewVelocity(deltaTime, velocity);
|
_characterController.computeNewVelocity(deltaTime, velocity);
|
||||||
|
|
||||||
float speed2 = glm::length2(velocity);
|
float speed2 = glm::length(velocity);
|
||||||
if (speed2 > MIN_AVATAR_SPEED_SQUARED) {
|
if (speed2 > sensorToWorldScale2 * MIN_AVATAR_SPEED_SQUARED) {
|
||||||
// update position ourselves
|
// update position ourselves
|
||||||
applyPositionDelta(deltaTime * velocity);
|
applyPositionDelta(deltaTime * velocity);
|
||||||
}
|
}
|
||||||
measureMotionDerivatives(deltaTime);
|
measureMotionDerivatives(deltaTime);
|
||||||
_moving = speed2 > MOVING_SPEED_THRESHOLD_SQUARED;
|
_moving = speed2 > sensorToWorldScale2 * MOVING_SPEED_THRESHOLD_SQUARED;
|
||||||
} else {
|
} else {
|
||||||
float speed2 = glm::length2(velocity);
|
float speed2 = glm::length2(velocity);
|
||||||
_moving = speed2 > MOVING_SPEED_THRESHOLD_SQUARED;
|
_moving = speed2 > sensorToWorldScale2 * MOVING_SPEED_THRESHOLD_SQUARED;
|
||||||
|
|
||||||
if (_moving) {
|
if (_moving) {
|
||||||
// scan for walkability
|
// scan for walkability
|
||||||
|
@ -2161,18 +2110,6 @@ void MyAvatar::updatePosition(float deltaTime) {
|
||||||
_characterController.setStepUpEnabled(result.walkable);
|
_characterController.setStepUpEnabled(result.walkable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// capture the head rotation, in sensor space, when the user first indicates they would like to move/fly.
|
|
||||||
if (!_hoverReferenceCameraFacingIsCaptured &&
|
|
||||||
(fabs(getDriveKey(TRANSLATE_Z)) > 0.1f || fabs(getDriveKey(TRANSLATE_X)) > 0.1f)) {
|
|
||||||
_hoverReferenceCameraFacingIsCaptured = true;
|
|
||||||
// transform the camera facing vector into sensor space.
|
|
||||||
_hoverReferenceCameraFacing = transformVectorFast(glm::inverse(_sensorToWorldMatrix),
|
|
||||||
getMyHead()->getHeadOrientation() * Vectors::UNIT_Z);
|
|
||||||
} else if (_hoverReferenceCameraFacingIsCaptured &&
|
|
||||||
(fabs(getDriveKey(TRANSLATE_Z)) <= 0.1f && fabs(getDriveKey(TRANSLATE_X)) <= 0.1f)) {
|
|
||||||
_hoverReferenceCameraFacingIsCaptured = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) {
|
void MyAvatar::updateCollisionSound(const glm::vec3 &penetration, float deltaTime, float frequency) {
|
||||||
|
@ -2325,7 +2262,8 @@ void MyAvatar::restrictScaleFromDomainSettings(const QJsonObject& domainSettings
|
||||||
_targetScale = clampedScale;
|
_targetScale = clampedScale;
|
||||||
}
|
}
|
||||||
|
|
||||||
setScale(glm::vec3(_targetScale));
|
setModelScale(_targetScale);
|
||||||
|
rebuildCollisionShape();
|
||||||
settings.endGroup();
|
settings.endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2711,11 +2649,30 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
|
||||||
// Y_180 is necessary because rig is z forward and hmdOrientation is -z forward
|
// Y_180 is necessary because rig is z forward and hmdOrientation is -z forward
|
||||||
glm::vec3 headToNeck = headOrientation * Quaternions::Y_180 * (localNeck - localHead);
|
glm::vec3 headToNeck = headOrientation * Quaternions::Y_180 * (localNeck - localHead);
|
||||||
glm::vec3 neckToRoot = headOrientationYawOnly * Quaternions::Y_180 * -localNeck;
|
glm::vec3 neckToRoot = headOrientationYawOnly * Quaternions::Y_180 * -localNeck;
|
||||||
glm::vec3 bodyPos = headPosition + headToNeck + neckToRoot;
|
|
||||||
|
float invSensorToWorldScale = getUserEyeHeight() / getEyeHeight();
|
||||||
|
glm::vec3 bodyPos = headPosition + invSensorToWorldScale * (headToNeck + neckToRoot);
|
||||||
|
|
||||||
return createMatFromQuatAndPos(headOrientationYawOnly, bodyPos);
|
return createMatFromQuatAndPos(headOrientationYawOnly, bodyPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float MyAvatar::getUserHeight() const {
|
||||||
|
return _userHeight.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setUserHeight(float value) {
|
||||||
|
_userHeight.set(value);
|
||||||
|
|
||||||
|
float sensorToWorldScale = getEyeHeight() / getUserEyeHeight();
|
||||||
|
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||||
|
}
|
||||||
|
|
||||||
|
float MyAvatar::getUserEyeHeight() const {
|
||||||
|
float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||||
|
float userHeight = _userHeight.get();
|
||||||
|
return userHeight - userHeight * ratio;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec3 MyAvatar::getPositionForAudio() {
|
glm::vec3 MyAvatar::getPositionForAudio() {
|
||||||
switch (_audioListenerMode) {
|
switch (_audioListenerMode) {
|
||||||
case AudioListenerMode::FROM_HEAD:
|
case AudioListenerMode::FROM_HEAD:
|
||||||
|
@ -2834,7 +2791,6 @@ bool MyAvatar::FollowHelper::shouldActivateRotation(const MyAvatar& myAvatar, co
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||||
|
|
||||||
// -z axis of currentBodyMatrix in world space.
|
// -z axis of currentBodyMatrix in world space.
|
||||||
glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][2], -currentBodyMatrix[1][2], -currentBodyMatrix[2][2]));
|
glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][2], -currentBodyMatrix[1][2], -currentBodyMatrix[2][2]));
|
||||||
// x axis of currentBodyMatrix in world space.
|
// x axis of currentBodyMatrix in world space.
|
||||||
|
@ -2858,7 +2814,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
|
||||||
}
|
}
|
||||||
|
|
||||||
bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
bool MyAvatar::FollowHelper::shouldActivateVertical(const MyAvatar& myAvatar, const glm::mat4& desiredBodyMatrix, const glm::mat4& currentBodyMatrix) const {
|
||||||
|
|
||||||
const float CYLINDER_TOP = 0.1f;
|
const float CYLINDER_TOP = 0.1f;
|
||||||
const float CYLINDER_BOTTOM = -1.5f;
|
const float CYLINDER_BOTTOM = -1.5f;
|
||||||
|
|
||||||
|
@ -2886,6 +2841,10 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
||||||
glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix;
|
glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix;
|
||||||
|
|
||||||
AnimPose followWorldPose(currentWorldMatrix);
|
AnimPose followWorldPose(currentWorldMatrix);
|
||||||
|
|
||||||
|
// remove scale present from sensorToWorldMatrix
|
||||||
|
followWorldPose.scale() = glm::vec3(1.0f);
|
||||||
|
|
||||||
if (isActive(Rotation)) {
|
if (isActive(Rotation)) {
|
||||||
followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix);
|
followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix);
|
||||||
}
|
}
|
||||||
|
@ -2910,16 +2869,16 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co
|
||||||
// apply follow displacement to the body matrix.
|
// apply follow displacement to the body matrix.
|
||||||
glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement();
|
glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement();
|
||||||
glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement();
|
glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement();
|
||||||
glm::quat sensorToWorld = glmExtractRotation(myAvatar.getSensorToWorldMatrix());
|
|
||||||
glm::quat worldToSensor = glm::inverse(sensorToWorld);
|
|
||||||
|
|
||||||
glm::vec3 sensorLinearDisplacement = worldToSensor * worldLinearDisplacement;
|
glm::mat4 sensorToWorldMatrix = myAvatar.getSensorToWorldMatrix();
|
||||||
glm::quat sensorAngularDisplacement = worldToSensor * worldAngularDisplacement * sensorToWorld;
|
glm::mat4 worldToSensorMatrix = glm::inverse(sensorToWorldMatrix);
|
||||||
|
|
||||||
|
glm::vec3 sensorLinearDisplacement = transformVectorFast(worldToSensorMatrix, worldLinearDisplacement);
|
||||||
|
glm::quat sensorAngularDisplacement = glmExtractRotation(worldToSensorMatrix) * worldAngularDisplacement * glmExtractRotation(sensorToWorldMatrix);
|
||||||
|
|
||||||
glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),
|
glm::mat4 newBodyMat = createMatFromQuatAndPos(sensorAngularDisplacement * glmExtractRotation(currentBodyMatrix),
|
||||||
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
|
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
|
||||||
return newBodyMat;
|
return newBodyMat;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
return currentBodyMatrix;
|
return currentBodyMatrix;
|
||||||
}
|
}
|
||||||
|
@ -2977,15 +2936,20 @@ glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& c
|
||||||
cameraWorldMatrix *= createMatFromScaleQuatAndPos(vec3(-1.0f, 1.0f, 1.0f), glm::quat(), glm::vec3());
|
cameraWorldMatrix *= createMatFromScaleQuatAndPos(vec3(-1.0f, 1.0f, 1.0f), glm::quat(), glm::vec3());
|
||||||
}
|
}
|
||||||
|
|
||||||
// compute a NEW sensorToWorldMatrix for the camera.
|
// move the camera into sensor space.
|
||||||
// The equation is cameraWorldMatrix = cameraSensorToWorldMatrix * _hmdSensorMatrix.
|
glm::mat4 cameraSensorMatrix = glm::inverse(getSensorToWorldMatrix()) * cameraWorldMatrix;
|
||||||
// here we solve for the unknown cameraSensorToWorldMatrix.
|
|
||||||
glm::mat4 cameraSensorToWorldMatrix = cameraWorldMatrix * glm::inverse(getHMDSensorMatrix());
|
|
||||||
|
|
||||||
// Using the new cameraSensorToWorldMatrix, compute where the controller is in world space.
|
// cancel out scale
|
||||||
glm::mat4 controllerWorldMatrix = cameraSensorToWorldMatrix * controllerSensorMatrix;
|
glm::vec3 scale = extractScale(cameraSensorMatrix);
|
||||||
|
cameraSensorMatrix = glm::scale(cameraSensorMatrix, 1.0f / scale);
|
||||||
|
|
||||||
// move it into avatar space
|
// measure the offset from the hmd and the camera, in sensor space
|
||||||
|
glm::mat4 delta = cameraSensorMatrix * glm::inverse(getHMDSensorMatrix());
|
||||||
|
|
||||||
|
// apply the delta offset to the controller, in sensor space, then transform it into world space.
|
||||||
|
glm::mat4 controllerWorldMatrix = getSensorToWorldMatrix() * delta * controllerSensorMatrix;
|
||||||
|
|
||||||
|
// transform controller into avatar space
|
||||||
glm::mat4 avatarMatrix = createMatFromQuatAndPos(getOrientation(), getPosition());
|
glm::mat4 avatarMatrix = createMatFromQuatAndPos(getOrientation(), getPosition());
|
||||||
return glm::inverse(avatarMatrix) * controllerWorldMatrix;
|
return glm::inverse(avatarMatrix) * controllerWorldMatrix;
|
||||||
}
|
}
|
||||||
|
@ -3257,3 +3221,12 @@ void MyAvatar::updateHoldActions(const AnimPose& prePhysicsPose, const AnimPose&
|
||||||
const MyHead* MyAvatar::getMyHead() const {
|
const MyHead* MyAvatar::getMyHead() const {
|
||||||
return static_cast<const MyHead*>(getHead());
|
return static_cast<const MyHead*>(getHead());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MyAvatar::setModelScale(float scale) {
|
||||||
|
bool changed = (scale != getModelScale());
|
||||||
|
Avatar::setModelScale(scale);
|
||||||
|
if (changed) {
|
||||||
|
float sensorToWorldScale = getEyeHeight() / getUserEyeHeight();
|
||||||
|
emit sensorToWorldScaleChanged(sensorToWorldScale);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
|
|
||||||
#include <controllers/Pose.h>
|
#include <controllers/Pose.h>
|
||||||
#include <controllers/Actions.h>
|
#include <controllers/Actions.h>
|
||||||
|
#include <AvatarConstants.h>
|
||||||
#include <avatars-renderer/Avatar.h>
|
#include <avatars-renderer/Avatar.h>
|
||||||
#include <avatars-renderer/ScriptAvatar.h>
|
#include <avatars-renderer/ScriptAvatar.h>
|
||||||
|
|
||||||
|
@ -103,6 +104,8 @@ class MyAvatar : public Avatar {
|
||||||
* @property collisionsEnabled {bool} This can be used to disable collisions between the avatar and the world.
|
* @property collisionsEnabled {bool} This can be used to disable collisions between the avatar and the world.
|
||||||
* @property useAdvancedMovementControls {bool} Stores the user preference only, does not change user mappings, this is done in the defaultScript
|
* @property useAdvancedMovementControls {bool} Stores the user preference only, does not change user mappings, this is done in the defaultScript
|
||||||
* "scripts/system/controllers/toggleAdvancedMovementForHandControllers.js".
|
* "scripts/system/controllers/toggleAdvancedMovementForHandControllers.js".
|
||||||
|
* @property userHeight {number} The height of the user in sensor space. (meters).
|
||||||
|
* @property userEyeHeight {number} Estimated height of the users eyes in sensor space. (meters)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// FIXME: `glm::vec3 position` is not accessible from QML, so this exposes position in a QML-native type
|
// FIXME: `glm::vec3 position` is not accessible from QML, so this exposes position in a QML-native type
|
||||||
|
@ -147,6 +150,9 @@ class MyAvatar : public Avatar {
|
||||||
Q_PROPERTY(float hmdRollControlDeadZone READ getHMDRollControlDeadZone WRITE setHMDRollControlDeadZone)
|
Q_PROPERTY(float hmdRollControlDeadZone READ getHMDRollControlDeadZone WRITE setHMDRollControlDeadZone)
|
||||||
Q_PROPERTY(float hmdRollControlRate READ getHMDRollControlRate WRITE setHMDRollControlRate)
|
Q_PROPERTY(float hmdRollControlRate READ getHMDRollControlRate WRITE setHMDRollControlRate)
|
||||||
|
|
||||||
|
Q_PROPERTY(float userHeight READ getUserHeight WRITE setUserHeight)
|
||||||
|
Q_PROPERTY(float userEyeHeight READ getUserEyeHeight)
|
||||||
|
|
||||||
const QString DOMINANT_LEFT_HAND = "left";
|
const QString DOMINANT_LEFT_HAND = "left";
|
||||||
const QString DOMINANT_RIGHT_HAND = "right";
|
const QString DOMINANT_RIGHT_HAND = "right";
|
||||||
|
|
||||||
|
@ -534,6 +540,10 @@ public:
|
||||||
Q_INVOKABLE bool isUp(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) > 0.0f; }; // true iff direction points up wrt avatar's definition of up.
|
Q_INVOKABLE bool isUp(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) > 0.0f; }; // true iff direction points up wrt avatar's definition of up.
|
||||||
Q_INVOKABLE bool isDown(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) < 0.0f; };
|
Q_INVOKABLE bool isDown(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) < 0.0f; };
|
||||||
|
|
||||||
|
void setUserHeight(float value);
|
||||||
|
float getUserHeight() const;
|
||||||
|
float getUserEyeHeight() const;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void increaseSize();
|
void increaseSize();
|
||||||
void decreaseSize();
|
void decreaseSize();
|
||||||
|
@ -581,6 +591,8 @@ public slots:
|
||||||
glm::vec3 getPositionForAudio();
|
glm::vec3 getPositionForAudio();
|
||||||
glm::quat getOrientationForAudio();
|
glm::quat getOrientationForAudio();
|
||||||
|
|
||||||
|
virtual void setModelScale(float scale) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void audioListenerModeChanged();
|
void audioListenerModeChanged();
|
||||||
void transformChanged();
|
void transformChanged();
|
||||||
|
@ -593,6 +605,7 @@ signals:
|
||||||
void wentActive();
|
void wentActive();
|
||||||
void skeletonChanged();
|
void skeletonChanged();
|
||||||
void dominantHandChanged(const QString& hand);
|
void dominantHandChanged(const QString& hand);
|
||||||
|
void sensorToWorldScaleChanged(float sensorToWorldScale);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -713,7 +726,7 @@ private:
|
||||||
float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT };
|
float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT };
|
||||||
float _lastDrivenSpeed { 0.0f };
|
float _lastDrivenSpeed { 0.0f };
|
||||||
|
|
||||||
// working copies -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
// working copy -- see AvatarData for thread-safe _sensorToWorldMatrixCache, used for outward facing access
|
||||||
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
|
glm::mat4 _sensorToWorldMatrix { glm::mat4() };
|
||||||
|
|
||||||
// cache of the current HMD sensor position and orientation in sensor space.
|
// cache of the current HMD sensor position and orientation in sensor space.
|
||||||
|
@ -779,8 +792,6 @@ private:
|
||||||
|
|
||||||
AtRestDetector _hmdAtRestDetector;
|
AtRestDetector _hmdAtRestDetector;
|
||||||
bool _lastIsMoving { false };
|
bool _lastIsMoving { false };
|
||||||
bool _hoverReferenceCameraFacingIsCaptured { false };
|
|
||||||
glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space
|
|
||||||
|
|
||||||
// all poses are in sensor-frame
|
// all poses are in sensor-frame
|
||||||
std::map<controller::Action, controller::Pose> _controllerPoseMap;
|
std::map<controller::Action, controller::Pose> _controllerPoseMap;
|
||||||
|
@ -807,6 +818,9 @@ private:
|
||||||
void setAway(bool value);
|
void setAway(bool value);
|
||||||
|
|
||||||
std::vector<int> _pinnedJoints;
|
std::vector<int> _pinnedJoints;
|
||||||
|
|
||||||
|
// height of user in sensor space, when standing erect.
|
||||||
|
ThreadSafeValueCache<float> _userHeight { DEFAULT_AVATAR_HEIGHT };
|
||||||
};
|
};
|
||||||
|
|
||||||
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
QScriptValue audioListenModeToScriptValue(QScriptEngine* engine, const AudioListenerMode& audioListenerMode);
|
||||||
|
|
|
@ -148,7 +148,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
|
|
||||||
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());
|
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());
|
||||||
|
|
||||||
auto velocity = myAvatar->getLocalVelocity();
|
auto velocity = myAvatar->getLocalVelocity() / myAvatar->getSensorToWorldScale();
|
||||||
auto position = myAvatar->getLocalPosition();
|
auto position = myAvatar->getLocalPosition();
|
||||||
auto orientation = myAvatar->getLocalOrientation();
|
auto orientation = myAvatar->getLocalOrientation();
|
||||||
_rig.computeMotionAnimationState(deltaTime, position, velocity, orientation, ccState);
|
_rig.computeMotionAnimationState(deltaTime, position, velocity, orientation, ccState);
|
||||||
|
|
|
@ -36,7 +36,7 @@ const PickRay JointRayPick::getPickRay(bool& valid) const {
|
||||||
glm::quat rot = useAvatarHead ? jointRot * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT) : avatarRot * jointRot;
|
glm::quat rot = useAvatarHead ? jointRot * glm::angleAxis(-PI / 2.0f, Vectors::RIGHT) : avatarRot * jointRot;
|
||||||
|
|
||||||
// Apply offset
|
// Apply offset
|
||||||
pos = pos + (rot * _posOffset);
|
pos = pos + (rot * (myAvatar->getSensorToWorldScale() * _posOffset));
|
||||||
glm::vec3 dir = rot * glm::normalize(_dirOffset);
|
glm::vec3 dir = rot * glm::normalize(_dirOffset);
|
||||||
|
|
||||||
valid = true;
|
valid = true;
|
||||||
|
|
|
@ -143,15 +143,16 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
|
||||||
}
|
}
|
||||||
if (!renderState.getEndID().isNull()) {
|
if (!renderState.getEndID().isNull()) {
|
||||||
QVariantMap endProps;
|
QVariantMap endProps;
|
||||||
|
glm::quat faceAvatarRotation = DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f)));
|
||||||
if (_centerEndY) {
|
if (_centerEndY) {
|
||||||
endProps.insert("position", end);
|
endProps.insert("position", end);
|
||||||
} else {
|
} else {
|
||||||
glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value);
|
glm::vec3 dim = vec3FromVariant(qApp->getOverlays().getProperty(renderState.getEndID(), "dimensions").value);
|
||||||
endProps.insert("position", vec3toVariant(endVec + glm::vec3(0, 0.5f * dim.y, 0)));
|
glm::vec3 currentUpVector = faceAvatarRotation * Vectors::UP;
|
||||||
|
endProps.insert("position", vec3toVariant(endVec + glm::vec3(currentUpVector.x * 0.5f * dim.y, currentUpVector.y * 0.5f * dim.y, currentUpVector.z * 0.5f * dim.y)));
|
||||||
}
|
}
|
||||||
if (_faceAvatar) {
|
if (_faceAvatar) {
|
||||||
glm::quat rotation = glm::inverse(glm::quat_cast(glm::lookAt(endVec, DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), Vectors::UP)));
|
endProps.insert("rotation", quatToVariant(faceAvatarRotation));
|
||||||
endProps.insert("rotation", quatToVariant(glm::quat(glm::radians(glm::vec3(0, glm::degrees(safeEulerAngles(rotation)).y, 0)))));
|
|
||||||
}
|
}
|
||||||
endProps.insert("visible", true);
|
endProps.insert("visible", true);
|
||||||
endProps.insert("ignoreRayIntersection", renderState.doesEndIgnoreRays());
|
endProps.insert("ignoreRayIntersection", renderState.doesEndIgnoreRays());
|
||||||
|
|
|
@ -108,4 +108,4 @@ void RayPickScriptingInterface::setIgnoreAvatars(QUuid uid, const QScriptValue&
|
||||||
|
|
||||||
void RayPickScriptingInterface::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
|
void RayPickScriptingInterface::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
|
||||||
qApp->getRayPickManager().setIncludeAvatars(uid, includeAvatars);
|
qApp->getRayPickManager().setIncludeAvatars(uid, includeAvatars);
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,7 +151,7 @@ glm::vec3 HMDScriptingInterface::getPosition() const {
|
||||||
|
|
||||||
glm::quat HMDScriptingInterface::getOrientation() const {
|
glm::quat HMDScriptingInterface::getOrientation() const {
|
||||||
if (qApp->getActiveDisplayPlugin()->isHmd()) {
|
if (qApp->getActiveDisplayPlugin()->isHmd()) {
|
||||||
return glm::normalize(glm::quat_cast(getWorldHMDMatrix()));
|
return glmExtractRotation(getWorldHMDMatrix());
|
||||||
}
|
}
|
||||||
return glm::quat();
|
return glm::quat();
|
||||||
}
|
}
|
||||||
|
|
|
@ -193,7 +193,7 @@ void setupPreferences() {
|
||||||
preferences->addPreference(new PrimaryHandPreference(AVATAR_TUNING, "Dominant Hand", getter, setter));
|
preferences->addPreference(new PrimaryHandPreference(AVATAR_TUNING, "Dominant Hand", getter, setter));
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
auto getter = [=]()->float { return myAvatar->getUniformScale(); };
|
auto getter = [=]()->float { return myAvatar->getTargetScale(); };
|
||||||
auto setter = [=](float value) { myAvatar->setTargetScale(value); };
|
auto setter = [=](float value) { myAvatar->setTargetScale(value); };
|
||||||
auto preference = new SpinnerSliderPreference(AVATAR_TUNING, "Avatar Scale", getter, setter);
|
auto preference = new SpinnerSliderPreference(AVATAR_TUNING, "Avatar Scale", getter, setter);
|
||||||
preference->setStep(0.05f);
|
preference->setStep(0.05f);
|
||||||
|
@ -205,6 +205,16 @@ void setupPreferences() {
|
||||||
// which can't be changed across domain switches. Having these values loaded up when you load the Dialog each time
|
// which can't be changed across domain switches. Having these values loaded up when you load the Dialog each time
|
||||||
// is a way around this, therefore they're not specified here but in the QML.
|
// is a way around this, therefore they're not specified here but in the QML.
|
||||||
}
|
}
|
||||||
|
{
|
||||||
|
auto getter = [=]()->float { return myAvatar->getUserHeight(); };
|
||||||
|
auto setter = [=](float value) { myAvatar->setUserHeight(value); };
|
||||||
|
auto preference = new SpinnerPreference(AVATAR_TUNING, "User height (meters)", getter, setter);
|
||||||
|
preference->setMin(1.0f);
|
||||||
|
preference->setMax(2.2f);
|
||||||
|
preference->setDecimals(3);
|
||||||
|
preference->setStep(0.001f);
|
||||||
|
preferences->addPreference(preference);
|
||||||
|
}
|
||||||
{
|
{
|
||||||
auto getter = []()->float { return DependencyManager::get<DdeFaceTracker>()->getEyeClosingThreshold(); };
|
auto getter = []()->float { return DependencyManager::get<DdeFaceTracker>()->getEyeClosingThreshold(); };
|
||||||
auto setter = [](float value) { DependencyManager::get<DdeFaceTracker>()->setEyeClosingThreshold(value); };
|
auto setter = [](float value) { DependencyManager::get<DdeFaceTracker>()->setEyeClosingThreshold(value); };
|
||||||
|
|
|
@ -46,13 +46,17 @@ void ModelOverlay::update(float deltatime) {
|
||||||
if (_updateModel) {
|
if (_updateModel) {
|
||||||
_updateModel = false;
|
_updateModel = false;
|
||||||
_model->setSnapModelToCenter(true);
|
_model->setSnapModelToCenter(true);
|
||||||
|
Transform transform = getTransform();
|
||||||
|
#ifndef USE_SN_SCALE
|
||||||
|
transform.setScale(1.0f); // disable inherited scale
|
||||||
|
#endif
|
||||||
if (_scaleToFit) {
|
if (_scaleToFit) {
|
||||||
_model->setScaleToFit(true, getScale() * getDimensions());
|
_model->setScaleToFit(true, transform.getScale() * getDimensions());
|
||||||
} else {
|
} else {
|
||||||
_model->setScale(getScale());
|
_model->setScale(transform.getScale());
|
||||||
}
|
}
|
||||||
_model->setRotation(getRotation());
|
_model->setRotation(transform.getRotation());
|
||||||
_model->setTranslation(getPosition());
|
_model->setTranslation(transform.getTranslation());
|
||||||
_model->setURL(_url);
|
_model->setURL(_url);
|
||||||
_model->simulate(deltatime, true);
|
_model->simulate(deltatime, true);
|
||||||
} else {
|
} else {
|
||||||
|
@ -93,13 +97,13 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
||||||
auto origPosition = getPosition();
|
auto origPosition = getPosition();
|
||||||
auto origRotation = getRotation();
|
auto origRotation = getRotation();
|
||||||
auto origDimensions = getDimensions();
|
auto origDimensions = getDimensions();
|
||||||
auto origScale = getScale();
|
auto origScale = getSNScale();
|
||||||
|
|
||||||
Base3DOverlay::setProperties(properties);
|
Base3DOverlay::setProperties(properties);
|
||||||
|
|
||||||
auto scale = properties["scale"];
|
auto scale = properties["scale"];
|
||||||
if (scale.isValid()) {
|
if (scale.isValid()) {
|
||||||
setScale(vec3FromVariant(scale));
|
setSNScale(vec3FromVariant(scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto dimensions = properties["dimensions"];
|
auto dimensions = properties["dimensions"];
|
||||||
|
@ -112,7 +116,7 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
||||||
_scaleToFit = false;
|
_scaleToFit = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (origPosition != getPosition() || origRotation != getRotation() || origDimensions != getDimensions() || origScale != getScale()) {
|
if (origPosition != getPosition() || origRotation != getRotation() || origDimensions != getDimensions() || origScale != getSNScale()) {
|
||||||
_updateModel = true;
|
_updateModel = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -194,7 +198,7 @@ QVariant ModelOverlay::getProperty(const QString& property) {
|
||||||
return vec3toVariant(getDimensions());
|
return vec3toVariant(getDimensions());
|
||||||
}
|
}
|
||||||
if (property == "scale") {
|
if (property == "scale") {
|
||||||
return vec3toVariant(getScale());
|
return vec3toVariant(getSNScale());
|
||||||
}
|
}
|
||||||
if (property == "textures") {
|
if (property == "textures") {
|
||||||
if (_modelTextures.size() > 0) {
|
if (_modelTextures.size() > 0) {
|
||||||
|
|
|
@ -1045,6 +1045,7 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
|
||||||
AABox overlayFrameBox(low, dimensions);
|
AABox overlayFrameBox(low, dimensions);
|
||||||
|
|
||||||
Transform overlayToWorldMatrix = overlay->getTransform();
|
Transform overlayToWorldMatrix = overlay->getTransform();
|
||||||
|
overlayToWorldMatrix.setScale(1.0f); // ignore inherited scale factor from parents
|
||||||
glm::mat4 worldToOverlayMatrix = glm::inverse(overlayToWorldMatrix.getMatrix());
|
glm::mat4 worldToOverlayMatrix = glm::inverse(overlayToWorldMatrix.getMatrix());
|
||||||
glm::vec3 overlayFrameSearchPosition = glm::vec3(worldToOverlayMatrix * glm::vec4(center, 1.0f));
|
glm::vec3 overlayFrameSearchPosition = glm::vec3(worldToOverlayMatrix * glm::vec4(center, 1.0f));
|
||||||
glm::vec3 penetration;
|
glm::vec3 penetration;
|
||||||
|
|
|
@ -74,7 +74,7 @@ namespace render {
|
||||||
glm::vec3 myAvatarPosition = avatar->getPosition();
|
glm::vec3 myAvatarPosition = avatar->getPosition();
|
||||||
float angle = glm::degrees(glm::angle(myAvatarRotation));
|
float angle = glm::degrees(glm::angle(myAvatarRotation));
|
||||||
glm::vec3 axis = glm::axis(myAvatarRotation);
|
glm::vec3 axis = glm::axis(myAvatarRotation);
|
||||||
float myAvatarScale = avatar->getUniformScale();
|
float myAvatarScale = avatar->getModelScale();
|
||||||
Transform transform = Transform();
|
Transform transform = Transform();
|
||||||
transform.setTranslation(myAvatarPosition);
|
transform.setTranslation(myAvatarPosition);
|
||||||
transform.setRotation(glm::angleAxis(angle, axis));
|
transform.setRotation(glm::angleAxis(angle, axis));
|
||||||
|
|
|
@ -69,8 +69,9 @@ bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
|
||||||
|
|
||||||
Transform Planar3DOverlay::evalRenderTransform() const {
|
Transform Planar3DOverlay::evalRenderTransform() const {
|
||||||
auto transform = getTransform();
|
auto transform = getTransform();
|
||||||
|
transform.setScale(1.0f); // ignore inherited scale factor from parents
|
||||||
if (glm::length2(getDimensions()) != 1.0f) {
|
if (glm::length2(getDimensions()) != 1.0f) {
|
||||||
transform.postScale(vec3(getDimensions(), 1.0f));
|
transform.postScale(vec3(getDimensions(), 1.0f));
|
||||||
}
|
}
|
||||||
return transform;
|
return transform;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,9 @@ void Sphere3DOverlay::render(RenderArgs* args) {
|
||||||
if (batch) {
|
if (batch) {
|
||||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
||||||
Transform transform = getTransform();
|
Transform transform = getTransform();
|
||||||
|
#ifndef USE_SN_SCALE
|
||||||
|
transform.setScale(1.0f); // ignore inherited scale from SpatiallyNestable
|
||||||
|
#endif
|
||||||
transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE);
|
transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE);
|
||||||
batch->setModelTransform(transform);
|
batch->setModelTransform(transform);
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,11 @@ bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
|
||||||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||||
// extents is the entity relative, scaled, centered extents of the entity
|
// extents is the entity relative, scaled, centered extents of the entity
|
||||||
glm::mat4 worldToEntityMatrix;
|
glm::mat4 worldToEntityMatrix;
|
||||||
getTransform().getInverseMatrix(worldToEntityMatrix);
|
Transform transform = getTransform();
|
||||||
|
#ifndef USE_SN_SCALE
|
||||||
|
transform.setScale(1.0f); // ignore any inherited scale from SpatiallyNestable
|
||||||
|
#endif
|
||||||
|
transform.getInverseMatrix(worldToEntityMatrix);
|
||||||
|
|
||||||
glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
glm::vec3 overlayFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||||
glm::vec3 overlayFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
|
glm::vec3 overlayFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
|
||||||
|
|
|
@ -200,7 +200,6 @@ QString Web3DOverlay::pickURL() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void Web3DOverlay::loadSourceURL() {
|
void Web3DOverlay::loadSourceURL() {
|
||||||
if (!_webSurface) {
|
if (!_webSurface) {
|
||||||
return;
|
return;
|
||||||
|
@ -303,7 +302,6 @@ void Web3DOverlay::render(RenderArgs* args) {
|
||||||
emit resizeWebSurface();
|
emit resizeWebSurface();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec2 halfSize = getSize() / 2.0f;
|
vec2 halfSize = getSize() / 2.0f;
|
||||||
vec4 color(toGlm(getColor()), getAlpha());
|
vec4 color(toGlm(getColor()), getAlpha());
|
||||||
|
|
||||||
|
@ -320,6 +318,7 @@ void Web3DOverlay::render(RenderArgs* args) {
|
||||||
Q_ASSERT(args->_batch);
|
Q_ASSERT(args->_batch);
|
||||||
gpu::Batch& batch = *args->_batch;
|
gpu::Batch& batch = *args->_batch;
|
||||||
batch.setResourceTexture(0, _texture);
|
batch.setResourceTexture(0, _texture);
|
||||||
|
auto renderTransform = getRenderTransform();
|
||||||
batch.setModelTransform(getRenderTransform());
|
batch.setModelTransform(getRenderTransform());
|
||||||
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
|
|
|
@ -1164,7 +1164,6 @@ static bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& sh
|
||||||
glm::vec3 localPoint = shapePose.inverse().xformPoint(point);
|
glm::vec3 localPoint = shapePose.inverse().xformPoint(point);
|
||||||
|
|
||||||
// Only works for 14-dop shape infos.
|
// Only works for 14-dop shape infos.
|
||||||
assert(shapeInfo.dots.size() == DOP14_COUNT);
|
|
||||||
if (shapeInfo.dots.size() != DOP14_COUNT) {
|
if (shapeInfo.dots.size() != DOP14_COUNT) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <glm/gtx/transform.hpp>
|
#include <glm/gtx/transform.hpp>
|
||||||
#include <glm/gtx/vector_query.hpp>
|
#include <glm/gtx/vector_query.hpp>
|
||||||
|
|
||||||
|
#include <AvatarConstants.h>
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <DeferredLightingEffect.h>
|
#include <DeferredLightingEffect.h>
|
||||||
#include <EntityTreeRenderer.h>
|
#include <EntityTreeRenderer.h>
|
||||||
|
@ -106,7 +107,7 @@ Avatar::Avatar(QThread* thread) :
|
||||||
// we may have been created in the network thread, but we live in the main thread
|
// we may have been created in the network thread, but we live in the main thread
|
||||||
moveToThread(thread);
|
moveToThread(thread);
|
||||||
|
|
||||||
setScale(glm::vec3(1.0f)); // avatar scale is uniform
|
setModelScale(1.0f); // avatar scale is uniform
|
||||||
|
|
||||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||||
_nameRectGeometryID = geometryCache->allocateID();
|
_nameRectGeometryID = geometryCache->allocateID();
|
||||||
|
@ -155,14 +156,14 @@ glm::vec3 Avatar::getNeckPosition() const {
|
||||||
AABox Avatar::getBounds() const {
|
AABox Avatar::getBounds() const {
|
||||||
if (!_skeletonModel->isRenderable() || _skeletonModel->needsFixupInScene()) {
|
if (!_skeletonModel->isRenderable() || _skeletonModel->needsFixupInScene()) {
|
||||||
// approximately 2m tall, scaled to user request.
|
// approximately 2m tall, scaled to user request.
|
||||||
return AABox(getPosition() - glm::vec3(getUniformScale()), getUniformScale() * 2.0f);
|
return AABox(getPosition() - glm::vec3(getModelScale()), getModelScale() * 2.0f);
|
||||||
}
|
}
|
||||||
return _skeletonModel->getRenderableMeshBound();
|
return _skeletonModel->getRenderableMeshBound();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::animateScaleChanges(float deltaTime) {
|
void Avatar::animateScaleChanges(float deltaTime) {
|
||||||
if (_isAnimatingScale) {
|
if (_isAnimatingScale) {
|
||||||
float currentScale = getUniformScale();
|
float currentScale = getModelScale();
|
||||||
float desiredScale = getDomainLimitedScale();
|
float desiredScale = getDomainLimitedScale();
|
||||||
|
|
||||||
// use exponential decay toward the domain limit clamped scale
|
// use exponential decay toward the domain limit clamped scale
|
||||||
|
@ -177,7 +178,7 @@ void Avatar::animateScaleChanges(float deltaTime) {
|
||||||
animatedScale = desiredScale;
|
animatedScale = desiredScale;
|
||||||
_isAnimatingScale = false;
|
_isAnimatingScale = false;
|
||||||
}
|
}
|
||||||
setScale(glm::vec3(animatedScale)); // avatar scale is uniform
|
setModelScale(animatedScale); // avatar scale is uniform
|
||||||
|
|
||||||
// flag the joints as having changed for force update to RenderItem
|
// flag the joints as having changed for force update to RenderItem
|
||||||
_hasNewJointData = true;
|
_hasNewJointData = true;
|
||||||
|
@ -364,7 +365,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
|
||||||
}
|
}
|
||||||
head->setPosition(headPosition);
|
head->setPosition(headPosition);
|
||||||
}
|
}
|
||||||
head->setScale(getUniformScale());
|
head->setScale(getModelScale());
|
||||||
head->simulate(deltaTime);
|
head->simulate(deltaTime);
|
||||||
} else {
|
} else {
|
||||||
// a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated.
|
// a non-full update is still required so that the position, rotation, scale and bounds of the skeletonModel are updated.
|
||||||
|
@ -422,7 +423,7 @@ bool Avatar::isLookingAtMe(AvatarSharedPointer avatar) const {
|
||||||
glm::vec3 theirLookAt = dynamic_pointer_cast<Avatar>(avatar)->getHead()->getLookAtPosition();
|
glm::vec3 theirLookAt = dynamic_pointer_cast<Avatar>(avatar)->getHead()->getLookAtPosition();
|
||||||
glm::vec3 myEyePosition = getHead()->getEyePosition();
|
glm::vec3 myEyePosition = getHead()->getEyePosition();
|
||||||
|
|
||||||
return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getUniformScale());
|
return glm::distance(theirLookAt, myEyePosition) <= (HEAD_SPHERE_RADIUS * getModelScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::slamPosition(const glm::vec3& newPosition) {
|
void Avatar::slamPosition(const glm::vec3& newPosition) {
|
||||||
|
@ -653,7 +654,7 @@ void Avatar::render(RenderArgs* renderArgs) {
|
||||||
if (showCollisionShapes && shouldRenderHead(renderArgs) && _skeletonModel->isRenderable()) {
|
if (showCollisionShapes && shouldRenderHead(renderArgs) && _skeletonModel->isRenderable()) {
|
||||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
|
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
|
||||||
const float BOUNDING_SHAPE_ALPHA = 0.7f;
|
const float BOUNDING_SHAPE_ALPHA = 0.7f;
|
||||||
_skeletonModel->renderBoundingCollisionShapes(renderArgs, *renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA);
|
_skeletonModel->renderBoundingCollisionShapes(renderArgs, *renderArgs->_batch, getModelScale(), BOUNDING_SHAPE_ALPHA);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (showReceiveStats || showNamesAboveHeads) {
|
if (showReceiveStats || showNamesAboveHeads) {
|
||||||
|
@ -726,9 +727,9 @@ void Avatar::simulateAttachments(float deltaTime) {
|
||||||
} else {
|
} else {
|
||||||
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPosition) &&
|
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPosition) &&
|
||||||
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRotation)) {
|
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRotation)) {
|
||||||
model->setTranslation(jointPosition + jointRotation * attachment.translation * getUniformScale());
|
model->setTranslation(jointPosition + jointRotation * attachment.translation * getModelScale());
|
||||||
model->setRotation(jointRotation * attachment.rotation);
|
model->setRotation(jointRotation * attachment.rotation);
|
||||||
float scale = getUniformScale() * attachment.scale;
|
float scale = getModelScale() * attachment.scale;
|
||||||
model->setScaleToFit(true, model->getNaturalDimensions() * scale, true); // hack to force rescale
|
model->setScaleToFit(true, model->getNaturalDimensions() * scale, true); // hack to force rescale
|
||||||
model->setSnapModelToCenter(false); // hack to force resnap
|
model->setSnapModelToCenter(false); // hack to force resnap
|
||||||
model->setSnapModelToCenter(true);
|
model->setSnapModelToCenter(true);
|
||||||
|
@ -888,7 +889,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setSkeletonOffset(const glm::vec3& offset) {
|
void Avatar::setSkeletonOffset(const glm::vec3& offset) {
|
||||||
const float MAX_OFFSET_LENGTH = getUniformScale() * 0.5f;
|
const float MAX_OFFSET_LENGTH = getModelScale() * 0.5f;
|
||||||
float offsetLength = glm::length(offset);
|
float offsetLength = glm::length(offset);
|
||||||
if (offsetLength > MAX_OFFSET_LENGTH) {
|
if (offsetLength > MAX_OFFSET_LENGTH) {
|
||||||
_skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset;
|
_skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset;
|
||||||
|
@ -986,14 +987,12 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||||
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(index) {
|
switch (index) {
|
||||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||||
bool success;
|
glm::mat4 avatarMatrix = getLocalTransform().getMatrix();
|
||||||
Transform avatarTransform;
|
glm::mat4 finalMat = glm::inverse(avatarMatrix) * sensorToWorldMatrix;
|
||||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
return glmExtractRotation(finalMat);
|
||||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
|
||||||
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
|
|
||||||
}
|
}
|
||||||
case CONTROLLER_LEFTHAND_INDEX: {
|
case CONTROLLER_LEFTHAND_INDEX: {
|
||||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||||
|
@ -1026,14 +1025,12 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||||
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(index) {
|
switch (index) {
|
||||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||||
bool success;
|
glm::mat4 avatarMatrix = getLocalTransform().getMatrix();
|
||||||
Transform avatarTransform;
|
glm::mat4 finalMat = glm::inverse(avatarMatrix) * sensorToWorldMatrix;
|
||||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
return extractTranslation(finalMat);
|
||||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
|
||||||
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
|
|
||||||
}
|
}
|
||||||
case CONTROLLER_LEFTHAND_INDEX: {
|
case CONTROLLER_LEFTHAND_INDEX: {
|
||||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||||
|
@ -1061,6 +1058,22 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::vec3 Avatar::getAbsoluteJointScaleInObjectFrame(int index) const {
|
||||||
|
if (index < 0) {
|
||||||
|
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||||
|
}
|
||||||
|
|
||||||
|
// only sensor to world matrix has non identity scale.
|
||||||
|
switch (index) {
|
||||||
|
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||||
|
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||||
|
return extractScale(sensorToWorldMatrix);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return AvatarData::getAbsoluteJointScaleInObjectFrame(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Avatar::invalidateJointIndicesCache() const {
|
void Avatar::invalidateJointIndicesCache() const {
|
||||||
QWriteLocker writeLock(&_modelJointIndicesCacheLock);
|
QWriteLocker writeLock(&_modelJointIndicesCacheLock);
|
||||||
_modelJointsCached = false;
|
_modelJointsCached = false;
|
||||||
|
@ -1149,7 +1162,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const {
|
||||||
|
|
||||||
void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
|
void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
|
||||||
//Scale a world space vector as if it was relative to the position
|
//Scale a world space vector as if it was relative to the position
|
||||||
positionToScale = getPosition() + getUniformScale() * (positionToScale - getPosition());
|
positionToScale = getPosition() + getModelScale() * (positionToScale - getPosition());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
void Avatar::setSkeletonModelURL(const QUrl& skeletonModelURL) {
|
||||||
|
@ -1351,7 +1364,7 @@ void Avatar::updateDisplayNameAlpha(bool showDisplayName) {
|
||||||
|
|
||||||
// virtual
|
// virtual
|
||||||
void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
|
void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||||
float uniformScale = getUniformScale();
|
float uniformScale = getModelScale();
|
||||||
shapeInfo.setCapsuleY(uniformScale * _skeletonModel->getBoundingCapsuleRadius(),
|
shapeInfo.setCapsuleY(uniformScale * _skeletonModel->getBoundingCapsuleRadius(),
|
||||||
0.5f * uniformScale * _skeletonModel->getBoundingCapsuleHeight());
|
0.5f * uniformScale * _skeletonModel->getBoundingCapsuleHeight());
|
||||||
shapeInfo.setOffset(uniformScale * _skeletonModel->getBoundingCapsuleOffset());
|
shapeInfo.setOffset(uniformScale * _skeletonModel->getBoundingCapsuleOffset());
|
||||||
|
@ -1548,3 +1561,54 @@ void Avatar::ensureInScene(AvatarSharedPointer self, const render::ScenePointer&
|
||||||
addToScene(self, scene);
|
addToScene(self, scene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float Avatar::getEyeHeight() const {
|
||||||
|
|
||||||
|
if (QThread::currentThread() != thread()) {
|
||||||
|
float result = DEFAULT_AVATAR_EYE_HEIGHT;
|
||||||
|
BLOCKING_INVOKE_METHOD(const_cast<Avatar*>(this), "getHeight", Q_RETURN_ARG(float, result));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: if performance becomes a concern we can cache this value rather then computing it everytime.
|
||||||
|
// Makes assumption that the y = 0 plane in geometry is the ground plane.
|
||||||
|
// We also make that assumption in Rig::computeAvatarBoundingCapsule()
|
||||||
|
float avatarScale = getModelScale();
|
||||||
|
if (_skeletonModel) {
|
||||||
|
auto& rig = _skeletonModel->getRig();
|
||||||
|
int headTopJoint = rig.indexOfJoint("HeadTop_End");
|
||||||
|
int headJoint = rig.indexOfJoint("Head");
|
||||||
|
int eyeJoint = rig.indexOfJoint("LeftEye") != -1 ? rig.indexOfJoint("LeftEye") : rig.indexOfJoint("RightEye");
|
||||||
|
int toeJoint = rig.indexOfJoint("LeftToeBase") != -1 ? rig.indexOfJoint("LeftToeBase") : rig.indexOfJoint("RightToeBase");
|
||||||
|
if (eyeJoint >= 0 && toeJoint >= 0) {
|
||||||
|
// measure from eyes to toes.
|
||||||
|
float eyeHeight = rig.getAbsoluteDefaultPose(eyeJoint).trans().y - rig.getAbsoluteDefaultPose(toeJoint).trans().y;
|
||||||
|
return eyeHeight;
|
||||||
|
} else if (eyeJoint >= 0) {
|
||||||
|
// measure eyes to y = 0 plane.
|
||||||
|
float groundHeight = transformPoint(rig.getGeometryToRigTransform(), glm::vec3(0.0f)).y;
|
||||||
|
float eyeHeight = rig.getAbsoluteDefaultPose(eyeJoint).trans().y - groundHeight;
|
||||||
|
return eyeHeight;
|
||||||
|
} else if (headTopJoint >= 0 && toeJoint >= 0) {
|
||||||
|
// measure toe to top of head. Note: default poses already include avatar scale factor
|
||||||
|
const float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||||
|
float height = rig.getAbsoluteDefaultPose(headTopJoint).trans().y - rig.getAbsoluteDefaultPose(toeJoint).trans().y;
|
||||||
|
return height - height * ratio;
|
||||||
|
} else if (headTopJoint >= 0) {
|
||||||
|
const float ratio = DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD / DEFAULT_AVATAR_HEIGHT;
|
||||||
|
float groundHeight = transformPoint(rig.getGeometryToRigTransform(), glm::vec3(0.0f)).y;
|
||||||
|
float headHeight = rig.getAbsoluteDefaultPose(headTopJoint).trans().y - groundHeight;
|
||||||
|
return headHeight - headHeight * ratio;
|
||||||
|
} else if (headJoint >= 0) {
|
||||||
|
float groundHeight = transformPoint(rig.getGeometryToRigTransform(), glm::vec3(0.0f)).y;
|
||||||
|
const float DEFAULT_AVATAR_NECK_TO_EYE = DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD - DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD;
|
||||||
|
const float ratio = DEFAULT_AVATAR_NECK_TO_EYE / DEFAULT_AVATAR_NECK_HEIGHT;
|
||||||
|
float neckHeight = rig.getAbsoluteDefaultPose(headJoint).trans().y - groundHeight;
|
||||||
|
return neckHeight + neckHeight * ratio;
|
||||||
|
} else {
|
||||||
|
return avatarScale * DEFAULT_AVATAR_EYE_HEIGHT;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return avatarScale * DEFAULT_AVATAR_EYE_HEIGHT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -108,7 +108,6 @@ public:
|
||||||
SkeletonModelPointer getSkeletonModel() { return _skeletonModel; }
|
SkeletonModelPointer getSkeletonModel() { return _skeletonModel; }
|
||||||
const SkeletonModelPointer getSkeletonModel() const { return _skeletonModel; }
|
const SkeletonModelPointer getSkeletonModel() const { return _skeletonModel; }
|
||||||
glm::vec3 getChestPosition() const;
|
glm::vec3 getChestPosition() const;
|
||||||
float getUniformScale() const { return getScale().y; }
|
|
||||||
const Head* getHead() const { return static_cast<const Head*>(_headData); }
|
const Head* getHead() const { return static_cast<const Head*>(_headData); }
|
||||||
Head* getHead() { return static_cast<Head*>(_headData); }
|
Head* getHead() { return static_cast<Head*>(_headData); }
|
||||||
|
|
||||||
|
@ -151,6 +150,7 @@ public:
|
||||||
*/
|
*/
|
||||||
Q_INVOKABLE virtual glm::vec3 getAbsoluteDefaultJointTranslationInObjectFrame(int index) const;
|
Q_INVOKABLE virtual glm::vec3 getAbsoluteDefaultJointTranslationInObjectFrame(int index) const;
|
||||||
|
|
||||||
|
virtual glm::vec3 getAbsoluteJointScaleInObjectFrame(int index) const override;
|
||||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
|
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const override;
|
||||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
|
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
|
||||||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
|
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
|
||||||
|
@ -232,6 +232,7 @@ public:
|
||||||
|
|
||||||
void animateScaleChanges(float deltaTime);
|
void animateScaleChanges(float deltaTime);
|
||||||
void setTargetScale(float targetScale) override;
|
void setTargetScale(float targetScale) override;
|
||||||
|
float getTargetScale() const { return _targetScale; }
|
||||||
|
|
||||||
Q_INVOKABLE float getSimulationRate(const QString& rateName = QString("")) const;
|
Q_INVOKABLE float getSimulationRate(const QString& rateName = QString("")) const;
|
||||||
|
|
||||||
|
@ -254,6 +255,16 @@ public:
|
||||||
bool isFading() const { return _isFading; }
|
bool isFading() const { return _isFading; }
|
||||||
void updateFadingStatus(render::ScenePointer scene);
|
void updateFadingStatus(render::ScenePointer scene);
|
||||||
|
|
||||||
|
/**jsdoc
|
||||||
|
* Provides read only access to the current eye height of the avatar.
|
||||||
|
* @function Avatar.getEyeHeight
|
||||||
|
* @returns {number} eye height of avatar in meters
|
||||||
|
*/
|
||||||
|
Q_INVOKABLE float getEyeHeight() const;
|
||||||
|
|
||||||
|
virtual float getModelScale() const { return _modelScale; }
|
||||||
|
virtual void setModelScale(float scale) { _modelScale = scale; }
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
||||||
// FIXME - these should be migrated to use Pose data instead
|
// FIXME - these should be migrated to use Pose data instead
|
||||||
|
@ -356,6 +367,7 @@ private:
|
||||||
bool _isAnimatingScale { false };
|
bool _isAnimatingScale { false };
|
||||||
bool _mustFadeIn { false };
|
bool _mustFadeIn { false };
|
||||||
bool _isFading { false };
|
bool _isFading { false };
|
||||||
|
float _modelScale { 1.0f };
|
||||||
|
|
||||||
static int _jointConesID;
|
static int _jointConesID;
|
||||||
|
|
||||||
|
@ -365,7 +377,6 @@ private:
|
||||||
|
|
||||||
float _displayNameTargetAlpha { 1.0f };
|
float _displayNameTargetAlpha { 1.0f };
|
||||||
float _displayNameAlpha { 1.0f };
|
float _displayNameAlpha { 1.0f };
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_Avatar_h
|
#endif // hifi_Avatar_h
|
||||||
|
|
|
@ -121,7 +121,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
||||||
void SkeletonModel::updateAttitude(const glm::quat& orientation) {
|
void SkeletonModel::updateAttitude(const glm::quat& orientation) {
|
||||||
setTranslation(_owningAvatar->getSkeletonPosition());
|
setTranslation(_owningAvatar->getSkeletonPosition());
|
||||||
setRotation(orientation * Quaternions::Y_180);
|
setRotation(orientation * Quaternions::Y_180);
|
||||||
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getScale());
|
setScale(glm::vec3(1.0f, 1.0f, 1.0f) * _owningAvatar->getModelScale());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed),
|
// Called by Avatar::simulate after it has set the joint states (fullUpdate true if changed),
|
||||||
|
@ -294,7 +294,7 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 SkeletonModel::getDefaultEyeModelPosition() const {
|
glm::vec3 SkeletonModel::getDefaultEyeModelPosition() const {
|
||||||
return _owningAvatar->getScale() * _defaultEyeModelPosition;
|
return _owningAvatar->getModelScale() * _defaultEyeModelPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
float DENSITY_OF_WATER = 1000.0f; // kg/m^3
|
float DENSITY_OF_WATER = 1000.0f; // kg/m^3
|
||||||
|
@ -316,7 +316,7 @@ void SkeletonModel::computeBoundingShape() {
|
||||||
float radius, height;
|
float radius, height;
|
||||||
glm::vec3 offset;
|
glm::vec3 offset;
|
||||||
_rig.computeAvatarBoundingCapsule(geometry, radius, height, offset);
|
_rig.computeAvatarBoundingCapsule(geometry, radius, height, offset);
|
||||||
float invScale = 1.0f / _owningAvatar->getUniformScale();
|
float invScale = 1.0f / _owningAvatar->getModelScale();
|
||||||
_boundingCapsuleRadius = invScale * radius;
|
_boundingCapsuleRadius = invScale * radius;
|
||||||
_boundingCapsuleHeight = invScale * height;
|
_boundingCapsuleHeight = invScale * height;
|
||||||
_boundingCapsuleLocalOffset = invScale * offset;
|
_boundingCapsuleLocalOffset = invScale * offset;
|
||||||
|
|
|
@ -2345,6 +2345,11 @@ glm::mat4 AvatarData::getSensorToWorldMatrix() const {
|
||||||
return _sensorToWorldMatrixCache.get();
|
return _sensorToWorldMatrixCache.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// thread-safe
|
||||||
|
float AvatarData::getSensorToWorldScale() const {
|
||||||
|
return extractUniformScale(_sensorToWorldMatrixCache.get());
|
||||||
|
}
|
||||||
|
|
||||||
// thread-safe
|
// thread-safe
|
||||||
glm::mat4 AvatarData::getControllerLeftHandMatrix() const {
|
glm::mat4 AvatarData::getControllerLeftHandMatrix() const {
|
||||||
return _controllerLeftHandMatrixCache.get();
|
return _controllerLeftHandMatrixCache.get();
|
||||||
|
|
|
@ -387,6 +387,8 @@ class AvatarData : public QObject, public SpatiallyNestable {
|
||||||
Q_PROPERTY(glm::mat4 controllerLeftHandMatrix READ getControllerLeftHandMatrix)
|
Q_PROPERTY(glm::mat4 controllerLeftHandMatrix READ getControllerLeftHandMatrix)
|
||||||
Q_PROPERTY(glm::mat4 controllerRightHandMatrix READ getControllerRightHandMatrix)
|
Q_PROPERTY(glm::mat4 controllerRightHandMatrix READ getControllerRightHandMatrix)
|
||||||
|
|
||||||
|
Q_PROPERTY(float sensorToWorldScale READ getSensorToWorldScale)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
virtual QString getName() const override { return QString("Avatar:") + _displayName; }
|
virtual QString getName() const override { return QString("Avatar:") + _displayName; }
|
||||||
|
@ -621,6 +623,7 @@ public:
|
||||||
|
|
||||||
// thread safe
|
// thread safe
|
||||||
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
|
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
|
||||||
|
Q_INVOKABLE float getSensorToWorldScale() const;
|
||||||
Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const;
|
Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const;
|
||||||
Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const;
|
Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const;
|
||||||
|
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include <QtGui/QWindow>
|
#include <QtGui/QWindow>
|
||||||
#include <QQuickWindow>
|
#include <QQuickWindow>
|
||||||
|
|
||||||
|
#include <DebugDraw.h>
|
||||||
#include <shared/QtHelpers.h>
|
#include <shared/QtHelpers.h>
|
||||||
#include <ui/Menu.h>
|
#include <ui/Menu.h>
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
|
@ -339,23 +340,29 @@ void CompositorHelper::computeHmdPickRay(const glm::vec2& cursorPos, glm::vec3&
|
||||||
glm::mat4 CompositorHelper::getUiTransform() const {
|
glm::mat4 CompositorHelper::getUiTransform() const {
|
||||||
glm::mat4 modelMat;
|
glm::mat4 modelMat;
|
||||||
_modelTransform.getMatrix(modelMat);
|
_modelTransform.getMatrix(modelMat);
|
||||||
return _currentCamera * glm::inverse(_currentDisplayPlugin->getHeadPose()) * modelMat;
|
return _sensorToWorldMatrix * modelMat;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Finds the collision point of a world space ray
|
//Finds the collision point of a world space ray
|
||||||
bool CompositorHelper::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const {
|
bool CompositorHelper::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const {
|
||||||
auto UITransform = getUiTransform();
|
glm::mat4 uiToWorld = getUiTransform();
|
||||||
auto relativePosition4 = glm::inverse(UITransform) * vec4(position, 1);
|
glm::mat4 worldToUi = glm::inverse(uiToWorld);
|
||||||
auto relativePosition = vec3(relativePosition4) / relativePosition4.w;
|
glm::vec3 localPosition = transformPoint(worldToUi, position);
|
||||||
auto relativeDirection = glm::inverse(glm::quat_cast(UITransform)) * direction;
|
glm::vec3 localDirection = glm::normalize(transformVectorFast(worldToUi, direction));
|
||||||
|
|
||||||
const float UI_RADIUS = 1.0f; // * myAvatar->getUniformScale(); // FIXME - how do we want to handle avatar scale
|
const float UI_RADIUS = 1.0f;
|
||||||
float instersectionDistance;
|
float instersectionDistance;
|
||||||
if (raySphereIntersect(relativeDirection, relativePosition, UI_RADIUS, &instersectionDistance)){
|
if (raySphereIntersect(localDirection, localPosition, UI_RADIUS, &instersectionDistance)) {
|
||||||
result = position + glm::normalize(direction) * instersectionDistance;
|
result = transformPoint(uiToWorld, localPosition + localDirection * instersectionDistance);
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
DebugDraw::getInstance().drawRay(position, result, glm::vec4(0.0f, 1.0f, 0.0f, 1.0f));
|
||||||
|
#endif
|
||||||
return true;
|
return true;
|
||||||
|
} else {
|
||||||
|
#ifdef WANT_DEBUG
|
||||||
|
DebugDraw::getInstance().drawRay(position, position + (direction * 1000.0f), glm::vec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -109,7 +109,10 @@ public:
|
||||||
void setReticleOverDesktop(bool value) { _isOverDesktop = value; }
|
void setReticleOverDesktop(bool value) { _isOverDesktop = value; }
|
||||||
|
|
||||||
void setDisplayPlugin(const DisplayPluginPointer& displayPlugin) { _currentDisplayPlugin = displayPlugin; }
|
void setDisplayPlugin(const DisplayPluginPointer& displayPlugin) { _currentDisplayPlugin = displayPlugin; }
|
||||||
void setFrameInfo(uint32_t frame, const glm::mat4& camera) { _currentCamera = camera; }
|
void setFrameInfo(uint32_t frame, const glm::mat4& camera, const glm::mat4& sensorToWorldMatrix) {
|
||||||
|
_currentCamera = camera;
|
||||||
|
_sensorToWorldMatrix = sensorToWorldMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void allowMouseCaptureChanged();
|
void allowMouseCaptureChanged();
|
||||||
|
@ -124,6 +127,7 @@ private:
|
||||||
|
|
||||||
DisplayPluginPointer _currentDisplayPlugin;
|
DisplayPluginPointer _currentDisplayPlugin;
|
||||||
glm::mat4 _currentCamera;
|
glm::mat4 _currentCamera;
|
||||||
|
glm::mat4 _sensorToWorldMatrix;
|
||||||
QWidget* _renderingWidget{ nullptr };
|
QWidget* _renderingWidget{ nullptr };
|
||||||
|
|
||||||
//// Support for hovering and tooltips
|
//// Support for hovering and tooltips
|
||||||
|
|
|
@ -27,8 +27,8 @@ public:
|
||||||
bool isHmd() const override final { return true; }
|
bool isHmd() const override final { return true; }
|
||||||
float getIPD() const override final { return _ipd; }
|
float getIPD() const override final { return _ipd; }
|
||||||
glm::mat4 getEyeToHeadTransform(Eye eye) const override final { return _eyeOffsets[eye]; }
|
glm::mat4 getEyeToHeadTransform(Eye eye) const override final { return _eyeOffsets[eye]; }
|
||||||
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override final { return _eyeProjections[eye]; }
|
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override { return _eyeProjections[eye]; }
|
||||||
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override final { return _cullingProjection; }
|
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override { return _cullingProjection; }
|
||||||
glm::uvec2 getRecommendedUiSize() const override final;
|
glm::uvec2 getRecommendedUiSize() const override final;
|
||||||
glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; }
|
glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; }
|
||||||
bool isDisplayVisible() const override { return isHmdMounted(); }
|
bool isDisplayVisible() const override { return isHmdMounted(); }
|
||||||
|
|
|
@ -98,15 +98,15 @@ void ShapeEntityRenderer::doRenderUpdateAsynchronousTyped(const TypedEntityPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
_shape = entity->getShape();
|
_shape = entity->getShape();
|
||||||
|
_position = entity->getPosition();
|
||||||
|
_dimensions = entity->getDimensions();
|
||||||
|
_orientation = entity->getOrientation();
|
||||||
|
|
||||||
if (_shape == entity::Sphere) {
|
if (_shape == entity::Sphere) {
|
||||||
_modelTransform.postScale(SPHERE_ENTITY_SCALE);
|
_modelTransform.postScale(SPHERE_ENTITY_SCALE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_modelTransform.postScale(_dimensions);
|
||||||
_position = entity->getPosition();
|
|
||||||
_dimensions = entity->getDimensions();
|
|
||||||
_orientation = entity->getOrientation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShapeEntityRenderer::isTransparent() const {
|
bool ShapeEntityRenderer::isTransparent() const {
|
||||||
|
|
|
@ -42,7 +42,8 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
||||||
setLocalVelocity(ENTITY_ITEM_DEFAULT_VELOCITY);
|
setLocalVelocity(ENTITY_ITEM_DEFAULT_VELOCITY);
|
||||||
setLocalAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
|
setLocalAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
|
||||||
// explicitly set transform parts to set dirty flags used by batch rendering
|
// explicitly set transform parts to set dirty flags used by batch rendering
|
||||||
setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
locationChanged();
|
||||||
|
dimensionsChanged();
|
||||||
quint64 now = usecTimestampNow();
|
quint64 now = usecTimestampNow();
|
||||||
_lastSimulated = now;
|
_lastSimulated = now;
|
||||||
_lastUpdated = now;
|
_lastUpdated = now;
|
||||||
|
@ -1376,7 +1377,11 @@ void EntityItem::setDimensions(const glm::vec3& value) {
|
||||||
if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) {
|
if (value.x <= 0.0f || value.y <= 0.0f || value.z <= 0.0f) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
setScale(value);
|
if (_dimensions != value) {
|
||||||
|
_dimensions = value;
|
||||||
|
locationChanged();
|
||||||
|
dimensionsChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||||
|
|
|
@ -179,7 +179,7 @@ public:
|
||||||
void setDescription(const QString& value);
|
void setDescription(const QString& value);
|
||||||
|
|
||||||
/// Dimensions in meters (0.0 - TREE_SCALE)
|
/// Dimensions in meters (0.0 - TREE_SCALE)
|
||||||
inline const glm::vec3 getDimensions() const { return getScale(); }
|
inline const glm::vec3 getDimensions() const { return _dimensions; }
|
||||||
virtual void setDimensions(const glm::vec3& value);
|
virtual void setDimensions(const glm::vec3& value);
|
||||||
|
|
||||||
float getLocalRenderAlpha() const;
|
float getLocalRenderAlpha() const;
|
||||||
|
@ -470,6 +470,7 @@ protected:
|
||||||
|
|
||||||
virtual void dimensionsChanged() override;
|
virtual void dimensionsChanged() override;
|
||||||
|
|
||||||
|
glm::vec3 _dimensions { ENTITY_ITEM_DEFAULT_DIMENSIONS };
|
||||||
EntityTypes::EntityType _type { EntityTypes::Unknown };
|
EntityTypes::EntityType _type { EntityTypes::Unknown };
|
||||||
quint64 _lastSimulated { 0 }; // last time this entity called simulate(), this includes velocity, angular velocity,
|
quint64 _lastSimulated { 0 }; // last time this entity called simulate(), this includes velocity, angular velocity,
|
||||||
// and physics changes
|
// and physics changes
|
||||||
|
|
|
@ -176,7 +176,7 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// if Polyline has only one or fewer points, use default dimension settings
|
// if Polyline has only one or fewer points, use default dimension settings
|
||||||
SpatiallyNestable::setScale(newScale);
|
setDimensions(newScale);
|
||||||
EntityItem::setRegistrationPoint(newRegistrationPoint);
|
EntityItem::setRegistrationPoint(newRegistrationPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -91,8 +91,6 @@ class PolyLineEntityItem : public EntityItem {
|
||||||
|
|
||||||
// disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain
|
// disable these external interfaces as PolyLineEntities caculate their own dimensions based on the points they contain
|
||||||
virtual void setRegistrationPoint(const glm::vec3& value) override {};
|
virtual void setRegistrationPoint(const glm::vec3& value) override {};
|
||||||
virtual void setScale(const glm::vec3& scale) override {};
|
|
||||||
virtual void setScale(float value) override {};
|
|
||||||
|
|
||||||
virtual void debugDump() const override;
|
virtual void debugDump() const override;
|
||||||
static const float DEFAULT_LINE_WIDTH;
|
static const float DEFAULT_LINE_WIDTH;
|
||||||
|
|
|
@ -12,14 +12,13 @@
|
||||||
#include "CharacterController.h"
|
#include "CharacterController.h"
|
||||||
|
|
||||||
#include <NumericalConstants.h>
|
#include <NumericalConstants.h>
|
||||||
|
#include <AvatarConstants.h>
|
||||||
|
|
||||||
#include "ObjectMotionState.h"
|
#include "ObjectMotionState.h"
|
||||||
#include "PhysicsHelpers.h"
|
#include "PhysicsHelpers.h"
|
||||||
#include "PhysicsLogging.h"
|
#include "PhysicsLogging.h"
|
||||||
|
|
||||||
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
|
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
|
||||||
const float JUMP_SPEED = 3.5f;
|
|
||||||
const float MAX_FALL_HEIGHT = 20.0f;
|
|
||||||
|
|
||||||
#ifdef DEBUG_STATE_CHANGE
|
#ifdef DEBUG_STATE_CHANGE
|
||||||
#define SET_STATE(desiredState, reason) setState(desiredState, reason)
|
#define SET_STATE(desiredState, reason) setState(desiredState, reason)
|
||||||
|
@ -62,12 +61,11 @@ CharacterController::CharacterMotor::CharacterMotor(const glm::vec3& vel, const
|
||||||
}
|
}
|
||||||
|
|
||||||
CharacterController::CharacterController() {
|
CharacterController::CharacterController() {
|
||||||
_floorDistance = MAX_FALL_HEIGHT;
|
_floorDistance = _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT;
|
||||||
|
|
||||||
_targetVelocity.setValue(0.0f, 0.0f, 0.0f);
|
_targetVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||||
_followDesiredBodyTransform.setIdentity();
|
_followDesiredBodyTransform.setIdentity();
|
||||||
_followTimeRemaining = 0.0f;
|
_followTimeRemaining = 0.0f;
|
||||||
_jumpSpeed = JUMP_SPEED;
|
|
||||||
_state = State::Hover;
|
_state = State::Hover;
|
||||||
_isPushingUp = false;
|
_isPushingUp = false;
|
||||||
_rayHitStartTime = 0;
|
_rayHitStartTime = 0;
|
||||||
|
@ -265,13 +263,13 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
|
||||||
btVector3 endPos = startPos + linearDisplacement;
|
btVector3 endPos = startPos + linearDisplacement;
|
||||||
|
|
||||||
btQuaternion startRot = bodyTransform.getRotation();
|
btQuaternion startRot = bodyTransform.getRotation();
|
||||||
glm::vec2 currentFacing = getFacingDir2D(bulletToGLM(startRot));
|
btQuaternion desiredRot = _followDesiredBodyTransform.getRotation();
|
||||||
glm::vec2 currentRight(currentFacing.y, -currentFacing.x);
|
if (desiredRot.dot(startRot) < 0.0f) {
|
||||||
glm::vec2 desiredFacing = getFacingDir2D(bulletToGLM(_followDesiredBodyTransform.getRotation()));
|
desiredRot = -desiredRot;
|
||||||
float deltaAngle = acosf(glm::clamp(glm::dot(currentFacing, desiredFacing), -1.0f, 1.0f));
|
}
|
||||||
float angularSpeed = deltaAngle / _followTimeRemaining;
|
btQuaternion deltaRot = desiredRot * startRot.inverse();
|
||||||
float sign = copysignf(1.0f, glm::dot(desiredFacing, currentRight));
|
float angularSpeed = deltaRot.getAngle() / _followTimeRemaining;
|
||||||
btQuaternion angularDisplacement = btQuaternion(btVector3(0.0f, 1.0f, 0.0f), sign * angularSpeed * dt);
|
btQuaternion angularDisplacement = btQuaternion(deltaRot.getAxis(), angularSpeed * dt);
|
||||||
btQuaternion endRot = angularDisplacement * startRot;
|
btQuaternion endRot = angularDisplacement * startRot;
|
||||||
|
|
||||||
// in order to accumulate displacement of avatar position, we need to take _shapeLocalOffset into account.
|
// in order to accumulate displacement of avatar position, we need to take _shapeLocalOffset into account.
|
||||||
|
@ -376,8 +374,7 @@ void CharacterController::updateGravity() {
|
||||||
if (_state == State::Hover || collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
if (_state == State::Hover || collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||||
_gravity = 0.0f;
|
_gravity = 0.0f;
|
||||||
} else {
|
} else {
|
||||||
const float DEFAULT_CHARACTER_GRAVITY = -5.0f;
|
_gravity = DEFAULT_AVATAR_GRAVITY;
|
||||||
_gravity = DEFAULT_CHARACTER_GRAVITY;
|
|
||||||
}
|
}
|
||||||
if (_rigidBody) {
|
if (_rigidBody) {
|
||||||
_rigidBody->setGravity(_gravity * _currentUp);
|
_rigidBody->setGravity(_gravity * _currentUp);
|
||||||
|
@ -653,7 +650,7 @@ void CharacterController::updateState() {
|
||||||
const btScalar FLY_TO_GROUND_THRESHOLD = 0.1f * _radius;
|
const btScalar FLY_TO_GROUND_THRESHOLD = 0.1f * _radius;
|
||||||
const btScalar GROUND_TO_FLY_THRESHOLD = 0.8f * _radius + _halfHeight;
|
const btScalar GROUND_TO_FLY_THRESHOLD = 0.8f * _radius + _halfHeight;
|
||||||
const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 250 * MSECS_PER_SECOND;
|
const quint64 TAKE_OFF_TO_IN_AIR_PERIOD = 250 * MSECS_PER_SECOND;
|
||||||
const btScalar MIN_HOVER_HEIGHT = 2.5f;
|
const btScalar MIN_HOVER_HEIGHT = _scaleFactor * DEFAULT_AVATAR_MIN_HOVER_HEIGHT;
|
||||||
const quint64 JUMP_TO_HOVER_PERIOD = 1100 * MSECS_PER_SECOND;
|
const quint64 JUMP_TO_HOVER_PERIOD = 1100 * MSECS_PER_SECOND;
|
||||||
|
|
||||||
// scan for distant floor
|
// scan for distant floor
|
||||||
|
@ -663,7 +660,7 @@ void CharacterController::updateState() {
|
||||||
btScalar rayLength = _radius;
|
btScalar rayLength = _radius;
|
||||||
int16_t collisionGroup = computeCollisionGroup();
|
int16_t collisionGroup = computeCollisionGroup();
|
||||||
if (collisionGroup == BULLET_COLLISION_GROUP_MY_AVATAR) {
|
if (collisionGroup == BULLET_COLLISION_GROUP_MY_AVATAR) {
|
||||||
rayLength += MAX_FALL_HEIGHT;
|
rayLength += _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT;
|
||||||
} else {
|
} else {
|
||||||
rayLength += MIN_HOVER_HEIGHT;
|
rayLength += MIN_HOVER_HEIGHT;
|
||||||
}
|
}
|
||||||
|
@ -717,11 +714,15 @@ void CharacterController::updateState() {
|
||||||
SET_STATE(State::Hover, "no ground");
|
SET_STATE(State::Hover, "no ground");
|
||||||
} else if ((now - _takeoffToInAirStartTime) > TAKE_OFF_TO_IN_AIR_PERIOD) {
|
} else if ((now - _takeoffToInAirStartTime) > TAKE_OFF_TO_IN_AIR_PERIOD) {
|
||||||
SET_STATE(State::InAir, "takeoff done");
|
SET_STATE(State::InAir, "takeoff done");
|
||||||
velocity += _jumpSpeed * _currentUp;
|
|
||||||
|
// compute jumpSpeed based on the scaled jump height for the default avatar in default gravity.
|
||||||
|
float jumpSpeed = sqrtf(2.0f * DEFAULT_AVATAR_GRAVITY * _scaleFactor * DEFAULT_AVATAR_JUMP_HEIGHT);
|
||||||
|
velocity += jumpSpeed * _currentUp;
|
||||||
_rigidBody->setLinearVelocity(velocity);
|
_rigidBody->setLinearVelocity(velocity);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case State::InAir: {
|
case State::InAir: {
|
||||||
|
const float JUMP_SPEED = _scaleFactor * DEFAULT_AVATAR_JUMP_SPEED;
|
||||||
if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < FLY_TO_GROUND_THRESHOLD) || _hasSupport)) {
|
if ((velocity.dot(_currentUp) <= (JUMP_SPEED / 2.0f)) && ((_floorDistance < FLY_TO_GROUND_THRESHOLD) || _hasSupport)) {
|
||||||
SET_STATE(State::Ground, "hit ground");
|
SET_STATE(State::Ground, "hit ground");
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -73,6 +73,7 @@ public:
|
||||||
void setStepUpEnabled(bool enabled) { _stepUpEnabled = enabled; }
|
void setStepUpEnabled(bool enabled) { _stepUpEnabled = enabled; }
|
||||||
void computeNewVelocity(btScalar dt, btVector3& velocity);
|
void computeNewVelocity(btScalar dt, btVector3& velocity);
|
||||||
void computeNewVelocity(btScalar dt, glm::vec3& velocity);
|
void computeNewVelocity(btScalar dt, glm::vec3& velocity);
|
||||||
|
void setScaleFactor(btScalar scaleFactor) { _scaleFactor = scaleFactor; }
|
||||||
|
|
||||||
// HACK for legacy 'thrust' feature
|
// HACK for legacy 'thrust' feature
|
||||||
void setLinearAcceleration(const glm::vec3& acceleration) { _linearAcceleration = glmToBullet(acceleration); }
|
void setLinearAcceleration(const glm::vec3& acceleration) { _linearAcceleration = glmToBullet(acceleration); }
|
||||||
|
@ -185,7 +186,6 @@ protected:
|
||||||
|
|
||||||
btScalar _gravity { 0.0f };
|
btScalar _gravity { 0.0f };
|
||||||
|
|
||||||
btScalar _jumpSpeed;
|
|
||||||
btScalar _followTime;
|
btScalar _followTime;
|
||||||
btVector3 _followLinearDisplacement;
|
btVector3 _followLinearDisplacement;
|
||||||
btQuaternion _followAngularDisplacement;
|
btQuaternion _followAngularDisplacement;
|
||||||
|
@ -203,6 +203,8 @@ protected:
|
||||||
bool _flyingAllowed { true };
|
bool _flyingAllowed { true };
|
||||||
bool _collisionlessAllowed { true };
|
bool _collisionlessAllowed { true };
|
||||||
bool _collisionless { false };
|
bool _collisionless { false };
|
||||||
|
|
||||||
|
btScalar _scaleFactor { 1.0f };
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // hifi_CharacterController_h
|
#endif // hifi_CharacterController_h
|
||||||
|
|
56
libraries/shared/src/AvatarConstants.h
Normal file
56
libraries/shared/src/AvatarConstants.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
//
|
||||||
|
// AvatarConstants.h
|
||||||
|
// libraries/shared/src
|
||||||
|
//
|
||||||
|
// Created by Anthony J. Thibault on Aug 16th 2017
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef hifi_AvatarConstants_h
|
||||||
|
#define hifi_AvatarConstants_h
|
||||||
|
|
||||||
|
// 50th Percentile Man
|
||||||
|
const float DEFAULT_AVATAR_HEIGHT = 1.755f; // meters
|
||||||
|
const float DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD = 0.11f; // meters
|
||||||
|
const float DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD = 0.185f; // meters
|
||||||
|
const float DEFAULT_AVATAR_NECK_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_NECK_TO_TOP_OF_HEAD;
|
||||||
|
const float DEFAULT_AVATAR_EYE_HEIGHT = DEFAULT_AVATAR_HEIGHT - DEFAULT_AVATAR_EYE_TO_TOP_OF_HEAD;
|
||||||
|
|
||||||
|
// Used when avatar is missing joints... (avatar space)
|
||||||
|
const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_MIDDLE_EYE_POS { 0.0f, 0.6f, 0.0f };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_HEAD_POS { 0.0f, 0.53f, 0.0f };
|
||||||
|
const glm::quat DEFAULT_AVATAR_HEAD_ROT { Quaternions::Y_180 };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_RIGHTARM_POS { -0.134824f, 0.396348f, -0.0515777f };
|
||||||
|
const glm::quat DEFAULT_AVATAR_RIGHTARM_ROT { -0.536241f, 0.536241f, -0.460918f, -0.460918f };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_LEFTARM_POS { 0.134795f, 0.396349f, -0.0515881f };
|
||||||
|
const glm::quat DEFAULT_AVATAR_LEFTARM_ROT { 0.536257f, 0.536258f, -0.460899f, 0.4609f };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_RIGHTHAND_POS { -0.72768f, 0.396349f, -0.0515779f };
|
||||||
|
const glm::quat DEFAULT_AVATAR_RIGHTHAND_ROT { 0.479184f, -0.520013f, 0.522537f, 0.476365f};
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_LEFTHAND_POS { 0.727588f, 0.39635f, -0.0515878f };
|
||||||
|
const glm::quat DEFAULT_AVATAR_LEFTHAND_ROT { -0.479181f, -0.52001f, 0.52254f, -0.476369f };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_NECK_POS { 0.0f, 0.445f, 0.025f };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_SPINE2_POS { 0.0f, 0.32f, 0.02f };
|
||||||
|
const glm::quat DEFAULT_AVATAR_SPINE2_ROT { Quaternions::Y_180 };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_HIPS_POS { 0.0f, 0.0f, 0.0f };
|
||||||
|
const glm::quat DEFAULT_AVATAR_HIPS_ROT { Quaternions::Y_180 };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_LEFTFOOT_POS { -0.08f, -0.96f, 0.029f};
|
||||||
|
const glm::quat DEFAULT_AVATAR_LEFTFOOT_ROT { -0.40167322754859924f, 0.9154590368270874f, -0.005437685176730156f, -0.023744143545627594f };
|
||||||
|
const glm::vec3 DEFAULT_AVATAR_RIGHTFOOT_POS { 0.08f, -0.96f, 0.029f };
|
||||||
|
const glm::quat DEFAULT_AVATAR_RIGHTFOOT_ROT { -0.4016716778278351f, 0.9154615998268127f, 0.0053307069465518f, 0.023696165531873703f };
|
||||||
|
|
||||||
|
const float DEFAULT_AVATAR_MAX_WALKING_SPEED = 2.6f; // meters / second
|
||||||
|
const float DEFAULT_AVATAR_MAX_FLYING_SPEED = 30.0f; // meters / second
|
||||||
|
|
||||||
|
const float DEFAULT_AVATAR_GRAVITY = -5.0f; // meters / second^2
|
||||||
|
const float DEFAULT_AVATAR_JUMP_SPEED = 3.5f; // meters / second
|
||||||
|
const float DEFAULT_AVATAR_JUMP_HEIGHT = (DEFAULT_AVATAR_JUMP_SPEED * DEFAULT_AVATAR_JUMP_SPEED) / (2.0f * DEFAULT_AVATAR_GRAVITY); // meters
|
||||||
|
|
||||||
|
const float DEFAULT_AVATAR_FALL_HEIGHT = 20.0f; // meters
|
||||||
|
const float DEFAULT_AVATAR_MIN_HOVER_HEIGHT = 2.5f; // meters
|
||||||
|
|
||||||
|
|
||||||
|
#endif // hifi_AvatarConstants_h
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
#include "DependencyManager.h"
|
#include "DependencyManager.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
#include "StreamUtils.h"
|
||||||
#include "SharedLogging.h"
|
#include "SharedLogging.h"
|
||||||
|
|
||||||
const float defaultAACubeSize = 1.0f;
|
const float defaultAACubeSize = 1.0f;
|
||||||
|
@ -83,8 +84,7 @@ Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
if (parent) {
|
if (parent) {
|
||||||
Transform parentTransform = parent->getTransform(_parentJointIndex, success, depth + 1);
|
result = parent->getTransform(_parentJointIndex, success, depth + 1);
|
||||||
result = parentTransform.setScale(1.0f); // TODO: scaling
|
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -156,7 +156,6 @@ void SpatiallyNestable::setParentJointIndex(quint16 parentJointIndex) {
|
||||||
glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position,
|
glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position,
|
||||||
const QUuid& parentID, int parentJointIndex,
|
const QUuid& parentID, int parentJointIndex,
|
||||||
bool& success) {
|
bool& success) {
|
||||||
Transform result;
|
|
||||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||||
if (!parentFinder) {
|
if (!parentFinder) {
|
||||||
success = false;
|
success = false;
|
||||||
|
@ -180,23 +179,17 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position,
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return glm::vec3(0.0f);
|
return glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
parentTransform.setScale(1.0f); // TODO: scale
|
|
||||||
}
|
}
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
Transform positionTransform;
|
Transform invParentTransform;
|
||||||
positionTransform.setTranslation(position);
|
parentTransform.evalInverse(invParentTransform);
|
||||||
Transform myWorldTransform;
|
return invParentTransform.transform(position);
|
||||||
Transform::mult(myWorldTransform, parentTransform, positionTransform);
|
|
||||||
myWorldTransform.setTranslation(position);
|
|
||||||
Transform::inverseMult(result, parentTransform, myWorldTransform);
|
|
||||||
return result.getTranslation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation,
|
glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation,
|
||||||
const QUuid& parentID, int parentJointIndex,
|
const QUuid& parentID, int parentJointIndex,
|
||||||
bool& success) {
|
bool& success) {
|
||||||
Transform result;
|
|
||||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||||
if (!parentFinder) {
|
if (!parentFinder) {
|
||||||
success = false;
|
success = false;
|
||||||
|
@ -220,17 +213,11 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation,
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return glm::quat();
|
return glm::quat();
|
||||||
}
|
}
|
||||||
parentTransform.setScale(1.0f); // TODO: scale
|
|
||||||
}
|
}
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
Transform orientationTransform;
|
glm::quat invParentOrientation = glm::inverse(parentTransform.getRotation());
|
||||||
orientationTransform.setRotation(orientation);
|
return invParentOrientation * orientation;
|
||||||
Transform myWorldTransform;
|
|
||||||
Transform::mult(myWorldTransform, parentTransform, orientationTransform);
|
|
||||||
myWorldTransform.setRotation(orientation);
|
|
||||||
Transform::inverseMult(result, parentTransform, myWorldTransform);
|
|
||||||
return result.getRotation();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 SpatiallyNestable::worldToLocalVelocity(const glm::vec3& velocity, const QUuid& parentID,
|
glm::vec3 SpatiallyNestable::worldToLocalVelocity(const glm::vec3& velocity, const QUuid& parentID,
|
||||||
|
@ -292,7 +279,6 @@ glm::vec3 SpatiallyNestable::localToWorld(const glm::vec3& position,
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return glm::vec3(0.0f);
|
return glm::vec3(0.0f);
|
||||||
}
|
}
|
||||||
parentTransform.setScale(1.0f); // TODO: scale
|
|
||||||
}
|
}
|
||||||
success = true;
|
success = true;
|
||||||
|
|
||||||
|
@ -634,7 +620,6 @@ const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, i
|
||||||
}
|
}
|
||||||
|
|
||||||
Transform worldTransform = getTransform(success, depth);
|
Transform worldTransform = getTransform(success, depth);
|
||||||
worldTransform.setScale(1.0f); // TODO -- scale;
|
|
||||||
if (!success) {
|
if (!success) {
|
||||||
return jointInWorldFrame;
|
return jointInWorldFrame;
|
||||||
}
|
}
|
||||||
|
@ -673,61 +658,51 @@ bool SpatiallyNestable::setTransform(const Transform& transform) {
|
||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 SpatiallyNestable::getScale() const {
|
glm::vec3 SpatiallyNestable::getSNScale() const {
|
||||||
// TODO: scale
|
bool success;
|
||||||
glm::vec3 result;
|
auto result = getSNScale(success);
|
||||||
_transformLock.withReadLock([&] {
|
#ifdef WANT_DEBUG
|
||||||
result = _transform.getScale();
|
if (!success) {
|
||||||
});
|
qCDebug(shared) << "Warning -- getScale failed" << getID();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 SpatiallyNestable::getScale(int jointIndex) const {
|
glm::vec3 SpatiallyNestable::getSNScale(bool& success) const {
|
||||||
// TODO: scale
|
return getTransform(success).getScale();
|
||||||
return getScale();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpatiallyNestable::setScale(const glm::vec3& scale) {
|
glm::vec3 SpatiallyNestable::getSNScale(int jointIndex, bool& success) const {
|
||||||
|
return getTransform(jointIndex, success).getScale();
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpatiallyNestable::setSNScale(const glm::vec3& scale) {
|
||||||
|
bool success;
|
||||||
|
setSNScale(scale, success);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SpatiallyNestable::setSNScale(const glm::vec3& scale, bool& success) {
|
||||||
// guard against introducing NaN into the transform
|
// guard against introducing NaN into the transform
|
||||||
if (isNaN(scale)) {
|
if (isNaN(scale)) {
|
||||||
qCDebug(shared) << "SpatiallyNestable::setScale -- scale contains NaN";
|
success = false;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
// TODO: scale
|
Transform parentTransform = getParentTransform(success);
|
||||||
|
Transform myWorldTransform;
|
||||||
_transformLock.withWriteLock([&] {
|
_transformLock.withWriteLock([&] {
|
||||||
if (_transform.getScale() != scale) {
|
Transform::mult(myWorldTransform, parentTransform, _transform);
|
||||||
_transform.setScale(scale);
|
if (myWorldTransform.getScale() != scale) {
|
||||||
changed = true;
|
changed = true;
|
||||||
|
myWorldTransform.setScale(scale);
|
||||||
|
Transform::inverseMult(_transform, parentTransform, myWorldTransform);
|
||||||
_scaleChanged = usecTimestampNow();
|
_scaleChanged = usecTimestampNow();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if (changed) {
|
if (success && changed) {
|
||||||
dimensionsChanged();
|
locationChanged();
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void SpatiallyNestable::setScale(float value) {
|
|
||||||
// guard against introducing NaN into the transform
|
|
||||||
if (value <= 0.0f) {
|
|
||||||
qCDebug(shared) << "SpatiallyNestable::setScale -- scale is zero or negative value";
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool changed = false;
|
|
||||||
// TODO: scale
|
|
||||||
_transformLock.withWriteLock([&] {
|
|
||||||
glm::vec3 beforeScale = _transform.getScale();
|
|
||||||
_transform.setScale(value);
|
|
||||||
if (_transform.getScale() != beforeScale) {
|
|
||||||
changed = true;
|
|
||||||
_scaleChanged = usecTimestampNow();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if (changed) {
|
|
||||||
dimensionsChanged();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,8 +819,7 @@ void SpatiallyNestable::setLocalAngularVelocity(const glm::vec3& angularVelocity
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
glm::vec3 SpatiallyNestable::getLocalScale() const {
|
glm::vec3 SpatiallyNestable::getLocalSNScale() const {
|
||||||
// TODO: scale
|
|
||||||
glm::vec3 result;
|
glm::vec3 result;
|
||||||
_transformLock.withReadLock([&] {
|
_transformLock.withReadLock([&] {
|
||||||
result = _transform.getScale();
|
result = _transform.getScale();
|
||||||
|
@ -853,7 +827,7 @@ glm::vec3 SpatiallyNestable::getLocalScale() const {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SpatiallyNestable::setLocalScale(const glm::vec3& scale) {
|
void SpatiallyNestable::setLocalSNScale(const glm::vec3& scale) {
|
||||||
// guard against introducing NaN into the transform
|
// guard against introducing NaN into the transform
|
||||||
if (isNaN(scale)) {
|
if (isNaN(scale)) {
|
||||||
qCDebug(shared) << "SpatiallyNestable::setLocalScale -- scale contains NaN";
|
qCDebug(shared) << "SpatiallyNestable::setLocalScale -- scale contains NaN";
|
||||||
|
@ -861,7 +835,6 @@ void SpatiallyNestable::setLocalScale(const glm::vec3& scale) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool changed = false;
|
bool changed = false;
|
||||||
// TODO: scale
|
|
||||||
_transformLock.withWriteLock([&] {
|
_transformLock.withWriteLock([&] {
|
||||||
if (_transform.getScale() != scale) {
|
if (_transform.getScale() != scale) {
|
||||||
_transform.setScale(scale);
|
_transform.setScale(scale);
|
||||||
|
@ -905,6 +878,8 @@ const Transform SpatiallyNestable::getAbsoluteJointTransformInObjectFrame(int jo
|
||||||
Transform jointTransformInObjectFrame;
|
Transform jointTransformInObjectFrame;
|
||||||
glm::vec3 position = getAbsoluteJointTranslationInObjectFrame(jointIndex);
|
glm::vec3 position = getAbsoluteJointTranslationInObjectFrame(jointIndex);
|
||||||
glm::quat orientation = getAbsoluteJointRotationInObjectFrame(jointIndex);
|
glm::quat orientation = getAbsoluteJointRotationInObjectFrame(jointIndex);
|
||||||
|
glm::vec3 scale = getAbsoluteJointScaleInObjectFrame(jointIndex);
|
||||||
|
jointTransformInObjectFrame.setScale(scale);
|
||||||
jointTransformInObjectFrame.setRotation(orientation);
|
jointTransformInObjectFrame.setRotation(orientation);
|
||||||
jointTransformInObjectFrame.setTranslation(position);
|
jointTransformInObjectFrame.setTranslation(position);
|
||||||
return jointTransformInObjectFrame;
|
return jointTransformInObjectFrame;
|
||||||
|
@ -1197,3 +1172,13 @@ QString SpatiallyNestable::nestableTypeToString(NestableType nestableType) {
|
||||||
return "unknown";
|
return "unknown";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SpatiallyNestable::dump(const QString& prefix) const {
|
||||||
|
qDebug().noquote() << prefix << "id = " << getID();
|
||||||
|
qDebug().noquote() << prefix << "transform = " << _transform;
|
||||||
|
bool success;
|
||||||
|
SpatiallyNestablePointer parent = getParentPointer(success);
|
||||||
|
if (success && parent) {
|
||||||
|
parent->dump(prefix + " ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -111,14 +111,15 @@ public:
|
||||||
virtual AACube getQueryAACube(bool& success) const;
|
virtual AACube getQueryAACube(bool& success) const;
|
||||||
virtual AACube getQueryAACube() const;
|
virtual AACube getQueryAACube() const;
|
||||||
|
|
||||||
virtual glm::vec3 getScale() const;
|
virtual glm::vec3 getSNScale() const;
|
||||||
virtual void setScale(const glm::vec3& scale);
|
virtual glm::vec3 getSNScale(bool& success) const;
|
||||||
virtual void setScale(float value);
|
virtual void setSNScale(const glm::vec3& scale);
|
||||||
|
virtual void setSNScale(const glm::vec3& scale, bool& success);
|
||||||
|
|
||||||
// get world-frame values for a specific joint
|
// get world-frame values for a specific joint
|
||||||
virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const;
|
virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) const;
|
||||||
virtual glm::vec3 getPosition(int jointIndex, bool& success) const;
|
virtual glm::vec3 getPosition(int jointIndex, bool& success) const;
|
||||||
virtual glm::vec3 getScale(int jointIndex) const;
|
virtual glm::vec3 getSNScale(int jointIndex, bool& success) const;
|
||||||
|
|
||||||
// object's parent's frame
|
// object's parent's frame
|
||||||
virtual Transform getLocalTransform() const;
|
virtual Transform getLocalTransform() const;
|
||||||
|
@ -136,8 +137,8 @@ public:
|
||||||
virtual glm::vec3 getLocalAngularVelocity() const;
|
virtual glm::vec3 getLocalAngularVelocity() const;
|
||||||
virtual void setLocalAngularVelocity(const glm::vec3& angularVelocity);
|
virtual void setLocalAngularVelocity(const glm::vec3& angularVelocity);
|
||||||
|
|
||||||
virtual glm::vec3 getLocalScale() const;
|
virtual glm::vec3 getLocalSNScale() const;
|
||||||
virtual void setLocalScale(const glm::vec3& scale);
|
virtual void setLocalSNScale(const glm::vec3& scale);
|
||||||
|
|
||||||
QList<SpatiallyNestablePointer> getChildren() const;
|
QList<SpatiallyNestablePointer> getChildren() const;
|
||||||
bool hasChildren() const;
|
bool hasChildren() const;
|
||||||
|
@ -146,6 +147,7 @@ public:
|
||||||
|
|
||||||
// this object's frame
|
// this object's frame
|
||||||
virtual const Transform getAbsoluteJointTransformInObjectFrame(int jointIndex) const;
|
virtual const Transform getAbsoluteJointTransformInObjectFrame(int jointIndex) const;
|
||||||
|
virtual glm::vec3 getAbsoluteJointScaleInObjectFrame(int index) const { return glm::vec3(1.0f); }
|
||||||
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const { return glm::quat(); }
|
virtual glm::quat getAbsoluteJointRotationInObjectFrame(int index) const { return glm::quat(); }
|
||||||
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const { return glm::vec3(); }
|
virtual glm::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const { return glm::vec3(); }
|
||||||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) { return false; }
|
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) { return false; }
|
||||||
|
@ -190,6 +192,8 @@ public:
|
||||||
bool tranlationChangedSince(quint64 time) const { return _translationChanged > time; }
|
bool tranlationChangedSince(quint64 time) const { return _translationChanged > time; }
|
||||||
bool rotationChangedSince(quint64 time) const { return _rotationChanged > time; }
|
bool rotationChangedSince(quint64 time) const { return _rotationChanged > time; }
|
||||||
|
|
||||||
|
void dump(const QString& prefix = "") const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
const NestableType _nestableType; // EntityItem or an AvatarData
|
const NestableType _nestableType; // EntityItem or an AvatarData
|
||||||
QUuid _id;
|
QUuid _id;
|
||||||
|
|
|
@ -150,3 +150,10 @@ QJsonObject Transform::toJson(const Transform& transform) {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QDebug& operator<<(QDebug& debug, const Transform& transform) {
|
||||||
|
debug << "Transform, trans = (" << transform._translation.x << transform._translation.y << transform._translation.z << "), rot = ("
|
||||||
|
<< transform._rotation.x << transform._rotation.y << transform._rotation.z << transform._rotation.w << "), scale = ("
|
||||||
|
<< transform._scale.x << transform._scale.y << transform._scale.z << ")";
|
||||||
|
return debug;
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ inline bool isValidScale(float scale) {
|
||||||
|
|
||||||
class Transform {
|
class Transform {
|
||||||
public:
|
public:
|
||||||
|
friend QDebug& operator<<(QDebug& debug, const Transform& transform);
|
||||||
using Pointer = std::shared_ptr<Transform>;
|
using Pointer = std::shared_ptr<Transform>;
|
||||||
typedef glm::mat4 Mat4;
|
typedef glm::mat4 Mat4;
|
||||||
typedef glm::mat3 Mat3;
|
typedef glm::mat3 Mat3;
|
||||||
|
@ -170,7 +171,6 @@ protected:
|
||||||
};
|
};
|
||||||
typedef std::bitset<NUM_FLAGS> Flags;
|
typedef std::bitset<NUM_FLAGS> Flags;
|
||||||
|
|
||||||
|
|
||||||
// TRS
|
// TRS
|
||||||
Quat _rotation;
|
Quat _rotation;
|
||||||
Vec3 _scale;
|
Vec3 _scale;
|
||||||
|
@ -202,6 +202,8 @@ protected:
|
||||||
Mat4& getCachedMatrix(Mat4& result) const;
|
Mat4& getCachedMatrix(Mat4& result) const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QDebug& operator<<(QDebug& debug, const Transform& transform);
|
||||||
|
|
||||||
inline Transform& Transform::setIdentity() {
|
inline Transform& Transform::setIdentity() {
|
||||||
_translation = Vec3(0.0f);
|
_translation = Vec3(0.0f);
|
||||||
_rotation = Quat(1.0f, 0.0f, 0.0f, 0.0f);
|
_rotation = Quat(1.0f, 0.0f, 0.0f, 0.0f);
|
||||||
|
|
|
@ -60,6 +60,36 @@ bool OculusBaseDisplayPlugin::isSupported() const {
|
||||||
return oculusAvailable();
|
return oculusAvailable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::mat4 OculusBaseDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const {
|
||||||
|
if (_session) {
|
||||||
|
ViewFrustum baseFrustum;
|
||||||
|
baseFrustum.setProjection(baseProjection);
|
||||||
|
float baseNearClip = baseFrustum.getNearClip();
|
||||||
|
float baseFarClip = baseFrustum.getFarClip();
|
||||||
|
ovrEyeType ovrEye = (eye == Left) ? ovrEye_Left : ovrEye_Right;
|
||||||
|
ovrFovPort fovPort = _hmdDesc.DefaultEyeFov[eye];
|
||||||
|
ovrEyeRenderDesc& erd = ovr_GetRenderDesc(_session, ovrEye, fovPort);
|
||||||
|
ovrMatrix4f ovrPerspectiveProjection = ovrMatrix4f_Projection(erd.Fov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL);
|
||||||
|
return toGlm(ovrPerspectiveProjection);
|
||||||
|
} else {
|
||||||
|
return baseProjection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 OculusBaseDisplayPlugin::getCullingProjection(const glm::mat4& baseProjection) const {
|
||||||
|
if (_session) {
|
||||||
|
ViewFrustum baseFrustum;
|
||||||
|
baseFrustum.setProjection(baseProjection);
|
||||||
|
float baseNearClip = baseFrustum.getNearClip();
|
||||||
|
float baseFarClip = baseFrustum.getFarClip();
|
||||||
|
auto combinedFov = _eyeFovs[0];
|
||||||
|
combinedFov.LeftTan = combinedFov.RightTan = std::max(combinedFov.LeftTan, combinedFov.RightTan);
|
||||||
|
return toGlm(ovrMatrix4f_Projection(combinedFov, baseNearClip, baseFarClip, ovrProjection_ClipRangeOpenGL));
|
||||||
|
} else {
|
||||||
|
return baseProjection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// DLL based display plugins MUST initialize GLEW inside the DLL code.
|
// DLL based display plugins MUST initialize GLEW inside the DLL code.
|
||||||
void OculusBaseDisplayPlugin::customizeContext() {
|
void OculusBaseDisplayPlugin::customizeContext() {
|
||||||
glewExperimental = true;
|
glewExperimental = true;
|
||||||
|
|
|
@ -19,6 +19,9 @@ public:
|
||||||
~OculusBaseDisplayPlugin();
|
~OculusBaseDisplayPlugin();
|
||||||
bool isSupported() const override;
|
bool isSupported() const override;
|
||||||
|
|
||||||
|
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override;
|
||||||
|
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override;
|
||||||
|
|
||||||
bool hasAsyncReprojection() const override { return true; }
|
bool hasAsyncReprojection() const override { return true; }
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -357,6 +357,32 @@ bool OpenVrDisplayPlugin::isSupported() const {
|
||||||
return openVrSupported();
|
return openVrSupported();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
glm::mat4 OpenVrDisplayPlugin::getEyeProjection(Eye eye, const glm::mat4& baseProjection) const {
|
||||||
|
if (_system) {
|
||||||
|
ViewFrustum baseFrustum;
|
||||||
|
baseFrustum.setProjection(baseProjection);
|
||||||
|
float baseNearClip = baseFrustum.getNearClip();
|
||||||
|
float baseFarClip = baseFrustum.getFarClip();
|
||||||
|
vr::EVREye openVrEye = (eye == Left) ? vr::Eye_Left : vr::Eye_Right;
|
||||||
|
return toGlm(_system->GetProjectionMatrix(openVrEye, baseNearClip, baseFarClip));
|
||||||
|
} else {
|
||||||
|
return baseProjection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
glm::mat4 OpenVrDisplayPlugin::getCullingProjection(const glm::mat4& baseProjection) const {
|
||||||
|
if (_system) {
|
||||||
|
ViewFrustum baseFrustum;
|
||||||
|
baseFrustum.setProjection(baseProjection);
|
||||||
|
float baseNearClip = baseFrustum.getNearClip();
|
||||||
|
float baseFarClip = baseFrustum.getFarClip();
|
||||||
|
// FIXME Calculate the proper combined projection by using GetProjectionRaw values from both eyes
|
||||||
|
return toGlm(_system->GetProjectionMatrix((vr::EVREye)0, baseNearClip, baseFarClip));
|
||||||
|
} else {
|
||||||
|
return baseProjection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
float OpenVrDisplayPlugin::getTargetFrameRate() const {
|
float OpenVrDisplayPlugin::getTargetFrameRate() const {
|
||||||
if (forceInterleavedReprojection && !_asyncReprojectionActive) {
|
if (forceInterleavedReprojection && !_asyncReprojectionActive) {
|
||||||
return TARGET_RATE_OpenVr / 2.0f;
|
return TARGET_RATE_OpenVr / 2.0f;
|
||||||
|
|
|
@ -38,6 +38,9 @@ public:
|
||||||
bool isSupported() const override;
|
bool isSupported() const override;
|
||||||
const QString getName() const override { return NAME; }
|
const QString getName() const override { return NAME; }
|
||||||
|
|
||||||
|
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override;
|
||||||
|
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override;
|
||||||
|
|
||||||
void init() override;
|
void init() override;
|
||||||
|
|
||||||
float getTargetFrameRate() const override;
|
float getTargetFrameRate() const override;
|
||||||
|
|
|
@ -14,6 +14,8 @@
|
||||||
// Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key.
|
// Goes into "paused" when the '.' key (and automatically when started in HMD), and normal when pressing any key.
|
||||||
// See MAIN CONTROL, below, for what "paused" actually does.
|
// See MAIN CONTROL, below, for what "paused" actually does.
|
||||||
|
|
||||||
|
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||||
|
|
||||||
(function() { // BEGIN LOCAL_SCOPE
|
(function() { // BEGIN LOCAL_SCOPE
|
||||||
|
|
||||||
var BASIC_TIMER_INTERVAL = 50; // 50ms = 20hz
|
var BASIC_TIMER_INTERVAL = 50; // 50ms = 20hz
|
||||||
|
@ -28,18 +30,22 @@ var OVERLAY_DATA = {
|
||||||
};
|
};
|
||||||
var AVATAR_MOVE_FOR_ACTIVE_DISTANCE = 0.8; // meters -- no longer away if avatar moves this far while away
|
var AVATAR_MOVE_FOR_ACTIVE_DISTANCE = 0.8; // meters -- no longer away if avatar moves this far while away
|
||||||
|
|
||||||
var lastOverlayPosition = { x: 0, y: 0, z: 0};
|
var AVATAR_SELF_ID = "{00000000-0000-0000-0000-000000000001}";
|
||||||
|
var CAMERA_MATRIX = -7;
|
||||||
|
|
||||||
var OVERLAY_DATA_HMD = {
|
var OVERLAY_DATA_HMD = {
|
||||||
position: lastOverlayPosition,
|
localPosition: {x: 0, y: 0, z: -1 * MyAvatar.sensorToWorldScale},
|
||||||
|
localRotation: {x: 0, y: 0, z: 0, w: 1},
|
||||||
width: OVERLAY_WIDTH,
|
width: OVERLAY_WIDTH,
|
||||||
height: OVERLAY_HEIGHT,
|
height: OVERLAY_HEIGHT,
|
||||||
url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png",
|
url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png",
|
||||||
color: {red: 255, green: 255, blue: 255},
|
color: {red: 255, green: 255, blue: 255},
|
||||||
alpha: 1,
|
alpha: 1,
|
||||||
scale: 2,
|
scale: 2 * MyAvatar.sensorToWorldScale,
|
||||||
emissive: true,
|
emissive: true,
|
||||||
isFacingAvatar: true,
|
drawInFront: true,
|
||||||
drawInFront: true
|
parentID: AVATAR_SELF_ID,
|
||||||
|
parentJointIndex: CAMERA_MATRIX
|
||||||
};
|
};
|
||||||
|
|
||||||
var AWAY_INTRO = {
|
var AWAY_INTRO = {
|
||||||
|
@ -83,25 +89,11 @@ function stopAwayAnimation() {
|
||||||
var overlay = Overlays.addOverlay("image", OVERLAY_DATA);
|
var overlay = Overlays.addOverlay("image", OVERLAY_DATA);
|
||||||
var overlayHMD = Overlays.addOverlay("image3d", OVERLAY_DATA_HMD);
|
var overlayHMD = Overlays.addOverlay("image3d", OVERLAY_DATA_HMD);
|
||||||
|
|
||||||
function moveCloserToCamera(positionAtHUD) {
|
|
||||||
// we don't actually want to render at the slerped look at... instead, we want to render
|
|
||||||
// slightly closer to the camera than that.
|
|
||||||
var MOVE_CLOSER_TO_CAMERA_BY = -0.25;
|
|
||||||
var cameraForward = Quat.getForward(Camera.orientation);
|
|
||||||
var closerToCamera = Vec3.multiply(cameraForward, MOVE_CLOSER_TO_CAMERA_BY); // slightly closer to camera
|
|
||||||
var slightlyCloserPosition = Vec3.sum(positionAtHUD, closerToCamera);
|
|
||||||
|
|
||||||
return slightlyCloserPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
function showOverlay() {
|
function showOverlay() {
|
||||||
if (HMD.active) {
|
if (HMD.active) {
|
||||||
// make sure desktop version is hidden
|
// make sure desktop version is hidden
|
||||||
Overlays.editOverlay(overlay, { visible: false });
|
Overlays.editOverlay(overlay, { visible: false });
|
||||||
|
Overlays.editOverlay(overlayHMD, { visible: true });
|
||||||
lastOverlayPosition = HMD.getHUDLookAtPosition3D();
|
|
||||||
var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition);
|
|
||||||
Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon });
|
|
||||||
} else {
|
} else {
|
||||||
// make sure HMD is hidden
|
// make sure HMD is hidden
|
||||||
Overlays.editOverlay(overlayHMD, { visible: false });
|
Overlays.editOverlay(overlayHMD, { visible: false });
|
||||||
|
@ -110,9 +102,11 @@ function showOverlay() {
|
||||||
var screen = Controller.getViewportDimensions();
|
var screen = Controller.getViewportDimensions();
|
||||||
|
|
||||||
// keep the overlay it's natural size and always center it...
|
// keep the overlay it's natural size and always center it...
|
||||||
Overlays.editOverlay(overlay, { visible: true,
|
Overlays.editOverlay(overlay, {
|
||||||
x: ((screen.x - OVERLAY_WIDTH) / 2),
|
visible: true,
|
||||||
y: ((screen.y - OVERLAY_HEIGHT) / 2) });
|
x: ((screen.x - OVERLAY_WIDTH) / 2),
|
||||||
|
y: ((screen.y - OVERLAY_HEIGHT) / 2)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,16 +126,10 @@ function maybeMoveOverlay() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HMD.active) {
|
if (HMD.active) {
|
||||||
// Note: instead of moving it directly to the lookAt, we will move it slightly toward the
|
|
||||||
// new look at. This will result in a more subtle slerp toward the look at and reduce jerkiness
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
var EASE_BY_RATIO = 0.1;
|
var localPosition = {x: 0, y: 0, z: -1 * sensorScaleFactor};
|
||||||
var lookAt = HMD.getHUDLookAtPosition3D();
|
Overlays.editOverlay(overlayHMD, { visible: true, localPosition: localPosition, scale: 2 * sensorScaleFactor });
|
||||||
var lookAtChange = Vec3.subtract(lookAt, lastOverlayPosition);
|
|
||||||
var halfWayBetweenOldAndLookAt = Vec3.multiply(lookAtChange, EASE_BY_RATIO);
|
|
||||||
var newOverlayPosition = Vec3.sum(lastOverlayPosition, halfWayBetweenOldAndLookAt);
|
|
||||||
lastOverlayPosition = newOverlayPosition;
|
|
||||||
var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition);
|
|
||||||
Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon });
|
|
||||||
|
|
||||||
// make sure desktop version is hidden
|
// make sure desktop version is hidden
|
||||||
Overlays.editOverlay(overlay, { visible: false });
|
Overlays.editOverlay(overlay, { visible: false });
|
||||||
|
@ -191,8 +179,8 @@ function goActive() {
|
||||||
MyAvatar.isAway = false;
|
MyAvatar.isAway = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MyAvatar.wentAway.connect(setAwayProperties)
|
MyAvatar.wentAway.connect(setAwayProperties);
|
||||||
MyAvatar.wentActive.connect(setActiveProperties)
|
MyAvatar.wentActive.connect(setActiveProperties);
|
||||||
|
|
||||||
function setAwayProperties() {
|
function setAwayProperties() {
|
||||||
isAway = true;
|
isAway = true;
|
||||||
|
@ -254,7 +242,7 @@ function maybeGoActive(event) {
|
||||||
if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it)
|
if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isAway && (event.text == 'ESC')) {
|
if (!isAway && (event.text === 'ESC')) {
|
||||||
goAway();
|
goAway();
|
||||||
} else {
|
} else {
|
||||||
goActive();
|
goActive();
|
||||||
|
@ -286,7 +274,7 @@ function maybeGoAway() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// If you've removed your HMD from your head, and we can detect it, we will also go away...
|
// If you've removed your HMD from your head, and we can detect it, we will also go away...
|
||||||
if (HMD.mounted != wasHmdMounted) {
|
if (HMD.mounted !== wasHmdMounted) {
|
||||||
wasHmdMounted = HMD.mounted;
|
wasHmdMounted = HMD.mounted;
|
||||||
print("HMD mounted changed...");
|
print("HMD mounted changed...");
|
||||||
|
|
||||||
|
@ -317,7 +305,7 @@ var handleMessage = function(channel, message, sender) {
|
||||||
print("away.js | Got message on Hifi-Away-Enable: ", message);
|
print("away.js | Got message on Hifi-Away-Enable: ", message);
|
||||||
setEnabled(message === 'enable');
|
setEnabled(message === 'enable');
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
Messages.subscribe(CHANNEL_AWAY_ENABLE);
|
Messages.subscribe(CHANNEL_AWAY_ENABLE);
|
||||||
Messages.messageReceived.connect(handleMessage);
|
Messages.messageReceived.connect(handleMessage);
|
||||||
|
|
||||||
|
|
|
@ -27,8 +27,8 @@
|
||||||
url: Script.resolvePath("assets/models/Bubble-v14.fbx"), // If you'd like to change the model, modify this line (and the dimensions below)
|
url: Script.resolvePath("assets/models/Bubble-v14.fbx"), // If you'd like to change the model, modify this line (and the dimensions below)
|
||||||
dimensions: { x: 1.0, y: 0.75, z: 1.0 },
|
dimensions: { x: 1.0, y: 0.75, z: 1.0 },
|
||||||
position: { x: MyAvatar.position.x, y: -MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE, z: MyAvatar.position.z },
|
position: { x: MyAvatar.position.x, y: -MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE, z: MyAvatar.position.z },
|
||||||
rotation: Quat.fromPitchYawRollDegrees(MyAvatar.bodyPitch, 0, MyAvatar.bodyRoll),
|
rotation: Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({x: 0.0, y: 180.0, z: 0.0})),
|
||||||
scale: { x: 2, y: MyAvatar.scale * 0.5 + 0.5, z: 2 },
|
scale: { x: 2 * MyAvatar.sensorToWorldScale, y: MyAvatar.scale * 0.5 + 0.2 * MyAvatar.sensorToWorldScale, z: 2 * MyAvatar.sensorToWorldScale },
|
||||||
visible: false,
|
visible: false,
|
||||||
ignoreRayIntersection: true
|
ignoreRayIntersection: true
|
||||||
});
|
});
|
||||||
|
@ -62,9 +62,17 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
Overlays.editOverlay(bubbleOverlay, {
|
Overlays.editOverlay(bubbleOverlay, {
|
||||||
position: { x: MyAvatar.position.x, y: -MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE, z: MyAvatar.position.z },
|
position: {
|
||||||
rotation: Quat.fromPitchYawRollDegrees(MyAvatar.bodyPitch, 0, MyAvatar.bodyRoll),
|
x: MyAvatar.position.x,
|
||||||
scale: { x: 2, y: MyAvatar.scale * 0.5 + 0.5, z: 2 },
|
y: -MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE,
|
||||||
|
z: MyAvatar.position.z
|
||||||
|
},
|
||||||
|
rotation: Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({x: 0.0, y: 180.0, z: 0.0})),
|
||||||
|
scale: {
|
||||||
|
x: 2 * MyAvatar.sensorToWorldScale,
|
||||||
|
y: MyAvatar.scale * 0.5 + 0.2 * MyAvatar.sensorToWorldScale,
|
||||||
|
z: 2 * MyAvatar.sensorToWorldScale
|
||||||
|
},
|
||||||
visible: true
|
visible: true
|
||||||
});
|
});
|
||||||
bubbleOverlayTimestamp = Date.now();
|
bubbleOverlayTimestamp = Date.now();
|
||||||
|
@ -105,11 +113,11 @@
|
||||||
y: (-((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE,
|
y: (-((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 2 + MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE,
|
||||||
z: MyAvatar.position.z
|
z: MyAvatar.position.z
|
||||||
},
|
},
|
||||||
rotation: Quat.fromPitchYawRollDegrees(MyAvatar.bodyPitch, 0, MyAvatar.bodyRoll),
|
rotation: Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({x: 0.0, y: 180.0, z: 0.0})),
|
||||||
scale: {
|
scale: {
|
||||||
x: 2,
|
x: 2 * MyAvatar.sensorToWorldScale,
|
||||||
y: ((1 - ((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 0.5 + 0.5),
|
y: ((1 - ((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 0.5 + 0.2 * MyAvatar.sensorToWorldScale),
|
||||||
z: 2
|
z: 2 * MyAvatar.sensorToWorldScale
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
|
@ -120,11 +128,11 @@
|
||||||
y: MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE,
|
y: MyAvatar.position.y + MyAvatar.scale * BUBBLE_HEIGHT_SCALE,
|
||||||
z: MyAvatar.position.z
|
z: MyAvatar.position.z
|
||||||
},
|
},
|
||||||
rotation: Quat.fromPitchYawRollDegrees(MyAvatar.bodyPitch, 0, MyAvatar.bodyRoll),
|
rotation: Quat.multiply(MyAvatar.orientation, Quat.fromVec3Degrees({x: 0.0, y: 180.0, z: 0.0})),
|
||||||
scale: {
|
scale: {
|
||||||
x: 2,
|
x: 2 * MyAvatar.sensorToWorldScale,
|
||||||
y: MyAvatar.scale * 0.5 + 0.5,
|
y: MyAvatar.scale * 0.5 + 0.2 * MyAvatar.sensorToWorldScale,
|
||||||
z: 2
|
z: 2 * MyAvatar.sensorToWorldScale
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,6 +150,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
if (PROFILE) {
|
if (PROFILE) {
|
||||||
Script.beginProfileRange("dispatch.pre");
|
Script.beginProfileRange("dispatch.pre");
|
||||||
}
|
}
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
var deltaTime = _this.updateTimings();
|
var deltaTime = _this.updateTimings();
|
||||||
_this.setIgnoreTablet();
|
_this.setIgnoreTablet();
|
||||||
|
|
||||||
|
@ -196,7 +197,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
var h;
|
var h;
|
||||||
for (h = LEFT_HAND; h <= RIGHT_HAND; h++) {
|
for (h = LEFT_HAND; h <= RIGHT_HAND; h++) {
|
||||||
if (controllerLocations[h].valid) {
|
if (controllerLocations[h].valid) {
|
||||||
var nearbyOverlays = Overlays.findOverlays(controllerLocations[h].position, NEAR_MAX_RADIUS);
|
var nearbyOverlays = Overlays.findOverlays(controllerLocations[h].position, NEAR_MAX_RADIUS * sensorScaleFactor);
|
||||||
nearbyOverlays.sort(function (a, b) {
|
nearbyOverlays.sort(function (a, b) {
|
||||||
var aPosition = Overlays.getProperty(a, "position");
|
var aPosition = Overlays.getProperty(a, "position");
|
||||||
var aDistance = Vec3.distance(aPosition, controllerLocations[h].position);
|
var aDistance = Vec3.distance(aPosition, controllerLocations[h].position);
|
||||||
|
@ -216,7 +217,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
for (h = LEFT_HAND; h <= RIGHT_HAND; h++) {
|
for (h = LEFT_HAND; h <= RIGHT_HAND; h++) {
|
||||||
if (controllerLocations[h].valid) {
|
if (controllerLocations[h].valid) {
|
||||||
var controllerPosition = controllerLocations[h].position;
|
var controllerPosition = controllerLocations[h].position;
|
||||||
var nearbyEntityIDs = Entities.findEntities(controllerPosition, NEAR_MAX_RADIUS);
|
var nearbyEntityIDs = Entities.findEntities(controllerPosition, NEAR_MAX_RADIUS * sensorScaleFactor);
|
||||||
for (var j = 0; j < nearbyEntityIDs.length; j++) {
|
for (var j = 0; j < nearbyEntityIDs.length; j++) {
|
||||||
var entityID = nearbyEntityIDs[j];
|
var entityID = nearbyEntityIDs[j];
|
||||||
var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
|
var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
|
||||||
|
@ -249,7 +250,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
|
|
||||||
if (rayPicks[h].type === RayPick.INTERSECTED_ENTITY) {
|
if (rayPicks[h].type === RayPick.INTERSECTED_ENTITY) {
|
||||||
// XXX check to make sure this one isn't already in nearbyEntityProperties?
|
// XXX check to make sure this one isn't already in nearbyEntityProperties?
|
||||||
if (rayPicks[h].distance < NEAR_GRAB_PICK_RADIUS) {
|
if (rayPicks[h].distance < NEAR_GRAB_PICK_RADIUS * sensorScaleFactor) {
|
||||||
var nearEntityID = rayPicks[h].objectID;
|
var nearEntityID = rayPicks[h].objectID;
|
||||||
var nearbyProps = Entities.getEntityProperties(nearEntityID, DISPATCHER_PROPERTIES);
|
var nearbyProps = Entities.getEntityProperties(nearEntityID, DISPATCHER_PROPERTIES);
|
||||||
nearbyProps.id = nearEntityID;
|
nearbyProps.id = nearEntityID;
|
||||||
|
@ -368,28 +369,28 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand)
|
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true)
|
||||||
});
|
});
|
||||||
this.leftControllerHudRayPick = RayPick.createRayPick({
|
this.leftControllerHudRayPick = RayPick.createRayPick({
|
||||||
joint: "_CONTROLLER_LEFTHAND",
|
joint: "_CONTROLLER_LEFTHAND",
|
||||||
filter: RayPick.PICK_HUD,
|
filter: RayPick.PICK_HUD,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand)
|
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true)
|
||||||
});
|
});
|
||||||
this.rightControllerRayPick = RayPick.createRayPick({
|
this.rightControllerRayPick = RayPick.createRayPick({
|
||||||
joint: "_CONTROLLER_RIGHTHAND",
|
joint: "_CONTROLLER_RIGHTHAND",
|
||||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand)
|
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true)
|
||||||
});
|
});
|
||||||
this.rightControllerHudRayPick = RayPick.createRayPick({
|
this.rightControllerHudRayPick = RayPick.createRayPick({
|
||||||
joint: "_CONTROLLER_RIGHTHAND",
|
joint: "_CONTROLLER_RIGHTHAND",
|
||||||
filter: RayPick.PICK_HUD,
|
filter: RayPick.PICK_HUD,
|
||||||
enabled: true,
|
enabled: true,
|
||||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand)
|
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true)
|
||||||
});
|
});
|
||||||
|
|
||||||
this.handleHandMessage = function(channel, message, sender) {
|
this.handleHandMessage = function(channel, message, sender) {
|
||||||
|
|
|
@ -59,7 +59,8 @@ createControllerDisplay = function(config) {
|
||||||
},
|
},
|
||||||
|
|
||||||
setPartVisible: function(partName, visible) {
|
setPartVisible: function(partName, visible) {
|
||||||
return;
|
// Disabled
|
||||||
|
/*
|
||||||
if (partName in this.partOverlays) {
|
if (partName in this.partOverlays) {
|
||||||
for (var i = 0; i < this.partOverlays[partName].length; ++i) {
|
for (var i = 0; i < this.partOverlays[partName].length; ++i) {
|
||||||
Overlays.editOverlay(this.partOverlays[partName][i], {
|
Overlays.editOverlay(this.partOverlays[partName][i], {
|
||||||
|
@ -67,6 +68,7 @@ createControllerDisplay = function(config) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
},
|
},
|
||||||
|
|
||||||
setLayerForPart: function(partName, layerName) {
|
setLayerForPart: function(partName, layerName) {
|
||||||
|
@ -85,12 +87,45 @@ createControllerDisplay = function(config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resize: function(sensorScaleFactor) {
|
||||||
|
if (this.overlays.length >= 0) {
|
||||||
|
var controller = config.controllers[0];
|
||||||
|
var position = controller.position;
|
||||||
|
|
||||||
|
// first overlay is main body.
|
||||||
|
var overlayID = this.overlays[0];
|
||||||
|
var localPosition = Vec3.multiply(sensorScaleFactor, Vec3.sum(Vec3.multiplyQbyV(controller.rotation, controller.naturalPosition), position));
|
||||||
|
var dimensions = Vec3.multiply(sensorScaleFactor, controller.dimensions);
|
||||||
|
|
||||||
|
Overlays.editOverlay(overlayID, {
|
||||||
|
dimensions: dimensions,
|
||||||
|
localPosition: localPosition
|
||||||
|
});
|
||||||
|
|
||||||
|
if (controller.parts) {
|
||||||
|
var i = 1;
|
||||||
|
for (var partName in controller.parts) {
|
||||||
|
overlayID = this.overlays[i++];
|
||||||
|
var part = controller.parts[partName];
|
||||||
|
var partPosition = Vec3.multiply(sensorScaleFactor, Vec3.sum(controller.position, Vec3.multiplyQbyV(controller.rotation, part.naturalPosition)));
|
||||||
|
var partDimensions = Vec3.multiply(sensorScaleFactor, part.naturalDimensions);
|
||||||
|
Overlays.editOverlay(overlayID, {
|
||||||
|
dimensions: partDimensions,
|
||||||
|
localPosition: partPosition
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var mapping = Controller.newMapping(controllerDisplay.mappingName);
|
var mapping = Controller.newMapping(controllerDisplay.mappingName);
|
||||||
for (var i = 0; i < config.controllers.length; ++i) {
|
for (var i = 0; i < config.controllers.length; ++i) {
|
||||||
var controller = config.controllers[i];
|
var controller = config.controllers[i];
|
||||||
var position = controller.position;
|
var position = controller.position;
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
|
|
||||||
if (controller.naturalPosition) {
|
if (controller.naturalPosition) {
|
||||||
position = Vec3.sum(Vec3.multiplyQbyV(controller.rotation, controller.naturalPosition), position);
|
position = Vec3.sum(Vec3.multiplyQbyV(controller.rotation, controller.naturalPosition), position);
|
||||||
|
@ -98,9 +133,9 @@ createControllerDisplay = function(config) {
|
||||||
|
|
||||||
var overlayID = Overlays.addOverlay("model", {
|
var overlayID = Overlays.addOverlay("model", {
|
||||||
url: controller.modelURL,
|
url: controller.modelURL,
|
||||||
dimensions: controller.dimensions,
|
dimensions: Vec3.multiply(sensorScaleFactor, controller.dimensions),
|
||||||
localRotation: controller.rotation,
|
localRotation: controller.rotation,
|
||||||
localPosition: position,
|
localPosition: Vec3.multiply(sensorScaleFactor, position),
|
||||||
parentID: PARENT_ID,
|
parentID: PARENT_ID,
|
||||||
parentJointIndex: controller.jointIndex,
|
parentJointIndex: controller.jointIndex,
|
||||||
ignoreRayIntersection: true
|
ignoreRayIntersection: true
|
||||||
|
@ -176,8 +211,8 @@ createControllerDisplay = function(config) {
|
||||||
});
|
});
|
||||||
} else if (part.type === "joystick") {
|
} else if (part.type === "joystick") {
|
||||||
(function(controller, overlayID, part) {
|
(function(controller, overlayID, part) {
|
||||||
const xInput = resolveHardware(part.xInput);
|
var xInput = resolveHardware(part.xInput);
|
||||||
const yInput = resolveHardware(part.yInput);
|
var yInput = resolveHardware(part.yInput);
|
||||||
|
|
||||||
var xvalue = 0;
|
var xvalue = 0;
|
||||||
var yvalue = 0;
|
var yvalue = 0;
|
||||||
|
@ -190,21 +225,20 @@ createControllerDisplay = function(config) {
|
||||||
offset = Vec3.multiplyQbyV(rotation, part.originOffset);
|
offset = Vec3.multiplyQbyV(rotation, part.originOffset);
|
||||||
offset = Vec3.subtract(part.originOffset, offset);
|
offset = Vec3.subtract(part.originOffset, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
var partPosition = Vec3.sum(controller.position,
|
var partPosition = Vec3.sum(controller.position,
|
||||||
Vec3.multiplyQbyV(controller.rotation, Vec3.sum(offset, part.naturalPosition)));
|
Vec3.multiplyQbyV(controller.rotation, Vec3.sum(offset, part.naturalPosition)));
|
||||||
|
|
||||||
var partRotation = Quat.multiply(controller.rotation, rotation)
|
var partRotation = Quat.multiply(controller.rotation, rotation);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
position: partPosition,
|
position: partPosition,
|
||||||
rotation: partRotation
|
rotation: partRotation
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
mapping.from([xInput]).peek().to(function(value) {
|
mapping.from([xInput]).peek().to(function(value) {
|
||||||
xvalue = value;
|
xvalue = value;
|
||||||
//print(overlayID, xvalue.toFixed(3), yvalue.toFixed(3));
|
|
||||||
var posRot = calculatePositionAndRotation(xvalue, yvalue);
|
var posRot = calculatePositionAndRotation(xvalue, yvalue);
|
||||||
Overlays.editOverlay(overlayID, {
|
Overlays.editOverlay(overlayID, {
|
||||||
localPosition: posRot.position,
|
localPosition: posRot.position,
|
||||||
|
@ -224,10 +258,9 @@ createControllerDisplay = function(config) {
|
||||||
|
|
||||||
} else if (part.type === "linear") {
|
} else if (part.type === "linear") {
|
||||||
(function(controller, overlayID, part) {
|
(function(controller, overlayID, part) {
|
||||||
const input = resolveHardware(part.input);
|
var input = resolveHardware(part.input);
|
||||||
|
|
||||||
mapping.from([input]).peek().to(function(value) {
|
mapping.from([input]).peek().to(function(value) {
|
||||||
//print(value);
|
|
||||||
var axis = Vec3.multiplyQbyV(controller.rotation, part.axis);
|
var axis = Vec3.multiplyQbyV(controller.rotation, part.axis);
|
||||||
var offset = Vec3.multiply(part.maxTranslation * value, axis);
|
var offset = Vec3.multiply(part.maxTranslation * value, axis);
|
||||||
|
|
||||||
|
@ -256,6 +289,7 @@ createControllerDisplay = function(config) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Controller.enableMapping(controllerDisplay.mappingName);
|
Controller.enableMapping(controllerDisplay.mappingName);
|
||||||
|
controllerDisplay.resize(MyAvatar.sensorToWorldScale);
|
||||||
return controllerDisplay;
|
return controllerDisplay;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,6 @@ ControllerDisplayManager = function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leftConfig !== null && rightConfig !== null) {
|
if (leftConfig !== null && rightConfig !== null) {
|
||||||
print("Loading controllers");
|
|
||||||
if (controllerLeft === null) {
|
if (controllerLeft === null) {
|
||||||
controllerLeft = createControllerDisplay(leftConfig);
|
controllerLeft = createControllerDisplay(leftConfig);
|
||||||
controllerLeft.setVisible(true);
|
controllerLeft.setVisible(true);
|
||||||
|
@ -70,6 +69,7 @@ ControllerDisplayManager = function() {
|
||||||
Script.clearInterval(controllerCheckerIntervalID);
|
Script.clearInterval(controllerCheckerIntervalID);
|
||||||
controllerCheckerIntervalID = null;
|
controllerCheckerIntervalID = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
self.deleteControllerDisplays();
|
self.deleteControllerDisplays();
|
||||||
if (!controllerCheckerIntervalID) {
|
if (!controllerCheckerIntervalID) {
|
||||||
|
@ -86,6 +86,15 @@ ControllerDisplayManager = function() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resizeControllers(sensorScaleFactor) {
|
||||||
|
if (controllerLeft) {
|
||||||
|
controllerLeft.resize(sensorScaleFactor);
|
||||||
|
}
|
||||||
|
if (controllerRight) {
|
||||||
|
controllerRight.resize(sensorScaleFactor);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var handleMessages = function(channel, message, sender) {
|
var handleMessages = function(channel, message, sender) {
|
||||||
var i, data, name, visible;
|
var i, data, name, visible;
|
||||||
if (!controllerLeft && !controllerRight) {
|
if (!controllerLeft && !controllerRight) {
|
||||||
|
@ -171,6 +180,7 @@ ControllerDisplayManager = function() {
|
||||||
|
|
||||||
HMD.displayModeChanged.connect(updateControllers);
|
HMD.displayModeChanged.connect(updateControllers);
|
||||||
HMD.shouldShowHandControllersChanged.connect(updateControllers);
|
HMD.shouldShowHandControllersChanged.connect(updateControllers);
|
||||||
|
MyAvatar.sensorToWorldScaleChanged.connect(resizeControllers);
|
||||||
|
|
||||||
updateControllers();
|
updateControllers();
|
||||||
};
|
};
|
||||||
|
|
|
@ -563,7 +563,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||||
maxDistance: PICK_MAX_DISTANCE,
|
maxDistance: PICK_MAX_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||||
renderStates: renderStates,
|
renderStates: renderStates,
|
||||||
faceAvatar: true,
|
faceAvatar: true,
|
||||||
defaultRenderStates: defaultRenderStates
|
defaultRenderStates: defaultRenderStates
|
||||||
|
|
|
@ -198,7 +198,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||||
maxDistance: PICK_MAX_DISTANCE,
|
maxDistance: PICK_MAX_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||||
renderStates: renderStates,
|
renderStates: renderStates,
|
||||||
faceAvatar: true,
|
faceAvatar: true,
|
||||||
defaultRenderStates: defaultRenderStates
|
defaultRenderStates: defaultRenderStates
|
||||||
|
|
|
@ -238,7 +238,7 @@ Script.include("/~/system/libraries/utils.js");
|
||||||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||||
maxDistance: PICK_MAX_DISTANCE,
|
maxDistance: PICK_MAX_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||||
renderStates: renderStates,
|
renderStates: renderStates,
|
||||||
faceAvatar: true,
|
faceAvatar: true,
|
||||||
defaultRenderStates: defaultRenderStates
|
defaultRenderStates: defaultRenderStates
|
||||||
|
|
|
@ -150,9 +150,10 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
||||||
this.getTargetProps = function (controllerData) {
|
this.getTargetProps = function (controllerData) {
|
||||||
// nearbyEntityProperties is already sorted by distance from controller
|
// nearbyEntityProperties is already sorted by distance from controller
|
||||||
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
||||||
var props = nearbyEntityProperties[i];
|
var props = nearbyEntityProperties[i];
|
||||||
if (props.distance > NEAR_GRAB_RADIUS) {
|
if (props.distance > NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (entityIsGrabbable(props) || entityIsCloneable(props)) {
|
if (entityIsGrabbable(props) || entityIsCloneable(props)) {
|
||||||
|
|
|
@ -146,11 +146,12 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
||||||
this.getTargetProps = function (controllerData) {
|
this.getTargetProps = function (controllerData) {
|
||||||
// nearbyEntityProperties is already sorted by length from controller
|
// nearbyEntityProperties is already sorted by length from controller
|
||||||
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
||||||
var props = nearbyEntityProperties[i];
|
var props = nearbyEntityProperties[i];
|
||||||
var handPosition = controllerData.controllerLocations[this.hand].position;
|
var handPosition = controllerData.controllerLocations[this.hand].position;
|
||||||
var distance = Vec3.distance(props.position, handPosition);
|
var distance = Vec3.distance(props.position, handPosition);
|
||||||
if (distance > NEAR_GRAB_RADIUS) {
|
if (distance > NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (entityIsGrabbable(props)) {
|
if (entityIsGrabbable(props)) {
|
||||||
|
|
|
@ -8,11 +8,12 @@
|
||||||
|
|
||||||
/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, AVATAR_SELF_ID, getControllerJointIndex, NULL_UUID,
|
/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, AVATAR_SELF_ID, getControllerJointIndex, NULL_UUID,
|
||||||
enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
||||||
makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3
|
makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings,
|
||||||
|
NEAR_GRAB_RADIUS
|
||||||
*/
|
*/
|
||||||
|
|
||||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
var GRAB_RADIUS = 0.35;
|
Script.include("/~/system/libraries/utils.js");
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
|
|
||||||
|
@ -119,6 +120,11 @@ var GRAB_RADIUS = 0.35;
|
||||||
}
|
}
|
||||||
Overlays.editOverlay(this.grabbedThingID, reparentProps);
|
Overlays.editOverlay(this.grabbedThingID, reparentProps);
|
||||||
|
|
||||||
|
// resizeTablet to counter adjust offsets to account for change of scale from sensorToWorldMatrix
|
||||||
|
if (this.grabbedThingID === HMD.tabletID) {
|
||||||
|
resizeTablet(getTabletWidthFromSettings(), reparentProps.parentJointIndex);
|
||||||
|
}
|
||||||
|
|
||||||
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
Messages.sendMessage('Hifi-Object-Manipulation', JSON.stringify({
|
||||||
action: 'grab',
|
action: 'grab',
|
||||||
grabbedEntity: this.grabbedThingID,
|
grabbedEntity: this.grabbedThingID,
|
||||||
|
@ -139,17 +145,23 @@ var GRAB_RADIUS = 0.35;
|
||||||
parentID: this.previousParentID[this.grabbedThingID],
|
parentID: this.previousParentID[this.grabbedThingID],
|
||||||
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID]
|
parentJointIndex: this.previousParentJointIndex[this.grabbedThingID]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// resizeTablet to counter adjust offsets to account for change of scale from sensorToWorldMatrix
|
||||||
|
if (this.grabbedThingID === HMD.tabletID) {
|
||||||
|
resizeTablet(getTabletWidthFromSettings(), this.previousParentJointIndex[this.grabbedThingID]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.grabbedThingID = null;
|
this.grabbedThingID = null;
|
||||||
};
|
};
|
||||||
|
|
||||||
this.getTargetID = function(overlays, controllerData) {
|
this.getTargetID = function(overlays, controllerData) {
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
for (var i = 0; i < overlays.length; i++) {
|
for (var i = 0; i < overlays.length; i++) {
|
||||||
var overlayPosition = Overlays.getProperty(overlays[i], "position");
|
var overlayPosition = Overlays.getProperty(overlays[i], "position");
|
||||||
var handPosition = controllerData.controllerLocations[this.hand].position;
|
var handPosition = controllerData.controllerLocations[this.hand].position;
|
||||||
var distance = Vec3.distance(overlayPosition, handPosition);
|
var distance = Vec3.distance(overlayPosition, handPosition);
|
||||||
if (distance <= GRAB_RADIUS) {
|
if (distance <= NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||||
return overlays[i];
|
return overlays[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,11 +36,12 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||||
this.getTargetProps = function (controllerData) {
|
this.getTargetProps = function (controllerData) {
|
||||||
// nearbyEntityProperties is already sorted by length from controller
|
// nearbyEntityProperties is already sorted by length from controller
|
||||||
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
||||||
var props = nearbyEntityProperties[i];
|
var props = nearbyEntityProperties[i];
|
||||||
var handPosition = controllerData.controllerLocations[this.hand].position;
|
var handPosition = controllerData.controllerLocations[this.hand].position;
|
||||||
var distance = Vec3.distance(props.position, handPosition);
|
var distance = Vec3.distance(props.position, handPosition);
|
||||||
if (distance > NEAR_GRAB_RADIUS) {
|
if (distance > NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (entityWantsNearTrigger(props)) {
|
if (entityWantsNearTrigger(props)) {
|
||||||
|
|
|
@ -526,7 +526,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||||
filter: RayPick.PICK_OVERLAYS,
|
filter: RayPick.PICK_OVERLAYS,
|
||||||
maxDistance: PICK_MAX_DISTANCE,
|
maxDistance: PICK_MAX_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||||
renderStates: renderStates,
|
renderStates: renderStates,
|
||||||
faceAvatar: true,
|
faceAvatar: true,
|
||||||
defaultRenderStates: defaultRenderStates
|
defaultRenderStates: defaultRenderStates
|
||||||
|
|
|
@ -357,7 +357,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
this.stylusTip = getControllerWorldLocation(this.handToController(), true);
|
this.stylusTip = getControllerWorldLocation(this.handToController(), true);
|
||||||
|
|
||||||
// translate tip forward according to constant.
|
// translate tip forward according to constant.
|
||||||
var TIP_OFFSET = {x: 0, y: WEB_STYLUS_LENGTH - WEB_TOUCH_Y_OFFSET, z: 0};
|
var TIP_OFFSET = Vec3.multiply(MyAvatar.sensorToWorldScale, {x: 0, y: WEB_STYLUS_LENGTH - WEB_TOUCH_Y_OFFSET, z: 0});
|
||||||
this.stylusTip.position = Vec3.sum(this.stylusTip.position,
|
this.stylusTip.position = Vec3.sum(this.stylusTip.position,
|
||||||
Vec3.multiplyQbyV(this.stylusTip.orientation, TIP_OFFSET));
|
Vec3.multiplyQbyV(this.stylusTip.orientation, TIP_OFFSET));
|
||||||
}
|
}
|
||||||
|
@ -381,17 +381,17 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var X_ROT_NEG_90 = { x: -0.70710678, y: 0, z: 0, w: 0.70710678 };
|
||||||
|
var modelOrientation = Quat.multiply(this.stylusTip.orientation, X_ROT_NEG_90);
|
||||||
|
var modelPositionOffset = Vec3.multiplyQbyV(modelOrientation, { x: 0, y: 0, z: MyAvatar.sensorToWorldScale * -WEB_STYLUS_LENGTH / 2 });
|
||||||
|
|
||||||
var stylusProperties = {
|
var stylusProperties = {
|
||||||
name: "stylus",
|
name: "stylus",
|
||||||
url: Script.resourcesPath() + "meshes/tablet-stylus-fat.fbx",
|
url: Script.resourcesPath() + "meshes/tablet-stylus-fat.fbx",
|
||||||
loadPriority: 10.0,
|
loadPriority: 10.0,
|
||||||
localPosition: Vec3.sum({
|
position: Vec3.sum(this.stylusTip.position, modelPositionOffset),
|
||||||
x: 0.0,
|
rotation: modelOrientation,
|
||||||
y: WEB_TOUCH_Y_OFFSET,
|
dimensions: Vec3.multiply(MyAvatar.sensorToWorldScale, { x: 0.01, y: 0.01, z: WEB_STYLUS_LENGTH }),
|
||||||
z: 0.0
|
|
||||||
}, getGrabPointSphereOffset(this.handToController())),
|
|
||||||
localRotation: Quat.fromVec3Degrees({ x: -90, y: 0, z: 0 }),
|
|
||||||
dimensions: { x: 0.01, y: 0.01, z: WEB_STYLUS_LENGTH },
|
|
||||||
solid: true,
|
solid: true,
|
||||||
visible: true,
|
visible: true,
|
||||||
ignoreRayIntersection: true,
|
ignoreRayIntersection: true,
|
||||||
|
@ -528,9 +528,11 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
hysteresisOffset = 0.05;
|
hysteresisOffset = 0.05;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.isNearStylusTarget = isNearStylusTarget(stylusTargets, EDGE_BORDER + hysteresisOffset,
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
TABLET_MIN_TOUCH_DISTANCE - hysteresisOffset,
|
this.isNearStylusTarget = isNearStylusTarget(stylusTargets,
|
||||||
WEB_DISPLAY_STYLUS_DISTANCE + hysteresisOffset);
|
(EDGE_BORDER + hysteresisOffset) * sensorScaleFactor,
|
||||||
|
(TABLET_MIN_TOUCH_DISTANCE - hysteresisOffset) * sensorScaleFactor,
|
||||||
|
(WEB_DISPLAY_STYLUS_DISTANCE + hysteresisOffset) * sensorScaleFactor);
|
||||||
|
|
||||||
if (this.isNearStylusTarget) {
|
if (this.isNearStylusTarget) {
|
||||||
if (!this.useFingerInsteadOfStylus) {
|
if (!this.useFingerInsteadOfStylus) {
|
||||||
|
@ -545,8 +547,12 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
var nearestStylusTarget = calculateNearestStylusTarget(stylusTargets);
|
var nearestStylusTarget = calculateNearestStylusTarget(stylusTargets);
|
||||||
|
|
||||||
if (nearestStylusTarget && nearestStylusTarget.distance > TABLET_MIN_TOUCH_DISTANCE &&
|
var SCALED_TABLET_MIN_TOUCH_DISTANCE = TABLET_MIN_TOUCH_DISTANCE * sensorScaleFactor;
|
||||||
nearestStylusTarget.distance < TABLET_MAX_HOVER_DISTANCE) {
|
var SCALED_TABLET_MAX_TOUCH_DISTANCE = TABLET_MAX_TOUCH_DISTANCE * sensorScaleFactor;
|
||||||
|
var SCALED_TABLET_MAX_HOVER_DISTANCE = TABLET_MAX_HOVER_DISTANCE * sensorScaleFactor;
|
||||||
|
|
||||||
|
if (nearestStylusTarget && nearestStylusTarget.distance > SCALED_TABLET_MIN_TOUCH_DISTANCE &&
|
||||||
|
nearestStylusTarget.distance < SCALED_TABLET_MAX_HOVER_DISTANCE) {
|
||||||
|
|
||||||
this.requestTouchFocus(nearestStylusTarget);
|
this.requestTouchFocus(nearestStylusTarget);
|
||||||
|
|
||||||
|
@ -560,8 +566,8 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
|
|
||||||
// filter out presses when tip is moving away from tablet.
|
// filter out presses when tip is moving away from tablet.
|
||||||
// ensure that stylus is within bounding box by checking normalizedPosition
|
// ensure that stylus is within bounding box by checking normalizedPosition
|
||||||
if (nearestStylusTarget.valid && nearestStylusTarget.distance > TABLET_MIN_TOUCH_DISTANCE &&
|
if (nearestStylusTarget.valid && nearestStylusTarget.distance > SCALED_TABLET_MIN_TOUCH_DISTANCE &&
|
||||||
nearestStylusTarget.distance < TABLET_MAX_TOUCH_DISTANCE &&
|
nearestStylusTarget.distance < SCALED_TABLET_MAX_TOUCH_DISTANCE &&
|
||||||
Vec3.dot(this.stylusTip.velocity, nearestStylusTarget.normal) < 0 &&
|
Vec3.dot(this.stylusTip.velocity, nearestStylusTarget.normal) < 0 &&
|
||||||
nearestStylusTarget.normalizedPosition.x >= 0 && nearestStylusTarget.normalizedPosition.x <= 1 &&
|
nearestStylusTarget.normalizedPosition.x >= 0 && nearestStylusTarget.normalizedPosition.x <= 1 &&
|
||||||
nearestStylusTarget.normalizedPosition.y >= 0 && nearestStylusTarget.normalizedPosition.y <= 1) {
|
nearestStylusTarget.normalizedPosition.y >= 0 && nearestStylusTarget.normalizedPosition.y <= 1) {
|
||||||
|
|
|
@ -247,6 +247,34 @@ function Teleporter(hand) {
|
||||||
_this.state = TELEPORTER_STATES.TARGETTING;
|
_this.state = TELEPORTER_STATES.TARGETTING;
|
||||||
}
|
}
|
||||||
}, COOL_IN_DURATION);
|
}, COOL_IN_DURATION);
|
||||||
|
|
||||||
|
// pad scale with avatar size
|
||||||
|
var AVATAR_PROPORTIONAL_TARGET_MODEL_DIMENSIONS = Vec3.multiply(MyAvatar.sensorToWorldScale, TARGET_MODEL_DIMENSIONS);
|
||||||
|
|
||||||
|
if (!Vec3.equal(AVATAR_PROPORTIONAL_TARGET_MODEL_DIMENSIONS, cancelEnd.dimensions)) {
|
||||||
|
cancelEnd.dimensions = AVATAR_PROPORTIONAL_TARGET_MODEL_DIMENSIONS;
|
||||||
|
teleportEnd.dimensions = AVATAR_PROPORTIONAL_TARGET_MODEL_DIMENSIONS;
|
||||||
|
seatEnd.dimensions = AVATAR_PROPORTIONAL_TARGET_MODEL_DIMENSIONS;
|
||||||
|
|
||||||
|
teleportRenderStates = [{name: "cancel", path: cancelPath, end: cancelEnd},
|
||||||
|
{name: "teleport", path: teleportPath, end: teleportEnd},
|
||||||
|
{name: "seat", path: seatPath, end: seatEnd}];
|
||||||
|
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHandVisible, "cancel", teleportRenderStates[0]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHandInvisible, "cancel", teleportRenderStates[0]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHeadVisible, "cancel", teleportRenderStates[0]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHeadInvisible, "cancel", teleportRenderStates[0]);
|
||||||
|
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHandVisible, "teleport", teleportRenderStates[1]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHandInvisible, "teleport", teleportRenderStates[1]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHeadVisible, "teleport", teleportRenderStates[1]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHeadInvisible, "teleport", teleportRenderStates[1]);
|
||||||
|
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHandVisible, "seat", teleportRenderStates[2]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHandInvisible, "seat", teleportRenderStates[2]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHeadVisible, "seat", teleportRenderStates[2]);
|
||||||
|
LaserPointers.editRenderState(this.teleportRayHeadInvisible, "seat", teleportRenderStates[2]);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
this.isReady = function(controllerData, deltaTime) {
|
this.isReady = function(controllerData, deltaTime) {
|
||||||
|
|
|
@ -456,7 +456,7 @@ Script.include("/~/system/libraries/controllers.js");
|
||||||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||||
filter: RayPick.PICK_ENTITIES,
|
filter: RayPick.PICK_ENTITIES,
|
||||||
maxDistance: PICK_MAX_DISTANCE,
|
maxDistance: PICK_MAX_DISTANCE,
|
||||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||||
renderStates: renderStates,
|
renderStates: renderStates,
|
||||||
faceAvatar: true,
|
faceAvatar: true,
|
||||||
defaultRenderStates: defaultRenderStates
|
defaultRenderStates: defaultRenderStates
|
||||||
|
|
|
@ -55,6 +55,7 @@ TOUCH_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "Oculus-Labels-L.fbx",
|
modelURL: BASE_URL + "Oculus-Labels-L.fbx",
|
||||||
naturalPosition: { x: -0.022335469722747803, y: 0.00022516027092933655, z: 0.020340695977211 },
|
naturalPosition: { x: -0.022335469722747803, y: 0.00022516027092933655, z: 0.020340695977211 },
|
||||||
|
naturalDimensions: { x: 0.132063, y: 0.0856, z: 0.130282 },
|
||||||
|
|
||||||
textureName: "blank",
|
textureName: "blank",
|
||||||
defaultTextureLayer: "blank",
|
defaultTextureLayer: "blank",
|
||||||
|
@ -84,6 +85,7 @@ TOUCH_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
type: "rotational",
|
type: "rotational",
|
||||||
modelURL: BASE_URL + "touch_l_trigger.fbx",
|
modelURL: BASE_URL + "touch_l_trigger.fbx",
|
||||||
naturalPosition: { x: 0.0008544912561774254, y: -0.019867943599820137, z: 0.018800459802150726 },
|
naturalPosition: { x: 0.0008544912561774254, y: -0.019867943599820137, z: 0.018800459802150726 },
|
||||||
|
naturalDimensions: { x: 0.027509, y: 0.025211, z: 0.018443 },
|
||||||
|
|
||||||
// rotational
|
// rotational
|
||||||
input: Controller.Standard.LT,
|
input: Controller.Standard.LT,
|
||||||
|
@ -109,6 +111,7 @@ TOUCH_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
type: "linear",
|
type: "linear",
|
||||||
modelURL: BASE_URL + "touch_l_bumper.fbx",
|
modelURL: BASE_URL + "touch_l_bumper.fbx",
|
||||||
naturalPosition: { x: 0.00008066371083259583, y: -0.02715788595378399, z: -0.02448512241244316 },
|
naturalPosition: { x: 0.00008066371083259583, y: -0.02715788595378399, z: -0.02448512241244316 },
|
||||||
|
naturalDimensions: { x: 0.017444, y: 0.020297, z: 0.026003 },
|
||||||
|
|
||||||
// linear properties
|
// linear properties
|
||||||
// Offset from origin = 0.36470, 0.11048, 0.11066
|
// Offset from origin = 0.36470, 0.11048, 0.11066
|
||||||
|
@ -132,6 +135,7 @@ TOUCH_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
type: "joystick",
|
type: "joystick",
|
||||||
modelURL: BASE_URL + "touch_l_joystick.fbx",
|
modelURL: BASE_URL + "touch_l_joystick.fbx",
|
||||||
naturalPosition: { x: 0.0075613949447870255, y: -0.008225866593420506, z: 0.004792703315615654 },
|
naturalPosition: { x: 0.0075613949447870255, y: -0.008225866593420506, z: 0.004792703315615654 },
|
||||||
|
naturalDimensions: { x: 0.027386, y: 0.033254, z: 0.027272 },
|
||||||
|
|
||||||
// joystick
|
// joystick
|
||||||
xInput: "OculusTouch.LX",
|
xInput: "OculusTouch.LX",
|
||||||
|
@ -156,6 +160,7 @@ TOUCH_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
type: "linear",
|
type: "linear",
|
||||||
modelURL: BASE_URL + "touch_l_button_x.fbx",
|
modelURL: BASE_URL + "touch_l_button_x.fbx",
|
||||||
naturalPosition: { x: -0.009307309985160828, y: -0.00005015172064304352, z: -0.012594521045684814 },
|
naturalPosition: { x: -0.009307309985160828, y: -0.00005015172064304352, z: -0.012594521045684814 },
|
||||||
|
naturalDimensions: { x: 0.009861, y: 0.004345, z: 0.00982 },
|
||||||
|
|
||||||
input: "OculusTouch.X",
|
input: "OculusTouch.X",
|
||||||
axis: { x: 0, y: -1, z: 0 },
|
axis: { x: 0, y: -1, z: 0 },
|
||||||
|
@ -177,6 +182,7 @@ TOUCH_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
type: "linear",
|
type: "linear",
|
||||||
modelURL: BASE_URL + "touch_l_button_y.fbx",
|
modelURL: BASE_URL + "touch_l_button_y.fbx",
|
||||||
naturalPosition: { x: -0.01616849936544895, y: -0.000050364527851343155, z: 0.0017703399062156677 },
|
naturalPosition: { x: -0.01616849936544895, y: -0.000050364527851343155, z: 0.0017703399062156677 },
|
||||||
|
naturalDimensions: { x: 0.010014, y: 0.004412, z: 0.009972 },
|
||||||
|
|
||||||
input: "OculusTouch.Y",
|
input: "OculusTouch.Y",
|
||||||
axis: { x: 0, y: -1, z: 0 },
|
axis: { x: 0, y: -1, z: 0 },
|
||||||
|
@ -214,6 +220,7 @@ TOUCH_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "Oculus-Labels-R.fbx",
|
modelURL: BASE_URL + "Oculus-Labels-R.fbx",
|
||||||
naturalPosition: { x: 0.009739525616168976, y: -0.0017818436026573181, z: 0.016794726252555847 },
|
naturalPosition: { x: 0.009739525616168976, y: -0.0017818436026573181, z: 0.016794726252555847 },
|
||||||
|
naturalDimensions: { x: 0.129049, y: 0.078297, z: 0.139492 },
|
||||||
|
|
||||||
textureName: "blank",
|
textureName: "blank",
|
||||||
defaultTextureLayer: "blank",
|
defaultTextureLayer: "blank",
|
||||||
|
@ -243,6 +250,7 @@ TOUCH_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
type: "rotational",
|
type: "rotational",
|
||||||
modelURL: BASE_URL + "touch_r_trigger.fbx",
|
modelURL: BASE_URL + "touch_r_trigger.fbx",
|
||||||
naturalPosition: { x: -0.0008544912561774254, y: -0.019867943599820137, z: 0.018800459802150726 },
|
naturalPosition: { x: -0.0008544912561774254, y: -0.019867943599820137, z: 0.018800459802150726 },
|
||||||
|
naturalDimensions: { x: 0.027384, y: 0.025201, z: 0.018425 },
|
||||||
|
|
||||||
// rotational
|
// rotational
|
||||||
input: "OculusTouch.RT",
|
input: "OculusTouch.RT",
|
||||||
|
@ -268,6 +276,7 @@ TOUCH_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
type: "linear",
|
type: "linear",
|
||||||
modelURL: BASE_URL + "touch_r_bumper.fbx",
|
modelURL: BASE_URL + "touch_r_bumper.fbx",
|
||||||
naturalPosition: { x: -0.0000806618481874466, y: -0.027157839387655258, z: -0.024485092610120773 },
|
naturalPosition: { x: -0.0000806618481874466, y: -0.027157839387655258, z: -0.024485092610120773 },
|
||||||
|
naturalDimensions: { x: 0.017268, y: 0.020366, z: 0.02599 },
|
||||||
|
|
||||||
// linear properties
|
// linear properties
|
||||||
// Offset from origin = 0.36470, 0.11048, 0.11066
|
// Offset from origin = 0.36470, 0.11048, 0.11066
|
||||||
|
@ -292,6 +301,7 @@ TOUCH_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
type: "joystick",
|
type: "joystick",
|
||||||
modelURL: BASE_URL + "touch_r_joystick.fbx",
|
modelURL: BASE_URL + "touch_r_joystick.fbx",
|
||||||
naturalPosition: { x: -0.007561382371932268, y: -0.008225853554904461, z: 0.00479268841445446 },
|
naturalPosition: { x: -0.007561382371932268, y: -0.008225853554904461, z: 0.00479268841445446 },
|
||||||
|
naturalDimensions: { x: 0.027272, y: 0.033254, z: 0.027272 },
|
||||||
|
|
||||||
// joystick
|
// joystick
|
||||||
xInput: "OculusTouch.RX",
|
xInput: "OculusTouch.RX",
|
||||||
|
@ -316,6 +326,7 @@ TOUCH_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
type: "linear",
|
type: "linear",
|
||||||
modelURL: BASE_URL + "touch_r_button_a.fbx",
|
modelURL: BASE_URL + "touch_r_button_a.fbx",
|
||||||
naturalPosition: { x: 0.009307296946644783, y: -0.00005015172064304352, z: -0.012594504281878471 },
|
naturalPosition: { x: 0.009307296946644783, y: -0.00005015172064304352, z: -0.012594504281878471 },
|
||||||
|
naturalDimensions: { x: 0.00982, y: 0.004345, z: 0.00982 },
|
||||||
|
|
||||||
input: "OculusTouch.A",
|
input: "OculusTouch.A",
|
||||||
axis: { x: 0, y: -1, z: 0 },
|
axis: { x: 0, y: -1, z: 0 },
|
||||||
|
@ -337,6 +348,7 @@ TOUCH_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
type: "linear",
|
type: "linear",
|
||||||
modelURL: BASE_URL + "touch_r_button_b.fbx",
|
modelURL: BASE_URL + "touch_r_button_b.fbx",
|
||||||
naturalPosition: { x: 0.01616847701370716, y: -0.000050364527851343155, z: 0.0017703361809253693 },
|
naturalPosition: { x: 0.01616847701370716, y: -0.000050364527851343155, z: 0.0017703361809253693 },
|
||||||
|
naturalDimensions: { x: 0.009972, y: 0.004412, z: 0.009972 },
|
||||||
|
|
||||||
input: "OculusTouch.B",
|
input: "OculusTouch.B",
|
||||||
axis: { x: 0, y: -1, z: 0 },
|
axis: { x: 0, y: -1, z: 0 },
|
||||||
|
|
|
@ -62,7 +62,7 @@ var TIP_TEXTURE_BASE_URL = BASE_URL + "meshes/controller/vive_tips.fbm/";
|
||||||
|
|
||||||
var viveModelURL = BASE_URL + "meshes/controller/vive_body.fbx";
|
var viveModelURL = BASE_URL + "meshes/controller/vive_body.fbx";
|
||||||
var viveTipsModelURL = BASE_URL + "meshes/controller/vive_tips.fbx";
|
var viveTipsModelURL = BASE_URL + "meshes/controller/vive_tips.fbx";
|
||||||
var viveTriggerModelURL = "meshes/controller/vive_trigger.fbx"
|
var viveTriggerModelURL = "meshes/controller/vive_trigger.fbx";
|
||||||
|
|
||||||
VIVE_CONTROLLER_CONFIGURATION_LEFT = {
|
VIVE_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
name: "Vive",
|
name: "Vive",
|
||||||
|
@ -81,6 +81,7 @@ VIVE_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: viveTipsModelURL,
|
modelURL: viveTipsModelURL,
|
||||||
naturalPosition: {"x":-0.004377640783786774,"y":-0.034371938556432724,"z":0.06769277155399323},
|
naturalPosition: {"x":-0.004377640783786774,"y":-0.034371938556432724,"z":0.06769277155399323},
|
||||||
|
naturalDimensions: {x: 0.191437, y: 0.094095, z: 0.085656},
|
||||||
|
|
||||||
textureName: "Tex.Blank",
|
textureName: "Tex.Blank",
|
||||||
defaultTextureLayer: "blank",
|
defaultTextureLayer: "blank",
|
||||||
|
@ -112,6 +113,7 @@ VIVE_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
xInput: "Vive.LX",
|
xInput: "Vive.LX",
|
||||||
yInput: "Vive.LY",
|
yInput: "Vive.LY",
|
||||||
naturalPosition: {"x":0,"y":0.000979491975158453,"z":0.04872849956154823},
|
naturalPosition: {"x":0,"y":0.000979491975158453,"z":0.04872849956154823},
|
||||||
|
naturalDimensions: {x: 0.042824, y: 0.012537, z: 0.043115},
|
||||||
minValue: 0.0,
|
minValue: 0.0,
|
||||||
maxValue: 1.0,
|
maxValue: 1.0,
|
||||||
minPosition: { x: -0.035, y: 0.004, z: -0.005 },
|
minPosition: { x: -0.035, y: 0.004, z: -0.005 },
|
||||||
|
@ -137,6 +139,7 @@ VIVE_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_trigger.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_trigger.fbx",
|
||||||
input: Controller.Standard.LT,
|
input: Controller.Standard.LT,
|
||||||
naturalPosition: {"x":0.000004500150680541992,"y":-0.027690507471561432,"z":0.04830199480056763},
|
naturalPosition: {"x":0.000004500150680541992,"y":-0.027690507471561432,"z":0.04830199480056763},
|
||||||
|
naturalDimensions: {x: 0.019105, y: 0.022189, z: 0.01909},
|
||||||
origin: { x: 0, y: -0.015, z: -0.00 },
|
origin: { x: 0, y: -0.015, z: -0.00 },
|
||||||
minValue: 0.0,
|
minValue: 0.0,
|
||||||
maxValue: 1.0,
|
maxValue: 1.0,
|
||||||
|
@ -147,10 +150,10 @@ VIVE_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
defaultTextureLayer: "normal",
|
defaultTextureLayer: "normal",
|
||||||
textureLayers: {
|
textureLayers: {
|
||||||
normal: {
|
normal: {
|
||||||
defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/black.jpg",
|
defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/black.jpg"
|
||||||
},
|
},
|
||||||
highlight: {
|
highlight: {
|
||||||
defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/yellow.jpg",
|
defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/yellow.jpg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -158,30 +161,35 @@ VIVE_CONTROLLER_CONFIGURATION_LEFT = {
|
||||||
l_grip: {
|
l_grip: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_l_grip.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_l_grip.fbx",
|
||||||
naturalPosition: {"x":-0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226}
|
naturalPosition: {"x":-0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226},
|
||||||
|
naturalDimensions: {x: 0.010094, y: 0.015064, z: 0.029552}
|
||||||
},
|
},
|
||||||
|
|
||||||
r_grip: {
|
r_grip: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_r_grip.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_r_grip.fbx",
|
||||||
naturalPosition: {"x":0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226}
|
naturalPosition: {"x":0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226},
|
||||||
|
naturalDimensions: {x: 0.010083, y: 0.015064, z: 0.029552}
|
||||||
},
|
},
|
||||||
|
|
||||||
sys_button: {
|
sys_button: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_sys_button.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_sys_button.fbx",
|
||||||
naturalPosition: {"x":0,"y":0.0020399854984134436,"z":0.08825899660587311}
|
naturalPosition: {"x":0,"y":0.0020399854984134436,"z":0.08825899660587311},
|
||||||
|
naturalDimensions: {x: 0.009986, y: 0.004282, z: 0.010264}
|
||||||
},
|
},
|
||||||
|
|
||||||
button: {
|
button: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_button.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_button.fbx",
|
||||||
naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564}
|
naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564},
|
||||||
|
naturalDimensions: {x: 0.009986, y: 0.004496, z: 0.010121}
|
||||||
},
|
},
|
||||||
button2: {
|
button2: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_button.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_button.fbx",
|
||||||
naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564}
|
naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564},
|
||||||
|
naturalDimensions: {x: 0.009986, y: 0.004496, z: 0.010121}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,6 +219,7 @@ VIVE_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: viveTipsModelURL,
|
modelURL: viveTipsModelURL,
|
||||||
naturalPosition: {"x":-0.004377640783786774,"y":-0.034371938556432724,"z":0.06769277155399323},
|
naturalPosition: {"x":-0.004377640783786774,"y":-0.034371938556432724,"z":0.06769277155399323},
|
||||||
|
naturalDimensions: {x: 0.191437, y: 0.094095, z: 0.085656},
|
||||||
|
|
||||||
textureName: "Tex.Blank",
|
textureName: "Tex.Blank",
|
||||||
|
|
||||||
|
@ -243,6 +252,7 @@ VIVE_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
xInput: "Vive.RX",
|
xInput: "Vive.RX",
|
||||||
yInput: "Vive.RY",
|
yInput: "Vive.RY",
|
||||||
naturalPosition: { x: 0, y: 0.000979491975158453, z: 0.04872849956154823 },
|
naturalPosition: { x: 0, y: 0.000979491975158453, z: 0.04872849956154823 },
|
||||||
|
naturalDimensions: {x: 0.042824, y: 0.012537, z: 0.043115},
|
||||||
minValue: 0.0,
|
minValue: 0.0,
|
||||||
maxValue: 1.0,
|
maxValue: 1.0,
|
||||||
minPosition: { x: -0.035, y: 0.004, z: -0.005 },
|
minPosition: { x: -0.035, y: 0.004, z: -0.005 },
|
||||||
|
@ -268,6 +278,7 @@ VIVE_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_trigger.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_trigger.fbx",
|
||||||
input: Controller.Standard.RT,
|
input: Controller.Standard.RT,
|
||||||
naturalPosition: {"x":0.000004500150680541992,"y":-0.027690507471561432,"z":0.04830199480056763},
|
naturalPosition: {"x":0.000004500150680541992,"y":-0.027690507471561432,"z":0.04830199480056763},
|
||||||
|
naturalDimensions: {x: 0.019105, y: 0.022189, z: 0.01909},
|
||||||
origin: { x: 0, y: -0.015, z: -0.00 },
|
origin: { x: 0, y: -0.015, z: -0.00 },
|
||||||
minValue: 0.0,
|
minValue: 0.0,
|
||||||
maxValue: 1.0,
|
maxValue: 1.0,
|
||||||
|
@ -278,10 +289,10 @@ VIVE_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
defaultTextureLayer: "normal",
|
defaultTextureLayer: "normal",
|
||||||
textureLayers: {
|
textureLayers: {
|
||||||
normal: {
|
normal: {
|
||||||
defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/black.jpg",
|
defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/black.jpg"
|
||||||
},
|
},
|
||||||
highlight: {
|
highlight: {
|
||||||
defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/yellow.jpg",
|
defaultTextureURL: BASE_URL + viveTriggerModelURL + "/Trigger.fbm/yellow.jpg"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -289,30 +300,35 @@ VIVE_CONTROLLER_CONFIGURATION_RIGHT = {
|
||||||
l_grip: {
|
l_grip: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_l_grip.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_l_grip.fbx",
|
||||||
naturalPosition: {"x":-0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226}
|
naturalPosition: {"x":-0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226},
|
||||||
|
naturalDimensions: {x: 0.010094, y: 0.015064, z: 0.029552}
|
||||||
},
|
},
|
||||||
|
|
||||||
r_grip: {
|
r_grip: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_r_grip.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_r_grip.fbx",
|
||||||
naturalPosition: {"x":0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226}
|
naturalPosition: {"x":0.01720449887216091,"y":-0.014324013143777847,"z":0.08714400231838226},
|
||||||
|
naturalDimensions: {x: 0.010083, y: 0.015064, z: 0.029552}
|
||||||
},
|
},
|
||||||
|
|
||||||
sys_button: {
|
sys_button: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_sys_button.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_sys_button.fbx",
|
||||||
naturalPosition: {"x":0,"y":0.0020399854984134436,"z":0.08825899660587311}
|
naturalPosition: {"x":0,"y":0.0020399854984134436,"z":0.08825899660587311},
|
||||||
|
naturalDimensions: {x: 0.009986, y: 0.004282, z: 0.010264}
|
||||||
},
|
},
|
||||||
|
|
||||||
button: {
|
button: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_button.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_button.fbx",
|
||||||
naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564}
|
naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564},
|
||||||
|
naturalDimensions: {x: 0.009986, y: 0.004496, z: 0.010121}
|
||||||
},
|
},
|
||||||
button2: {
|
button2: {
|
||||||
type: "static",
|
type: "static",
|
||||||
modelURL: BASE_URL + "meshes/controller/vive_button.fbx",
|
modelURL: BASE_URL + "meshes/controller/vive_button.fbx",
|
||||||
naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564}
|
naturalPosition: {"x":0,"y":0.005480996798723936,"z":0.019918499514460564},
|
||||||
|
naturalDimensions: {x: 0.009986, y: 0.004496, z: 0.010121}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||||
//
|
//
|
||||||
/* global getControllerWorldLocation, Tablet, WebTablet:true, HMD, Settings, Script,
|
/* global getControllerWorldLocation, Tablet, WebTablet:true, HMD, Settings, Script,
|
||||||
Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp, Controller, Mat4 */
|
Vec3, Quat, MyAvatar, Entities, Overlays, Camera, Messages, Xform, clamp, Controller, Mat4, resizeTablet */
|
||||||
|
|
||||||
Script.include(Script.resolvePath("../libraries/utils.js"));
|
Script.include(Script.resolvePath("../libraries/utils.js"));
|
||||||
Script.include(Script.resolvePath("../libraries/controllers.js"));
|
Script.include(Script.resolvePath("../libraries/controllers.js"));
|
||||||
|
@ -42,56 +42,20 @@ var LOCAL_TABLET_MODEL_PATH = Script.resourcesPath() + "meshes/tablet-with-home-
|
||||||
// returns object with two fields:
|
// returns object with two fields:
|
||||||
// * position - position in front of the user
|
// * position - position in front of the user
|
||||||
// * rotation - rotation of entity so it faces the user.
|
// * rotation - rotation of entity so it faces the user.
|
||||||
function calcSpawnInfo(hand, tabletHeight, landscape) {
|
function calcSpawnInfo(hand, landscape) {
|
||||||
var finalPosition;
|
var finalPosition;
|
||||||
|
|
||||||
var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position;
|
var headPos = (HMD.active && Camera.mode === "first person") ? HMD.position : Camera.position;
|
||||||
var headRot = (HMD.active && Camera.mode === "first person") ? HMD.orientation : Camera.orientation;
|
var headRot = (HMD.active && Camera.mode === "first person") ? HMD.orientation : Camera.orientation;
|
||||||
|
|
||||||
if (!hand) {
|
var forward = Quat.getForward(headRot);
|
||||||
hand = NO_HANDS;
|
var FORWARD_OFFSET = 0.6 * MyAvatar.sensorToWorldScale;
|
||||||
}
|
finalPosition = Vec3.sum(headPos, Vec3.multiply(FORWARD_OFFSET, forward));
|
||||||
|
var orientation = Quat.lookAt({x: 0, y: 0, z: 0}, forward, {x: 0, y: 1, z: 0});
|
||||||
var handController = null;
|
return {
|
||||||
if (HMD.active && hand !== NO_HANDS) {
|
position: finalPosition,
|
||||||
handController = getControllerWorldLocation(hand, true);
|
rotation: landscape ? Quat.multiply(orientation, ROT_LANDSCAPE) : Quat.multiply(orientation, ROT_Y_180)
|
||||||
}
|
};
|
||||||
|
|
||||||
if (handController && handController.valid) {
|
|
||||||
// Orient tablet per hand pitch and yaw.
|
|
||||||
// Angle it back similar to holding it like a book.
|
|
||||||
// Move tablet up so that hand is at bottom.
|
|
||||||
// Move tablet back so that hand is in front.
|
|
||||||
|
|
||||||
var position = handController.position;
|
|
||||||
var rotation = handController.rotation;
|
|
||||||
|
|
||||||
if (hand === Controller.Standard.LeftHand) {
|
|
||||||
rotation = Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, 90, 0));
|
|
||||||
} else {
|
|
||||||
rotation = Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(0, -90, 0));
|
|
||||||
}
|
|
||||||
var normal = Vec3.multiplyQbyV(rotation, Vec3.UNIT_NEG_Y);
|
|
||||||
var lookAt = Quat.lookAt(Vec3.ZERO, normal, Vec3.multiplyQbyV(MyAvatar.orientation, Vec3.UNIT_Y));
|
|
||||||
var TABLET_RAKE_ANGLE = 30;
|
|
||||||
rotation = Quat.multiply(Quat.angleAxis(TABLET_RAKE_ANGLE, Vec3.multiplyQbyV(lookAt, Vec3.UNIT_X)), lookAt);
|
|
||||||
|
|
||||||
var RELATIVE_SPAWN_OFFSET = { x: 0, y: 0.6, z: 0.1 };
|
|
||||||
position = Vec3.sum(position, Vec3.multiplyQbyV(rotation, Vec3.multiply(tabletHeight, RELATIVE_SPAWN_OFFSET)));
|
|
||||||
|
|
||||||
return {
|
|
||||||
position: position,
|
|
||||||
rotation: landscape ? Quat.multiply(rotation, { x: 0.0, y: 0.0, z: 0.707, w: 0.707 }) : rotation
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
var forward = Quat.getForward(headRot);
|
|
||||||
finalPosition = Vec3.sum(headPos, Vec3.multiply(0.6, forward));
|
|
||||||
var orientation = Quat.lookAt({x: 0, y: 0, z: 0}, forward, {x: 0, y: 1, z: 0});
|
|
||||||
return {
|
|
||||||
position: finalPosition,
|
|
||||||
rotation: landscape ? Quat.multiply(orientation, ROT_LANDSCAPE) : Quat.multiply(orientation, ROT_Y_180)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -106,19 +70,22 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
|
|
||||||
var _this = this;
|
var _this = this;
|
||||||
|
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
|
|
||||||
// scale factor of natural tablet dimensions.
|
// scale factor of natural tablet dimensions.
|
||||||
this.width = width || DEFAULT_WIDTH;
|
var tabletWidth = (width || DEFAULT_WIDTH) * sensorScaleFactor;
|
||||||
var tabletScaleFactor = this.width / TABLET_NATURAL_DIMENSIONS.x;
|
var tabletScaleFactor = tabletWidth / TABLET_NATURAL_DIMENSIONS.x;
|
||||||
this.height = TABLET_NATURAL_DIMENSIONS.y * tabletScaleFactor;
|
var tabletHeight = TABLET_NATURAL_DIMENSIONS.y * tabletScaleFactor;
|
||||||
this.depth = TABLET_NATURAL_DIMENSIONS.z * tabletScaleFactor;
|
var tabletDepth = TABLET_NATURAL_DIMENSIONS.z * tabletScaleFactor;
|
||||||
this.landscape = false;
|
this.landscape = false;
|
||||||
|
|
||||||
visible = visible === true;
|
visible = visible === true;
|
||||||
|
|
||||||
|
var tabletDpi;
|
||||||
if (dpi) {
|
if (dpi) {
|
||||||
this.dpi = dpi;
|
tabletDpi = dpi;
|
||||||
} else {
|
} else {
|
||||||
this.dpi = DEFAULT_DPI * (DEFAULT_WIDTH / this.width);
|
tabletDpi = DEFAULT_DPI * (DEFAULT_WIDTH / tabletWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
var modelURL = LOCAL_TABLET_MODEL_PATH;
|
var modelURL = LOCAL_TABLET_MODEL_PATH;
|
||||||
|
@ -132,7 +99,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
userData: JSON.stringify({
|
userData: JSON.stringify({
|
||||||
"grabbableKey": {"grabbable": true}
|
"grabbableKey": {"grabbable": true}
|
||||||
}),
|
}),
|
||||||
dimensions: this.getDimensions(),
|
dimensions: { x: tabletWidth, y: tabletHeight, z: tabletDepth },
|
||||||
parentID: AVATAR_SELF_ID,
|
parentID: AVATAR_SELF_ID,
|
||||||
visible: visible
|
visible: visible
|
||||||
};
|
};
|
||||||
|
@ -152,8 +119,8 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
Overlays.deleteOverlay(this.webOverlayID);
|
Overlays.deleteOverlay(this.webOverlayID);
|
||||||
}
|
}
|
||||||
|
|
||||||
var WEB_ENTITY_Z_OFFSET = (this.depth / 2);
|
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2) * (1 / sensorScaleFactor);
|
||||||
var WEB_ENTITY_Y_OFFSET = 0.004;
|
var WEB_ENTITY_Y_OFFSET = 0.004 * (1 / sensorScaleFactor);
|
||||||
|
|
||||||
this.webOverlayID = Overlays.addOverlay("web3d", {
|
this.webOverlayID = Overlays.addOverlay("web3d", {
|
||||||
name: "WebTablet Web",
|
name: "WebTablet Web",
|
||||||
|
@ -161,7 +128,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
localRotation: Quat.angleAxis(180, Y_AXIS),
|
localRotation: Quat.angleAxis(180, Y_AXIS),
|
||||||
resolution: this.getTabletTextureResolution(),
|
resolution: this.getTabletTextureResolution(),
|
||||||
dpi: this.dpi,
|
dpi: tabletDpi,
|
||||||
color: { red: 255, green: 255, blue: 255 },
|
color: { red: 255, green: 255, blue: 255 },
|
||||||
alpha: 1.0,
|
alpha: 1.0,
|
||||||
parentID: this.tabletEntityID,
|
parentID: this.tabletEntityID,
|
||||||
|
@ -170,7 +137,7 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
visible: visible
|
visible: visible
|
||||||
});
|
});
|
||||||
|
|
||||||
var HOME_BUTTON_Y_OFFSET = (this.height / 2) - (this.height / 20);
|
var HOME_BUTTON_Y_OFFSET = ((tabletHeight / 2) - (tabletHeight / 20)) * (1 / sensorScaleFactor);
|
||||||
this.homeButtonID = Overlays.addOverlay("sphere", {
|
this.homeButtonID = Overlays.addOverlay("sphere", {
|
||||||
name: "homeButton",
|
name: "homeButton",
|
||||||
localPosition: {x: -0.001, y: -HOME_BUTTON_Y_OFFSET, z: 0.0},
|
localPosition: {x: -0.001, y: -HOME_BUTTON_Y_OFFSET, z: 0.0},
|
||||||
|
@ -247,10 +214,6 @@ WebTablet = function (url, width, dpi, hand, clientOnly, location, visible) {
|
||||||
Camera.modeUpdated.connect(this.myCameraModeChanged);
|
Camera.modeUpdated.connect(this.myCameraModeChanged);
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.getDimensions = function() {
|
|
||||||
return { x: this.width, y: this.height, z: this.depth };
|
|
||||||
};
|
|
||||||
|
|
||||||
WebTablet.prototype.getTabletTextureResolution = function() {
|
WebTablet.prototype.getTabletTextureResolution = function() {
|
||||||
if (this.landscape) {
|
if (this.landscape) {
|
||||||
return { x: TABLET_TEXTURE_RESOLUTION.y , y: TABLET_TEXTURE_RESOLUTION.x };
|
return { x: TABLET_TEXTURE_RESOLUTION.y , y: TABLET_TEXTURE_RESOLUTION.x };
|
||||||
|
@ -301,31 +264,8 @@ WebTablet.prototype.getOverlayObject = function () {
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.setWidth = function (width) {
|
WebTablet.prototype.setWidth = function (width) {
|
||||||
|
// imported from libraries/utils.js
|
||||||
// scale factor of natural tablet dimensions.
|
resizeTablet(width);
|
||||||
this.width = width || DEFAULT_WIDTH;
|
|
||||||
var tabletScaleFactor = this.width / TABLET_NATURAL_DIMENSIONS.x;
|
|
||||||
this.height = TABLET_NATURAL_DIMENSIONS.y * tabletScaleFactor;
|
|
||||||
this.depth = TABLET_NATURAL_DIMENSIONS.z * tabletScaleFactor;
|
|
||||||
this.dpi = DEFAULT_DPI * (DEFAULT_WIDTH / this.width);
|
|
||||||
|
|
||||||
// update tablet model dimensions
|
|
||||||
Overlays.editOverlay(this.tabletEntityID, { dimensions: this.getDimensions() });
|
|
||||||
|
|
||||||
// update webOverlay
|
|
||||||
var WEB_ENTITY_Z_OFFSET = (this.depth / 2);
|
|
||||||
var WEB_ENTITY_Y_OFFSET = 0.004;
|
|
||||||
Overlays.editOverlay(this.webOverlayID, {
|
|
||||||
localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
|
||||||
dpi: this.dpi
|
|
||||||
});
|
|
||||||
|
|
||||||
// update homeButton
|
|
||||||
var HOME_BUTTON_Y_OFFSET = (this.height / 2) - (this.height / 20);
|
|
||||||
Overlays.editOverlay(this.homeButtonID, {
|
|
||||||
localPosition: {x: -0.001, y: -HOME_BUTTON_Y_OFFSET, z: 0.0},
|
|
||||||
dimensions: { x: 4 * tabletScaleFactor, y: 4 * tabletScaleFactor, z: 4 * tabletScaleFactor}
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.destroy = function () {
|
WebTablet.prototype.destroy = function () {
|
||||||
|
@ -345,11 +285,9 @@ WebTablet.prototype.destroy = function () {
|
||||||
WebTablet.prototype.geometryChanged = function (geometry) {
|
WebTablet.prototype.geometryChanged = function (geometry) {
|
||||||
if (!HMD.active) {
|
if (!HMD.active) {
|
||||||
var tabletProperties = {};
|
var tabletProperties = {};
|
||||||
|
|
||||||
// compute position, rotation & parentJointIndex of the tablet
|
// compute position, rotation & parentJointIndex of the tablet
|
||||||
this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties);
|
this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties);
|
||||||
// TODO -- is this still needed?
|
Overlays.editOverlay(HMD.tabletID, tabletProperties);
|
||||||
// Entities.editEntity(this.tabletEntityID, tabletProperties);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -380,10 +318,19 @@ WebTablet.prototype.calculateWorldAttitudeRelativeToCamera = function (windowPos
|
||||||
windowPos.y = clamp(windowPos.y, Y_CLAMP, Window.innerHeight - Y_CLAMP);
|
windowPos.y = clamp(windowPos.y, Y_CLAMP, Window.innerHeight - Y_CLAMP);
|
||||||
|
|
||||||
var fov = (Settings.getValue('fieldOfView') || DEFAULT_VERTICAL_FIELD_OF_VIEW) * (Math.PI / 180);
|
var fov = (Settings.getValue('fieldOfView') || DEFAULT_VERTICAL_FIELD_OF_VIEW) * (Math.PI / 180);
|
||||||
|
|
||||||
|
// scale factor of natural tablet dimensions.
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
|
var tabletWidth = getTabletWidthFromSettings() * sensorScaleFactor;
|
||||||
|
var tabletScaleFactor = tabletWidth / TABLET_NATURAL_DIMENSIONS.x;
|
||||||
|
var tabletHeight = TABLET_NATURAL_DIMENSIONS.y * tabletScaleFactor;
|
||||||
|
var tabletDepth = TABLET_NATURAL_DIMENSIONS.z * tabletScaleFactor;
|
||||||
|
var tabletDpi = DEFAULT_DPI * (DEFAULT_WIDTH / tabletWidth);
|
||||||
|
|
||||||
var MAX_PADDING_FACTOR = 2.2;
|
var MAX_PADDING_FACTOR = 2.2;
|
||||||
var PADDING_FACTOR = Math.min(Window.innerHeight / this.getTabletTextureResolution().y, MAX_PADDING_FACTOR);
|
var PADDING_FACTOR = Math.min(Window.innerHeight / this.getTabletTextureResolution().y, MAX_PADDING_FACTOR);
|
||||||
var TABLET_HEIGHT = (this.getTabletTextureResolution().y / this.dpi) * INCHES_TO_METERS;
|
var TABLET_HEIGHT = (this.getTabletTextureResolution().y / tabletDpi) * INCHES_TO_METERS;
|
||||||
var WEB_ENTITY_Z_OFFSET = (this.depth / 2);
|
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2);
|
||||||
|
|
||||||
// calcualte distance from camera
|
// calcualte distance from camera
|
||||||
var dist = (PADDING_FACTOR * TABLET_HEIGHT) / (2 * Math.tan(fov / 2) * (DESKTOP_TABLET_SCALE / 100)) - WEB_ENTITY_Z_OFFSET;
|
var dist = (PADDING_FACTOR * TABLET_HEIGHT) / (2 * Math.tan(fov / 2) * (DESKTOP_TABLET_SCALE / 100)) - WEB_ENTITY_Z_OFFSET;
|
||||||
|
@ -423,7 +370,7 @@ WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, useMou
|
||||||
tabletProperties.parentJointIndex = SENSOR_TO_ROOM_MATRIX;
|
tabletProperties.parentJointIndex = SENSOR_TO_ROOM_MATRIX;
|
||||||
|
|
||||||
// compute the appropriate position of the tablet, near the hand controller that was used to spawn it.
|
// compute the appropriate position of the tablet, near the hand controller that was used to spawn it.
|
||||||
var spawnInfo = calcSpawnInfo(hand, this.height, this.landscape);
|
var spawnInfo = calcSpawnInfo(hand, this.landscape);
|
||||||
tabletProperties.position = spawnInfo.position;
|
tabletProperties.position = spawnInfo.position;
|
||||||
tabletProperties.rotation = spawnInfo.rotation;
|
tabletProperties.rotation = spawnInfo.rotation;
|
||||||
} else {
|
} else {
|
||||||
|
@ -446,12 +393,10 @@ WebTablet.prototype.calculateTabletAttachmentProperties = function (hand, useMou
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.onHmdChanged = function () {
|
WebTablet.prototype.onHmdChanged = function () {
|
||||||
|
|
||||||
var tabletProperties = {};
|
var tabletProperties = {};
|
||||||
// compute position, rotation & parentJointIndex of the tablet
|
// compute position, rotation & parentJointIndex of the tablet
|
||||||
this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties);
|
this.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties);
|
||||||
// TODO -- is this still needed?
|
Overlays.editOverlay(HMD.tabletID, tabletProperties);
|
||||||
// Entities.editEntity(this.tabletEntityID, tabletProperties);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.pickle = function () {
|
WebTablet.prototype.pickle = function () {
|
||||||
|
@ -531,16 +476,7 @@ WebTablet.prototype.mousePressEvent = function (event) {
|
||||||
};
|
};
|
||||||
|
|
||||||
WebTablet.prototype.cameraModeChanged = function (newMode) {
|
WebTablet.prototype.cameraModeChanged = function (newMode) {
|
||||||
// reposition the tablet.
|
;
|
||||||
// This allows HMD.position to reflect the new camera mode.
|
|
||||||
if (HMD.active) {
|
|
||||||
var self = this;
|
|
||||||
var tabletProperties = {};
|
|
||||||
// compute position, rotation & parentJointIndex of the tablet
|
|
||||||
self.calculateTabletAttachmentProperties(NO_HANDS, false, tabletProperties);
|
|
||||||
// TODO -- is this still needed?
|
|
||||||
// Entities.editEntity(self.tabletEntityID, tabletProperties);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection) {
|
function rayIntersectPlane(planePosition, planeNormal, rayStart, rayDirection) {
|
||||||
|
|
|
@ -18,15 +18,20 @@ getGrabCommunications = function getFarGrabCommunications() {
|
||||||
// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378
|
// this offset needs to match the one in libraries/display-plugins/src/display-plugins/hmd/HmdDisplayPlugin.cpp:378
|
||||||
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
|
var GRAB_POINT_SPHERE_OFFSET = { x: 0.04, y: 0.13, z: 0.039 }; // x = upward, y = forward, z = lateral
|
||||||
|
|
||||||
getGrabPointSphereOffset = function(handController) {
|
getGrabPointSphereOffset = function(handController, ignoreSensorToWorldScale) {
|
||||||
if (handController === Controller.Standard.RightHand) {
|
var offset = GRAB_POINT_SPHERE_OFFSET;
|
||||||
return GRAB_POINT_SPHERE_OFFSET;
|
if (handController === Controller.Standard.LeftHand) {
|
||||||
|
offset = {
|
||||||
|
x: -GRAB_POINT_SPHERE_OFFSET.x,
|
||||||
|
y: GRAB_POINT_SPHERE_OFFSET.y,
|
||||||
|
z: GRAB_POINT_SPHERE_OFFSET.z
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (ignoreSensorToWorldScale) {
|
||||||
|
return offset;
|
||||||
|
} else {
|
||||||
|
return Vec3.multiply(MyAvatar.sensorToWorldScale, offset);
|
||||||
}
|
}
|
||||||
return {
|
|
||||||
x: GRAB_POINT_SPHERE_OFFSET.x * -1,
|
|
||||||
y: GRAB_POINT_SPHERE_OFFSET.y,
|
|
||||||
z: GRAB_POINT_SPHERE_OFFSET.z
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// controllerWorldLocation is where the controller would be, in-world, with an added offset
|
// controllerWorldLocation is where the controller would be, in-world, with an added offset
|
||||||
|
@ -53,7 +58,7 @@ getControllerWorldLocation = function (handController, doOffset) {
|
||||||
|
|
||||||
} else if (!HMD.isHandControllerAvailable()) {
|
} else if (!HMD.isHandControllerAvailable()) {
|
||||||
// NOTE: keep this offset in sync with scripts/system/controllers/handControllerPointer.js:493
|
// NOTE: keep this offset in sync with scripts/system/controllers/handControllerPointer.js:493
|
||||||
var VERTICAL_HEAD_LASER_OFFSET = 0.1;
|
var VERTICAL_HEAD_LASER_OFFSET = 0.1 * MyAvatar.sensorToWorldScale;
|
||||||
position = Vec3.sum(Camera.position, Vec3.multiplyQbyV(Camera.orientation, {x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0}));
|
position = Vec3.sum(Camera.position, Vec3.multiplyQbyV(Camera.orientation, {x: 0, y: VERTICAL_HEAD_LASER_OFFSET, z: 0}));
|
||||||
orientation = Quat.multiply(Camera.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));
|
orientation = Quat.multiply(Camera.orientation, Quat.angleAxis(-90, { x: 1, y: 0, z: 0 }));
|
||||||
valid = true;
|
valid = true;
|
||||||
|
|
|
@ -351,3 +351,66 @@ clamp = function(val, min, max){
|
||||||
flatten = function(array) {
|
flatten = function(array) {
|
||||||
return [].concat.apply([], array);
|
return [].concat.apply([], array);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTabletWidthFromSettings = function () {
|
||||||
|
var DEFAULT_TABLET_WIDTH = 0.4375;
|
||||||
|
var tablet = Tablet.getTablet("com.highfidelity.interface.tablet.system");
|
||||||
|
var toolbarMode = tablet.toolbarMode;
|
||||||
|
var DEFAULT_TABLET_SCALE = 100;
|
||||||
|
var tabletScalePercentage = DEFAULT_TABLET_SCALE;
|
||||||
|
if (!toolbarMode) {
|
||||||
|
if (HMD.active) {
|
||||||
|
tabletScalePercentage = Settings.getValue("hmdTabletScale") || DEFAULT_TABLET_SCALE;
|
||||||
|
} else {
|
||||||
|
tabletScalePercentage = Settings.getValue("desktopTabletScale") || DEFAULT_TABLET_SCALE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return DEFAULT_TABLET_WIDTH * (tabletScalePercentage / 100);
|
||||||
|
};
|
||||||
|
|
||||||
|
resizeTablet = function (width, newParentJointIndex, sensorToWorldScaleOverride) {
|
||||||
|
|
||||||
|
if (!HMD.tabletID || !HMD.tabletScreenID || !HMD.homeButtonID) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sensorScaleFactor = sensorToWorldScaleOverride || MyAvatar.sensorToWorldScale;
|
||||||
|
var sensorScaleOffsetOverride = 1;
|
||||||
|
var SENSOR_TO_ROOM_MATRIX = 65534;
|
||||||
|
var parentJointIndex = newParentJointIndex || Overlays.getProperty(HMD.tabletID, "parentJointIndex");
|
||||||
|
if (parentJointIndex === SENSOR_TO_ROOM_MATRIX) {
|
||||||
|
sensorScaleOffsetOverride = 1 / sensorScaleFactor;
|
||||||
|
}
|
||||||
|
|
||||||
|
// will need to be recaclulated if dimensions of fbx model change.
|
||||||
|
var TABLET_NATURAL_DIMENSIONS = {x: 33.797, y: 50.129, z: 2.269};
|
||||||
|
var DEFAULT_DPI = 34;
|
||||||
|
var DEFAULT_WIDTH = 0.4375;
|
||||||
|
|
||||||
|
// scale factor of natural tablet dimensions.
|
||||||
|
var tabletWidth = (width || DEFAULT_WIDTH) * sensorScaleFactor;
|
||||||
|
var tabletScaleFactor = tabletWidth / TABLET_NATURAL_DIMENSIONS.x;
|
||||||
|
var tabletHeight = TABLET_NATURAL_DIMENSIONS.y * tabletScaleFactor;
|
||||||
|
var tabletDepth = TABLET_NATURAL_DIMENSIONS.z * tabletScaleFactor;
|
||||||
|
var tabletDpi = DEFAULT_DPI * (DEFAULT_WIDTH / tabletWidth);
|
||||||
|
|
||||||
|
// update tablet model dimensions
|
||||||
|
Overlays.editOverlay(HMD.tabletID, {
|
||||||
|
dimensions: { x: tabletWidth, y: tabletHeight, z: tabletDepth }
|
||||||
|
});
|
||||||
|
|
||||||
|
// update webOverlay
|
||||||
|
var WEB_ENTITY_Z_OFFSET = (tabletDepth / 2) * sensorScaleOffsetOverride;
|
||||||
|
var WEB_ENTITY_Y_OFFSET = 0.004 * sensorScaleOffsetOverride;
|
||||||
|
Overlays.editOverlay(HMD.tabletScreenID, {
|
||||||
|
localPosition: { x: 0, y: WEB_ENTITY_Y_OFFSET, z: -WEB_ENTITY_Z_OFFSET },
|
||||||
|
dpi: tabletDpi
|
||||||
|
});
|
||||||
|
|
||||||
|
// update homeButton
|
||||||
|
var HOME_BUTTON_Y_OFFSET = ((tabletHeight / 2) - (tabletHeight / 20)) * sensorScaleOffsetOverride;
|
||||||
|
Overlays.editOverlay(HMD.homeButtonID, {
|
||||||
|
localPosition: {x: -0.001, y: -HOME_BUTTON_Y_OFFSET, z: 0.0},
|
||||||
|
dimensions: { x: 4 * tabletScaleFactor, y: 4 * tabletScaleFactor, z: 4 * tabletScaleFactor}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
|
@ -207,7 +207,7 @@
|
||||||
notificationOrientation,
|
notificationOrientation,
|
||||||
notificationPosition,
|
notificationPosition,
|
||||||
buttonPosition;
|
buttonPosition;
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
// Notification plane positions
|
// Notification plane positions
|
||||||
noticeY = -y * NOTIFICATION_3D_SCALE - noticeHeight / 2;
|
noticeY = -y * NOTIFICATION_3D_SCALE - noticeHeight / 2;
|
||||||
notificationPosition = { x: 0, y: noticeY, z: 0 };
|
notificationPosition = { x: 0, y: noticeY, z: 0 };
|
||||||
|
@ -221,8 +221,8 @@
|
||||||
|
|
||||||
// Translate plane
|
// Translate plane
|
||||||
originOffset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, NOTIFICATIONS_3D_DIRECTION, 0),
|
originOffset = Vec3.multiplyQbyV(Quat.fromPitchYawRollDegrees(0, NOTIFICATIONS_3D_DIRECTION, 0),
|
||||||
{ x: 0, y: 0, z: -NOTIFICATIONS_3D_DISTANCE });
|
{ x: 0, y: 0, z: -NOTIFICATIONS_3D_DISTANCE * sensorScaleFactor});
|
||||||
originOffset.y += NOTIFICATIONS_3D_ELEVATION;
|
originOffset.y += NOTIFICATIONS_3D_ELEVATION * sensorScaleFactor;
|
||||||
notificationPosition = Vec3.sum(originOffset, notificationPosition);
|
notificationPosition = Vec3.sum(originOffset, notificationPosition);
|
||||||
buttonPosition = Vec3.sum(originOffset, buttonPosition);
|
buttonPosition = Vec3.sum(originOffset, buttonPosition);
|
||||||
|
|
||||||
|
@ -242,14 +242,14 @@
|
||||||
noticeHeight,
|
noticeHeight,
|
||||||
positions,
|
positions,
|
||||||
last;
|
last;
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
if (isOnHMD) {
|
if (isOnHMD) {
|
||||||
// Calculate 3D values from 2D overlay properties.
|
// Calculate 3D values from 2D overlay properties.
|
||||||
|
|
||||||
noticeWidth = notice.width * NOTIFICATION_3D_SCALE + NOTIFICATION_3D_BUTTON_WIDTH;
|
noticeWidth = notice.width * NOTIFICATION_3D_SCALE + NOTIFICATION_3D_BUTTON_WIDTH;
|
||||||
noticeHeight = notice.height * NOTIFICATION_3D_SCALE;
|
noticeHeight = notice.height * NOTIFICATION_3D_SCALE;
|
||||||
|
|
||||||
notice.size = { x: noticeWidth, y: noticeHeight };
|
notice.size = { x: noticeWidth, y: noticeHeight};
|
||||||
|
|
||||||
positions = calculate3DOverlayPositions(noticeWidth, noticeHeight, notice.y);
|
positions = calculate3DOverlayPositions(noticeWidth, noticeHeight, notice.y);
|
||||||
|
|
||||||
|
@ -261,7 +261,7 @@
|
||||||
notice.leftMargin = 2 * notice.leftMargin * NOTIFICATION_3D_SCALE;
|
notice.leftMargin = 2 * notice.leftMargin * NOTIFICATION_3D_SCALE;
|
||||||
notice.bottomMargin = 0;
|
notice.bottomMargin = 0;
|
||||||
notice.rightMargin = 0;
|
notice.rightMargin = 0;
|
||||||
notice.lineHeight = 10.0 * (fontSize / 12.0) * NOTIFICATION_3D_SCALE;
|
notice.lineHeight = 10.0 * (fontSize * sensorScaleFactor / 12.0) * NOTIFICATION_3D_SCALE;
|
||||||
notice.isFacingAvatar = false;
|
notice.isFacingAvatar = false;
|
||||||
|
|
||||||
notificationText = Overlays.addOverlay("text3d", notice);
|
notificationText = Overlays.addOverlay("text3d", notice);
|
||||||
|
@ -366,6 +366,7 @@
|
||||||
buttonProperties,
|
buttonProperties,
|
||||||
i;
|
i;
|
||||||
|
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
if (text.length >= breakPoint) {
|
if (text.length >= breakPoint) {
|
||||||
breaks = count;
|
breaks = count;
|
||||||
}
|
}
|
||||||
|
@ -387,7 +388,7 @@
|
||||||
alpha: backgroundAlpha,
|
alpha: backgroundAlpha,
|
||||||
topMargin: topMargin,
|
topMargin: topMargin,
|
||||||
leftMargin: leftMargin,
|
leftMargin: leftMargin,
|
||||||
font: {size: fontSize},
|
font: {size: fontSize * sensorScaleFactor},
|
||||||
text: text
|
text: text
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -448,7 +449,23 @@
|
||||||
return finishedLines.join('\n');
|
return finishedLines.join('\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function updateNotificationsTexts() {
|
||||||
|
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||||
|
for (var i = 0; i < notifications.length; i++) {
|
||||||
|
var overlayType = Overlays.getOverlayType(notifications[i]);
|
||||||
|
|
||||||
|
if (overlayType === "text3d") {
|
||||||
|
var props = {
|
||||||
|
font: {size: fontSize * sensorScaleFactor},
|
||||||
|
lineHeight: 10.0 * (fontSize * sensorScaleFactor / 12.0) * NOTIFICATION_3D_SCALE
|
||||||
|
};
|
||||||
|
Overlays.editOverlay(notifications[i], props);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function update() {
|
function update() {
|
||||||
|
updateNotificationsTexts();
|
||||||
var noticeOut,
|
var noticeOut,
|
||||||
buttonOut,
|
buttonOut,
|
||||||
arraysOut,
|
arraysOut,
|
||||||
|
|
|
@ -71,9 +71,9 @@
|
||||||
return tabletScalePercentage;
|
return tabletScalePercentage;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateTabletWidthFromSettings() {
|
function updateTabletWidthFromSettings(force) {
|
||||||
var newTabletScalePercentage = getTabletScalePercentageFromSettings();
|
var newTabletScalePercentage = getTabletScalePercentageFromSettings();
|
||||||
if (newTabletScalePercentage !== tabletScalePercentage && UIWebTablet) {
|
if ((force || (newTabletScalePercentage !== tabletScalePercentage)) && UIWebTablet) {
|
||||||
tabletScalePercentage = newTabletScalePercentage;
|
tabletScalePercentage = newTabletScalePercentage;
|
||||||
UIWebTablet.setWidth(DEFAULT_WIDTH * (tabletScalePercentage / 100));
|
UIWebTablet.setWidth(DEFAULT_WIDTH * (tabletScalePercentage / 100));
|
||||||
}
|
}
|
||||||
|
@ -83,6 +83,13 @@
|
||||||
updateTabletWidthFromSettings();
|
updateTabletWidthFromSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onSensorToWorldScaleChanged(sensorScaleFactor) {
|
||||||
|
if (HMD.active) {
|
||||||
|
var newTabletScalePercentage = getTabletScalePercentageFromSettings();
|
||||||
|
resizeTablet(DEFAULT_WIDTH * (newTabletScalePercentage / 100), undefined, sensorScaleFactor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function rezTablet() {
|
function rezTablet() {
|
||||||
if (debugTablet) {
|
if (debugTablet) {
|
||||||
print("TABLET rezzing");
|
print("TABLET rezzing");
|
||||||
|
@ -98,6 +105,7 @@
|
||||||
HMD.homeButtonID = UIWebTablet.homeButtonID;
|
HMD.homeButtonID = UIWebTablet.homeButtonID;
|
||||||
HMD.tabletScreenID = UIWebTablet.webOverlayID;
|
HMD.tabletScreenID = UIWebTablet.webOverlayID;
|
||||||
HMD.displayModeChanged.connect(onHmdChanged);
|
HMD.displayModeChanged.connect(onHmdChanged);
|
||||||
|
MyAvatar.sensorToWorldScaleChanged.connect(onSensorToWorldScaleChanged);
|
||||||
|
|
||||||
tabletRezzed = true;
|
tabletRezzed = true;
|
||||||
}
|
}
|
||||||
|
@ -121,6 +129,7 @@
|
||||||
Overlays.editOverlay(HMD.homeButtonID, { visible: true });
|
Overlays.editOverlay(HMD.homeButtonID, { visible: true });
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, { visible: true });
|
Overlays.editOverlay(HMD.tabletScreenID, { visible: true });
|
||||||
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 });
|
Overlays.editOverlay(HMD.tabletScreenID, { maxFPS: 90 });
|
||||||
|
updateTabletWidthFromSettings(true);
|
||||||
}
|
}
|
||||||
gTablet.tabletShown = true;
|
gTablet.tabletShown = true;
|
||||||
}
|
}
|
||||||
|
@ -185,7 +194,9 @@
|
||||||
|
|
||||||
if (now - validCheckTime > MSECS_PER_SEC) {
|
if (now - validCheckTime > MSECS_PER_SEC) {
|
||||||
validCheckTime = now;
|
validCheckTime = now;
|
||||||
|
|
||||||
updateTabletWidthFromSettings();
|
updateTabletWidthFromSettings();
|
||||||
|
|
||||||
if (UIWebTablet) {
|
if (UIWebTablet) {
|
||||||
UIWebTablet.setLandscape(landscape);
|
UIWebTablet.setLandscape(landscape);
|
||||||
}
|
}
|
||||||
|
|
30
tools/dimensions.mel
Normal file
30
tools/dimensions.mel
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
//
|
||||||
|
// dimensions.mel
|
||||||
|
//
|
||||||
|
// Created by Anthony J. Thibault on September 5th, 2017.
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// Maya Mel script to determine the High Fidelity "naturalDimensions" of a model.
|
||||||
|
|
||||||
|
// get a list of all mesh objects
|
||||||
|
string $meshes[] = `ls -type mesh`;
|
||||||
|
|
||||||
|
// compute the bounding box
|
||||||
|
float $boundingBox[] = `polyEvaluate -boundingBox $meshes`;
|
||||||
|
|
||||||
|
// copy values into variables for readability
|
||||||
|
float $xmin = $boundingBox[0];
|
||||||
|
float $xmax = $boundingBox[1];
|
||||||
|
float $ymin = $boundingBox[2];
|
||||||
|
float $ymax = $boundingBox[3];
|
||||||
|
float $zmin = $boundingBox[4];
|
||||||
|
float $zmax = $boundingBox[5];
|
||||||
|
|
||||||
|
// compute dimensions, and convert from cm to meters
|
||||||
|
vector $dim = <<($xmax - $xmin) / 100.0, ($ymax - $ymin) / 100.0, ($zmax - $zmin) / 100.0>>;
|
||||||
|
|
||||||
|
// print result
|
||||||
|
print $dim;
|
Loading…
Reference in a new issue