mirror of
https://github.com/lubosz/overte.git
synced 2025-04-27 00:15:32 +02:00
Fixed things
This commit is contained in:
commit
796e9e7ab3
114 changed files with 1490 additions and 912 deletions
assignment-client/src
interface
resources/qml
src
Application.cppApplication.h
avatar
raypick
scripting
ui
JSConsole.cppJSConsole.hPreferencesDialog.cppTestingDialog.cppTestingDialog.h
overlays
Base3DOverlay.cppBase3DOverlay.hCircle3DOverlay.cppCube3DOverlay.cppGrid3DOverlay.cppImage3DOverlay.cppLine3DOverlay.cppModelOverlay.cppOverlays.cppOverlaysPayload.cppPlanar3DOverlay.cppPlanar3DOverlay.hRectangle3DOverlay.cppShape3DOverlay.cppSphere3DOverlay.cppText3DOverlay.cppVolume3DOverlay.cppWeb3DOverlay.cppWeb3DOverlay.h
libraries
animation/src
avatars-renderer/src/avatars-renderer
avatars/src
display-plugins/src/display-plugins
entities-renderer/src
entities/src
EntityItem.cppEntityItem.hEntityScriptingInterface.cppEntityScriptingInterface.hPolyLineEntityItem.cppPolyLineEntityItem.h
physics/src
script-engine/src
AbstractScriptingServicesInterface.hRecordingScriptingInterface.hScriptEngine.cppScriptEngine.hScriptEngines.cppScriptEngines.h
shared/src
ui/src/ui
plugins
oculus/src
openvr/src
scripts
|
@ -354,15 +354,16 @@ void Agent::scriptRequestFinished() {
|
|||
|
||||
|
||||
void Agent::executeScript() {
|
||||
_scriptEngine = std::unique_ptr<ScriptEngine>(new ScriptEngine(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload));
|
||||
_scriptEngine = scriptEngineFactory(ScriptEngine::AGENT_SCRIPT, _scriptContents, _payload);
|
||||
_scriptEngine->setParent(this); // be the parent of the script engine so it gets moved when we do
|
||||
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine.get());
|
||||
DependencyManager::get<RecordingScriptingInterface>()->setScriptEngine(_scriptEngine);
|
||||
|
||||
// setup an Avatar for the script to use
|
||||
auto scriptedAvatar = DependencyManager::get<ScriptableAvatar>();
|
||||
|
||||
connect(_scriptEngine.get(), SIGNAL(update(float)), scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection);
|
||||
connect(_scriptEngine.data(), SIGNAL(update(float)),
|
||||
scriptedAvatar.data(), SLOT(update(float)), Qt::ConnectionType::QueuedConnection);
|
||||
scriptedAvatar->setForceFaceTrackerConnected(true);
|
||||
|
||||
// call model URL setters with empty URLs so our avatar, if user, will have the default models
|
||||
|
|
|
@ -88,7 +88,7 @@ private:
|
|||
void encodeFrameOfZeros(QByteArray& encodedZeros);
|
||||
void computeLoudness(const QByteArray* decodedBuffer, QSharedPointer<ScriptableAvatar>);
|
||||
|
||||
std::unique_ptr<ScriptEngine> _scriptEngine;
|
||||
ScriptEnginePointer _scriptEngine;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
EntityTreeHeadlessViewer _entityViewer;
|
||||
|
||||
|
|
|
@ -170,9 +170,9 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
auto avatarPacketList = NLPacketList::create(PacketType::BulkAvatarData);
|
||||
|
||||
// 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
|
||||
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
|
||||
AABox nodeBox(nodeData->getGlobalBoundingBoxCorner(), nodeBoxScale);
|
||||
// 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
|
||||
return nodeData->getLastBroadcastTime(avatarNode->getUUID());
|
||||
}, [&](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));
|
||||
}, [&](AvatarSharedPointer avatar)->bool {
|
||||
if (avatar == thisAvatar) {
|
||||
|
@ -244,9 +244,9 @@ void AvatarMixerSlave::broadcastAvatarDataToAgent(const SharedNodePointer& node)
|
|||
// 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
|
||||
if (node->isIgnoreRadiusEnabled() || (avatarNode->isIgnoreRadiusEnabled() && !getsAnyIgnored)) {
|
||||
|
||||
float sensorToWorldScale = avatarNodeData->getAvatarSharedPointer()->getSensorToWorldScale();
|
||||
// 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
|
||||
AABox otherNodeBox(avatarNodeData->getGlobalBoundingBoxCorner(), otherNodeBoxScale);
|
||||
// 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();
|
||||
|
||||
|
||||
// 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);
|
||||
bool isInView = nodeData->otherAvatarInView(otherNodeBox);
|
||||
|
||||
|
|
|
@ -415,8 +415,7 @@ void EntityScriptServer::selectAudioFormat(const QString& selectedCodecName) {
|
|||
|
||||
void EntityScriptServer::resetEntitiesScriptEngine() {
|
||||
auto engineName = QString("about:Entities %1").arg(++_entitiesScriptEngineCount);
|
||||
auto newEngine = QSharedPointer<ScriptEngine>(new ScriptEngine(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName),
|
||||
&ScriptEngine::deleteLater);
|
||||
auto newEngine = scriptEngineFactory(ScriptEngine::ENTITY_SERVER_SCRIPT, NO_SCRIPT, engineName);
|
||||
|
||||
auto webSocketServerConstructorValue = newEngine->newFunction(WebSocketServerClass::constructor);
|
||||
newEngine->globalObject().setProperty("WebSocketServer", webSocketServerConstructorValue);
|
||||
|
@ -437,11 +436,14 @@ void EntityScriptServer::resetEntitiesScriptEngine() {
|
|||
|
||||
|
||||
newEngine->runInThread();
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngine.data());
|
||||
auto newEngineSP = qSharedPointerCast<EntitiesScriptEngineProvider>(newEngine);
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(newEngineSP);
|
||||
|
||||
disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS);
|
||||
disconnect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated,
|
||||
this, &EntityScriptServer::updateEntityPPS);
|
||||
_entitiesScriptEngine.swap(newEngine);
|
||||
connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated, this, &EntityScriptServer::updateEntityPPS);
|
||||
connect(_entitiesScriptEngine.data(), &ScriptEngine::entityScriptDetailsUpdated,
|
||||
this, &EntityScriptServer::updateEntityPPS);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -72,7 +72,7 @@ private:
|
|||
bool _shuttingDown { false };
|
||||
|
||||
static int _entitiesScriptEngineCount;
|
||||
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
|
||||
ScriptEnginePointer _entitiesScriptEngine;
|
||||
EntityEditPacketSender _entityEditSender;
|
||||
EntityTreeHeadlessViewer _entityViewer;
|
||||
|
||||
|
|
|
@ -486,9 +486,9 @@ ModalWindow {
|
|||
model: filesModel
|
||||
|
||||
function updateSort() {
|
||||
model.sortOrder = sortIndicatorOrder;
|
||||
model.sortColumn = sortIndicatorColumn;
|
||||
model.update();
|
||||
fileTableModel.sortOrder = sortIndicatorOrder;
|
||||
fileTableModel.sortColumn = sortIndicatorColumn;
|
||||
fileTableModel.update();
|
||||
}
|
||||
|
||||
onSortIndicatorColumnChanged: { updateSort(); }
|
||||
|
|
|
@ -484,9 +484,9 @@ TabletModalWindow {
|
|||
model: filesModel
|
||||
|
||||
function updateSort() {
|
||||
model.sortOrder = sortIndicatorOrder;
|
||||
model.sortColumn = sortIndicatorColumn;
|
||||
model.update();
|
||||
fileTableModel.sortOrder = sortIndicatorOrder;
|
||||
fileTableModel.sortColumn = sortIndicatorColumn;
|
||||
fileTableModel.update();
|
||||
}
|
||||
|
||||
onSortIndicatorColumnChanged: { updateSort(); }
|
||||
|
|
|
@ -14,6 +14,8 @@ import "../../windows" as Windows
|
|||
import QtQuick 2.0
|
||||
import Hifi 1.0
|
||||
|
||||
import Qt.labs.settings 1.0
|
||||
|
||||
Windows.ScrollingWindow {
|
||||
id: tabletRoot
|
||||
objectName: "tabletRoot"
|
||||
|
@ -25,8 +27,32 @@ Windows.ScrollingWindow {
|
|||
shown: false
|
||||
resizable: false
|
||||
|
||||
Settings {
|
||||
id: settings
|
||||
category: "WindowRoot.Windows"
|
||||
property real width: 480
|
||||
property real height: 706
|
||||
}
|
||||
|
||||
onResizableChanged: {
|
||||
if (!resizable) {
|
||||
// restore default size
|
||||
settings.width = tabletRoot.width
|
||||
settings.height = tabletRoot.height
|
||||
tabletRoot.width = 480
|
||||
tabletRoot.height = 706
|
||||
} else {
|
||||
tabletRoot.width = settings.width
|
||||
tabletRoot.height = settings.height
|
||||
}
|
||||
}
|
||||
|
||||
signal showDesktop();
|
||||
|
||||
function setResizable(value) {
|
||||
tabletRoot.resizable = value;
|
||||
}
|
||||
|
||||
function setMenuProperties(rootMenu, subMenu) {
|
||||
tabletRoot.rootMenu = rootMenu;
|
||||
tabletRoot.subMenu = subMenu;
|
||||
|
|
|
@ -963,7 +963,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer, bo
|
|||
DependencyManager::get<AddressManager>().data(), &AddressManager::storeCurrentAddress);
|
||||
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>().data();
|
||||
scriptEngines->registerScriptInitializer([this](ScriptEngine* engine){
|
||||
scriptEngines->registerScriptInitializer([this](ScriptEnginePointer engine){
|
||||
registerScriptEngineWithApplicationServices(engine);
|
||||
});
|
||||
|
||||
|
@ -2413,10 +2413,18 @@ void Application::paintGL() {
|
|||
auto lodManager = DependencyManager::get<LODManager>();
|
||||
|
||||
RenderArgs renderArgs;
|
||||
|
||||
float sensorToWorldScale = getMyAvatar()->getSensorToWorldScale();
|
||||
{
|
||||
PROFILE_RANGE(render, "/buildFrustrumAndArgs");
|
||||
{
|
||||
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();
|
||||
}
|
||||
renderArgs = RenderArgs(_gpuContext, lodManager->getOctreeSizeScale(),
|
||||
|
@ -2464,7 +2472,7 @@ void Application::paintGL() {
|
|||
PerformanceTimer perfTimer("CameraUpdates");
|
||||
|
||||
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
|
||||
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||
|
@ -2476,7 +2484,7 @@ void Application::paintGL() {
|
|||
if (isHMDMode()) {
|
||||
mat4 camMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||
_myCamera.setPosition(extractTranslation(camMat));
|
||||
_myCamera.setOrientation(glm::quat_cast(camMat));
|
||||
_myCamera.setOrientation(glmExtractRotation(camMat));
|
||||
} else {
|
||||
_myCamera.setPosition(myAvatar->getDefaultEyePosition());
|
||||
_myCamera.setOrientation(myAvatar->getMyHead()->getHeadOrientation());
|
||||
|
@ -2484,7 +2492,7 @@ void Application::paintGL() {
|
|||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||
if (isHMDMode()) {
|
||||
auto hmdWorldMat = myAvatar->getSensorToWorldMatrix() * myAvatar->getHMDSensorMatrix();
|
||||
_myCamera.setOrientation(glm::normalize(glm::quat_cast(hmdWorldMat)));
|
||||
_myCamera.setOrientation(glm::normalize(glmExtractRotation(hmdWorldMat)));
|
||||
_myCamera.setPosition(extractTranslation(hmdWorldMat) +
|
||||
myAvatar->getOrientation() * boomOffset);
|
||||
} else {
|
||||
|
@ -2517,14 +2525,14 @@ void Application::paintGL() {
|
|||
hmdOffset.x = -hmdOffset.x;
|
||||
|
||||
_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 * hmdOffset);
|
||||
} else {
|
||||
_myCamera.setOrientation(myAvatar->getOrientation()
|
||||
* glm::quat(glm::vec3(0.0f, PI + _rotateMirror, 0.0f)));
|
||||
_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))) *
|
||||
glm::vec3(0.0f, 0.0f, -1.0f) * MIRROR_FULLSCREEN_DISTANCE * _scaleMirror);
|
||||
}
|
||||
|
@ -2552,7 +2560,7 @@ void Application::paintGL() {
|
|||
|
||||
{
|
||||
PROFILE_RANGE(render, "/updateCompositor");
|
||||
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform());
|
||||
getApplicationCompositor().setFrameInfo(_frameCount, _myCamera.getTransform(), getMyAvatar()->getSensorToWorldMatrix());
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer finalFramebuffer;
|
||||
|
@ -2566,6 +2574,12 @@ void Application::paintGL() {
|
|||
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];
|
||||
{
|
||||
PROFILE_RANGE(render, "/mainRender");
|
||||
|
@ -2575,6 +2589,7 @@ void Application::paintGL() {
|
|||
// in the overlay render?
|
||||
// Viewport is assigned to the size of the framebuffer
|
||||
renderArgs._viewport = ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height());
|
||||
auto baseProjection = renderArgs.getViewFrustum().getProjection();
|
||||
if (displayPlugin->isStereo()) {
|
||||
// Stereo modes will typically have a larger projection matrix overall,
|
||||
// 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
|
||||
// overall culling margin of error doesn't cause popping in the
|
||||
// right eye. There are FIXMEs in the relevant plugins
|
||||
_myCamera.setProjection(displayPlugin->getCullingProjection(_myCamera.getProjection()));
|
||||
_myCamera.setProjection(displayPlugin->getCullingProjection(baseProjection));
|
||||
renderArgs._context->enableStereo(true);
|
||||
mat4 eyeOffsets[2];
|
||||
auto baseProjection = renderArgs.getViewFrustum().getProjection();
|
||||
auto hmdInterface = DependencyManager::get<HMDScriptingInterface>();
|
||||
float IPDScale = hmdInterface->getIPDScale();
|
||||
mat4 eyeProjections[2];
|
||||
|
||||
// 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
|
||||
|
@ -2604,7 +2617,7 @@ void Application::paintGL() {
|
|||
// Grab the translation
|
||||
vec3 eyeOffset = glm::vec3(eyeToHead[3]);
|
||||
// Apply IPD scaling
|
||||
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * IPDScale);
|
||||
mat4 eyeOffsetTransform = glm::translate(mat4(), eyeOffset * -1.0f * ipdScale);
|
||||
eyeOffsets[eye] = eyeOffsetTransform;
|
||||
eyeProjections[eye] = displayPlugin->getEyeProjection(eye, baseProjection);
|
||||
});
|
||||
|
@ -2624,8 +2637,14 @@ void Application::paintGL() {
|
|||
PerformanceTimer perfTimer("postComposite");
|
||||
renderArgs._batch = &postCompositeBatch;
|
||||
renderArgs._batch->setViewportTransform(ivec4(0, 0, finalFramebufferSize.width(), finalFramebufferSize.height()));
|
||||
renderArgs._batch->setViewTransform(renderArgs.getViewFrustum().getView());
|
||||
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]);
|
||||
_overlays.render3DHUDOverlays(&renderArgs);
|
||||
});
|
||||
|
@ -5209,7 +5228,7 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
avatarManager->postUpdate(deltaTime);
|
||||
avatarManager->postUpdate(deltaTime, getMain3DScene());
|
||||
|
||||
{
|
||||
PROFILE_RANGE_EX(app, "PreRenderLambdas", 0xffff0000, (uint64_t)0);
|
||||
|
@ -5930,7 +5949,7 @@ int Application::processOctreeStats(ReceivedMessage& message, SharedNodePointer
|
|||
void Application::packetSent(quint64 length) {
|
||||
}
|
||||
|
||||
void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) {
|
||||
void Application::registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) {
|
||||
|
||||
scriptEngine->setEmitScriptUpdatesFunction([this]() {
|
||||
SharedNodePointer entityServerNode = DependencyManager::get<NodeList>()->soloNodeOfType(NodeType::EntityServer);
|
||||
|
@ -5965,29 +5984,31 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
|
||||
ClipboardScriptingInterface* clipboardScriptable = new ClipboardScriptingInterface();
|
||||
scriptEngine->registerGlobalObject("Clipboard", clipboardScriptable);
|
||||
connect(scriptEngine, &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater);
|
||||
connect(scriptEngine.data(), &ScriptEngine::finished, clipboardScriptable, &ClipboardScriptingInterface::deleteLater);
|
||||
|
||||
scriptEngine->registerGlobalObject("Overlays", &_overlays);
|
||||
qScriptRegisterMetaType(scriptEngine, OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
|
||||
qScriptRegisterMetaType(scriptEngine, RayToOverlayIntersectionResultToScriptValue,
|
||||
qScriptRegisterMetaType(scriptEngine.data(), OverlayPropertyResultToScriptValue, OverlayPropertyResultFromScriptValue);
|
||||
qScriptRegisterMetaType(scriptEngine.data(), RayToOverlayIntersectionResultToScriptValue,
|
||||
RayToOverlayIntersectionResultFromScriptValue);
|
||||
|
||||
scriptEngine->registerGlobalObject("OffscreenFlags", DependencyManager::get<OffscreenUi>()->getFlags());
|
||||
scriptEngine->registerGlobalObject("Desktop", DependencyManager::get<DesktopScriptingInterface>().data());
|
||||
|
||||
qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue<ToolbarProxy>, wrapperFromScriptValue<ToolbarProxy>);
|
||||
qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue<ToolbarButtonProxy>, wrapperFromScriptValue<ToolbarButtonProxy>);
|
||||
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<ToolbarProxy>, wrapperFromScriptValue<ToolbarProxy>);
|
||||
qScriptRegisterMetaType(scriptEngine.data(),
|
||||
wrapperToScriptValue<ToolbarButtonProxy>, wrapperFromScriptValue<ToolbarButtonProxy>);
|
||||
scriptEngine->registerGlobalObject("Toolbars", DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||
|
||||
qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue<TabletProxy>, wrapperFromScriptValue<TabletProxy>);
|
||||
qScriptRegisterMetaType(scriptEngine, wrapperToScriptValue<TabletButtonProxy>, wrapperFromScriptValue<TabletButtonProxy>);
|
||||
qScriptRegisterMetaType(scriptEngine.data(), wrapperToScriptValue<TabletProxy>, wrapperFromScriptValue<TabletProxy>);
|
||||
qScriptRegisterMetaType(scriptEngine.data(),
|
||||
wrapperToScriptValue<TabletButtonProxy>, wrapperFromScriptValue<TabletButtonProxy>);
|
||||
scriptEngine->registerGlobalObject("Tablet", DependencyManager::get<TabletScriptingInterface>().data());
|
||||
|
||||
|
||||
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(DependencyManager::get<ToolbarScriptingInterface>().data());
|
||||
auto toolbarScriptingInterface = DependencyManager::get<ToolbarScriptingInterface>().data();
|
||||
DependencyManager::get<TabletScriptingInterface>().data()->setToolbarScriptingInterface(toolbarScriptingInterface);
|
||||
|
||||
scriptEngine->registerGlobalObject("Window", DependencyManager::get<WindowScriptingInterface>().data());
|
||||
qScriptRegisterMetaType(scriptEngine, CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue);
|
||||
qScriptRegisterMetaType(scriptEngine.data(), CustomPromptResultToScriptValue, CustomPromptResultFromScriptValue);
|
||||
scriptEngine->registerGetterSetter("location", LocationScriptingInterface::locationGetter,
|
||||
LocationScriptingInterface::locationSetter, "Window");
|
||||
// register `location` on the global object.
|
||||
|
@ -6019,7 +6040,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("DialogsManager", _dialogsManagerScriptingInterface);
|
||||
|
||||
scriptEngine->registerGlobalObject("GlobalServices", GlobalServicesScriptingInterface::getInstance());
|
||||
qScriptRegisterMetaType(scriptEngine, DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
|
||||
qScriptRegisterMetaType(scriptEngine.data(), DownloadInfoResultToScriptValue, DownloadInfoResultFromScriptValue);
|
||||
|
||||
scriptEngine->registerGlobalObject("FaceTracker", DependencyManager::get<DdeFaceTracker>().data());
|
||||
|
||||
|
@ -6047,11 +6068,11 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("LimitlessSpeechRecognition", DependencyManager::get<LimitlessVoiceRecognitionScriptingInterface>().data());
|
||||
|
||||
if (auto steamClient = PluginManager::getInstance()->getSteamClientPlugin()) {
|
||||
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine, steamClient.get()));
|
||||
scriptEngine->registerGlobalObject("Steam", new SteamScriptingInterface(scriptEngine.data(), steamClient.get()));
|
||||
}
|
||||
auto scriptingInterface = DependencyManager::get<controller::ScriptingInterface>();
|
||||
scriptEngine->registerGlobalObject("Controller", scriptingInterface.data());
|
||||
UserInputMapper::registerControllerTypes(scriptEngine);
|
||||
UserInputMapper::registerControllerTypes(scriptEngine.data());
|
||||
|
||||
auto recordingInterface = DependencyManager::get<RecordingScriptingInterface>();
|
||||
scriptEngine->registerGlobalObject("Recording", recordingInterface.data());
|
||||
|
@ -6062,14 +6083,19 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerGlobalObject("Selection", DependencyManager::get<SelectionScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("ContextOverlay", DependencyManager::get<ContextOverlayInterface>().data());
|
||||
|
||||
qScriptRegisterMetaType(scriptEngine, OverlayIDtoScriptValue, OverlayIDfromScriptValue);
|
||||
qScriptRegisterMetaType(scriptEngine.data(), OverlayIDtoScriptValue, OverlayIDfromScriptValue);
|
||||
|
||||
// connect this script engines printedMessage signal to the global ScriptEngines these various messages
|
||||
connect(scriptEngine, &ScriptEngine::printedMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onPrintedMessage);
|
||||
connect(scriptEngine, &ScriptEngine::errorMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onErrorMessage);
|
||||
connect(scriptEngine, &ScriptEngine::warningMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onWarningMessage);
|
||||
connect(scriptEngine, &ScriptEngine::infoMessage, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onInfoMessage);
|
||||
connect(scriptEngine, &ScriptEngine::clearDebugWindow, DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onClearDebugWindow);
|
||||
connect(scriptEngine.data(), &ScriptEngine::printedMessage,
|
||||
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onPrintedMessage);
|
||||
connect(scriptEngine.data(), &ScriptEngine::errorMessage,
|
||||
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onErrorMessage);
|
||||
connect(scriptEngine.data(), &ScriptEngine::warningMessage,
|
||||
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onWarningMessage);
|
||||
connect(scriptEngine.data(), &ScriptEngine::infoMessage,
|
||||
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onInfoMessage);
|
||||
connect(scriptEngine.data(), &ScriptEngine::clearDebugWindow,
|
||||
DependencyManager::get<ScriptEngines>().data(), &ScriptEngines::onClearDebugWindow);
|
||||
|
||||
}
|
||||
|
||||
|
@ -6404,7 +6430,12 @@ void Application::addAssetToWorldFromURL(QString url) {
|
|||
}
|
||||
if (url.contains("vr.google.com/downloads")) {
|
||||
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()) {
|
||||
|
@ -6434,7 +6465,11 @@ void Application::addAssetToWorldFromURLRequestFinished() {
|
|||
}
|
||||
if (url.contains("vr.google.com/downloads")) {
|
||||
filename = url.section('/', -1);
|
||||
filename.remove(".zip");
|
||||
if (url.contains("noDownload")) {
|
||||
filename.remove(".zip?noDownload=false");
|
||||
} else {
|
||||
filename.remove(".zip");
|
||||
}
|
||||
isBlocks = true;
|
||||
}
|
||||
|
||||
|
@ -6601,7 +6636,9 @@ void Application::addAssetToWorldAddEntity(QString filePath, QString mapping) {
|
|||
properties.setShapeType(SHAPE_TYPE_SIMPLE_COMPOUND);
|
||||
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.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));
|
||||
auto entityID = DependencyManager::get<EntityScriptingInterface>()->addEntity(properties);
|
||||
|
||||
|
@ -6648,7 +6685,7 @@ void Application::addAssetToWorldCheckModelSize() {
|
|||
if (dimensions != DEFAULT_DIMENSIONS) {
|
||||
|
||||
// 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 scale = std::min(MAXIMUM_DIMENSION / dimensions.x, std::min(MAXIMUM_DIMENSION / dimensions.y,
|
||||
MAXIMUM_DIMENSION / dimensions.z));
|
||||
|
|
|
@ -218,7 +218,7 @@ public:
|
|||
NodeToOctreeSceneStats* getOcteeSceneStats() { return &_octreeServerSceneStats; }
|
||||
|
||||
virtual controller::ScriptingInterface* getControllerScriptingInterface() { return _controllerScriptingInterface; }
|
||||
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) override;
|
||||
virtual void registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) override;
|
||||
|
||||
virtual void copyCurrentViewFrustum(ViewFrustum& viewOut) const override { copyDisplayViewFrustum(viewOut); }
|
||||
virtual QThread* getMainThread() override { return thread(); }
|
||||
|
|
|
@ -165,7 +165,7 @@ bool AvatarActionHold::getTarget(float deltaTimeStep, glm::quat& rotation, glm::
|
|||
|
||||
Transform avatarTransform;
|
||||
avatarTransform = myAvatar->getTransform();
|
||||
palmPosition = avatarTransform.transform(camRelPos / myAvatar->getDomainLimitedScale());
|
||||
palmPosition = avatarTransform.transform(camRelPos);
|
||||
palmRotation = avatarTransform.getRotation() * camRelRot;
|
||||
} else {
|
||||
glm::vec3 avatarRigidBodyPosition;
|
||||
|
|
|
@ -259,12 +259,12 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
simulateAvatarFades(deltaTime);
|
||||
}
|
||||
|
||||
void AvatarManager::postUpdate(float deltaTime) {
|
||||
void AvatarManager::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||
auto hashCopy = getHashCopy();
|
||||
AvatarHash::iterator avatarIterator = hashCopy.begin();
|
||||
for (avatarIterator = hashCopy.begin(); avatarIterator != hashCopy.end(); avatarIterator++) {
|
||||
auto avatar = std::static_pointer_cast<Avatar>(avatarIterator.value());
|
||||
avatar->postUpdate(deltaTime);
|
||||
avatar->postUpdate(deltaTime, scene);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ public:
|
|||
void updateMyAvatar(float deltaTime);
|
||||
void updateOtherAvatars(float deltaTime);
|
||||
|
||||
void postUpdate(float deltaTime);
|
||||
void postUpdate(float deltaTime, const render::ScenePointer& scene);
|
||||
|
||||
void clearOtherAvatars();
|
||||
void deleteAllAvatars();
|
||||
|
|
|
@ -64,18 +64,13 @@ using namespace std;
|
|||
|
||||
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 PITCH_SPEED_DEFAULT = 75.0f; // degrees/sec
|
||||
|
||||
// TODO: normalize avatar speed for standard avatar size, then scale all motion logic
|
||||
// to properly follow avatar size.
|
||||
float MAX_AVATAR_SPEED = 30.0f;
|
||||
float MAX_ACTION_MOTOR_SPEED = MAX_AVATAR_SPEED;
|
||||
const float MAX_BOOST_SPEED = 0.5f * DEFAULT_AVATAR_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
|
||||
|
||||
float MIN_SCRIPTED_MOTOR_TIMESCALE = 0.005f;
|
||||
float DEFAULT_SCRIPTED_MOTOR_TIMESCALE = 1.0e6f;
|
||||
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_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) :
|
||||
Avatar(thread),
|
||||
_yawSpeed(YAW_SPEED_DEFAULT),
|
||||
|
@ -262,7 +234,7 @@ void MyAvatar::setDominantHand(const QString& hand) {
|
|||
}
|
||||
}
|
||||
|
||||
void MyAvatar::registerMetaTypes(QScriptEngine* engine) {
|
||||
void MyAvatar::registerMetaTypes(ScriptEnginePointer engine) {
|
||||
QScriptValue value = engine->newQObject(this, QScriptEngine::QtOwnership, QScriptEngine::ExcludeDeleteLater | QScriptEngine::ExcludeChildObjects);
|
||||
engine->globalObject().setProperty("MyAvatar", value);
|
||||
|
||||
|
@ -273,8 +245,8 @@ void MyAvatar::registerMetaTypes(QScriptEngine* engine) {
|
|||
}
|
||||
engine->globalObject().setProperty("DriveKeys", driveKeys);
|
||||
|
||||
qScriptRegisterMetaType(engine, audioListenModeToScriptValue, audioListenModeFromScriptValue);
|
||||
qScriptRegisterMetaType(engine, driveKeysToScriptValue, driveKeysFromScriptValue);
|
||||
qScriptRegisterMetaType(engine.data(), audioListenModeToScriptValue, audioListenModeFromScriptValue);
|
||||
qScriptRegisterMetaType(engine.data(), driveKeysToScriptValue, driveKeysFromScriptValue);
|
||||
}
|
||||
|
||||
void MyAvatar::setOrientationVar(const QVariant& newOrientationVar) {
|
||||
|
@ -344,7 +316,7 @@ void MyAvatar::centerBody() {
|
|||
// transform this body into world space
|
||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||
auto worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||
auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
||||
auto worldBodyRot = glmExtractRotation(worldBodyMatrix);
|
||||
|
||||
if (_characterController.getState() == CharacterController::State::Ground) {
|
||||
// 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
|
||||
auto worldBodyMatrix = _sensorToWorldMatrix * newBodySensorMatrix;
|
||||
auto worldBodyPos = extractTranslation(worldBodyMatrix);
|
||||
auto worldBodyRot = glm::normalize(glm::quat_cast(worldBodyMatrix));
|
||||
auto worldBodyRot = glmExtractRotation(worldBodyMatrix);
|
||||
|
||||
// this will become our new position.
|
||||
setPosition(worldBodyPos);
|
||||
|
@ -586,7 +558,7 @@ void MyAvatar::simulate(float deltaTime) {
|
|||
headPosition = getPosition();
|
||||
}
|
||||
head->setPosition(headPosition);
|
||||
head->setScale(getUniformScale());
|
||||
head->setScale(getModelScale());
|
||||
head->simulate(deltaTime);
|
||||
}
|
||||
|
||||
|
@ -664,7 +636,7 @@ void MyAvatar::updateFromHMDSensorMatrix(const glm::mat4& hmdSensorMatrix) {
|
|||
}
|
||||
|
||||
_hmdSensorPosition = newHmdSensorPosition;
|
||||
_hmdSensorOrientation = glm::quat_cast(hmdSensorMatrix);
|
||||
_hmdSensorOrientation = glmExtractRotation(hmdSensorMatrix);
|
||||
auto headPose = getControllerPoseInSensorFrame(controller::Action::HEAD);
|
||||
if (headPose.isValid()) {
|
||||
_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.
|
||||
// This is so the correct camera can be used for rendering.
|
||||
void MyAvatar::updateSensorToWorldMatrix() {
|
||||
|
||||
// update the sensor mat so that the body position will end up in the desired
|
||||
// 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);
|
||||
|
||||
lateUpdatePalms();
|
||||
|
@ -1002,6 +976,7 @@ void MyAvatar::saveData() {
|
|||
settings.setValue("collisionSoundURL", _collisionSoundURL);
|
||||
settings.setValue("useSnapTurn", _useSnapTurn);
|
||||
settings.setValue("clearOverlayWhenMoving", _clearOverlayWhenMoving);
|
||||
settings.setValue("userHeight", getUserHeight());
|
||||
|
||||
settings.endGroup();
|
||||
}
|
||||
|
@ -1142,6 +1117,7 @@ void MyAvatar::loadData() {
|
|||
setSnapTurn(settings.value("useSnapTurn", _useSnapTurn).toBool());
|
||||
setClearOverlayWhenMoving(settings.value("clearOverlayWhenMoving", _clearOverlayWhenMoving).toBool());
|
||||
setDominantHand(settings.value("dominantHand", _dominantHand).toString().toLower());
|
||||
setUserHeight(settings.value("userHeight", DEFAULT_AVATAR_HEIGHT).toDouble());
|
||||
settings.endGroup();
|
||||
|
||||
setEnableMeshVisible(Menu::getInstance()->isOptionChecked(MenuOption::MeshVisible));
|
||||
|
@ -1247,7 +1223,7 @@ void MyAvatar::updateLookAtTargetAvatar() {
|
|||
float distanceTo = glm::length(avatar->getHead()->getEyePosition() - cameraPosition);
|
||||
avatar->setIsLookAtTarget(false);
|
||||
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 angleTo = coneSphereAngle(getHead()->getEyePosition(), lookForward, avatar->getHead()->getEyePosition(), radius);
|
||||
if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) {
|
||||
|
@ -1489,7 +1465,7 @@ glm::vec3 MyAvatar::getSkeletonPosition() const {
|
|||
|
||||
void MyAvatar::rebuildCollisionShape() {
|
||||
// compute localAABox
|
||||
float scale = getUniformScale();
|
||||
float scale = getModelScale();
|
||||
float radius = scale * _skeletonModel->getBoundingCapsuleRadius();
|
||||
float height = scale * _skeletonModel->getBoundingCapsuleHeight() + 2.0f * radius;
|
||||
glm::vec3 corner(-radius, -0.5f * height, -radius);
|
||||
|
@ -1595,6 +1571,7 @@ void MyAvatar::prepareForPhysicsSimulation() {
|
|||
}
|
||||
_characterController.handleChangedCollisionGroup();
|
||||
_characterController.setParentVelocity(parentVelocity);
|
||||
_characterController.setScaleFactor(getSensorToWorldScale());
|
||||
|
||||
_characterController.setPositionAndOrientation(getPosition(), getOrientation());
|
||||
auto headPose = getControllerPoseInAvatarFrame(controller::Action::HEAD);
|
||||
|
@ -1814,11 +1791,11 @@ void MyAvatar::destroyAnimGraph() {
|
|||
_skeletonModel->getRig().destroyAnimGraph();
|
||||
}
|
||||
|
||||
void MyAvatar::postUpdate(float deltaTime) {
|
||||
void MyAvatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||
|
||||
Avatar::postUpdate(deltaTime);
|
||||
Avatar::postUpdate(deltaTime, scene);
|
||||
|
||||
if (DependencyManager::get<SceneScriptingInterface>()->shouldRenderAvatars() && _skeletonModel->initWhenReady(qApp->getMain3DScene())) {
|
||||
if (_skeletonModel->isLoaded() && !_skeletonModel->getRig().getAnimNode()) {
|
||||
initHeadBones();
|
||||
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
|
||||
_fstAnimGraphOverrideUrl = _skeletonModel->getGeometry()->getAnimGraphOverrideUrl();
|
||||
|
@ -1930,7 +1907,7 @@ void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
|||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.3f;
|
||||
|
||||
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 {
|
||||
|
@ -1978,38 +1955,8 @@ void MyAvatar::updateOrientation(float deltaTime) {
|
|||
snapTurn = true;
|
||||
}
|
||||
|
||||
// use head/HMD orientation to turn while flying
|
||||
if (getCharacterController()->getState() == CharacterController::State::Hover) {
|
||||
|
||||
// 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()) {
|
||||
// Use head/HMD roll to turn while flying, but not when standing still.
|
||||
if (qApp->isHMDMode() && getCharacterController()->getState() == CharacterController::State::Hover && _hmdRollControlEnabled && hasDriveInput()) {
|
||||
// Turn with head roll.
|
||||
const float MIN_CONTROL_SPEED = 0.01f;
|
||||
float speed = glm::length(getVelocity());
|
||||
|
@ -2103,17 +2050,17 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
|||
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
|
||||
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 speedIncreaseFactor = 1.8f;
|
||||
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 (motorSpeed < maxBoostSpeed) {
|
||||
// an active action motor should never be slower than this
|
||||
float boostCoefficient = (maxBoostSpeed - motorSpeed) / maxBoostSpeed;
|
||||
motorSpeed += MIN_AVATAR_SPEED * boostCoefficient;
|
||||
motorSpeed += getSensorToWorldScale() * MIN_AVATAR_SPEED * boostCoefficient;
|
||||
} else if (motorSpeed > finalMaxMotorSpeed) {
|
||||
motorSpeed = finalMaxMotorSpeed;
|
||||
}
|
||||
|
@ -2121,7 +2068,7 @@ void MyAvatar::updateActionMotor(float deltaTime) {
|
|||
_actionMotorVelocity = motorSpeed * direction;
|
||||
} else {
|
||||
// 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);
|
||||
|
@ -2135,22 +2082,24 @@ void MyAvatar::updatePosition(float deltaTime) {
|
|||
}
|
||||
|
||||
vec3 velocity = getVelocity();
|
||||
float sensorToWorldScale = getSensorToWorldScale();
|
||||
float sensorToWorldScale2 = sensorToWorldScale * sensorToWorldScale;
|
||||
const float MOVING_SPEED_THRESHOLD_SQUARED = 0.0001f; // 0.01 m/s
|
||||
if (!_characterController.isEnabledAndReady()) {
|
||||
// _characterController is not in physics simulation but it can still compute its target velocity
|
||||
updateMotors();
|
||||
_characterController.computeNewVelocity(deltaTime, velocity);
|
||||
|
||||
float speed2 = glm::length2(velocity);
|
||||
if (speed2 > MIN_AVATAR_SPEED_SQUARED) {
|
||||
float speed2 = glm::length(velocity);
|
||||
if (speed2 > sensorToWorldScale2 * MIN_AVATAR_SPEED_SQUARED) {
|
||||
// update position ourselves
|
||||
applyPositionDelta(deltaTime * velocity);
|
||||
}
|
||||
measureMotionDerivatives(deltaTime);
|
||||
_moving = speed2 > MOVING_SPEED_THRESHOLD_SQUARED;
|
||||
_moving = speed2 > sensorToWorldScale2 * MOVING_SPEED_THRESHOLD_SQUARED;
|
||||
} else {
|
||||
float speed2 = glm::length2(velocity);
|
||||
_moving = speed2 > MOVING_SPEED_THRESHOLD_SQUARED;
|
||||
_moving = speed2 > sensorToWorldScale2 * MOVING_SPEED_THRESHOLD_SQUARED;
|
||||
|
||||
if (_moving) {
|
||||
// scan for walkability
|
||||
|
@ -2161,18 +2110,6 @@ void MyAvatar::updatePosition(float deltaTime) {
|
|||
_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) {
|
||||
|
@ -2333,7 +2270,8 @@ void MyAvatar::restrictScaleFromDomainSettings(const QJsonObject& domainSettings
|
|||
_targetScale = clampedScale;
|
||||
}
|
||||
|
||||
setScale(glm::vec3(_targetScale));
|
||||
setModelScale(_targetScale);
|
||||
rebuildCollisionShape();
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
|
@ -2719,11 +2657,30 @@ glm::mat4 MyAvatar::deriveBodyFromHMDSensor() const {
|
|||
// 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 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);
|
||||
}
|
||||
|
||||
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() {
|
||||
switch (_audioListenerMode) {
|
||||
case AudioListenerMode::FROM_HEAD:
|
||||
|
@ -2842,7 +2799,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 {
|
||||
|
||||
// -z axis of currentBodyMatrix in world space.
|
||||
glm::vec3 forward = glm::normalize(glm::vec3(-currentBodyMatrix[0][2], -currentBodyMatrix[1][2], -currentBodyMatrix[2][2]));
|
||||
// x axis of currentBodyMatrix in world space.
|
||||
|
@ -2866,7 +2822,6 @@ bool MyAvatar::FollowHelper::shouldActivateHorizontal(const MyAvatar& myAvatar,
|
|||
}
|
||||
|
||||
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_BOTTOM = -1.5f;
|
||||
|
||||
|
@ -2894,6 +2849,10 @@ void MyAvatar::FollowHelper::prePhysicsUpdate(MyAvatar& myAvatar, const glm::mat
|
|||
glm::mat4 currentWorldMatrix = myAvatar.getSensorToWorldMatrix() * currentBodyMatrix;
|
||||
|
||||
AnimPose followWorldPose(currentWorldMatrix);
|
||||
|
||||
// remove scale present from sensorToWorldMatrix
|
||||
followWorldPose.scale() = glm::vec3(1.0f);
|
||||
|
||||
if (isActive(Rotation)) {
|
||||
followWorldPose.rot() = glmExtractRotation(desiredWorldMatrix);
|
||||
}
|
||||
|
@ -2918,16 +2877,16 @@ glm::mat4 MyAvatar::FollowHelper::postPhysicsUpdate(const MyAvatar& myAvatar, co
|
|||
// apply follow displacement to the body matrix.
|
||||
glm::vec3 worldLinearDisplacement = myAvatar.getCharacterController()->getFollowLinearDisplacement();
|
||||
glm::quat worldAngularDisplacement = myAvatar.getCharacterController()->getFollowAngularDisplacement();
|
||||
glm::quat sensorToWorld = glmExtractRotation(myAvatar.getSensorToWorldMatrix());
|
||||
glm::quat worldToSensor = glm::inverse(sensorToWorld);
|
||||
|
||||
glm::vec3 sensorLinearDisplacement = worldToSensor * worldLinearDisplacement;
|
||||
glm::quat sensorAngularDisplacement = worldToSensor * worldAngularDisplacement * sensorToWorld;
|
||||
glm::mat4 sensorToWorldMatrix = myAvatar.getSensorToWorldMatrix();
|
||||
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),
|
||||
sensorLinearDisplacement + extractTranslation(currentBodyMatrix));
|
||||
return newBodyMat;
|
||||
|
||||
} else {
|
||||
return currentBodyMatrix;
|
||||
}
|
||||
|
@ -2985,15 +2944,20 @@ glm::mat4 MyAvatar::computeCameraRelativeHandControllerMatrix(const glm::mat4& c
|
|||
cameraWorldMatrix *= createMatFromScaleQuatAndPos(vec3(-1.0f, 1.0f, 1.0f), glm::quat(), glm::vec3());
|
||||
}
|
||||
|
||||
// compute a NEW sensorToWorldMatrix for the camera.
|
||||
// The equation is cameraWorldMatrix = cameraSensorToWorldMatrix * _hmdSensorMatrix.
|
||||
// here we solve for the unknown cameraSensorToWorldMatrix.
|
||||
glm::mat4 cameraSensorToWorldMatrix = cameraWorldMatrix * glm::inverse(getHMDSensorMatrix());
|
||||
// move the camera into sensor space.
|
||||
glm::mat4 cameraSensorMatrix = glm::inverse(getSensorToWorldMatrix()) * cameraWorldMatrix;
|
||||
|
||||
// Using the new cameraSensorToWorldMatrix, compute where the controller is in world space.
|
||||
glm::mat4 controllerWorldMatrix = cameraSensorToWorldMatrix * controllerSensorMatrix;
|
||||
// cancel out scale
|
||||
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());
|
||||
return glm::inverse(avatarMatrix) * controllerWorldMatrix;
|
||||
}
|
||||
|
@ -3265,3 +3229,12 @@ void MyAvatar::updateHoldActions(const AnimPose& prePhysicsPose, const AnimPose&
|
|||
const MyHead* MyAvatar::getMyHead() const {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,9 +19,11 @@
|
|||
#include <SettingHandle.h>
|
||||
#include <Rig.h>
|
||||
#include <Sound.h>
|
||||
#include <ScriptEngine.h>
|
||||
|
||||
#include <controllers/Pose.h>
|
||||
#include <controllers/Actions.h>
|
||||
#include <AvatarConstants.h>
|
||||
#include <avatars-renderer/Avatar.h>
|
||||
#include <avatars-renderer/ScriptAvatar.h>
|
||||
|
||||
|
@ -102,6 +104,8 @@ class MyAvatar : public Avatar {
|
|||
* @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
|
||||
* "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
|
||||
|
@ -145,7 +149,7 @@ class MyAvatar : public Avatar {
|
|||
Q_PROPERTY(bool hmdRollControlEnabled READ getHMDRollControlEnabled WRITE setHMDRollControlEnabled)
|
||||
Q_PROPERTY(float hmdRollControlDeadZone READ getHMDRollControlDeadZone WRITE setHMDRollControlDeadZone)
|
||||
Q_PROPERTY(float hmdRollControlRate READ getHMDRollControlRate WRITE setHMDRollControlRate)
|
||||
|
||||
|
||||
const QString DOMINANT_LEFT_HAND = "left";
|
||||
const QString DOMINANT_RIGHT_HAND = "right";
|
||||
|
||||
|
@ -169,7 +173,7 @@ public:
|
|||
~MyAvatar();
|
||||
|
||||
void instantiableAvatar() override {};
|
||||
void registerMetaTypes(QScriptEngine* engine);
|
||||
void registerMetaTypes(ScriptEnginePointer engine);
|
||||
|
||||
virtual void simulateAttachments(float deltaTime) override;
|
||||
|
||||
|
@ -196,7 +200,7 @@ public:
|
|||
Q_INVOKABLE void clearIKJointLimitHistory(); // thread-safe
|
||||
|
||||
void update(float deltaTime);
|
||||
virtual void postUpdate(float deltaTime) override;
|
||||
virtual void postUpdate(float deltaTime, const render::ScenePointer& scene) override;
|
||||
void preDisplaySide(RenderArgs* renderArgs);
|
||||
|
||||
const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; }
|
||||
|
@ -533,6 +537,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 isDown(const glm::vec3& direction) { return glm::dot(direction, _worldUpDirection) < 0.0f; };
|
||||
|
||||
void setUserHeight(float value);
|
||||
float getUserHeight() const;
|
||||
float getUserEyeHeight() const;
|
||||
|
||||
public slots:
|
||||
void increaseSize();
|
||||
void decreaseSize();
|
||||
|
@ -583,6 +591,8 @@ public slots:
|
|||
glm::vec3 getPositionForAudio();
|
||||
glm::quat getOrientationForAudio();
|
||||
|
||||
virtual void setModelScale(float scale) override;
|
||||
|
||||
signals:
|
||||
void audioListenerModeChanged();
|
||||
void transformChanged();
|
||||
|
@ -595,6 +605,7 @@ signals:
|
|||
void wentActive();
|
||||
void skeletonChanged();
|
||||
void dominantHandChanged(const QString& hand);
|
||||
void sensorToWorldScaleChanged(float sensorToWorldScale);
|
||||
|
||||
private:
|
||||
|
||||
|
@ -715,7 +726,7 @@ private:
|
|||
float _hmdRollControlRate { ROLL_CONTROL_RATE_DEFAULT };
|
||||
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() };
|
||||
|
||||
// cache of the current HMD sensor position and orientation in sensor space.
|
||||
|
@ -781,8 +792,6 @@ private:
|
|||
|
||||
AtRestDetector _hmdAtRestDetector;
|
||||
bool _lastIsMoving { false };
|
||||
bool _hoverReferenceCameraFacingIsCaptured { false };
|
||||
glm::vec3 _hoverReferenceCameraFacing { 0.0f, 0.0f, -1.0f }; // hmd sensor space
|
||||
|
||||
// all poses are in sensor-frame
|
||||
std::map<controller::Action, controller::Pose> _controllerPoseMap;
|
||||
|
@ -809,6 +818,9 @@ private:
|
|||
void setAway(bool value);
|
||||
|
||||
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);
|
||||
|
|
|
@ -148,7 +148,7 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
Rig::CharacterControllerState ccState = convertCharacterControllerState(myAvatar->getCharacterController()->getState());
|
||||
|
||||
auto velocity = myAvatar->getLocalVelocity();
|
||||
auto velocity = myAvatar->getLocalVelocity() / myAvatar->getSensorToWorldScale();
|
||||
auto position = myAvatar->getLocalPosition();
|
||||
auto orientation = myAvatar->getLocalOrientation();
|
||||
_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;
|
||||
|
||||
// Apply offset
|
||||
pos = pos + (rot * _posOffset);
|
||||
pos = pos + (rot * (myAvatar->getSensorToWorldScale() * _posOffset));
|
||||
glm::vec3 dir = rot * glm::normalize(_dirOffset);
|
||||
|
||||
valid = true;
|
||||
|
|
|
@ -143,15 +143,16 @@ void LaserPointer::updateRenderState(const RenderState& renderState, const Inter
|
|||
}
|
||||
if (!renderState.getEndID().isNull()) {
|
||||
QVariantMap endProps;
|
||||
glm::quat faceAvatarRotation = DependencyManager::get<AvatarManager>()->getMyAvatar()->getOrientation() * glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f)));
|
||||
if (_centerEndY) {
|
||||
endProps.insert("position", end);
|
||||
} else {
|
||||
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) {
|
||||
glm::quat rotation = glm::inverse(glm::quat_cast(glm::lookAt(endVec, DependencyManager::get<AvatarManager>()->getMyAvatar()->getPosition(), Vectors::UP)));
|
||||
endProps.insert("rotation", quatToVariant(glm::quat(glm::radians(glm::vec3(0, glm::degrees(safeEulerAngles(rotation)).y, 0)))));
|
||||
endProps.insert("rotation", quatToVariant(faceAvatarRotation));
|
||||
}
|
||||
endProps.insert("visible", true);
|
||||
endProps.insert("ignoreRayIntersection", renderState.doesEndIgnoreRays());
|
||||
|
|
|
@ -108,4 +108,4 @@ void RayPickScriptingInterface::setIgnoreAvatars(QUuid uid, const QScriptValue&
|
|||
|
||||
void RayPickScriptingInterface::setIncludeAvatars(QUuid uid, const QScriptValue& includeAvatars) {
|
||||
qApp->getRayPickManager().setIncludeAvatars(uid, includeAvatars);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -151,7 +151,7 @@ glm::vec3 HMDScriptingInterface::getPosition() const {
|
|||
|
||||
glm::quat HMDScriptingInterface::getOrientation() const {
|
||||
if (qApp->getActiveDisplayPlugin()->isHmd()) {
|
||||
return glm::normalize(glm::quat_cast(getWorldHMDMatrix()));
|
||||
return glmExtractRotation(getWorldHMDMatrix());
|
||||
}
|
||||
return glm::quat();
|
||||
}
|
||||
|
|
|
@ -61,7 +61,7 @@ void _writeLines(const QString& filename, const QList<QString>& lines) {
|
|||
QTextStream(&file) << json;
|
||||
}
|
||||
|
||||
JSConsole::JSConsole(QWidget* parent, const QSharedPointer<ScriptEngine>& scriptEngine) :
|
||||
JSConsole::JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine) :
|
||||
QWidget(parent),
|
||||
_ui(new Ui::Console),
|
||||
_currentCommandInHistory(NO_CURRENT_HISTORY_COMMAND),
|
||||
|
@ -97,7 +97,7 @@ JSConsole::~JSConsole() {
|
|||
delete _ui;
|
||||
}
|
||||
|
||||
void JSConsole::setScriptEngine(const QSharedPointer<ScriptEngine>& scriptEngine) {
|
||||
void JSConsole::setScriptEngine(const ScriptEnginePointer& scriptEngine) {
|
||||
if (_scriptEngine == scriptEngine && scriptEngine != NULL) {
|
||||
return;
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ void JSConsole::setScriptEngine(const QSharedPointer<ScriptEngine>& scriptEngin
|
|||
|
||||
// if scriptEngine is NULL then create one and keep track of it using _ownScriptEngine
|
||||
if (scriptEngine.isNull()) {
|
||||
_scriptEngine = QSharedPointer<ScriptEngine>(DependencyManager::get<ScriptEngines>()->loadScript(_consoleFileName, false), &QObject::deleteLater);
|
||||
_scriptEngine = DependencyManager::get<ScriptEngines>()->loadScript(_consoleFileName, false);
|
||||
} else {
|
||||
_scriptEngine = scriptEngine;
|
||||
}
|
||||
|
|
|
@ -30,10 +30,10 @@ const int CONSOLE_HEIGHT = 200;
|
|||
class JSConsole : public QWidget {
|
||||
Q_OBJECT
|
||||
public:
|
||||
JSConsole(QWidget* parent, const QSharedPointer<ScriptEngine>& scriptEngine = QSharedPointer<ScriptEngine>());
|
||||
JSConsole(QWidget* parent, const ScriptEnginePointer& scriptEngine = ScriptEnginePointer());
|
||||
~JSConsole();
|
||||
|
||||
void setScriptEngine(const QSharedPointer<ScriptEngine>& scriptEngine = QSharedPointer<ScriptEngine>());
|
||||
void setScriptEngine(const ScriptEnginePointer& scriptEngine = ScriptEnginePointer());
|
||||
void clear();
|
||||
|
||||
public slots:
|
||||
|
@ -66,7 +66,7 @@ private:
|
|||
QString _savedHistoryFilename;
|
||||
QList<QString> _commandHistory;
|
||||
QString _rootCommand;
|
||||
QSharedPointer<ScriptEngine> _scriptEngine;
|
||||
ScriptEnginePointer _scriptEngine;
|
||||
static const QString _consoleFileName;
|
||||
};
|
||||
|
||||
|
|
|
@ -193,7 +193,7 @@ void setupPreferences() {
|
|||
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 preference = new SpinnerSliderPreference(AVATAR_TUNING, "Avatar Scale", getter, setter);
|
||||
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
|
||||
// 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 setter = [](float value) { DependencyManager::get<DdeFaceTracker>()->setEyeClosingThreshold(value); };
|
||||
|
|
|
@ -24,7 +24,7 @@ TestingDialog::TestingDialog(QWidget* parent) :
|
|||
_console->setFixedHeight(TESTING_CONSOLE_HEIGHT);
|
||||
|
||||
auto _engines = DependencyManager::get<ScriptEngines>();
|
||||
_engine.reset(_engines->loadScript(qApp->applicationDirPath() + testRunnerRelativePath));
|
||||
_engine = _engines->loadScript(qApp->applicationDirPath() + testRunnerRelativePath);
|
||||
_console->setScriptEngine(_engine);
|
||||
connect(_engine.data(), &ScriptEngine::finished, this, &TestingDialog::onTestingFinished);
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ public:
|
|||
|
||||
private:
|
||||
std::unique_ptr<JSConsole> _console;
|
||||
QSharedPointer<ScriptEngine> _engine;
|
||||
ScriptEnginePointer _engine;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -256,15 +256,46 @@ bool Base3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::vec3
|
|||
void Base3DOverlay::locationChanged(bool tellPhysics) {
|
||||
SpatiallyNestable::locationChanged(tellPhysics);
|
||||
|
||||
auto itemID = getRenderItemID();
|
||||
if (render::Item::isValidID(itemID)) {
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
transaction.updateItem(itemID);
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
// Force the actual update of the render transform through the notify call
|
||||
notifyRenderTransformChange();
|
||||
}
|
||||
|
||||
void Base3DOverlay::parentDeleted() {
|
||||
qApp->getOverlays().deleteOverlay(getOverlayID());
|
||||
}
|
||||
|
||||
void Base3DOverlay::update(float duration) {
|
||||
|
||||
// In Base3DOverlay, if its location or bound changed, the renderTrasnformDirty flag is true.
|
||||
// then the correct transform used for rendering is computed in the update transaction and assigned.
|
||||
// TODO: Fix the value to be computed in main thread now and passed by value to the render item.
|
||||
// This is the simplest fix for the web overlay of the tablet for now
|
||||
if (_renderTransformDirty) {
|
||||
_renderTransformDirty = false;
|
||||
auto itemID = getRenderItemID();
|
||||
if (render::Item::isValidID(itemID)) {
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
render::Transaction transaction;
|
||||
transaction.updateItem<Overlay>(itemID, [](Overlay& data) {
|
||||
auto overlay3D = dynamic_cast<Base3DOverlay*>(&data);
|
||||
if (overlay3D) {
|
||||
auto latestTransform = overlay3D->evalRenderTransform();
|
||||
overlay3D->setRenderTransform(latestTransform);
|
||||
}
|
||||
});
|
||||
scene->enqueueTransaction(transaction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Base3DOverlay::notifyRenderTransformChange() const {
|
||||
_renderTransformDirty = true;
|
||||
}
|
||||
|
||||
Transform Base3DOverlay::evalRenderTransform() const {
|
||||
return getTransform();
|
||||
}
|
||||
|
||||
void Base3DOverlay::setRenderTransform(const Transform& transform) {
|
||||
_renderTransform = transform;
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@ public:
|
|||
|
||||
virtual AABox getBounds() const override = 0;
|
||||
|
||||
void update(float deltatime) override;
|
||||
|
||||
void notifyRenderTransformChange() const;
|
||||
|
||||
void setProperties(const QVariantMap& properties) override;
|
||||
QVariant getProperty(const QString& property) override;
|
||||
|
||||
|
@ -67,12 +71,18 @@ protected:
|
|||
virtual void locationChanged(bool tellPhysics = true) override;
|
||||
virtual void parentDeleted() override;
|
||||
|
||||
mutable Transform _renderTransform;
|
||||
virtual Transform evalRenderTransform() const;
|
||||
virtual void setRenderTransform(const Transform& transform);
|
||||
const Transform& getRenderTransform() const { return _renderTransform; }
|
||||
|
||||
float _lineWidth;
|
||||
bool _isSolid;
|
||||
bool _isDashedLine;
|
||||
bool _ignoreRayIntersection;
|
||||
bool _drawInFront;
|
||||
bool _isGrabbable { false };
|
||||
mutable bool _renderTransformDirty{ true };
|
||||
|
||||
QString _name;
|
||||
};
|
||||
|
|
|
@ -85,6 +85,7 @@ void Circle3DOverlay::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
// FIXME: THe line width of _lineWidth is not supported anymore, we ll need a workaround
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
|
||||
|
||||
auto transform = getTransform();
|
||||
transform.postScale(glm::vec3(getDimensions(), 1.0f));
|
||||
|
|
|
@ -54,6 +54,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
|
||||
// TODO: handle registration point??
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
glm::quat rotation = getRotation();
|
||||
|
|
|
@ -79,6 +79,7 @@ void Grid3DOverlay::render(RenderArgs* args) {
|
|||
position += glm::vec3(cameraPosition.x, 0.0f, cameraPosition.z);
|
||||
}
|
||||
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
|
||||
Transform transform;
|
||||
transform.setRotation(getRotation());
|
||||
transform.setScale(glm::vec3(getDimensions(), 1.0f));
|
||||
|
|
|
@ -117,6 +117,7 @@ void Image3DOverlay::render(RenderArgs* args) {
|
|||
xColor color = getColor();
|
||||
float alpha = getAlpha();
|
||||
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform from here, do the custom things needed in evalRenderTransform()
|
||||
Transform transform = getTransform();
|
||||
bool transformChanged = applyTransformTo(transform, true);
|
||||
// If the transform is not modified, setting the transform to
|
||||
|
|
|
@ -132,6 +132,7 @@ void Line3DOverlay::render(RenderArgs* args) {
|
|||
glm::vec4 colorv4(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
auto batch = args->_batch;
|
||||
if (batch) {
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform and start and end from here, do the custom things needed in evalRenderTransform()
|
||||
batch->setModelTransform(Transform());
|
||||
glm::vec3 start = getStart();
|
||||
glm::vec3 end = getEnd();
|
||||
|
|
|
@ -46,13 +46,17 @@ void ModelOverlay::update(float deltatime) {
|
|||
if (_updateModel) {
|
||||
_updateModel = false;
|
||||
_model->setSnapModelToCenter(true);
|
||||
Transform transform = getTransform();
|
||||
#ifndef USE_SN_SCALE
|
||||
transform.setScale(1.0f); // disable inherited scale
|
||||
#endif
|
||||
if (_scaleToFit) {
|
||||
_model->setScaleToFit(true, getScale() * getDimensions());
|
||||
_model->setScaleToFit(true, transform.getScale() * getDimensions());
|
||||
} else {
|
||||
_model->setScale(getScale());
|
||||
_model->setScale(transform.getScale());
|
||||
}
|
||||
_model->setRotation(getRotation());
|
||||
_model->setTranslation(getPosition());
|
||||
_model->setRotation(transform.getRotation());
|
||||
_model->setTranslation(transform.getTranslation());
|
||||
_model->setURL(_url);
|
||||
_model->simulate(deltatime, true);
|
||||
} else {
|
||||
|
@ -93,13 +97,13 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
|||
auto origPosition = getPosition();
|
||||
auto origRotation = getRotation();
|
||||
auto origDimensions = getDimensions();
|
||||
auto origScale = getScale();
|
||||
auto origScale = getSNScale();
|
||||
|
||||
Base3DOverlay::setProperties(properties);
|
||||
|
||||
auto scale = properties["scale"];
|
||||
if (scale.isValid()) {
|
||||
setScale(vec3FromVariant(scale));
|
||||
setSNScale(vec3FromVariant(scale));
|
||||
}
|
||||
|
||||
auto dimensions = properties["dimensions"];
|
||||
|
@ -112,7 +116,7 @@ void ModelOverlay::setProperties(const QVariantMap& properties) {
|
|||
_scaleToFit = false;
|
||||
}
|
||||
|
||||
if (origPosition != getPosition() || origRotation != getRotation() || origDimensions != getDimensions() || origScale != getScale()) {
|
||||
if (origPosition != getPosition() || origRotation != getRotation() || origDimensions != getDimensions() || origScale != getSNScale()) {
|
||||
_updateModel = true;
|
||||
}
|
||||
|
||||
|
@ -194,7 +198,7 @@ QVariant ModelOverlay::getProperty(const QString& property) {
|
|||
return vec3toVariant(getDimensions());
|
||||
}
|
||||
if (property == "scale") {
|
||||
return vec3toVariant(getScale());
|
||||
return vec3toVariant(getSNScale());
|
||||
}
|
||||
if (property == "textures") {
|
||||
if (_modelTextures.size() > 0) {
|
||||
|
@ -281,6 +285,7 @@ ModelOverlay* ModelOverlay::createClone() const {
|
|||
void ModelOverlay::locationChanged(bool tellPhysics) {
|
||||
Base3DOverlay::locationChanged(tellPhysics);
|
||||
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
||||
if (_model && _model->isActive()) {
|
||||
_model->setRotation(getRotation());
|
||||
_model->setTranslation(getPosition());
|
||||
|
|
|
@ -1045,6 +1045,7 @@ QVector<QUuid> Overlays::findOverlays(const glm::vec3& center, float radius) {
|
|||
AABox overlayFrameBox(low, dimensions);
|
||||
|
||||
Transform overlayToWorldMatrix = overlay->getTransform();
|
||||
overlayToWorldMatrix.setScale(1.0f); // ignore inherited scale factor from parents
|
||||
glm::mat4 worldToOverlayMatrix = glm::inverse(overlayToWorldMatrix.getMatrix());
|
||||
glm::vec3 overlayFrameSearchPosition = glm::vec3(worldToOverlayMatrix * glm::vec4(center, 1.0f));
|
||||
glm::vec3 penetration;
|
||||
|
|
|
@ -74,7 +74,7 @@ namespace render {
|
|||
glm::vec3 myAvatarPosition = avatar->getPosition();
|
||||
float angle = glm::degrees(glm::angle(myAvatarRotation));
|
||||
glm::vec3 axis = glm::axis(myAvatarRotation);
|
||||
float myAvatarScale = avatar->getUniformScale();
|
||||
float myAvatarScale = avatar->getModelScale();
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(myAvatarPosition);
|
||||
transform.setRotation(glm::angleAxis(angle, axis));
|
||||
|
|
|
@ -66,3 +66,12 @@ bool Planar3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
|
|||
// FIXME - face and surfaceNormal not being returned
|
||||
return findRayRectangleIntersection(origin, direction, getRotation(), getPosition(), getDimensions(), distance);
|
||||
}
|
||||
|
||||
Transform Planar3DOverlay::evalRenderTransform() const {
|
||||
auto transform = getTransform();
|
||||
transform.setScale(1.0f); // ignore inherited scale factor from parents
|
||||
if (glm::length2(getDimensions()) != 1.0f) {
|
||||
transform.postScale(vec3(getDimensions(), 1.0f));
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,9 @@ public:
|
|||
|
||||
virtual bool findRayIntersection(const glm::vec3& origin, const glm::vec3& direction, float& distance,
|
||||
BoxFace& face, glm::vec3& surfaceNormal) override;
|
||||
|
||||
|
||||
Transform evalRenderTransform() const override;
|
||||
|
||||
protected:
|
||||
glm::vec2 _dimensions;
|
||||
};
|
||||
|
|
|
@ -66,6 +66,7 @@ void Rectangle3DOverlay::render(RenderArgs* args) {
|
|||
auto batch = args->_batch;
|
||||
|
||||
if (batch) {
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
||||
Transform transform;
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(rotation);
|
||||
|
|
|
@ -33,6 +33,7 @@ void Shape3DOverlay::render(RenderArgs* args) {
|
|||
const float MAX_COLOR = 255.0f;
|
||||
glm::vec4 cubeColor(color.red / MAX_COLOR, color.green / MAX_COLOR, color.blue / MAX_COLOR, alpha);
|
||||
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
||||
// TODO: handle registration point??
|
||||
glm::vec3 position = getPosition();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
|
|
|
@ -39,7 +39,11 @@ void Sphere3DOverlay::render(RenderArgs* args) {
|
|||
auto batch = args->_batch;
|
||||
|
||||
if (batch) {
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
||||
Transform transform = getTransform();
|
||||
#ifndef USE_SN_SCALE
|
||||
transform.setScale(1.0f); // ignore inherited scale from SpatiallyNestable
|
||||
#endif
|
||||
transform.postScale(getDimensions() * SPHERE_OVERLAY_SCALE);
|
||||
batch->setModelTransform(transform);
|
||||
|
||||
|
|
|
@ -96,6 +96,7 @@ void Text3DOverlay::render(RenderArgs* args) {
|
|||
Q_ASSERT(args->_batch);
|
||||
auto& batch = *args->_batch;
|
||||
|
||||
// FIXME Start using the _renderTransform instead of calling for Transform and Dimensions from here, do the custom things needed in evalRenderTransform()
|
||||
Transform transform = getTransform();
|
||||
applyTransformTo(transform, true);
|
||||
setTransform(transform);
|
||||
|
|
|
@ -56,7 +56,11 @@ bool Volume3DOverlay::findRayIntersection(const glm::vec3& origin, const glm::ve
|
|||
float& distance, BoxFace& face, glm::vec3& surfaceNormal) {
|
||||
// extents is the entity relative, scaled, centered extents of the entity
|
||||
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 overlayFrameDirection = glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f));
|
||||
|
|
|
@ -184,6 +184,7 @@ void Web3DOverlay::update(float deltatime) {
|
|||
// update globalPosition
|
||||
_webSurface->getSurfaceContext()->setContextProperty("globalPosition", vec3toVariant(getPosition()));
|
||||
}
|
||||
Parent::update(deltatime);
|
||||
}
|
||||
|
||||
QString Web3DOverlay::pickURL() {
|
||||
|
@ -199,7 +200,6 @@ QString Web3DOverlay::pickURL() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void Web3DOverlay::loadSourceURL() {
|
||||
if (!_webSurface) {
|
||||
return;
|
||||
|
@ -302,23 +302,9 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
emit resizeWebSurface();
|
||||
}
|
||||
|
||||
|
||||
vec2 halfSize = getSize() / 2.0f;
|
||||
vec4 color(toGlm(getColor()), getAlpha());
|
||||
|
||||
Transform transform = getTransform();
|
||||
|
||||
// FIXME: applyTransformTo causes tablet overlay to detach from tablet entity.
|
||||
// Perhaps rather than deleting the following code it should be run only if isFacingAvatar() is true?
|
||||
/*
|
||||
applyTransformTo(transform, true);
|
||||
setTransform(transform);
|
||||
*/
|
||||
|
||||
if (glm::length2(getDimensions()) != 1.0f) {
|
||||
transform.postScale(vec3(getDimensions(), 1.0f));
|
||||
}
|
||||
|
||||
if (!_texture) {
|
||||
_texture = gpu::Texture::createExternal(OffscreenQmlSurface::getDiscardLambda());
|
||||
_texture->setSource(__FUNCTION__);
|
||||
|
@ -332,7 +318,9 @@ void Web3DOverlay::render(RenderArgs* args) {
|
|||
Q_ASSERT(args->_batch);
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
batch.setResourceTexture(0, _texture);
|
||||
batch.setModelTransform(transform);
|
||||
auto renderTransform = getRenderTransform();
|
||||
batch.setModelTransform(getRenderTransform());
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
if (color.a < OPAQUE_ALPHA_THRESHOLD) {
|
||||
geometryCache->bindWebBrowserProgram(batch, true);
|
||||
|
|
|
@ -19,8 +19,10 @@ class OffscreenQmlSurface;
|
|||
|
||||
class Web3DOverlay : public Billboard3DOverlay {
|
||||
Q_OBJECT
|
||||
using Parent = Billboard3DOverlay;
|
||||
|
||||
public:
|
||||
|
||||
static const QString QML;
|
||||
static QString const TYPE;
|
||||
virtual QString getType() const override { return TYPE; }
|
||||
|
|
|
@ -1164,7 +1164,6 @@ static bool findPointKDopDisplacement(const glm::vec3& point, const AnimPose& sh
|
|||
glm::vec3 localPoint = shapePose.inverse().xformPoint(point);
|
||||
|
||||
// Only works for 14-dop shape infos.
|
||||
assert(shapeInfo.dots.size() == DOP14_COUNT);
|
||||
if (shapeInfo.dots.size() != DOP14_COUNT) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include <glm/gtx/transform.hpp>
|
||||
#include <glm/gtx/vector_query.hpp>
|
||||
|
||||
#include <AvatarConstants.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
#include <DeferredLightingEffect.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
|
||||
moveToThread(thread);
|
||||
|
||||
setScale(glm::vec3(1.0f)); // avatar scale is uniform
|
||||
setModelScale(1.0f); // avatar scale is uniform
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
_nameRectGeometryID = geometryCache->allocateID();
|
||||
|
@ -155,14 +156,14 @@ glm::vec3 Avatar::getNeckPosition() const {
|
|||
AABox Avatar::getBounds() const {
|
||||
if (!_skeletonModel->isRenderable() || _skeletonModel->needsFixupInScene()) {
|
||||
// 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();
|
||||
}
|
||||
|
||||
void Avatar::animateScaleChanges(float deltaTime) {
|
||||
if (_isAnimatingScale) {
|
||||
float currentScale = getUniformScale();
|
||||
float currentScale = getModelScale();
|
||||
float desiredScale = getDomainLimitedScale();
|
||||
|
||||
// use exponential decay toward the domain limit clamped scale
|
||||
|
@ -177,7 +178,7 @@ void Avatar::animateScaleChanges(float deltaTime) {
|
|||
animatedScale = desiredScale;
|
||||
_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
|
||||
_hasNewJointData = true;
|
||||
|
@ -364,7 +365,7 @@ void Avatar::simulate(float deltaTime, bool inView) {
|
|||
}
|
||||
head->setPosition(headPosition);
|
||||
}
|
||||
head->setScale(getUniformScale());
|
||||
head->setScale(getModelScale());
|
||||
head->simulate(deltaTime);
|
||||
} else {
|
||||
// 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 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) {
|
||||
|
@ -553,7 +554,7 @@ void Avatar::updateRenderItem(render::Transaction& transaction) {
|
|||
}
|
||||
}
|
||||
|
||||
void Avatar::postUpdate(float deltaTime) {
|
||||
void Avatar::postUpdate(float deltaTime, const render::ScenePointer& scene) {
|
||||
|
||||
if (isMyAvatar() ? showMyLookAtVectors : showOtherLookAtVectors) {
|
||||
const float EYE_RAY_LENGTH = 10.0;
|
||||
|
@ -577,6 +578,8 @@ void Avatar::postUpdate(float deltaTime) {
|
|||
DebugDraw::getInstance().drawRay(rightEyePosition, rightEyePosition + rightEyeRotation * Vectors::UNIT_Z * EYE_RAY_LENGTH, RED);
|
||||
}
|
||||
}
|
||||
|
||||
fixupModelsInScene(scene);
|
||||
}
|
||||
|
||||
void Avatar::render(RenderArgs* renderArgs) {
|
||||
|
@ -648,14 +651,10 @@ void Avatar::render(RenderArgs* renderArgs) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!isMyAvatar()) {
|
||||
fixupModelsInScene(renderArgs->_scene);
|
||||
}
|
||||
|
||||
if (showCollisionShapes && shouldRenderHead(renderArgs) && _skeletonModel->isRenderable()) {
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":skeletonBoundingCollisionShapes");
|
||||
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) {
|
||||
|
@ -728,9 +727,9 @@ void Avatar::simulateAttachments(float deltaTime) {
|
|||
} else {
|
||||
if (_skeletonModel->getJointPositionInWorldFrame(jointIndex, jointPosition) &&
|
||||
_skeletonModel->getJointRotationInWorldFrame(jointIndex, jointRotation)) {
|
||||
model->setTranslation(jointPosition + jointRotation * attachment.translation * getUniformScale());
|
||||
model->setTranslation(jointPosition + jointRotation * attachment.translation * getModelScale());
|
||||
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->setSnapModelToCenter(false); // hack to force resnap
|
||||
model->setSnapModelToCenter(true);
|
||||
|
@ -890,7 +889,7 @@ void Avatar::renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const
|
|||
}
|
||||
|
||||
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);
|
||||
if (offsetLength > MAX_OFFSET_LENGTH) {
|
||||
_skeletonOffset = (MAX_OFFSET_LENGTH / offsetLength) * offset;
|
||||
|
@ -988,14 +987,12 @@ glm::quat Avatar::getAbsoluteJointRotationInObjectFrame(int index) const {
|
|||
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||
}
|
||||
|
||||
switch(index) {
|
||||
switch (index) {
|
||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return glmExtractRotation(invAvatarMat * sensorToWorldMatrix);
|
||||
glm::mat4 avatarMatrix = getLocalTransform().getMatrix();
|
||||
glm::mat4 finalMat = glm::inverse(avatarMatrix) * sensorToWorldMatrix;
|
||||
return glmExtractRotation(finalMat);
|
||||
}
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||
|
@ -1028,14 +1025,12 @@ glm::vec3 Avatar::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
|||
index += numeric_limits<unsigned short>::max() + 1; // 65536
|
||||
}
|
||||
|
||||
switch(index) {
|
||||
switch (index) {
|
||||
case SENSOR_TO_WORLD_MATRIX_INDEX: {
|
||||
glm::mat4 sensorToWorldMatrix = getSensorToWorldMatrix();
|
||||
bool success;
|
||||
Transform avatarTransform;
|
||||
Transform::mult(avatarTransform, getParentTransform(success), getLocalTransform());
|
||||
glm::mat4 invAvatarMat = avatarTransform.getInverseMatrix();
|
||||
return extractTranslation(invAvatarMat * sensorToWorldMatrix);
|
||||
glm::mat4 avatarMatrix = getLocalTransform().getMatrix();
|
||||
glm::mat4 finalMat = glm::inverse(avatarMatrix) * sensorToWorldMatrix;
|
||||
return extractTranslation(finalMat);
|
||||
}
|
||||
case CONTROLLER_LEFTHAND_INDEX: {
|
||||
Transform controllerLeftHandTransform = Transform(getControllerLeftHandMatrix());
|
||||
|
@ -1063,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 {
|
||||
QWriteLocker writeLock(&_modelJointIndicesCacheLock);
|
||||
_modelJointsCached = false;
|
||||
|
@ -1151,7 +1162,7 @@ glm::vec3 Avatar::getJointPosition(const QString& name) const {
|
|||
|
||||
void Avatar::scaleVectorRelativeToPosition(glm::vec3 &positionToScale) const {
|
||||
//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) {
|
||||
|
@ -1353,7 +1364,7 @@ void Avatar::updateDisplayNameAlpha(bool showDisplayName) {
|
|||
|
||||
// virtual
|
||||
void Avatar::computeShapeInfo(ShapeInfo& shapeInfo) {
|
||||
float uniformScale = getUniformScale();
|
||||
float uniformScale = getModelScale();
|
||||
shapeInfo.setCapsuleY(uniformScale * _skeletonModel->getBoundingCapsuleRadius(),
|
||||
0.5f * uniformScale * _skeletonModel->getBoundingCapsuleHeight());
|
||||
shapeInfo.setOffset(uniformScale * _skeletonModel->getBoundingCapsuleOffset());
|
||||
|
@ -1550,3 +1561,54 @@ void Avatar::ensureInScene(AvatarSharedPointer self, const render::ScenePointer&
|
|||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -98,7 +98,7 @@ public:
|
|||
|
||||
void updateRenderItem(render::Transaction& transaction);
|
||||
|
||||
virtual void postUpdate(float deltaTime);
|
||||
virtual void postUpdate(float deltaTime, const render::ScenePointer& scene);
|
||||
|
||||
//setters
|
||||
void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; }
|
||||
|
@ -108,7 +108,6 @@ public:
|
|||
SkeletonModelPointer getSkeletonModel() { return _skeletonModel; }
|
||||
const SkeletonModelPointer getSkeletonModel() const { return _skeletonModel; }
|
||||
glm::vec3 getChestPosition() const;
|
||||
float getUniformScale() const { return getScale().y; }
|
||||
const Head* getHead() const { return static_cast<const Head*>(_headData); }
|
||||
Head* getHead() { return static_cast<Head*>(_headData); }
|
||||
|
||||
|
@ -151,6 +150,7 @@ public:
|
|||
*/
|
||||
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::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const override;
|
||||
virtual bool setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) override { return false; }
|
||||
|
@ -232,6 +232,7 @@ public:
|
|||
|
||||
void animateScaleChanges(float deltaTime);
|
||||
void setTargetScale(float targetScale) override;
|
||||
float getTargetScale() const { return _targetScale; }
|
||||
|
||||
Q_INVOKABLE float getSimulationRate(const QString& rateName = QString("")) const;
|
||||
|
||||
|
@ -254,6 +255,16 @@ public:
|
|||
bool isFading() const { return _isFading; }
|
||||
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:
|
||||
|
||||
// FIXME - these should be migrated to use Pose data instead
|
||||
|
@ -356,6 +367,7 @@ private:
|
|||
bool _isAnimatingScale { false };
|
||||
bool _mustFadeIn { false };
|
||||
bool _isFading { false };
|
||||
float _modelScale { 1.0f };
|
||||
|
||||
static int _jointConesID;
|
||||
|
||||
|
@ -365,7 +377,6 @@ private:
|
|||
|
||||
float _displayNameTargetAlpha { 1.0f };
|
||||
float _displayNameAlpha { 1.0f };
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_Avatar_h
|
||||
|
|
|
@ -121,7 +121,7 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
void SkeletonModel::updateAttitude(const glm::quat& orientation) {
|
||||
setTranslation(_owningAvatar->getSkeletonPosition());
|
||||
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),
|
||||
|
@ -294,7 +294,7 @@ bool SkeletonModel::getEyePositions(glm::vec3& firstEyePosition, glm::vec3& seco
|
|||
}
|
||||
|
||||
glm::vec3 SkeletonModel::getDefaultEyeModelPosition() const {
|
||||
return _owningAvatar->getScale() * _defaultEyeModelPosition;
|
||||
return _owningAvatar->getModelScale() * _defaultEyeModelPosition;
|
||||
}
|
||||
|
||||
float DENSITY_OF_WATER = 1000.0f; // kg/m^3
|
||||
|
@ -316,7 +316,7 @@ void SkeletonModel::computeBoundingShape() {
|
|||
float radius, height;
|
||||
glm::vec3 offset;
|
||||
_rig.computeAvatarBoundingCapsule(geometry, radius, height, offset);
|
||||
float invScale = 1.0f / _owningAvatar->getUniformScale();
|
||||
float invScale = 1.0f / _owningAvatar->getModelScale();
|
||||
_boundingCapsuleRadius = invScale * radius;
|
||||
_boundingCapsuleHeight = invScale * height;
|
||||
_boundingCapsuleLocalOffset = invScale * offset;
|
||||
|
|
|
@ -2345,6 +2345,11 @@ glm::mat4 AvatarData::getSensorToWorldMatrix() const {
|
|||
return _sensorToWorldMatrixCache.get();
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
float AvatarData::getSensorToWorldScale() const {
|
||||
return extractUniformScale(_sensorToWorldMatrixCache.get());
|
||||
}
|
||||
|
||||
// thread-safe
|
||||
glm::mat4 AvatarData::getControllerLeftHandMatrix() const {
|
||||
return _controllerLeftHandMatrixCache.get();
|
||||
|
|
|
@ -387,6 +387,8 @@ class AvatarData : public QObject, public SpatiallyNestable {
|
|||
Q_PROPERTY(glm::mat4 controllerLeftHandMatrix READ getControllerLeftHandMatrix)
|
||||
Q_PROPERTY(glm::mat4 controllerRightHandMatrix READ getControllerRightHandMatrix)
|
||||
|
||||
Q_PROPERTY(float sensorToWorldScale READ getSensorToWorldScale)
|
||||
|
||||
public:
|
||||
|
||||
virtual QString getName() const override { return QString("Avatar:") + _displayName; }
|
||||
|
@ -621,6 +623,7 @@ public:
|
|||
|
||||
// thread safe
|
||||
Q_INVOKABLE glm::mat4 getSensorToWorldMatrix() const;
|
||||
Q_INVOKABLE float getSensorToWorldScale() const;
|
||||
Q_INVOKABLE glm::mat4 getControllerLeftHandMatrix() const;
|
||||
Q_INVOKABLE glm::mat4 getControllerRightHandMatrix() const;
|
||||
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <QtGui/QWindow>
|
||||
#include <QQuickWindow>
|
||||
|
||||
#include <DebugDraw.h>
|
||||
#include <shared/QtHelpers.h>
|
||||
#include <ui/Menu.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
@ -339,23 +340,29 @@ void CompositorHelper::computeHmdPickRay(const glm::vec2& cursorPos, glm::vec3&
|
|||
glm::mat4 CompositorHelper::getUiTransform() const {
|
||||
glm::mat4 modelMat;
|
||||
_modelTransform.getMatrix(modelMat);
|
||||
return _currentCamera * glm::inverse(_currentDisplayPlugin->getHeadPose()) * modelMat;
|
||||
return _sensorToWorldMatrix * modelMat;
|
||||
}
|
||||
|
||||
//Finds the collision point of a world space ray
|
||||
bool CompositorHelper::calculateRayUICollisionPoint(const glm::vec3& position, const glm::vec3& direction, glm::vec3& result) const {
|
||||
auto UITransform = getUiTransform();
|
||||
auto relativePosition4 = glm::inverse(UITransform) * vec4(position, 1);
|
||||
auto relativePosition = vec3(relativePosition4) / relativePosition4.w;
|
||||
auto relativeDirection = glm::inverse(glm::quat_cast(UITransform)) * direction;
|
||||
glm::mat4 uiToWorld = getUiTransform();
|
||||
glm::mat4 worldToUi = glm::inverse(uiToWorld);
|
||||
glm::vec3 localPosition = transformPoint(worldToUi, position);
|
||||
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;
|
||||
if (raySphereIntersect(relativeDirection, relativePosition, UI_RADIUS, &instersectionDistance)){
|
||||
result = position + glm::normalize(direction) * instersectionDistance;
|
||||
if (raySphereIntersect(localDirection, localPosition, UI_RADIUS, &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;
|
||||
} 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;
|
||||
}
|
||||
|
||||
|
|
|
@ -109,7 +109,10 @@ public:
|
|||
void setReticleOverDesktop(bool value) { _isOverDesktop = value; }
|
||||
|
||||
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:
|
||||
void allowMouseCaptureChanged();
|
||||
|
@ -124,6 +127,7 @@ private:
|
|||
|
||||
DisplayPluginPointer _currentDisplayPlugin;
|
||||
glm::mat4 _currentCamera;
|
||||
glm::mat4 _sensorToWorldMatrix;
|
||||
QWidget* _renderingWidget{ nullptr };
|
||||
|
||||
//// Support for hovering and tooltips
|
||||
|
|
|
@ -27,8 +27,8 @@ public:
|
|||
bool isHmd() const override final { return true; }
|
||||
float getIPD() const override final { return _ipd; }
|
||||
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 getCullingProjection(const glm::mat4& baseProjection) const override final { return _cullingProjection; }
|
||||
glm::mat4 getEyeProjection(Eye eye, const glm::mat4& baseProjection) const override { return _eyeProjections[eye]; }
|
||||
glm::mat4 getCullingProjection(const glm::mat4& baseProjection) const override { return _cullingProjection; }
|
||||
glm::uvec2 getRecommendedUiSize() const override final;
|
||||
glm::uvec2 getRecommendedRenderSize() const override final { return _renderTargetSize; }
|
||||
bool isDisplayVisible() const override { return isHmdMounted(); }
|
||||
|
|
|
@ -70,45 +70,21 @@ EntityRendererPointer EntityTreeRenderer::renderableForEntityId(const EntityItem
|
|||
return itr->second;
|
||||
}
|
||||
|
||||
render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& id) const {
|
||||
auto renderable = renderableForEntityId(id);
|
||||
return renderable ? renderable->getRenderItemID() : render::Item::INVALID_ITEM_ID;
|
||||
render::ItemID EntityTreeRenderer::renderableIdForEntityId(const EntityItemID& id) const {
|
||||
auto renderable = renderableForEntityId(id);
|
||||
return renderable ? renderable->getRenderItemID() : render::Item::INVALID_ITEM_ID;
|
||||
}
|
||||
|
||||
int EntityTreeRenderer::_entitiesScriptEngineCount = 0;
|
||||
|
||||
void entitiesScriptEngineDeleter(ScriptEngine* engine) {
|
||||
class WaitRunnable : public QRunnable {
|
||||
public:
|
||||
WaitRunnable(ScriptEngine* engine) : _engine(engine) {}
|
||||
virtual void run() override {
|
||||
_engine->waitTillDoneRunning();
|
||||
_engine->deleteLater();
|
||||
}
|
||||
|
||||
private:
|
||||
ScriptEngine* _engine;
|
||||
};
|
||||
|
||||
// Wait for the scripting thread from the thread pool to avoid hanging the main thread
|
||||
auto threadPool = QThreadPool::globalInstance();
|
||||
if (threadPool) {
|
||||
threadPool->start(new WaitRunnable(engine));
|
||||
} else {
|
||||
delete engine;
|
||||
}
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::resetEntitiesScriptEngine() {
|
||||
// Keep a ref to oldEngine until newEngine is ready so EntityScriptingInterface has something to use
|
||||
auto oldEngine = _entitiesScriptEngine;
|
||||
|
||||
auto newEngine = new ScriptEngine(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT, QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
|
||||
_entitiesScriptEngine = QSharedPointer<ScriptEngine>(newEngine, entitiesScriptEngineDeleter);
|
||||
|
||||
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine.data());
|
||||
_entitiesScriptEngine = scriptEngineFactory(ScriptEngine::ENTITY_CLIENT_SCRIPT, NO_SCRIPT,
|
||||
QString("about:Entities %1").arg(++_entitiesScriptEngineCount));
|
||||
_scriptingServices->registerScriptEngineWithApplicationServices(_entitiesScriptEngine);
|
||||
_entitiesScriptEngine->runInThread();
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(_entitiesScriptEngine.data());
|
||||
auto entitiesScriptEngineProvider = qSharedPointerCast<EntitiesScriptEngineProvider>(_entitiesScriptEngine);
|
||||
DependencyManager::get<EntityScriptingInterface>()->setEntitiesScriptEngine(entitiesScriptEngineProvider);
|
||||
}
|
||||
|
||||
void EntityTreeRenderer::clear() {
|
||||
|
|
|
@ -181,7 +181,7 @@ private:
|
|||
QVector<EntityItemID> _currentEntitiesInside;
|
||||
|
||||
bool _wantScripts;
|
||||
QSharedPointer<ScriptEngine> _entitiesScriptEngine;
|
||||
ScriptEnginePointer _entitiesScriptEngine;
|
||||
|
||||
void playEntityCollisionSound(const EntityItemPointer& entity, const Collision& collision);
|
||||
|
||||
|
|
|
@ -36,6 +36,29 @@
|
|||
|
||||
static CollisionRenderMeshCache collisionMeshCache;
|
||||
|
||||
void ModelEntityWrapper::setModel(const ModelPointer& model) {
|
||||
withWriteLock([&] {
|
||||
if (_model != model) {
|
||||
_model = model;
|
||||
if (_model) {
|
||||
_needsInitialSimulation = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ModelPointer ModelEntityWrapper::getModel() const {
|
||||
return resultWithReadLock<ModelPointer>([&] {
|
||||
return _model;
|
||||
});
|
||||
}
|
||||
|
||||
bool ModelEntityWrapper::isModelLoaded() const {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return _model.operator bool() && _model->isLoaded();
|
||||
});
|
||||
}
|
||||
|
||||
EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItemPointer entity{ new RenderableModelEntityItem(entityID, properties.getDimensionsInitialized()) };
|
||||
entity->setProperties(properties);
|
||||
|
@ -43,7 +66,7 @@ EntityItemPointer RenderableModelEntityItem::factory(const EntityItemID& entityI
|
|||
}
|
||||
|
||||
RenderableModelEntityItem::RenderableModelEntityItem(const EntityItemID& entityItemID, bool dimensionsInitialized) :
|
||||
ModelEntityItem(entityItemID),
|
||||
ModelEntityWrapper(entityItemID),
|
||||
_dimensionsInitialized(dimensionsInitialized) {
|
||||
}
|
||||
|
||||
|
@ -83,41 +106,47 @@ QVariantMap parseTexturesToMap(QString textures, const QVariantMap& defaultTextu
|
|||
}
|
||||
|
||||
void RenderableModelEntityItem::doInitialModelSimulation() {
|
||||
ModelPointer model = getModel();
|
||||
if (!model) {
|
||||
return;
|
||||
}
|
||||
// The machinery for updateModelBounds will give existing models the opportunity to fix their
|
||||
// translation/rotation/scale/registration. The first two are straightforward, but the latter two have guards to
|
||||
// make sure they don't happen after they've already been set. Here we reset those guards. This doesn't cause the
|
||||
// entity values to change -- it just allows the model to match once it comes in.
|
||||
_model->setScaleToFit(false, getDimensions());
|
||||
_model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
|
||||
model->setScaleToFit(false, getDimensions());
|
||||
model->setSnapModelToRegistrationPoint(false, getRegistrationPoint());
|
||||
|
||||
// now recalculate the bounds and registration
|
||||
_model->setScaleToFit(true, getDimensions());
|
||||
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
||||
_model->setRotation(getRotation());
|
||||
_model->setTranslation(getPosition());
|
||||
model->setScaleToFit(true, getDimensions());
|
||||
model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
|
||||
model->setRotation(getRotation());
|
||||
model->setTranslation(getPosition());
|
||||
{
|
||||
PerformanceTimer perfTimer("_model->simulate");
|
||||
_model->simulate(0.0f);
|
||||
PerformanceTimer perfTimer("model->simulate");
|
||||
model->simulate(0.0f);
|
||||
}
|
||||
_needsInitialSimulation = false;
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::autoResizeJointArrays() {
|
||||
if (_model && _model->isLoaded() && !_needsInitialSimulation) {
|
||||
resizeJointArrays(_model->getJointStateCount());
|
||||
ModelPointer model = getModel();
|
||||
if (model && model->isLoaded() && !_needsInitialSimulation) {
|
||||
resizeJointArrays(model->getJointStateCount());
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::needsUpdateModelBounds() const {
|
||||
if (!hasModel() || !_model) {
|
||||
ModelPointer model = getModel();
|
||||
if (!hasModel() || !model) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_dimensionsInitialized || !_model->isActive()) {
|
||||
if (!_dimensionsInitialized || !model->isActive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_model->needsReload()) {
|
||||
if (model->needsReload()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -129,21 +158,21 @@ bool RenderableModelEntityItem::needsUpdateModelBounds() const {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (_model->getScaleToFitDimensions() != getDimensions()) {
|
||||
if (model->getScaleToFitDimensions() != getDimensions()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_model->getRegistrationPoint() != getRegistrationPoint()) {
|
||||
if (model->getRegistrationPoint() != getRegistrationPoint()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool success;
|
||||
auto transform = getTransform(success);
|
||||
if (success) {
|
||||
if (_model->getTranslation() != transform.getTranslation()) {
|
||||
if (model->getTranslation() != transform.getTranslation()) {
|
||||
return true;
|
||||
}
|
||||
if (_model->getRotation() != transform.getRotation()) {
|
||||
if (model->getRotation() != transform.getRotation()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -158,16 +187,6 @@ void RenderableModelEntityItem::updateModelBounds() {
|
|||
}
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setModel(const ModelPointer& model) {
|
||||
withWriteLock([&] {
|
||||
if (_model != model) {
|
||||
_model = model;
|
||||
if (_model) {
|
||||
_needsInitialSimulation = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlags desiredProperties) const {
|
||||
EntityItemProperties properties = ModelEntityItem::getProperties(desiredProperties); // get the properties from our base class
|
||||
|
@ -175,43 +194,44 @@ EntityItemProperties RenderableModelEntityItem::getProperties(EntityPropertyFlag
|
|||
properties.setTextureNames(_originalTextures);
|
||||
}
|
||||
|
||||
if (_model) {
|
||||
properties.setRenderInfoVertexCount(_model->getRenderInfoVertexCount());
|
||||
properties.setRenderInfoTextureCount(_model->getRenderInfoTextureCount());
|
||||
properties.setRenderInfoTextureSize(_model->getRenderInfoTextureSize());
|
||||
properties.setRenderInfoDrawCalls(_model->getRenderInfoDrawCalls());
|
||||
properties.setRenderInfoHasTransparent(_model->getRenderInfoHasTransparent());
|
||||
ModelPointer model = getModel();
|
||||
if (model) {
|
||||
properties.setRenderInfoVertexCount(model->getRenderInfoVertexCount());
|
||||
properties.setRenderInfoTextureCount(model->getRenderInfoTextureCount());
|
||||
properties.setRenderInfoTextureSize(model->getRenderInfoTextureSize());
|
||||
properties.setRenderInfoDrawCalls(model->getRenderInfoDrawCalls());
|
||||
properties.setRenderInfoHasTransparent(model->getRenderInfoHasTransparent());
|
||||
|
||||
if (model->isLoaded()) {
|
||||
// TODO: improve naturalDimensions in the future,
|
||||
// for now we've added this hack for setting natural dimensions of models
|
||||
Extents meshExtents = model->getFBXGeometry().getUnscaledMeshExtents();
|
||||
properties.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);
|
||||
properties.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (_model && _model->isLoaded()) {
|
||||
// TODO: improve naturalDimensions in the future,
|
||||
// for now we've added this hack for setting natural dimensions of models
|
||||
Extents meshExtents = _model->getFBXGeometry().getUnscaledMeshExtents();
|
||||
properties.setNaturalDimensions(meshExtents.maximum - meshExtents.minimum);
|
||||
properties.calculateNaturalPosition(meshExtents.minimum, meshExtents.maximum);
|
||||
}
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::supportsDetailedRayIntersection() const {
|
||||
return resultWithReadLock<bool>([&] {
|
||||
return _model && _model->isLoaded();
|
||||
});
|
||||
return isModelLoaded();
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElementPointer& element, float& distance, BoxFace& face,
|
||||
glm::vec3& surfaceNormal, void** intersectedObject, bool precisionPicking) const {
|
||||
if (!_model) {
|
||||
auto model = getModel();
|
||||
if (!model) {
|
||||
return true;
|
||||
}
|
||||
// qCDebug(entitiesrenderer) << "RenderableModelEntityItem::findDetailedRayIntersection() precisionPicking:"
|
||||
// << precisionPicking;
|
||||
|
||||
QString extraInfo;
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
return model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking, false);
|
||||
}
|
||||
|
||||
|
@ -242,7 +262,7 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
|
|||
// parse it twice.
|
||||
auto currentCompoundShapeURL = getCompoundShapeURL();
|
||||
ModelEntityItem::setCompoundShapeURL(url);
|
||||
if (getCompoundShapeURL() != currentCompoundShapeURL || !_model) {
|
||||
if (getCompoundShapeURL() != currentCompoundShapeURL || !getModel()) {
|
||||
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
|
||||
getCollisionGeometryResource();
|
||||
}
|
||||
|
@ -252,17 +272,18 @@ void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
|
|||
bool RenderableModelEntityItem::isReadyToComputeShape() const {
|
||||
ShapeType type = getShapeType();
|
||||
|
||||
auto model = getModel();
|
||||
if (type == SHAPE_TYPE_COMPOUND) {
|
||||
if (!_model || getCompoundShapeURL().isEmpty()) {
|
||||
if (!model || getCompoundShapeURL().isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_model->getURL().isEmpty()) {
|
||||
if (model->getURL().isEmpty()) {
|
||||
// we need a render geometry with a scale to proceed, so give up.
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_model->isLoaded()) {
|
||||
if (model->isLoaded()) {
|
||||
if (!getCompoundShapeURL().isEmpty() && !_compoundShapeResource) {
|
||||
const_cast<RenderableModelEntityItem*>(this)->getCollisionGeometryResource();
|
||||
}
|
||||
|
@ -281,7 +302,7 @@ bool RenderableModelEntityItem::isReadyToComputeShape() const {
|
|||
// the model is still being downloaded.
|
||||
return false;
|
||||
} else if (type >= SHAPE_TYPE_SIMPLE_HULL && type <= SHAPE_TYPE_STATIC_MESH) {
|
||||
return (_model && _model->isLoaded());
|
||||
return isModelLoaded();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
@ -292,6 +313,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
|
||||
ShapeType type = getShapeType();
|
||||
glm::vec3 dimensions = getDimensions();
|
||||
auto model = getModel();
|
||||
if (type == SHAPE_TYPE_COMPOUND) {
|
||||
updateModelBounds();
|
||||
|
||||
|
@ -373,14 +395,14 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
// to the visual model and apply them to the collision model (without regard for the
|
||||
// collision model's extents).
|
||||
|
||||
glm::vec3 scaleToFit = dimensions / _model->getFBXGeometry().getUnscaledMeshExtents().size();
|
||||
glm::vec3 scaleToFit = dimensions / model->getFBXGeometry().getUnscaledMeshExtents().size();
|
||||
// multiply each point by scale before handing the point-set off to the physics engine.
|
||||
// also determine the extents of the collision model.
|
||||
glm::vec3 registrationOffset = dimensions * (ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
|
||||
for (int32_t i = 0; i < pointCollection.size(); i++) {
|
||||
for (int32_t j = 0; j < pointCollection[i].size(); j++) {
|
||||
// back compensate for registration so we can apply that offset to the shapeInfo later
|
||||
pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + _model->getOffset()) - registrationOffset;
|
||||
pointCollection[i][j] = scaleToFit * (pointCollection[i][j] + model->getOffset()) - registrationOffset;
|
||||
}
|
||||
}
|
||||
shapeInfo.setParams(type, dimensions, getCompoundShapeURL());
|
||||
|
@ -389,11 +411,11 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
assert(_model && _model->isLoaded());
|
||||
|
||||
updateModelBounds();
|
||||
_model->updateGeometry();
|
||||
model->updateGeometry();
|
||||
|
||||
// compute meshPart local transforms
|
||||
QVector<glm::mat4> localTransforms;
|
||||
const FBXGeometry& fbxGeometry = _model->getFBXGeometry();
|
||||
const FBXGeometry& fbxGeometry = model->getFBXGeometry();
|
||||
int numFbxMeshes = fbxGeometry.meshes.size();
|
||||
int totalNumVertices = 0;
|
||||
glm::mat4 invRegistraionOffset = glm::translate(dimensions * (getRegistrationPoint() - ENTITY_ITEM_DEFAULT_REGISTRATION_POINT));
|
||||
|
@ -401,7 +423,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
const FBXMesh& mesh = fbxGeometry.meshes.at(i);
|
||||
if (mesh.clusters.size() > 0) {
|
||||
const FBXCluster& cluster = mesh.clusters.at(0);
|
||||
auto jointMatrix = _model->getRig().getJointTransform(cluster.jointIndex);
|
||||
auto jointMatrix = model->getRig().getJointTransform(cluster.jointIndex);
|
||||
// we backtranslate by the registration offset so we can apply that offset to the shapeInfo later
|
||||
localTransforms.push_back(invRegistraionOffset * jointMatrix * cluster.inverseBindMatrix);
|
||||
} else {
|
||||
|
@ -417,7 +439,7 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& shapeInfo) {
|
|||
return;
|
||||
}
|
||||
|
||||
auto& meshes = _model->getGeometry()->getMeshes();
|
||||
auto& meshes = model->getGeometry()->getMeshes();
|
||||
int32_t numMeshes = (int32_t)(meshes.size());
|
||||
|
||||
const int MAX_ALLOWED_MESH_COUNT = 1000;
|
||||
|
@ -631,7 +653,8 @@ void RenderableModelEntityItem::setCollisionShape(const btCollisionShape* shape)
|
|||
}
|
||||
|
||||
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
|
||||
if (EntityItem::contains(point) && _model && _compoundShapeResource && _compoundShapeResource->isLoaded()) {
|
||||
auto model = getModel();
|
||||
if (EntityItem::contains(point) && model && _compoundShapeResource && _compoundShapeResource->isLoaded()) {
|
||||
return _compoundShapeResource->getFBXGeometry().convexHullContains(worldToEntity(point));
|
||||
}
|
||||
|
||||
|
@ -639,11 +662,12 @@ bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
|
|||
}
|
||||
|
||||
bool RenderableModelEntityItem::shouldBePhysical() const {
|
||||
auto model = getModel();
|
||||
// If we have a model, make sure it hasn't failed to download.
|
||||
// If it has, we'll report back that we shouldn't be physical so that physics aren't held waiting for us to be ready.
|
||||
if (_model && getShapeType() == SHAPE_TYPE_COMPOUND && _model->didCollisionGeometryRequestFail()) {
|
||||
if (model && getShapeType() == SHAPE_TYPE_COMPOUND && model->didCollisionGeometryRequestFail()) {
|
||||
return false;
|
||||
} else if (_model && getShapeType() != SHAPE_TYPE_NONE && _model->didVisualGeometryRequestFail()) {
|
||||
} else if (model && getShapeType() != SHAPE_TYPE_NONE && model->didVisualGeometryRequestFail()) {
|
||||
return false;
|
||||
} else {
|
||||
return ModelEntityItem::shouldBePhysical();
|
||||
|
@ -651,9 +675,10 @@ bool RenderableModelEntityItem::shouldBePhysical() const {
|
|||
}
|
||||
|
||||
glm::quat RenderableModelEntityItem::getAbsoluteJointRotationInObjectFrame(int index) const {
|
||||
if (_model) {
|
||||
auto model = getModel();
|
||||
if (model) {
|
||||
glm::quat result;
|
||||
if (_model->getAbsoluteJointRotationInRigFrame(index, result)) {
|
||||
if (model->getAbsoluteJointRotationInRigFrame(index, result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -661,9 +686,10 @@ glm::quat RenderableModelEntityItem::getAbsoluteJointRotationInObjectFrame(int i
|
|||
}
|
||||
|
||||
glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(int index) const {
|
||||
if (_model) {
|
||||
auto model = getModel();
|
||||
if (model) {
|
||||
glm::vec3 result;
|
||||
if (_model->getAbsoluteJointTranslationInRigFrame(index, result)) {
|
||||
if (model->getAbsoluteJointTranslationInRigFrame(index, result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -671,10 +697,11 @@ glm::vec3 RenderableModelEntityItem::getAbsoluteJointTranslationInObjectFrame(in
|
|||
}
|
||||
|
||||
bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index, const glm::quat& rotation) {
|
||||
if (!_model) {
|
||||
auto model = getModel();
|
||||
if (!model) {
|
||||
return false;
|
||||
}
|
||||
const Rig& rig = _model->getRig();
|
||||
const Rig& rig = model->getRig();
|
||||
int jointParentIndex = rig.getJointParentIndex(index);
|
||||
if (jointParentIndex == -1) {
|
||||
return setLocalJointRotation(index, rotation);
|
||||
|
@ -700,10 +727,11 @@ bool RenderableModelEntityItem::setAbsoluteJointRotationInObjectFrame(int index,
|
|||
}
|
||||
|
||||
bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int index, const glm::vec3& translation) {
|
||||
if (!_model) {
|
||||
auto model = getModel();
|
||||
if (!model) {
|
||||
return false;
|
||||
}
|
||||
const Rig& rig = _model->getRig();
|
||||
const Rig& rig = model->getRig();
|
||||
|
||||
int jointParentIndex = rig.getJointParentIndex(index);
|
||||
if (jointParentIndex == -1) {
|
||||
|
@ -730,9 +758,10 @@ bool RenderableModelEntityItem::setAbsoluteJointTranslationInObjectFrame(int ind
|
|||
}
|
||||
|
||||
glm::quat RenderableModelEntityItem::getLocalJointRotation(int index) const {
|
||||
if (_model) {
|
||||
auto model = getModel();
|
||||
if (model) {
|
||||
glm::quat result;
|
||||
if (_model->getJointRotation(index, result)) {
|
||||
if (model->getJointRotation(index, result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -740,9 +769,10 @@ glm::quat RenderableModelEntityItem::getLocalJointRotation(int index) const {
|
|||
}
|
||||
|
||||
glm::vec3 RenderableModelEntityItem::getLocalJointTranslation(int index) const {
|
||||
if (_model) {
|
||||
auto model = getModel();
|
||||
if (model) {
|
||||
glm::vec3 result;
|
||||
if (_model->getJointTranslation(index, result)) {
|
||||
if (model->getJointTranslation(index, result)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
@ -810,19 +840,22 @@ void RenderableModelEntityItem::setJointTranslationsSet(const QVector<bool>& tra
|
|||
void RenderableModelEntityItem::locationChanged(bool tellPhysics) {
|
||||
PerformanceTimer pertTimer("locationChanged");
|
||||
EntityItem::locationChanged(tellPhysics);
|
||||
if (_model && _model->isLoaded()) {
|
||||
_model->updateRenderItems();
|
||||
auto model = getModel();
|
||||
if (model && model->isLoaded()) {
|
||||
model->updateRenderItems();
|
||||
}
|
||||
}
|
||||
|
||||
int RenderableModelEntityItem::getJointIndex(const QString& name) const {
|
||||
return (_model && _model->isActive()) ? _model->getRig().indexOfJoint(name) : -1;
|
||||
auto model = getModel();
|
||||
return (model && model->isActive()) ? model->getRig().indexOfJoint(name) : -1;
|
||||
}
|
||||
|
||||
QStringList RenderableModelEntityItem::getJointNames() const {
|
||||
QStringList result;
|
||||
if (_model && _model->isActive()) {
|
||||
const Rig& rig = _model->getRig();
|
||||
auto model = getModel();
|
||||
if (model && model->isActive()) {
|
||||
const Rig& rig = model->getRig();
|
||||
int jointCount = rig.getJointStateCount();
|
||||
for (int jointIndex = 0; jointIndex < jointCount; jointIndex++) {
|
||||
result << rig.nameOfJoint(jointIndex);
|
||||
|
@ -832,19 +865,16 @@ QStringList RenderableModelEntityItem::getJointNames() const {
|
|||
}
|
||||
|
||||
bool RenderableModelEntityItem::getMeshes(MeshProxyList& result) {
|
||||
if (!_model || !_model->isLoaded()) {
|
||||
auto model = getModel();
|
||||
if (!model || !model->isLoaded()) {
|
||||
return false;
|
||||
}
|
||||
BLOCKING_INVOKE_METHOD(_model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result));
|
||||
BLOCKING_INVOKE_METHOD(model.get(), "getMeshes", Q_RETURN_ARG(MeshProxyList, result));
|
||||
return !result.isEmpty();
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::copyAnimationJointDataToModel() {
|
||||
ModelPointer model;
|
||||
withReadLock([&] {
|
||||
model = _model;
|
||||
});
|
||||
|
||||
auto model = getModel();
|
||||
if (!model || !model->isLoaded()) {
|
||||
return;
|
||||
}
|
||||
|
@ -859,7 +889,7 @@ void RenderableModelEntityItem::copyAnimationJointDataToModel() {
|
|||
jointData.rotationDirty = false;
|
||||
}
|
||||
if (jointData.translationDirty) {
|
||||
_model->setJointTranslation(index, true, jointData.joint.translation, 1.0f);
|
||||
model->setJointTranslation(index, true, jointData.joint.translation, 1.0f);
|
||||
jointData.translationDirty = false;
|
||||
}
|
||||
}
|
||||
|
@ -1192,7 +1222,6 @@ void ModelEntityRenderer::doRenderUpdateSynchronousTyped(const ScenePointer& sce
|
|||
// When the individual mesh parts of a model finish fading, they will mark their Model as needing updating
|
||||
// we will watch for that and ask the model to update it's render items
|
||||
if (model->getRenderItemsNeedUpdate()) {
|
||||
qDebug() << "QQQ" << __FUNCTION__ << "Update model render items" << model->getURL();
|
||||
model->updateRenderItems();
|
||||
}
|
||||
|
||||
|
|
|
@ -34,10 +34,24 @@ class ModelEntityRenderer;
|
|||
} }
|
||||
|
||||
//#define MODEL_ENTITY_USE_FADE_EFFECT
|
||||
|
||||
class RenderableModelEntityItem : public ModelEntityItem {
|
||||
class ModelEntityWrapper : public ModelEntityItem {
|
||||
using Parent = ModelEntityItem;
|
||||
friend class render::entities::ModelEntityRenderer;
|
||||
|
||||
protected:
|
||||
ModelEntityWrapper(const EntityItemID& entityItemID) : Parent(entityItemID) {}
|
||||
void setModel(const ModelPointer& model);
|
||||
ModelPointer getModel() const;
|
||||
bool isModelLoaded() const;
|
||||
|
||||
bool _needsInitialSimulation{ true };
|
||||
private:
|
||||
ModelPointer _model;
|
||||
};
|
||||
|
||||
class RenderableModelEntityItem : public ModelEntityWrapper {
|
||||
friend class render::entities::ModelEntityRenderer;
|
||||
using Parent = ModelEntityWrapper;
|
||||
public:
|
||||
static EntityItemPointer factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
|
@ -97,14 +111,11 @@ private:
|
|||
bool isAnimatingSomething() const;
|
||||
void autoResizeJointArrays();
|
||||
void copyAnimationJointDataToModel();
|
||||
void setModel(const ModelPointer& model);
|
||||
|
||||
void getCollisionGeometryResource();
|
||||
GeometryResource::Pointer _compoundShapeResource;
|
||||
bool _originalTexturesRead { false };
|
||||
QVariantMap _originalTextures;
|
||||
ModelPointer _model;
|
||||
bool _needsInitialSimulation { true };
|
||||
bool _dimensionsInitialized { true };
|
||||
bool _needsJointSimulation { false };
|
||||
bool _showCollisionGeometry { false };
|
||||
|
|
|
@ -42,7 +42,8 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) :
|
|||
setLocalVelocity(ENTITY_ITEM_DEFAULT_VELOCITY);
|
||||
setLocalAngularVelocity(ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY);
|
||||
// explicitly set transform parts to set dirty flags used by batch rendering
|
||||
setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS);
|
||||
locationChanged();
|
||||
dimensionsChanged();
|
||||
quint64 now = usecTimestampNow();
|
||||
_lastSimulated = 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) {
|
||||
return;
|
||||
}
|
||||
setScale(value);
|
||||
if (_dimensions != value) {
|
||||
_dimensions = value;
|
||||
locationChanged();
|
||||
dimensionsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||
|
|
|
@ -179,7 +179,7 @@ public:
|
|||
void setDescription(const QString& value);
|
||||
|
||||
/// 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);
|
||||
|
||||
float getLocalRenderAlpha() const;
|
||||
|
@ -470,6 +470,7 @@ protected:
|
|||
|
||||
virtual void dimensionsChanged() override;
|
||||
|
||||
glm::vec3 _dimensions { ENTITY_ITEM_DEFAULT_DIMENSIONS };
|
||||
EntityTypes::EntityType _type { EntityTypes::Unknown };
|
||||
quint64 _lastSimulated { 0 }; // last time this entity called simulate(), this includes velocity, angular velocity,
|
||||
// and physics changes
|
||||
|
|
|
@ -539,7 +539,7 @@ void EntityScriptingInterface::deleteEntity(QUuid id) {
|
|||
}
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine) {
|
||||
void EntityScriptingInterface::setEntitiesScriptEngine(QSharedPointer<EntitiesScriptEngineProvider> engine) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
|
||||
_entitiesScriptEngine = engine;
|
||||
}
|
||||
|
@ -749,7 +749,7 @@ bool EntityPropertyMetadataRequest::script(EntityItemID entityID, QScriptValue h
|
|||
request->deleteLater();
|
||||
});
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
entityScriptingInterface->withEntitiesScriptEngine([&](EntitiesScriptEngineProvider* entitiesScriptEngine) {
|
||||
entityScriptingInterface->withEntitiesScriptEngine([&](QSharedPointer<EntitiesScriptEngineProvider> entitiesScriptEngine) {
|
||||
if (entitiesScriptEngine) {
|
||||
request->setFuture(entitiesScriptEngine->getLocalEntityScriptDetails(entityID));
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ public:
|
|||
|
||||
void setEntityTree(EntityTreePointer modelTree);
|
||||
EntityTreePointer getEntityTree() { return _entityTree; }
|
||||
void setEntitiesScriptEngine(EntitiesScriptEngineProvider* engine);
|
||||
void setEntitiesScriptEngine(QSharedPointer<EntitiesScriptEngineProvider> engine);
|
||||
float calculateCost(float mass, float oldVelocity, float newVelocity);
|
||||
|
||||
void resetActivityTracking();
|
||||
|
@ -405,7 +405,7 @@ signals:
|
|||
void webEventReceived(const EntityItemID& entityItemID, const QVariant& message);
|
||||
|
||||
protected:
|
||||
void withEntitiesScriptEngine(std::function<void(EntitiesScriptEngineProvider*)> function) {
|
||||
void withEntitiesScriptEngine(std::function<void(QSharedPointer<EntitiesScriptEngineProvider>)> function) {
|
||||
std::lock_guard<std::recursive_mutex> lock(_entitiesScriptEngineLock);
|
||||
function(_entitiesScriptEngine);
|
||||
};
|
||||
|
@ -427,7 +427,7 @@ private:
|
|||
EntityTreePointer _entityTree;
|
||||
|
||||
std::recursive_mutex _entitiesScriptEngineLock;
|
||||
EntitiesScriptEngineProvider* _entitiesScriptEngine { nullptr };
|
||||
QSharedPointer<EntitiesScriptEngineProvider> _entitiesScriptEngine;
|
||||
|
||||
bool _bidOnSimulationOwnership { false };
|
||||
float _currentAvatarEnergy = { FLT_MAX };
|
||||
|
|
|
@ -176,7 +176,7 @@ void PolyLineEntityItem::calculateScaleAndRegistrationPoint() {
|
|||
}
|
||||
|
||||
// if Polyline has only one or fewer points, use default dimension settings
|
||||
SpatiallyNestable::setScale(newScale);
|
||||
setDimensions(newScale);
|
||||
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
|
||||
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;
|
||||
static const float DEFAULT_LINE_WIDTH;
|
||||
|
|
|
@ -12,14 +12,13 @@
|
|||
#include "CharacterController.h"
|
||||
|
||||
#include <NumericalConstants.h>
|
||||
#include <AvatarConstants.h>
|
||||
|
||||
#include "ObjectMotionState.h"
|
||||
#include "PhysicsHelpers.h"
|
||||
#include "PhysicsLogging.h"
|
||||
|
||||
const btVector3 LOCAL_UP_AXIS(0.0f, 1.0f, 0.0f);
|
||||
const float JUMP_SPEED = 3.5f;
|
||||
const float MAX_FALL_HEIGHT = 20.0f;
|
||||
float DEFAULT_CHARACTER_GRAVITY = -5.0f;
|
||||
|
||||
#ifdef DEBUG_STATE_CHANGE
|
||||
|
@ -63,12 +62,11 @@ CharacterController::CharacterMotor::CharacterMotor(const glm::vec3& vel, const
|
|||
}
|
||||
|
||||
CharacterController::CharacterController() {
|
||||
_floorDistance = MAX_FALL_HEIGHT;
|
||||
_floorDistance = _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT;
|
||||
|
||||
_targetVelocity.setValue(0.0f, 0.0f, 0.0f);
|
||||
_followDesiredBodyTransform.setIdentity();
|
||||
_followTimeRemaining = 0.0f;
|
||||
_jumpSpeed = JUMP_SPEED;
|
||||
_state = State::Hover;
|
||||
_isPushingUp = false;
|
||||
_rayHitStartTime = 0;
|
||||
|
@ -266,13 +264,13 @@ void CharacterController::playerStep(btCollisionWorld* collisionWorld, btScalar
|
|||
btVector3 endPos = startPos + linearDisplacement;
|
||||
|
||||
btQuaternion startRot = bodyTransform.getRotation();
|
||||
glm::vec2 currentFacing = getFacingDir2D(bulletToGLM(startRot));
|
||||
glm::vec2 currentRight(currentFacing.y, -currentFacing.x);
|
||||
glm::vec2 desiredFacing = getFacingDir2D(bulletToGLM(_followDesiredBodyTransform.getRotation()));
|
||||
float deltaAngle = acosf(glm::clamp(glm::dot(currentFacing, desiredFacing), -1.0f, 1.0f));
|
||||
float angularSpeed = deltaAngle / _followTimeRemaining;
|
||||
float sign = copysignf(1.0f, glm::dot(desiredFacing, currentRight));
|
||||
btQuaternion angularDisplacement = btQuaternion(btVector3(0.0f, 1.0f, 0.0f), sign * angularSpeed * dt);
|
||||
btQuaternion desiredRot = _followDesiredBodyTransform.getRotation();
|
||||
if (desiredRot.dot(startRot) < 0.0f) {
|
||||
desiredRot = -desiredRot;
|
||||
}
|
||||
btQuaternion deltaRot = desiredRot * startRot.inverse();
|
||||
float angularSpeed = deltaRot.getAngle() / _followTimeRemaining;
|
||||
btQuaternion angularDisplacement = btQuaternion(deltaRot.getAxis(), angularSpeed * dt);
|
||||
btQuaternion endRot = angularDisplacement * startRot;
|
||||
|
||||
// in order to accumulate displacement of avatar position, we need to take _shapeLocalOffset into account.
|
||||
|
@ -393,6 +391,21 @@ void CharacterController::setState(State desiredState) {
|
|||
}
|
||||
}
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
void CharacterController::updateGravity() {
|
||||
int16_t collisionGroup = computeCollisionGroup();
|
||||
if (_state == State::Hover || collisionGroup == BULLET_COLLISION_GROUP_COLLISIONLESS) {
|
||||
_gravity = 0.0f;
|
||||
} else {
|
||||
_gravity = DEFAULT_AVATAR_GRAVITY;
|
||||
}
|
||||
if (_rigidBody) {
|
||||
_rigidBody->setGravity(_gravity * _currentUp);
|
||||
}
|
||||
}
|
||||
|
||||
>>>>>>> 5e5b77fbaaeff61a26144a240329eca70765c1a9
|
||||
void CharacterController::setLocalBoundingBox(const glm::vec3& minCorner, const glm::vec3& scale) {
|
||||
float x = scale.x;
|
||||
float z = scale.z;
|
||||
|
@ -662,7 +675,7 @@ void CharacterController::updateState() {
|
|||
const btScalar FLY_TO_GROUND_THRESHOLD = 0.1f * _radius;
|
||||
const btScalar GROUND_TO_FLY_THRESHOLD = 0.8f * _radius + _halfHeight;
|
||||
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;
|
||||
|
||||
// scan for distant floor
|
||||
|
@ -672,7 +685,7 @@ void CharacterController::updateState() {
|
|||
btScalar rayLength = _radius;
|
||||
int16_t collisionGroup = computeCollisionGroup();
|
||||
if (collisionGroup == BULLET_COLLISION_GROUP_MY_AVATAR) {
|
||||
rayLength += MAX_FALL_HEIGHT;
|
||||
rayLength += _scaleFactor * DEFAULT_AVATAR_FALL_HEIGHT;
|
||||
} else {
|
||||
rayLength += MIN_HOVER_HEIGHT;
|
||||
}
|
||||
|
@ -726,11 +739,15 @@ void CharacterController::updateState() {
|
|||
SET_STATE(State::Hover, "no ground");
|
||||
} else if ((now - _takeoffToInAirStartTime) > TAKE_OFF_TO_IN_AIR_PERIOD) {
|
||||
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);
|
||||
}
|
||||
break;
|
||||
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)) {
|
||||
SET_STATE(State::Ground, "hit ground");
|
||||
} else {
|
||||
|
|
|
@ -76,6 +76,7 @@ public:
|
|||
void setStepUpEnabled(bool enabled) { _stepUpEnabled = enabled; }
|
||||
void computeNewVelocity(btScalar dt, btVector3& velocity);
|
||||
void computeNewVelocity(btScalar dt, glm::vec3& velocity);
|
||||
void setScaleFactor(btScalar scaleFactor) { _scaleFactor = scaleFactor; }
|
||||
|
||||
// HACK for legacy 'thrust' feature
|
||||
void setLinearAcceleration(const glm::vec3& acceleration) { _linearAcceleration = glmToBullet(acceleration); }
|
||||
|
@ -188,7 +189,6 @@ protected:
|
|||
|
||||
btScalar _gravity { 0.0f };
|
||||
|
||||
btScalar _jumpSpeed;
|
||||
btScalar _followTime;
|
||||
btVector3 _followLinearDisplacement;
|
||||
btQuaternion _followAngularDisplacement;
|
||||
|
@ -206,6 +206,8 @@ protected:
|
|||
bool _flyingAllowed { true };
|
||||
bool _collisionlessAllowed { true };
|
||||
bool _collisionless { false };
|
||||
|
||||
btScalar _scaleFactor { 1.0f };
|
||||
};
|
||||
|
||||
#endif // hifi_CharacterController_h
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
#ifndef hifi_AbstractScriptingServicesInterface_h
|
||||
#define hifi_AbstractScriptingServicesInterface_h
|
||||
|
||||
class ScriptEngine;
|
||||
#include <BaseScriptEngine.h>
|
||||
|
||||
/// Interface provided by Application to other objects that need access to scripting services of the application
|
||||
class AbstractScriptingServicesInterface {
|
||||
public:
|
||||
/// Registers application specific services with a script engine.
|
||||
virtual void registerScriptEngineWithApplicationServices(ScriptEngine* scriptEngine) = 0;
|
||||
virtual void registerScriptEngineWithApplicationServices(ScriptEnginePointer scriptEngine) = 0;
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <BaseScriptEngine.h>
|
||||
#include <DependencyManager.h>
|
||||
#include <recording/ClipCache.h>
|
||||
#include <recording/Forward.h>
|
||||
|
@ -28,7 +29,7 @@ class RecordingScriptingInterface : public QObject, public Dependency {
|
|||
public:
|
||||
RecordingScriptingInterface();
|
||||
|
||||
void setScriptEngine(QScriptEngine* scriptEngine) { _scriptEngine = scriptEngine; }
|
||||
void setScriptEngine(QSharedPointer<BaseScriptEngine> scriptEngine) { _scriptEngine = scriptEngine; }
|
||||
|
||||
public slots:
|
||||
void loadRecording(const QString& url, QScriptValue callback = QScriptValue());
|
||||
|
@ -85,7 +86,7 @@ protected:
|
|||
Flag _useSkeletonModel { false };
|
||||
recording::ClipPointer _lastClip;
|
||||
|
||||
QScriptEngine* _scriptEngine;
|
||||
QSharedPointer<BaseScriptEngine> _scriptEngine;
|
||||
QSet<recording::NetworkClipLoaderPointer> _clipLoaders;
|
||||
};
|
||||
|
||||
|
|
|
@ -153,6 +153,15 @@ QString ScriptEngine::logException(const QScriptValue& exception) {
|
|||
return message;
|
||||
}
|
||||
|
||||
ScriptEnginePointer scriptEngineFactory(ScriptEngine::Context context,
|
||||
const QString& scriptContents,
|
||||
const QString& fileNameString) {
|
||||
ScriptEngine* engine = new ScriptEngine(context, scriptContents, fileNameString);
|
||||
ScriptEnginePointer engineSP = ScriptEnginePointer(engine);
|
||||
DependencyManager::get<ScriptEngines>()->addScriptEngine(qSharedPointerCast<ScriptEngine>(engineSP));
|
||||
return engineSP;
|
||||
}
|
||||
|
||||
int ScriptEngine::processLevelMaxRetries { ScriptRequest::MAX_RETRIES };
|
||||
ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const QString& fileNameString) :
|
||||
BaseScriptEngine(),
|
||||
|
@ -160,10 +169,10 @@ ScriptEngine::ScriptEngine(Context context, const QString& scriptContents, const
|
|||
_scriptContents(scriptContents),
|
||||
_timerFunctionMap(),
|
||||
_fileNameString(fileNameString),
|
||||
_arrayBufferClass(new ArrayBufferClass(this))
|
||||
_arrayBufferClass(new ArrayBufferClass(this)),
|
||||
// don't delete `ScriptEngines` until all `ScriptEngine`s are gone
|
||||
_scriptEngines(DependencyManager::get<ScriptEngines>())
|
||||
{
|
||||
DependencyManager::get<ScriptEngines>()->addScriptEngine(this);
|
||||
|
||||
connect(this, &QScriptEngine::signalHandlerException, this, [this](const QScriptValue& exception) {
|
||||
if (hasUncaughtException()) {
|
||||
// the engine's uncaughtException() seems to produce much better stack traces here
|
||||
|
@ -208,22 +217,9 @@ QString ScriptEngine::getContext() const {
|
|||
}
|
||||
|
||||
ScriptEngine::~ScriptEngine() {
|
||||
// FIXME: are these scriptInfoMessage/scriptWarningMessage segfaulting anybody else at app shutdown?
|
||||
#if !defined(Q_OS_LINUX)
|
||||
scriptInfoMessage("Script Engine shutting down:" + getFilename());
|
||||
#else
|
||||
qCDebug(scriptengine) << "~ScriptEngine()" << this;
|
||||
#endif
|
||||
|
||||
auto scriptEngines = DependencyManager::get<ScriptEngines>();
|
||||
if (scriptEngines) {
|
||||
scriptEngines->removeScriptEngine(this);
|
||||
} else {
|
||||
#if !defined(Q_OS_LINUX)
|
||||
scriptWarningMessage("Script destroyed after ScriptEngines!");
|
||||
#else
|
||||
qCWarning(scriptengine) << ("Script destroyed after ScriptEngines!");
|
||||
#endif
|
||||
scriptEngines->removeScriptEngine(qSharedPointerCast<ScriptEngine>(sharedFromThis()));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -294,7 +290,7 @@ void ScriptEngine::runDebuggable() {
|
|||
stopAllTimers(); // make sure all our timers are stopped if the script is ending
|
||||
|
||||
emit scriptEnding();
|
||||
emit finished(_fileNameString, this);
|
||||
emit finished(_fileNameString, qSharedPointerCast<ScriptEngine>(sharedFromThis()));
|
||||
_isRunning = false;
|
||||
|
||||
emit runningStateChanged();
|
||||
|
@ -503,7 +499,8 @@ static void animVarMapFromScriptValue(const QScriptValue& value, AnimVariantMap&
|
|||
parameters.animVariantMapFromScriptValue(value);
|
||||
}
|
||||
// ... while these two are not. But none of the four are ever used.
|
||||
static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine, const AnimVariantResultHandler& resultHandler) {
|
||||
static QScriptValue resultHandlerToScriptValue(QScriptEngine* engine,
|
||||
const AnimVariantResultHandler& resultHandler) {
|
||||
qCCritical(scriptengine) << "Attempt to marshall result handler to javascript";
|
||||
assert(false);
|
||||
return QScriptValue();
|
||||
|
@ -516,7 +513,8 @@ static void resultHandlerFromScriptValue(const QScriptValue& value, AnimVariantR
|
|||
// Templated qScriptRegisterMetaType fails to compile with raw pointers
|
||||
using ScriptableResourceRawPtr = ScriptableResource*;
|
||||
|
||||
static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine, const ScriptableResourceRawPtr& resource) {
|
||||
static QScriptValue scriptableResourceToScriptValue(QScriptEngine* engine,
|
||||
const ScriptableResourceRawPtr& resource) {
|
||||
// The first script to encounter this resource will track its memory.
|
||||
// In this way, it will be more likely to GC.
|
||||
// This fails in the case that the resource is used across many scripts, but
|
||||
|
@ -539,11 +537,11 @@ static void scriptableResourceFromScriptValue(const QScriptValue& value, Scripta
|
|||
resource = static_cast<ScriptableResourceRawPtr>(value.toQObject());
|
||||
}
|
||||
|
||||
static QScriptValue createScriptableResourcePrototype(QScriptEngine* engine) {
|
||||
static QScriptValue createScriptableResourcePrototype(ScriptEnginePointer engine) {
|
||||
auto prototype = engine->newObject();
|
||||
|
||||
// Expose enum State to JS/QML via properties
|
||||
QObject* state = new QObject(engine);
|
||||
QObject* state = new QObject(engine.data());
|
||||
state->setObjectName("ResourceState");
|
||||
auto metaEnum = QMetaEnum::fromType<ScriptableResource::State>();
|
||||
for (int i = 0; i < metaEnum.keyCount(); ++i) {
|
||||
|
@ -693,7 +691,7 @@ void ScriptEngine::init() {
|
|||
qScriptRegisterMetaType(this, resultHandlerToScriptValue, resultHandlerFromScriptValue);
|
||||
|
||||
// Scriptable cache access
|
||||
auto resourcePrototype = createScriptableResourcePrototype(this);
|
||||
auto resourcePrototype = createScriptableResourcePrototype(qSharedPointerCast<ScriptEngine>(sharedFromThis()));
|
||||
globalObject().setProperty("Resource", resourcePrototype);
|
||||
setDefaultPrototype(qMetaTypeId<ScriptableResource*>(), resourcePrototype);
|
||||
qScriptRegisterMetaType(this, scriptableResourceToScriptValue, scriptableResourceFromScriptValue);
|
||||
|
@ -1178,7 +1176,7 @@ void ScriptEngine::run() {
|
|||
}
|
||||
}
|
||||
|
||||
emit finished(_fileNameString, this);
|
||||
emit finished(_fileNameString, qSharedPointerCast<ScriptEngine>(sharedFromThis()));
|
||||
|
||||
_isRunning = false;
|
||||
emit runningStateChanged();
|
||||
|
|
|
@ -53,6 +53,8 @@ static const int SCRIPT_FPS = 60;
|
|||
static const int DEFAULT_MAX_ENTITY_PPS = 9000;
|
||||
static const int DEFAULT_ENTITY_PPS_PER_SCRIPT = 900;
|
||||
|
||||
class ScriptEngines;
|
||||
|
||||
class CallbackData {
|
||||
public:
|
||||
QScriptValue function;
|
||||
|
@ -242,7 +244,7 @@ signals:
|
|||
void errorLoadingScript(const QString& scriptFilename);
|
||||
void update(float deltaTime);
|
||||
void scriptEnding();
|
||||
void finished(const QString& fileNameString, ScriptEngine* engine);
|
||||
void finished(const QString& fileNameString, ScriptEnginePointer);
|
||||
void cleanupMenuItem(const QString& menuItemString);
|
||||
void printedMessage(const QString& message, const QString& scriptName);
|
||||
void errorMessage(const QString& message, const QString& scriptName);
|
||||
|
@ -328,6 +330,12 @@ protected:
|
|||
static const QString _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS;
|
||||
|
||||
Setting::Handle<bool> _enableExtendedJSExceptions { _SETTINGS_ENABLE_EXTENDED_EXCEPTIONS, true };
|
||||
|
||||
QSharedPointer<ScriptEngines> _scriptEngines;
|
||||
};
|
||||
|
||||
ScriptEnginePointer scriptEngineFactory(ScriptEngine::Context context,
|
||||
const QString& scriptContents,
|
||||
const QString& fileNameString);
|
||||
|
||||
#endif // hifi_ScriptEngine_h
|
||||
|
|
|
@ -137,16 +137,14 @@ void ScriptEngines::registerScriptInitializer(ScriptInitializer initializer) {
|
|||
_scriptInitializers.push_back(initializer);
|
||||
}
|
||||
|
||||
void ScriptEngines::addScriptEngine(ScriptEngine* engine) {
|
||||
if (_isStopped) {
|
||||
engine->deleteLater();
|
||||
} else {
|
||||
void ScriptEngines::addScriptEngine(ScriptEnginePointer engine) {
|
||||
if (!_isStopped) {
|
||||
QMutexLocker locker(&_allScriptsMutex);
|
||||
_allKnownScriptEngines.insert(engine);
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEngines::removeScriptEngine(ScriptEngine* engine) {
|
||||
void ScriptEngines::removeScriptEngine(ScriptEnginePointer engine) {
|
||||
// If we're not already in the middle of stopping all scripts, then we should remove ourselves
|
||||
// from the list of running scripts. We don't do this if we're in the process of stopping all scripts
|
||||
// because that method removes scripts from its list as it iterates them
|
||||
|
@ -161,9 +159,9 @@ void ScriptEngines::shutdownScripting() {
|
|||
QMutexLocker locker(&_allScriptsMutex);
|
||||
qCDebug(scriptengine) << "Stopping all scripts.... currently known scripts:" << _allKnownScriptEngines.size();
|
||||
|
||||
QMutableSetIterator<ScriptEngine*> i(_allKnownScriptEngines);
|
||||
QMutableSetIterator<ScriptEnginePointer> i(_allKnownScriptEngines);
|
||||
while (i.hasNext()) {
|
||||
ScriptEngine* scriptEngine = i.next();
|
||||
ScriptEnginePointer scriptEngine = i.next();
|
||||
QString scriptName = scriptEngine->getFilename();
|
||||
|
||||
// NOTE: typically all script engines are running. But there's at least one known exception to this, the
|
||||
|
@ -187,12 +185,9 @@ void ScriptEngines::shutdownScripting() {
|
|||
qCDebug(scriptengine) << "waiting on script:" << scriptName;
|
||||
scriptEngine->waitTillDoneRunning();
|
||||
qCDebug(scriptengine) << "done waiting on script:" << scriptName;
|
||||
|
||||
scriptEngine->deleteLater();
|
||||
|
||||
// Once the script is stopped, we can remove it from our set
|
||||
i.remove();
|
||||
}
|
||||
// Once the script is stopped, we can remove it from our set
|
||||
i.remove();
|
||||
}
|
||||
qCDebug(scriptengine) << "DONE Stopping all scripts....";
|
||||
}
|
||||
|
@ -369,9 +364,9 @@ void ScriptEngines::stopAllScripts(bool restart) {
|
|||
_isReloading = true;
|
||||
}
|
||||
|
||||
for (QHash<QUrl, ScriptEngine*>::const_iterator it = _scriptEnginesHash.constBegin();
|
||||
for (QHash<QUrl, ScriptEnginePointer>::const_iterator it = _scriptEnginesHash.constBegin();
|
||||
it != _scriptEnginesHash.constEnd(); it++) {
|
||||
ScriptEngine *scriptEngine = it.value();
|
||||
ScriptEnginePointer scriptEngine = it.value();
|
||||
// skip already stopped scripts
|
||||
if (scriptEngine->isFinished() || scriptEngine->isStopping()) {
|
||||
continue;
|
||||
|
@ -417,11 +412,12 @@ bool ScriptEngines::stopScript(const QString& rawScriptURL, bool restart) {
|
|||
|
||||
QReadLocker lock(&_scriptEnginesHashLock);
|
||||
if (_scriptEnginesHash.contains(scriptURL)) {
|
||||
ScriptEngine* scriptEngine = _scriptEnginesHash[scriptURL];
|
||||
ScriptEnginePointer scriptEngine = _scriptEnginesHash[scriptURL];
|
||||
if (restart) {
|
||||
auto scriptCache = DependencyManager::get<ScriptCache>();
|
||||
scriptCache->deleteScript(scriptURL);
|
||||
connect(scriptEngine, &ScriptEngine::finished, this, [this](QString scriptName, ScriptEngine* engine) {
|
||||
connect(scriptEngine.data(), &ScriptEngine::finished,
|
||||
this, [this](QString scriptName, ScriptEnginePointer engine) {
|
||||
reloadScript(scriptName);
|
||||
});
|
||||
}
|
||||
|
@ -449,11 +445,11 @@ void ScriptEngines::reloadAllScripts() {
|
|||
stopAllScripts(true);
|
||||
}
|
||||
|
||||
ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor,
|
||||
ScriptEnginePointer ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserLoaded, bool loadScriptFromEditor,
|
||||
bool activateMainWindow, bool reload) {
|
||||
if (thread() != QThread::currentThread()) {
|
||||
ScriptEngine* result { nullptr };
|
||||
BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEngine*, result),
|
||||
ScriptEnginePointer result { nullptr };
|
||||
BLOCKING_INVOKE_METHOD(this, "loadScript", Q_RETURN_ARG(ScriptEnginePointer, result),
|
||||
Q_ARG(QUrl, scriptFilename),
|
||||
Q_ARG(bool, isUserLoaded),
|
||||
Q_ARG(bool, loadScriptFromEditor),
|
||||
|
@ -479,19 +475,16 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL
|
|||
return scriptEngine;
|
||||
}
|
||||
|
||||
scriptEngine = new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName());
|
||||
scriptEngine = ScriptEnginePointer(new ScriptEngine(_context, NO_SCRIPT, "about:" + scriptFilename.fileName()));
|
||||
addScriptEngine(scriptEngine);
|
||||
scriptEngine->setUserLoaded(isUserLoaded);
|
||||
connect(scriptEngine, &ScriptEngine::doneRunning, this, [scriptEngine] {
|
||||
scriptEngine->deleteLater();
|
||||
}, Qt::QueuedConnection);
|
||||
|
||||
|
||||
if (scriptFilename.isEmpty() || !scriptUrl.isValid()) {
|
||||
launchScriptEngine(scriptEngine);
|
||||
} else {
|
||||
// connect to the appropriate signals of this script engine
|
||||
connect(scriptEngine, &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded);
|
||||
connect(scriptEngine, &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError);
|
||||
connect(scriptEngine.data(), &ScriptEngine::scriptLoaded, this, &ScriptEngines::onScriptEngineLoaded);
|
||||
connect(scriptEngine.data(), &ScriptEngine::errorLoadingScript, this, &ScriptEngines::onScriptEngineError);
|
||||
|
||||
// get the script engine object to load the script at the designated script URL
|
||||
scriptEngine->loadURL(scriptUrl, reload);
|
||||
|
@ -500,8 +493,8 @@ ScriptEngine* ScriptEngines::loadScript(const QUrl& scriptFilename, bool isUserL
|
|||
return scriptEngine;
|
||||
}
|
||||
|
||||
ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) {
|
||||
ScriptEngine* result = nullptr;
|
||||
ScriptEnginePointer ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) {
|
||||
ScriptEnginePointer result;
|
||||
{
|
||||
QReadLocker lock(&_scriptEnginesHashLock);
|
||||
const QUrl scriptURL = normalizeScriptURL(rawScriptURL);
|
||||
|
@ -516,7 +509,8 @@ ScriptEngine* ScriptEngines::getScriptEngine(const QUrl& rawScriptURL) {
|
|||
// FIXME - change to new version of ScriptCache loading notification
|
||||
void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
|
||||
UserActivityLogger::getInstance().loadedScript(rawScriptURL);
|
||||
ScriptEngine* scriptEngine = qobject_cast<ScriptEngine*>(sender());
|
||||
QSharedPointer<BaseScriptEngine> baseScriptEngine = qobject_cast<ScriptEngine*>(sender())->sharedFromThis();
|
||||
ScriptEnginePointer scriptEngine = qSharedPointerCast<ScriptEngine>(baseScriptEngine);
|
||||
|
||||
launchScriptEngine(scriptEngine);
|
||||
|
||||
|
@ -532,12 +526,12 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
|
|||
emit scriptCountChanged();
|
||||
}
|
||||
|
||||
void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) {
|
||||
connect(scriptEngine, &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection);
|
||||
connect(scriptEngine, &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) {
|
||||
void ScriptEngines::launchScriptEngine(ScriptEnginePointer scriptEngine) {
|
||||
connect(scriptEngine.data(), &ScriptEngine::finished, this, &ScriptEngines::onScriptFinished, Qt::DirectConnection);
|
||||
connect(scriptEngine.data(), &ScriptEngine::loadScript, [&](const QString& scriptName, bool userLoaded) {
|
||||
loadScript(scriptName, userLoaded);
|
||||
});
|
||||
connect(scriptEngine, &ScriptEngine::reloadScript, [&](const QString& scriptName, bool userLoaded) {
|
||||
connect(scriptEngine.data(), &ScriptEngine::reloadScript, [&](const QString& scriptName, bool userLoaded) {
|
||||
loadScript(scriptName, userLoaded, false, false, true);
|
||||
});
|
||||
|
||||
|
@ -558,7 +552,7 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) {
|
|||
}
|
||||
}
|
||||
|
||||
void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine* engine) {
|
||||
void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEnginePointer engine) {
|
||||
bool removed = false;
|
||||
{
|
||||
QWriteLocker lock(&_scriptEnginesHashLock);
|
||||
|
|
|
@ -33,7 +33,7 @@ class ScriptEngines : public QObject, public Dependency {
|
|||
Q_PROPERTY(ScriptsModelFilter* scriptsModelFilter READ scriptsModelFilter CONSTANT)
|
||||
|
||||
public:
|
||||
using ScriptInitializer = std::function<void(ScriptEngine*)>;
|
||||
using ScriptInitializer = std::function<void(ScriptEnginePointer)>;
|
||||
|
||||
ScriptEngines(ScriptEngine::Context context);
|
||||
void registerScriptInitializer(ScriptInitializer initializer);
|
||||
|
@ -45,7 +45,7 @@ public:
|
|||
void loadDefaultScripts();
|
||||
void setScriptsLocation(const QString& scriptsLocation);
|
||||
QStringList getRunningScripts();
|
||||
ScriptEngine* getScriptEngine(const QUrl& scriptHash);
|
||||
ScriptEnginePointer getScriptEngine(const QUrl& scriptHash);
|
||||
|
||||
ScriptsModel* scriptsModel() { return &_scriptsModel; };
|
||||
ScriptsModelFilter* scriptsModelFilter() { return &_scriptsModelFilter; };
|
||||
|
@ -53,7 +53,7 @@ public:
|
|||
QString getDefaultScriptsLocation() const;
|
||||
|
||||
Q_INVOKABLE void loadOneScript(const QString& scriptFilename);
|
||||
Q_INVOKABLE ScriptEngine* loadScript(const QUrl& scriptFilename = QString(),
|
||||
Q_INVOKABLE ScriptEnginePointer loadScript(const QUrl& scriptFilename = QString(),
|
||||
bool isUserLoaded = true, bool loadScriptFromEditor = false, bool activateMainWindow = false, bool reload = false);
|
||||
Q_INVOKABLE bool stopScript(const QString& scriptHash, bool restart = false);
|
||||
|
||||
|
@ -72,6 +72,8 @@ public:
|
|||
void shutdownScripting();
|
||||
bool isStopped() const { return _isStopped; }
|
||||
|
||||
void addScriptEngine(ScriptEnginePointer);
|
||||
|
||||
signals:
|
||||
void scriptCountChanged();
|
||||
void scriptsReloading();
|
||||
|
@ -92,22 +94,21 @@ public slots:
|
|||
void onClearDebugWindow();
|
||||
|
||||
protected slots:
|
||||
void onScriptFinished(const QString& fileNameString, ScriptEngine* engine);
|
||||
void onScriptFinished(const QString& fileNameString, ScriptEnginePointer engine);
|
||||
|
||||
protected:
|
||||
friend class ScriptEngine;
|
||||
|
||||
void reloadScript(const QString& scriptName) { loadScript(scriptName, true, false, false, true); }
|
||||
void addScriptEngine(ScriptEngine* engine);
|
||||
void removeScriptEngine(ScriptEngine* engine);
|
||||
void removeScriptEngine(ScriptEnginePointer);
|
||||
void onScriptEngineLoaded(const QString& scriptFilename);
|
||||
void onScriptEngineError(const QString& scriptFilename);
|
||||
void launchScriptEngine(ScriptEngine* engine);
|
||||
void launchScriptEngine(ScriptEnginePointer);
|
||||
|
||||
ScriptEngine::Context _context;
|
||||
QReadWriteLock _scriptEnginesHashLock;
|
||||
QHash<QUrl, ScriptEngine*> _scriptEnginesHash;
|
||||
QSet<ScriptEngine*> _allKnownScriptEngines;
|
||||
QHash<QUrl, ScriptEnginePointer> _scriptEnginesHash;
|
||||
QSet<ScriptEnginePointer> _allKnownScriptEngines;
|
||||
QMutex _allScriptsMutex;
|
||||
std::list<ScriptInitializer> _scriptInitializers;
|
||||
mutable Setting::Handle<QString> _scriptsLocationHandle;
|
||||
|
|
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
|
|
@ -16,6 +16,9 @@
|
|||
#include <QtCore/QDebug>
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
class ScriptEngine;
|
||||
using ScriptEnginePointer = QSharedPointer<ScriptEngine>;
|
||||
|
||||
// common base class for extending QScriptEngine itself
|
||||
class BaseScriptEngine : public QScriptEngine, public QEnableSharedFromThis<BaseScriptEngine> {
|
||||
Q_OBJECT
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
#include "DependencyManager.h"
|
||||
#include "SharedUtil.h"
|
||||
#include "StreamUtils.h"
|
||||
#include "SharedLogging.h"
|
||||
|
||||
const float defaultAACubeSize = 1.0f;
|
||||
|
@ -83,8 +84,7 @@ Transform SpatiallyNestable::getParentTransform(bool& success, int depth) const
|
|||
return result;
|
||||
}
|
||||
if (parent) {
|
||||
Transform parentTransform = parent->getTransform(_parentJointIndex, success, depth + 1);
|
||||
result = parentTransform.setScale(1.0f); // TODO: scaling
|
||||
result = parent->getTransform(_parentJointIndex, success, depth + 1);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
@ -156,7 +156,6 @@ void SpatiallyNestable::setParentJointIndex(quint16 parentJointIndex) {
|
|||
glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position,
|
||||
const QUuid& parentID, int parentJointIndex,
|
||||
bool& success) {
|
||||
Transform result;
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
if (!parentFinder) {
|
||||
success = false;
|
||||
|
@ -180,23 +179,17 @@ glm::vec3 SpatiallyNestable::worldToLocal(const glm::vec3& position,
|
|||
if (!success) {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
parentTransform.setScale(1.0f); // TODO: scale
|
||||
}
|
||||
success = true;
|
||||
|
||||
Transform positionTransform;
|
||||
positionTransform.setTranslation(position);
|
||||
Transform myWorldTransform;
|
||||
Transform::mult(myWorldTransform, parentTransform, positionTransform);
|
||||
myWorldTransform.setTranslation(position);
|
||||
Transform::inverseMult(result, parentTransform, myWorldTransform);
|
||||
return result.getTranslation();
|
||||
Transform invParentTransform;
|
||||
parentTransform.evalInverse(invParentTransform);
|
||||
return invParentTransform.transform(position);
|
||||
}
|
||||
|
||||
glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation,
|
||||
const QUuid& parentID, int parentJointIndex,
|
||||
bool& success) {
|
||||
Transform result;
|
||||
QSharedPointer<SpatialParentFinder> parentFinder = DependencyManager::get<SpatialParentFinder>();
|
||||
if (!parentFinder) {
|
||||
success = false;
|
||||
|
@ -220,17 +213,11 @@ glm::quat SpatiallyNestable::worldToLocal(const glm::quat& orientation,
|
|||
if (!success) {
|
||||
return glm::quat();
|
||||
}
|
||||
parentTransform.setScale(1.0f); // TODO: scale
|
||||
}
|
||||
success = true;
|
||||
|
||||
Transform orientationTransform;
|
||||
orientationTransform.setRotation(orientation);
|
||||
Transform myWorldTransform;
|
||||
Transform::mult(myWorldTransform, parentTransform, orientationTransform);
|
||||
myWorldTransform.setRotation(orientation);
|
||||
Transform::inverseMult(result, parentTransform, myWorldTransform);
|
||||
return result.getRotation();
|
||||
glm::quat invParentOrientation = glm::inverse(parentTransform.getRotation());
|
||||
return invParentOrientation * orientation;
|
||||
}
|
||||
|
||||
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) {
|
||||
return glm::vec3(0.0f);
|
||||
}
|
||||
parentTransform.setScale(1.0f); // TODO: scale
|
||||
}
|
||||
success = true;
|
||||
|
||||
|
@ -634,7 +620,6 @@ const Transform SpatiallyNestable::getTransform(int jointIndex, bool& success, i
|
|||
}
|
||||
|
||||
Transform worldTransform = getTransform(success, depth);
|
||||
worldTransform.setScale(1.0f); // TODO -- scale;
|
||||
if (!success) {
|
||||
return jointInWorldFrame;
|
||||
}
|
||||
|
@ -673,61 +658,51 @@ bool SpatiallyNestable::setTransform(const Transform& transform) {
|
|||
return success;
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getScale() const {
|
||||
// TODO: scale
|
||||
glm::vec3 result;
|
||||
_transformLock.withReadLock([&] {
|
||||
result = _transform.getScale();
|
||||
});
|
||||
glm::vec3 SpatiallyNestable::getSNScale() const {
|
||||
bool success;
|
||||
auto result = getSNScale(success);
|
||||
#ifdef WANT_DEBUG
|
||||
if (!success) {
|
||||
qCDebug(shared) << "Warning -- getScale failed" << getID();
|
||||
}
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getScale(int jointIndex) const {
|
||||
// TODO: scale
|
||||
return getScale();
|
||||
glm::vec3 SpatiallyNestable::getSNScale(bool& success) const {
|
||||
return getTransform(success).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
|
||||
if (isNaN(scale)) {
|
||||
qCDebug(shared) << "SpatiallyNestable::setScale -- scale contains NaN";
|
||||
success = false;
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = false;
|
||||
// TODO: scale
|
||||
Transform parentTransform = getParentTransform(success);
|
||||
Transform myWorldTransform;
|
||||
_transformLock.withWriteLock([&] {
|
||||
if (_transform.getScale() != scale) {
|
||||
_transform.setScale(scale);
|
||||
Transform::mult(myWorldTransform, parentTransform, _transform);
|
||||
if (myWorldTransform.getScale() != scale) {
|
||||
changed = true;
|
||||
myWorldTransform.setScale(scale);
|
||||
Transform::inverseMult(_transform, parentTransform, myWorldTransform);
|
||||
_scaleChanged = usecTimestampNow();
|
||||
}
|
||||
});
|
||||
if (changed) {
|
||||
dimensionsChanged();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
if (success && changed) {
|
||||
locationChanged();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -844,8 +819,7 @@ void SpatiallyNestable::setLocalAngularVelocity(const glm::vec3& angularVelocity
|
|||
});
|
||||
}
|
||||
|
||||
glm::vec3 SpatiallyNestable::getLocalScale() const {
|
||||
// TODO: scale
|
||||
glm::vec3 SpatiallyNestable::getLocalSNScale() const {
|
||||
glm::vec3 result;
|
||||
_transformLock.withReadLock([&] {
|
||||
result = _transform.getScale();
|
||||
|
@ -853,7 +827,7 @@ glm::vec3 SpatiallyNestable::getLocalScale() const {
|
|||
return result;
|
||||
}
|
||||
|
||||
void SpatiallyNestable::setLocalScale(const glm::vec3& scale) {
|
||||
void SpatiallyNestable::setLocalSNScale(const glm::vec3& scale) {
|
||||
// guard against introducing NaN into the transform
|
||||
if (isNaN(scale)) {
|
||||
qCDebug(shared) << "SpatiallyNestable::setLocalScale -- scale contains NaN";
|
||||
|
@ -861,7 +835,6 @@ void SpatiallyNestable::setLocalScale(const glm::vec3& scale) {
|
|||
}
|
||||
|
||||
bool changed = false;
|
||||
// TODO: scale
|
||||
_transformLock.withWriteLock([&] {
|
||||
if (_transform.getScale() != scale) {
|
||||
_transform.setScale(scale);
|
||||
|
@ -905,6 +878,8 @@ const Transform SpatiallyNestable::getAbsoluteJointTransformInObjectFrame(int jo
|
|||
Transform jointTransformInObjectFrame;
|
||||
glm::vec3 position = getAbsoluteJointTranslationInObjectFrame(jointIndex);
|
||||
glm::quat orientation = getAbsoluteJointRotationInObjectFrame(jointIndex);
|
||||
glm::vec3 scale = getAbsoluteJointScaleInObjectFrame(jointIndex);
|
||||
jointTransformInObjectFrame.setScale(scale);
|
||||
jointTransformInObjectFrame.setRotation(orientation);
|
||||
jointTransformInObjectFrame.setTranslation(position);
|
||||
return jointTransformInObjectFrame;
|
||||
|
@ -1197,3 +1172,13 @@ QString SpatiallyNestable::nestableTypeToString(NestableType nestableType) {
|
|||
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() const;
|
||||
|
||||
virtual glm::vec3 getScale() const;
|
||||
virtual void setScale(const glm::vec3& scale);
|
||||
virtual void setScale(float value);
|
||||
virtual glm::vec3 getSNScale() const;
|
||||
virtual glm::vec3 getSNScale(bool& success) const;
|
||||
virtual void setSNScale(const glm::vec3& scale);
|
||||
virtual void setSNScale(const glm::vec3& scale, bool& success);
|
||||
|
||||
// get world-frame values for a specific joint
|
||||
virtual const Transform getTransform(int jointIndex, bool& success, int depth = 0) 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
|
||||
virtual Transform getLocalTransform() const;
|
||||
|
@ -136,8 +137,8 @@ public:
|
|||
virtual glm::vec3 getLocalAngularVelocity() const;
|
||||
virtual void setLocalAngularVelocity(const glm::vec3& angularVelocity);
|
||||
|
||||
virtual glm::vec3 getLocalScale() const;
|
||||
virtual void setLocalScale(const glm::vec3& scale);
|
||||
virtual glm::vec3 getLocalSNScale() const;
|
||||
virtual void setLocalSNScale(const glm::vec3& scale);
|
||||
|
||||
QList<SpatiallyNestablePointer> getChildren() const;
|
||||
bool hasChildren() const;
|
||||
|
@ -146,6 +147,7 @@ public:
|
|||
|
||||
// this object's frame
|
||||
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::vec3 getAbsoluteJointTranslationInObjectFrame(int index) const { return glm::vec3(); }
|
||||
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 rotationChangedSince(quint64 time) const { return _rotationChanged > time; }
|
||||
|
||||
void dump(const QString& prefix = "") const;
|
||||
|
||||
protected:
|
||||
const NestableType _nestableType; // EntityItem or an AvatarData
|
||||
QUuid _id;
|
||||
|
|
|
@ -150,3 +150,10 @@ QJsonObject Transform::toJson(const Transform& transform) {
|
|||
}
|
||||
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 {
|
||||
public:
|
||||
friend QDebug& operator<<(QDebug& debug, const Transform& transform);
|
||||
using Pointer = std::shared_ptr<Transform>;
|
||||
typedef glm::mat4 Mat4;
|
||||
typedef glm::mat3 Mat3;
|
||||
|
@ -170,7 +171,6 @@ protected:
|
|||
};
|
||||
typedef std::bitset<NUM_FLAGS> Flags;
|
||||
|
||||
|
||||
// TRS
|
||||
Quat _rotation;
|
||||
Vec3 _scale;
|
||||
|
@ -202,6 +202,8 @@ protected:
|
|||
Mat4& getCachedMatrix(Mat4& result) const;
|
||||
};
|
||||
|
||||
QDebug& operator<<(QDebug& debug, const Transform& transform);
|
||||
|
||||
inline Transform& Transform::setIdentity() {
|
||||
_translation = Vec3(0.0f);
|
||||
_rotation = Quat(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
|
|
|
@ -425,6 +425,9 @@ void TabletProxy::gotoMenuScreen(const QString& submenu) {
|
|||
emit screenChanged(QVariant("Menu"), QVariant(VRMENU_SOURCE_URL));
|
||||
_currentPathLoaded = VRMENU_SOURCE_URL;
|
||||
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||
if (_toolbarMode && _desktopWindow) {
|
||||
QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -444,6 +447,9 @@ void TabletProxy::loadQMLOnTop(const QVariant& path) {
|
|||
if (root) {
|
||||
QMetaObject::invokeMethod(root, "loadQMLOnTop", Q_ARG(const QVariant&, path));
|
||||
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||
if (_toolbarMode && _desktopWindow) {
|
||||
QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false)));
|
||||
}
|
||||
} else {
|
||||
qCDebug(uiLogging) << "tablet cannot load QML because _qmlTabletRoot is null";
|
||||
}
|
||||
|
@ -470,9 +476,9 @@ void TabletProxy::returnToPreviousApp() {
|
|||
}
|
||||
}
|
||||
|
||||
void TabletProxy::loadQMLSource(const QVariant& path) {
|
||||
void TabletProxy::loadQMLSource(const QVariant& path, bool resizable) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "loadQMLSource", Q_ARG(QVariant, path));
|
||||
QMetaObject::invokeMethod(this, "loadQMLSource", Q_ARG(QVariant, path), Q_ARG(bool, resizable));
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -492,6 +498,10 @@ void TabletProxy::loadQMLSource(const QVariant& path) {
|
|||
}
|
||||
_currentPathLoaded = path;
|
||||
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||
if (_toolbarMode && _desktopWindow) {
|
||||
QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(resizable)));
|
||||
}
|
||||
|
||||
} else {
|
||||
qCDebug(uiLogging) << "tablet cannot load QML because _qmlTabletRoot is null";
|
||||
}
|
||||
|
@ -523,6 +533,9 @@ bool TabletProxy::pushOntoStack(const QVariant& path) {
|
|||
} else {
|
||||
loadQMLSource(path);
|
||||
}
|
||||
if (_toolbarMode && _desktopWindow) {
|
||||
QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false)));
|
||||
}
|
||||
} else {
|
||||
qCDebug(uiLogging) << "tablet cannot push QML because _qmlTabletRoot or _desktopWindow is null";
|
||||
}
|
||||
|
@ -599,6 +612,9 @@ void TabletProxy::loadWebScreenOnTop(const QVariant& url, const QString& injectJ
|
|||
if (root) {
|
||||
QMetaObject::invokeMethod(root, "loadQMLOnTop", Q_ARG(const QVariant&, QVariant(WEB_VIEW_SOURCE_URL)));
|
||||
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||
if (_toolbarMode && _desktopWindow) {
|
||||
QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false)));
|
||||
}
|
||||
QMetaObject::invokeMethod(root, "loadWebOnTop", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectJavaScriptUrl)));
|
||||
}
|
||||
_state = State::Web;
|
||||
|
@ -625,6 +641,9 @@ void TabletProxy::gotoWebScreen(const QString& url, const QString& injectedJavaS
|
|||
QMetaObject::invokeMethod(root, "loadWebBase");
|
||||
}
|
||||
QMetaObject::invokeMethod(root, "setShown", Q_ARG(const QVariant&, QVariant(true)));
|
||||
if (_toolbarMode && _desktopWindow) {
|
||||
QMetaObject::invokeMethod(root, "setResizable", Q_ARG(const QVariant&, QVariant(false)));
|
||||
}
|
||||
QMetaObject::invokeMethod(root, "loadWebUrl", Q_ARG(const QVariant&, QVariant(url)), Q_ARG(const QVariant&, QVariant(injectedJavaScriptUrl)));
|
||||
}
|
||||
_state = State::Web;
|
||||
|
|
|
@ -124,7 +124,7 @@ public:
|
|||
Q_INVOKABLE void gotoWebScreen(const QString& url);
|
||||
Q_INVOKABLE void gotoWebScreen(const QString& url, const QString& injectedJavaScriptUrl, bool loadOtherBase = false);
|
||||
|
||||
Q_INVOKABLE void loadQMLSource(const QVariant& path);
|
||||
Q_INVOKABLE void loadQMLSource(const QVariant& path, bool resizable = false);
|
||||
// FIXME: This currently relies on a script initializing the tablet (hence the bool denoting success);
|
||||
// it should be initialized internally so it cannot fail
|
||||
Q_INVOKABLE bool pushOntoStack(const QVariant& path);
|
||||
|
|
|
@ -60,6 +60,36 @@ bool OculusBaseDisplayPlugin::isSupported() const {
|
|||
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.
|
||||
void OculusBaseDisplayPlugin::customizeContext() {
|
||||
glewExperimental = true;
|
||||
|
|
|
@ -19,6 +19,9 @@ public:
|
|||
~OculusBaseDisplayPlugin();
|
||||
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; }
|
||||
|
||||
|
||||
|
|
|
@ -357,6 +357,32 @@ bool OpenVrDisplayPlugin::isSupported() const {
|
|||
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 {
|
||||
if (forceInterleavedReprojection && !_asyncReprojectionActive) {
|
||||
return TARGET_RATE_OpenVr / 2.0f;
|
||||
|
|
|
@ -38,6 +38,9 @@ public:
|
|||
bool isSupported() const override;
|
||||
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;
|
||||
|
||||
float getTargetFrameRate() const override;
|
||||
|
|
|
@ -89,9 +89,9 @@ var coatButton = new ToggleButtonBuddy(buttonPositionX, buttonPositionY, BUTTON_
|
|||
var HAT_ATTACHMENT = {
|
||||
modelURL: "https://s3.amazonaws.com/hifi-public/tony/cowboy-hat.fbx",
|
||||
jointName: "Head",
|
||||
translation: {"x": 0, "y": 0.2, "z": 0},
|
||||
translation: {"x": 0, "y": 0.25, "z": 0.03},
|
||||
rotation: {"x": 0, "y": 0, "z": 0, "w": 1},
|
||||
scale: 1,
|
||||
scale: 0.052,
|
||||
isSoft: false
|
||||
};
|
||||
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
// 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.
|
||||
|
||||
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||
|
||||
(function() { // BEGIN LOCAL_SCOPE
|
||||
|
||||
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 lastOverlayPosition = { x: 0, y: 0, z: 0};
|
||||
var AVATAR_SELF_ID = "{00000000-0000-0000-0000-000000000001}";
|
||||
var CAMERA_MATRIX = -7;
|
||||
|
||||
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,
|
||||
height: OVERLAY_HEIGHT,
|
||||
url: "http://hifi-content.s3.amazonaws.com/alan/production/images/images/Overlay-Viz-blank.png",
|
||||
color: {red: 255, green: 255, blue: 255},
|
||||
alpha: 1,
|
||||
scale: 2,
|
||||
scale: 2 * MyAvatar.sensorToWorldScale,
|
||||
emissive: true,
|
||||
isFacingAvatar: true,
|
||||
drawInFront: true
|
||||
drawInFront: true,
|
||||
parentID: AVATAR_SELF_ID,
|
||||
parentJointIndex: CAMERA_MATRIX
|
||||
};
|
||||
|
||||
var AWAY_INTRO = {
|
||||
|
@ -83,25 +89,11 @@ function stopAwayAnimation() {
|
|||
var overlay = Overlays.addOverlay("image", OVERLAY_DATA);
|
||||
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() {
|
||||
if (HMD.active) {
|
||||
// make sure desktop version is hidden
|
||||
Overlays.editOverlay(overlay, { visible: false });
|
||||
|
||||
lastOverlayPosition = HMD.getHUDLookAtPosition3D();
|
||||
var actualOverlayPositon = moveCloserToCamera(lastOverlayPosition);
|
||||
Overlays.editOverlay(overlayHMD, { visible: true, position: actualOverlayPositon });
|
||||
Overlays.editOverlay(overlayHMD, { visible: true });
|
||||
} else {
|
||||
// make sure HMD is hidden
|
||||
Overlays.editOverlay(overlayHMD, { visible: false });
|
||||
|
@ -110,9 +102,11 @@ function showOverlay() {
|
|||
var screen = Controller.getViewportDimensions();
|
||||
|
||||
// keep the overlay it's natural size and always center it...
|
||||
Overlays.editOverlay(overlay, { visible: true,
|
||||
x: ((screen.x - OVERLAY_WIDTH) / 2),
|
||||
y: ((screen.y - OVERLAY_HEIGHT) / 2) });
|
||||
Overlays.editOverlay(overlay, {
|
||||
visible: true,
|
||||
x: ((screen.x - OVERLAY_WIDTH) / 2),
|
||||
y: ((screen.y - OVERLAY_HEIGHT) / 2)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -132,16 +126,10 @@ function maybeMoveOverlay() {
|
|||
}
|
||||
|
||||
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 EASE_BY_RATIO = 0.1;
|
||||
var lookAt = HMD.getHUDLookAtPosition3D();
|
||||
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 });
|
||||
|
||||
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||
var localPosition = {x: 0, y: 0, z: -1 * sensorScaleFactor};
|
||||
Overlays.editOverlay(overlayHMD, { visible: true, localPosition: localPosition, scale: 2 * sensorScaleFactor });
|
||||
|
||||
// make sure desktop version is hidden
|
||||
Overlays.editOverlay(overlay, { visible: false });
|
||||
|
@ -191,8 +179,8 @@ function goActive() {
|
|||
MyAvatar.isAway = false;
|
||||
}
|
||||
|
||||
MyAvatar.wentAway.connect(setAwayProperties)
|
||||
MyAvatar.wentActive.connect(setActiveProperties)
|
||||
MyAvatar.wentAway.connect(setAwayProperties);
|
||||
MyAvatar.wentActive.connect(setActiveProperties);
|
||||
|
||||
function setAwayProperties() {
|
||||
isAway = true;
|
||||
|
@ -254,7 +242,7 @@ function maybeGoActive(event) {
|
|||
if (event.isAutoRepeat) { // isAutoRepeat is true when held down (or when Windows feels like it)
|
||||
return;
|
||||
}
|
||||
if (!isAway && (event.text == 'ESC')) {
|
||||
if (!isAway && (event.text === 'ESC')) {
|
||||
goAway();
|
||||
} else {
|
||||
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 (HMD.mounted != wasHmdMounted) {
|
||||
if (HMD.mounted !== wasHmdMounted) {
|
||||
wasHmdMounted = HMD.mounted;
|
||||
print("HMD mounted changed...");
|
||||
|
||||
|
@ -317,7 +305,7 @@ var handleMessage = function(channel, message, sender) {
|
|||
print("away.js | Got message on Hifi-Away-Enable: ", message);
|
||||
setEnabled(message === 'enable');
|
||||
}
|
||||
}
|
||||
};
|
||||
Messages.subscribe(CHANNEL_AWAY_ENABLE);
|
||||
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)
|
||||
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 },
|
||||
rotation: Quat.fromPitchYawRollDegrees(MyAvatar.bodyPitch, 0, MyAvatar.bodyRoll),
|
||||
scale: { x: 2, y: MyAvatar.scale * 0.5 + 0.5, z: 2 },
|
||||
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: false,
|
||||
ignoreRayIntersection: true
|
||||
});
|
||||
|
@ -62,9 +62,17 @@
|
|||
}
|
||||
|
||||
Overlays.editOverlay(bubbleOverlay, {
|
||||
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),
|
||||
scale: { x: 2, y: MyAvatar.scale * 0.5 + 0.5, z: 2 },
|
||||
position: {
|
||||
x: MyAvatar.position.x,
|
||||
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
|
||||
});
|
||||
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,
|
||||
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: ((1 - ((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 0.5 + 0.5),
|
||||
z: 2
|
||||
x: 2 * MyAvatar.sensorToWorldScale,
|
||||
y: ((1 - ((BUBBLE_RAISE_ANIMATION_DURATION_MS - delay) / BUBBLE_RAISE_ANIMATION_DURATION_MS)) * MyAvatar.scale * 0.5 + 0.2 * MyAvatar.sensorToWorldScale),
|
||||
z: 2 * MyAvatar.sensorToWorldScale
|
||||
}
|
||||
});
|
||||
} else {
|
||||
|
@ -120,11 +128,11 @@
|
|||
y: 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
|
||||
x: 2 * MyAvatar.sensorToWorldScale,
|
||||
y: MyAvatar.scale * 0.5 + 0.2 * MyAvatar.sensorToWorldScale,
|
||||
z: 2 * MyAvatar.sensorToWorldScale
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -150,6 +150,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
if (PROFILE) {
|
||||
Script.beginProfileRange("dispatch.pre");
|
||||
}
|
||||
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||
var deltaTime = _this.updateTimings();
|
||||
_this.setIgnoreTablet();
|
||||
|
||||
|
@ -196,7 +197,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
var h;
|
||||
for (h = LEFT_HAND; h <= RIGHT_HAND; h++) {
|
||||
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) {
|
||||
var aPosition = Overlays.getProperty(a, "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++) {
|
||||
if (controllerLocations[h].valid) {
|
||||
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++) {
|
||||
var entityID = nearbyEntityIDs[j];
|
||||
var props = Entities.getEntityProperties(entityID, DISPATCHER_PROPERTIES);
|
||||
|
@ -249,7 +250,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
|
||||
if (rayPicks[h].type === RayPick.INTERSECTED_ENTITY) {
|
||||
// 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 nearbyProps = Entities.getEntityProperties(nearEntityID, DISPATCHER_PROPERTIES);
|
||||
nearbyProps.id = nearEntityID;
|
||||
|
@ -368,28 +369,28 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
enabled: true,
|
||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand)
|
||||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true)
|
||||
});
|
||||
this.leftControllerHudRayPick = RayPick.createRayPick({
|
||||
joint: "_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_HUD,
|
||||
enabled: true,
|
||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand)
|
||||
posOffset: getGrabPointSphereOffset(Controller.Standard.LeftHand, true)
|
||||
});
|
||||
this.rightControllerRayPick = RayPick.createRayPick({
|
||||
joint: "_CONTROLLER_RIGHTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
enabled: true,
|
||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand)
|
||||
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true)
|
||||
});
|
||||
this.rightControllerHudRayPick = RayPick.createRayPick({
|
||||
joint: "_CONTROLLER_RIGHTHAND",
|
||||
filter: RayPick.PICK_HUD,
|
||||
enabled: true,
|
||||
maxDistance: DEFAULT_SEARCH_SPHERE_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand)
|
||||
posOffset: getGrabPointSphereOffset(Controller.Standard.RightHand, true)
|
||||
});
|
||||
|
||||
this.handleHandMessage = function(channel, message, sender) {
|
||||
|
|
|
@ -59,7 +59,8 @@ createControllerDisplay = function(config) {
|
|||
},
|
||||
|
||||
setPartVisible: function(partName, visible) {
|
||||
return;
|
||||
// Disabled
|
||||
/*
|
||||
if (partName in this.partOverlays) {
|
||||
for (var i = 0; i < this.partOverlays[partName].length; ++i) {
|
||||
Overlays.editOverlay(this.partOverlays[partName][i], {
|
||||
|
@ -67,6 +68,7 @@ createControllerDisplay = function(config) {
|
|||
});
|
||||
}
|
||||
}
|
||||
*/
|
||||
},
|
||||
|
||||
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);
|
||||
for (var i = 0; i < config.controllers.length; ++i) {
|
||||
var controller = config.controllers[i];
|
||||
var position = controller.position;
|
||||
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||
|
||||
if (controller.naturalPosition) {
|
||||
position = Vec3.sum(Vec3.multiplyQbyV(controller.rotation, controller.naturalPosition), position);
|
||||
|
@ -98,9 +133,9 @@ createControllerDisplay = function(config) {
|
|||
|
||||
var overlayID = Overlays.addOverlay("model", {
|
||||
url: controller.modelURL,
|
||||
dimensions: controller.dimensions,
|
||||
dimensions: Vec3.multiply(sensorScaleFactor, controller.dimensions),
|
||||
localRotation: controller.rotation,
|
||||
localPosition: position,
|
||||
localPosition: Vec3.multiply(sensorScaleFactor, position),
|
||||
parentID: PARENT_ID,
|
||||
parentJointIndex: controller.jointIndex,
|
||||
ignoreRayIntersection: true
|
||||
|
@ -176,8 +211,8 @@ createControllerDisplay = function(config) {
|
|||
});
|
||||
} else if (part.type === "joystick") {
|
||||
(function(controller, overlayID, part) {
|
||||
const xInput = resolveHardware(part.xInput);
|
||||
const yInput = resolveHardware(part.yInput);
|
||||
var xInput = resolveHardware(part.xInput);
|
||||
var yInput = resolveHardware(part.yInput);
|
||||
|
||||
var xvalue = 0;
|
||||
var yvalue = 0;
|
||||
|
@ -190,21 +225,20 @@ createControllerDisplay = function(config) {
|
|||
offset = Vec3.multiplyQbyV(rotation, part.originOffset);
|
||||
offset = Vec3.subtract(part.originOffset, offset);
|
||||
}
|
||||
|
||||
|
||||
var partPosition = Vec3.sum(controller.position,
|
||||
Vec3.multiplyQbyV(controller.rotation, Vec3.sum(offset, part.naturalPosition)));
|
||||
|
||||
var partRotation = Quat.multiply(controller.rotation, rotation)
|
||||
var partRotation = Quat.multiply(controller.rotation, rotation);
|
||||
|
||||
return {
|
||||
position: partPosition,
|
||||
rotation: partRotation
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
mapping.from([xInput]).peek().to(function(value) {
|
||||
xvalue = value;
|
||||
//print(overlayID, xvalue.toFixed(3), yvalue.toFixed(3));
|
||||
var posRot = calculatePositionAndRotation(xvalue, yvalue);
|
||||
Overlays.editOverlay(overlayID, {
|
||||
localPosition: posRot.position,
|
||||
|
@ -224,10 +258,9 @@ createControllerDisplay = function(config) {
|
|||
|
||||
} else if (part.type === "linear") {
|
||||
(function(controller, overlayID, part) {
|
||||
const input = resolveHardware(part.input);
|
||||
var input = resolveHardware(part.input);
|
||||
|
||||
mapping.from([input]).peek().to(function(value) {
|
||||
//print(value);
|
||||
var axis = Vec3.multiplyQbyV(controller.rotation, part.axis);
|
||||
var offset = Vec3.multiply(part.maxTranslation * value, axis);
|
||||
|
||||
|
@ -256,6 +289,7 @@ createControllerDisplay = function(config) {
|
|||
}
|
||||
}
|
||||
Controller.enableMapping(controllerDisplay.mappingName);
|
||||
controllerDisplay.resize(MyAvatar.sensorToWorldScale);
|
||||
return controllerDisplay;
|
||||
};
|
||||
|
||||
|
|
|
@ -56,7 +56,6 @@ ControllerDisplayManager = function() {
|
|||
}
|
||||
|
||||
if (leftConfig !== null && rightConfig !== null) {
|
||||
print("Loading controllers");
|
||||
if (controllerLeft === null) {
|
||||
controllerLeft = createControllerDisplay(leftConfig);
|
||||
controllerLeft.setVisible(true);
|
||||
|
@ -70,6 +69,7 @@ ControllerDisplayManager = function() {
|
|||
Script.clearInterval(controllerCheckerIntervalID);
|
||||
controllerCheckerIntervalID = null;
|
||||
}
|
||||
|
||||
} else {
|
||||
self.deleteControllerDisplays();
|
||||
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 i, data, name, visible;
|
||||
if (!controllerLeft && !controllerRight) {
|
||||
|
@ -171,6 +180,7 @@ ControllerDisplayManager = function() {
|
|||
|
||||
HMD.displayModeChanged.connect(updateControllers);
|
||||
HMD.shouldShowHandControllersChanged.connect(updateControllers);
|
||||
MyAvatar.sensorToWorldScaleChanged.connect(resizeControllers);
|
||||
|
||||
updateControllers();
|
||||
};
|
||||
|
|
|
@ -1,15 +1,13 @@
|
|||
"use strict";
|
||||
|
||||
// nearTrigger.js
|
||||
// disableOtherModule.js
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
|
||||
enableDispatcherModule, disableDispatcherModule, getGrabbableData, Vec3,
|
||||
TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS,
|
||||
getEnabledModuleByName
|
||||
/* global Script, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule,
|
||||
makeDispatcherModuleParameters, makeRunningValues, getEnabledModuleByName, Messages
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -20,7 +18,9 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
this.disableModules = false;
|
||||
this.parameters = makeDispatcherModuleParameters(
|
||||
90,
|
||||
this.hand === RIGHT_HAND ? ["rightHand", "rightHandEquip", "rightHandTrigger"] : ["leftHand", "leftHandEquip", "leftHandTrigger"],
|
||||
this.hand === RIGHT_HAND ?
|
||||
["rightHand", "rightHandEquip", "rightHandTrigger"] :
|
||||
["leftHand", "leftHandEquip", "leftHandTrigger"],
|
||||
[],
|
||||
100);
|
||||
|
||||
|
@ -37,11 +37,11 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
|
||||
if (teleportModule) {
|
||||
var ready = teleportModule.isReady(controllerData);
|
||||
if (ready) {
|
||||
if (ready.active) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
}
|
||||
if (!this.disablemodules) {
|
||||
if (!this.disableModules) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
return makeRunningValues(true, [], []);
|
||||
|
@ -61,7 +61,6 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
}
|
||||
if (message === 'right') {
|
||||
rightDisableModules.disableModules = true;
|
||||
|
||||
}
|
||||
if (message === 'both' || message === 'none') {
|
||||
if (message === 'both') {
|
||||
|
@ -75,7 +74,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Messages.subscribe('Hifi-Hand-Disabler');
|
||||
this.cleanup = function() {
|
||||
disableDispatcherModule("LeftDisableModules");
|
||||
|
|
|
@ -602,11 +602,8 @@ EquipHotspotBuddy.prototype.update = function(deltaTime, timestamp, controllerDa
|
|||
};
|
||||
|
||||
this.isTargetIDValid = function() {
|
||||
var entityProperties = Entities.getEntityProperties(this.targetEntityID);
|
||||
for (var propertry in entityProperties) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
var entityProperties = Entities.getEntityProperties(this.targetEntityID, ["type"]);
|
||||
return "type" in entityProperties;
|
||||
};
|
||||
|
||||
this.isReady = function (controllerData, deltaTime) {
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
||||
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
||||
AVATAR_SELF_ID, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
|
||||
getControllerWorldLocation, projectOntoEntityXYPlane
|
||||
getControllerWorldLocation, projectOntoEntityXYPlane, ContextOverlay, HMD, Reticle, Overlays
|
||||
|
||||
*/
|
||||
|
||||
|
@ -236,10 +236,10 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.actionID = null;
|
||||
}
|
||||
|
||||
// XXX
|
||||
// if (this.actionID !== null) {
|
||||
// this.callEntityMethodOnGrabbed("startDistanceGrab");
|
||||
// }
|
||||
if (this.actionID !== null) {
|
||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(this.grabbedThingID, "startDistanceGrab", args);
|
||||
}
|
||||
|
||||
Controller.triggerHapticPulse(HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, this.hand);
|
||||
this.previousRoomControllerPosition = roomControllerPosition;
|
||||
|
@ -271,8 +271,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
var handMoved = Vec3.multiply(worldHandDelta, radius);
|
||||
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, handMoved);
|
||||
|
||||
// XXX
|
||||
// this.callEntityMethodOnGrabbed("continueDistantGrab");
|
||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(this.grabbedThingID, "continueDistanceGrab", args);
|
||||
|
||||
// Update radialVelocity
|
||||
var lastVelocity = Vec3.multiply(worldHandDelta, 1.0 / deltaObjectTime);
|
||||
|
@ -335,6 +335,10 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.distanceHolding = false;
|
||||
this.distanceRotating = false;
|
||||
Entities.deleteAction(this.grabbedThingID, this.actionID);
|
||||
|
||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(this.grabbedThingID, "releaseGrab", args);
|
||||
|
||||
this.actionID = null;
|
||||
this.grabbedThingID = null;
|
||||
};
|
||||
|
@ -343,7 +347,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
var intersection = controllerData.rayPicks[this.hand];
|
||||
var entityProperty = Entities.getEntityProperties(intersection.objectID);
|
||||
var entityType = entityProperty.type;
|
||||
if ((intersection.type === RayPick.INTERSECTED_ENTITY && entityType === "Web") || intersection.type === RayPick.INTERSECTED_OVERLAY) {
|
||||
if ((intersection.type === RayPick.INTERSECTED_ENTITY && entityType === "Web") ||
|
||||
intersection.type === RayPick.INTERSECTED_OVERLAY) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -354,7 +359,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
this.distanceHolding = false;
|
||||
|
||||
var worldControllerRotation = getControllerWorldLocation(this.handToController(), true).orientation;
|
||||
var controllerRotationDelta = Quat.multiply(worldControllerRotation, Quat.inverse(this.previousWorldControllerRotation));
|
||||
var controllerRotationDelta =
|
||||
Quat.multiply(worldControllerRotation, Quat.inverse(this.previousWorldControllerRotation));
|
||||
// Rotate entity by twice the delta rotation.
|
||||
controllerRotationDelta = Quat.multiply(controllerRotationDelta, controllerRotationDelta);
|
||||
|
||||
|
@ -426,7 +432,8 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
};
|
||||
|
||||
this.run = function (controllerData) {
|
||||
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE || this.notPointingAtEntity(controllerData) || this.isPointingAtUI(controllerData)) {
|
||||
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE ||
|
||||
this.notPointingAtEntity(controllerData) || this.isPointingAtUI(controllerData)) {
|
||||
this.endNearGrabAction();
|
||||
this.laserPointerOff();
|
||||
return makeRunningValues(false, [], []);
|
||||
|
@ -471,6 +478,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
for (var j = 0; j < nearGrabReadiness.length; j++) {
|
||||
if (nearGrabReadiness[j].active) {
|
||||
this.laserPointerOff();
|
||||
this.endNearGrabAction();
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
}
|
||||
|
@ -555,7 +563,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
maxDistance: PICK_MAX_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
||||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
|
|
|
@ -6,14 +6,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
/* global Script, Controller, LaserPointers, RayPick, RIGHT_HAND, LEFT_HAND, Mat4, MyAvatar, Vec3, Camera, Quat,
|
||||
getGrabPointSphereOffset, getEnabledModuleByName, makeRunningValues, Entities, NULL_UUID,
|
||||
enableDispatcherModule, disableDispatcherModule, entityIsDistanceGrabbable,
|
||||
makeDispatcherModuleParameters, MSECS_PER_SEC, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
||||
/* global Script, Controller, LaserPointers, RayPick, RIGHT_HAND, LEFT_HAND, MyAvatar, getGrabPointSphereOffset,
|
||||
makeRunningValues, Entities, enableDispatcherModule, disableDispatcherModule, makeDispatcherModuleParameters,
|
||||
PICK_MAX_DISTANCE, COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
||||
AVATAR_SELF_ID, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_OFF_VALUE, TRIGGER_ON_VALUE, ZERO_VEC, ensureDynamic,
|
||||
getControllerWorldLocation, projectOntoEntityXYPlane, getGrabbableData
|
||||
|
||||
AVATAR_SELF_ID, DEFAULT_SEARCH_SPHERE_DISTANCE, getGrabbableData
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -202,7 +198,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
joint: (this.hand === RIGHT_HAND) ? "_CAMERA_RELATIVE_CONTROLLER_RIGHTHAND" : "_CAMERA_RELATIVE_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
maxDistance: PICK_MAX_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
||||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
|
|
|
@ -5,13 +5,12 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
|
||||
NULL_UUID, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
|
||||
Messages, Quat, Vec3, getControllerWorldLocation, makeDispatcherModuleParameters, Overlays, ZERO_VEC,
|
||||
AVATAR_SELF_ID, HMD, INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, Settings, getGrabPointSphereOffset,
|
||||
COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
||||
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE,
|
||||
isInEditMode
|
||||
/* jslint bitwise: true */
|
||||
|
||||
/* global Script, Controller, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
|
||||
Messages, makeDispatcherModuleParameters, AVATAR_SELF_ID, HMD, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
|
||||
getEnabledModuleByName, PICK_MAX_DISTANCE, isInEditMode, LaserPointers, RayPick
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -239,7 +238,7 @@ Script.include("/~/system/libraries/utils.js");
|
|||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_ENTITIES | RayPick.PICK_OVERLAYS,
|
||||
maxDistance: PICK_MAX_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
||||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
|
|
|
@ -111,6 +111,9 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
|||
grabbedEntity: this.targetEntityID,
|
||||
joint: this.hand === RIGHT_HAND ? "RightHand" : "LeftHand"
|
||||
}));
|
||||
|
||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(this.targetEntityID, "startNearGrab", args);
|
||||
};
|
||||
|
||||
// this is for when the action is going to time-out
|
||||
|
@ -147,10 +150,10 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
|||
this.getTargetProps = function (controllerData) {
|
||||
// nearbyEntityProperties is already sorted by distance from controller
|
||||
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
||||
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
||||
var props = nearbyEntityProperties[i];
|
||||
var handPosition = controllerData.controllerLocations[this.hand].position;
|
||||
if (props.distance > NEAR_GRAB_RADIUS) {
|
||||
if (props.distance > NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||
break;
|
||||
}
|
||||
if (entityIsGrabbable(props) || entityIsCloneable(props)) {
|
||||
|
@ -173,7 +176,8 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
|||
this.targetEntityID = null;
|
||||
|
||||
var targetProps = this.getTargetProps(controllerData);
|
||||
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE && controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE &&
|
||||
controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
|
||||
|
@ -192,7 +196,8 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
|||
|
||||
this.run = function (controllerData) {
|
||||
if (this.actionID) {
|
||||
if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE &&
|
||||
controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
this.endNearGrabAction();
|
||||
this.hapticTargetID = null;
|
||||
return makeRunningValues(false, [], []);
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, AVATAR_SELF_ID,
|
||||
getControllerJointIndex, NULL_UUID, enableDispatcherModule, disableDispatcherModule,
|
||||
propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, TRIGGER_OFF_VALUE,
|
||||
makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS,
|
||||
findGroupParent, Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, AVATAR_SELF_ID, getControllerJointIndex, NULL_UUID,
|
||||
enableDispatcherModule, disableDispatcherModule, propsArePhysical, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
||||
TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, entityIsGrabbable, makeRunningValues, NEAR_GRAB_RADIUS, findGroupParent,
|
||||
Vec3, cloneEntity, entityIsCloneable, propsAreCloneDynamic, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION, BUMPER_ON_VALUE
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -147,11 +146,12 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
|||
this.getTargetProps = function (controllerData) {
|
||||
// nearbyEntityProperties is already sorted by length from controller
|
||||
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
||||
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
||||
var props = nearbyEntityProperties[i];
|
||||
var handPosition = controllerData.controllerLocations[this.hand].position;
|
||||
var distance = Vec3.distance(props.position, handPosition);
|
||||
if (distance > NEAR_GRAB_RADIUS) {
|
||||
if (distance > NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||
continue;
|
||||
}
|
||||
if (entityIsGrabbable(props)) {
|
||||
|
@ -176,7 +176,8 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
|||
this.grabbing = false;
|
||||
|
||||
var targetProps = this.getTargetProps(controllerData);
|
||||
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE && controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
if (controllerData.triggerValues[this.hand] < TRIGGER_OFF_VALUE &&
|
||||
controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
return makeRunningValues(false, [], []);
|
||||
}
|
||||
|
||||
|
@ -195,7 +196,8 @@ Script.include("/~/system/libraries/cloneEntityUtils.js");
|
|||
|
||||
this.run = function (controllerData, deltaTime) {
|
||||
if (this.grabbing) {
|
||||
if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE && controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
if (controllerData.triggerClicks[this.hand] < TRIGGER_OFF_VALUE &&
|
||||
controllerData.secondaryValues[this.hand] < TRIGGER_OFF_VALUE) {
|
||||
this.endNearParentingGrabEntity();
|
||||
this.hapticTargetID = null;
|
||||
return makeRunningValues(false, [], []);
|
||||
|
|
|
@ -6,14 +6,14 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, AVATAR_SELF_ID,
|
||||
getControllerJointIndex, NULL_UUID, enableDispatcherModule, disableDispatcherModule,
|
||||
Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
||||
makeDispatcherModuleParameters, Overlays, makeRunningValues
|
||||
/* global Script, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND, AVATAR_SELF_ID, getControllerJointIndex, NULL_UUID,
|
||||
enableDispatcherModule, disableDispatcherModule, Messages, HAPTIC_PULSE_STRENGTH, HAPTIC_PULSE_DURATION,
|
||||
makeDispatcherModuleParameters, Overlays, makeRunningValues, Vec3, resizeTablet, getTabletWidthFromSettings,
|
||||
NEAR_GRAB_RADIUS
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
var GRAB_RADIUS = 0.35;
|
||||
Script.include("/~/system/libraries/utils.js");
|
||||
|
||||
(function() {
|
||||
|
||||
|
@ -120,6 +120,11 @@ var GRAB_RADIUS = 0.35;
|
|||
}
|
||||
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({
|
||||
action: 'grab',
|
||||
grabbedEntity: this.grabbedThingID,
|
||||
|
@ -140,17 +145,23 @@ var GRAB_RADIUS = 0.35;
|
|||
parentID: this.previousParentID[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.getTargetID = function(overlays, controllerData) {
|
||||
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||
for (var i = 0; i < overlays.length; i++) {
|
||||
var overlayPosition = Overlays.getProperty(overlays[i], "position");
|
||||
var handPosition = controllerData.controllerLocations[this.hand].position;
|
||||
var distance = Vec3.distance(overlayPosition, handPosition);
|
||||
if (distance <= GRAB_RADIUS) {
|
||||
if (distance <= NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||
return overlays[i];
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,9 +6,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
|
||||
enableDispatcherModule, disableDispatcherModule, getGrabbableData, Vec3,
|
||||
TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS
|
||||
/* global Script, Entities, MyAvatar, RIGHT_HAND, LEFT_HAND, enableDispatcherModule, disableDispatcherModule, getGrabbableData,
|
||||
Vec3, TRIGGER_OFF_VALUE, makeDispatcherModuleParameters, makeRunningValues, NEAR_GRAB_RADIUS
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -37,11 +36,12 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
this.getTargetProps = function (controllerData) {
|
||||
// nearbyEntityProperties is already sorted by length from controller
|
||||
var nearbyEntityProperties = controllerData.nearbyEntityProperties[this.hand];
|
||||
var sensorScaleFactor = MyAvatar.sensorToWorldScale;
|
||||
for (var i = 0; i < nearbyEntityProperties.length; i++) {
|
||||
var props = nearbyEntityProperties[i];
|
||||
var handPosition = controllerData.controllerLocations[this.hand].position;
|
||||
var distance = Vec3.distance(props.position, handPosition);
|
||||
if (distance > NEAR_GRAB_RADIUS) {
|
||||
if (distance > NEAR_GRAB_RADIUS * sensorScaleFactor) {
|
||||
continue;
|
||||
}
|
||||
if (entityWantsNearTrigger(props)) {
|
||||
|
@ -63,7 +63,7 @@ Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
|||
|
||||
this.endNearTrigger = function (controllerData) {
|
||||
var args = [this.hand === RIGHT_HAND ? "right" : "left", MyAvatar.sessionUUID];
|
||||
Entities.callEntityMethod(this.targetEntityID, "endNearTrigger", args);
|
||||
Entities.callEntityMethod(this.targetEntityID, "stopNearTrigger", args);
|
||||
};
|
||||
|
||||
this.isReady = function (controllerData) {
|
||||
|
|
|
@ -5,13 +5,11 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
/* global Script, Entities, MyAvatar, Controller, RIGHT_HAND, LEFT_HAND,
|
||||
NULL_UUID, enableDispatcherModule, disableDispatcherModule, makeRunningValues,
|
||||
Messages, Quat, Vec3, getControllerWorldLocation, makeDispatcherModuleParameters, Overlays, ZERO_VEC,
|
||||
AVATAR_SELF_ID, HMD, INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, Settings, getGrabPointSphereOffset,
|
||||
COLORS_GRAB_SEARCHING_HALF_SQUEEZE, COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD,
|
||||
DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE, TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE,
|
||||
DISPATCHER_PROPERTIES
|
||||
/* global Script, Entities, Controller, RIGHT_HAND, LEFT_HAND, NULL_UUID, enableDispatcherModule, disableDispatcherModule,
|
||||
makeRunningValues, Messages, Quat, Vec3, makeDispatcherModuleParameters, Overlays, ZERO_VEC, AVATAR_SELF_ID, HMD,
|
||||
INCHES_TO_METERS, DEFAULT_REGISTRATION_POINT, getGrabPointSphereOffset, COLORS_GRAB_SEARCHING_HALF_SQUEEZE,
|
||||
COLORS_GRAB_SEARCHING_FULL_SQUEEZE, COLORS_GRAB_DISTANCE_HOLD, DEFAULT_SEARCH_SPHERE_DISTANCE, TRIGGER_ON_VALUE,
|
||||
TRIGGER_OFF_VALUE, getEnabledModuleByName, PICK_MAX_DISTANCE, LaserPointers, RayPick, ContextOverlay
|
||||
*/
|
||||
|
||||
Script.include("/~/system/libraries/controllerDispatcherUtils.js");
|
||||
|
@ -528,7 +526,7 @@ Script.include("/~/system/libraries/controllers.js");
|
|||
joint: (this.hand === RIGHT_HAND) ? "_CONTROLLER_RIGHTHAND" : "_CONTROLLER_LEFTHAND",
|
||||
filter: RayPick.PICK_OVERLAYS,
|
||||
maxDistance: PICK_MAX_DISTANCE,
|
||||
posOffset: getGrabPointSphereOffset(this.handToController()),
|
||||
posOffset: getGrabPointSphereOffset(this.handToController(), true),
|
||||
renderStates: renderStates,
|
||||
faceAvatar: true,
|
||||
defaultRenderStates: defaultRenderStates
|
||||
|
|
|
@ -7,9 +7,7 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
/* global getEntityCustomData, flatten, Xform, Script, Quat, Vec3, MyAvatar, Entities, Overlays, Settings,
|
||||
Reticle, Controller, Camera, Messages, Mat4, getControllerWorldLocation, getGrabPointSphereOffset,
|
||||
setGrabCommunications, Menu, HMD, isInEditMode, AvatarList */
|
||||
/* global Script, Vec3, MyAvatar, RIGHT_HAND */
|
||||
/* eslint indent: ["error", 4, { "outerIIFEBody": 0 }] */
|
||||
|
||||
(function () {
|
||||
|
@ -37,7 +35,8 @@
|
|||
};
|
||||
|
||||
this.triggersPressed = function(controllerData) {
|
||||
if (controllerData.triggerClicks[this.hand] && controllerData.secondaryValues[this.hand] > dispatcherUtils.BUMPER_ON_VALUE) {
|
||||
if (controllerData.triggerClicks[this.hand] &&
|
||||
controllerData.secondaryValues[this.hand] > dispatcherUtils.BUMPER_ON_VALUE) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -58,7 +57,8 @@
|
|||
var otherModule = this.getOtherModule();
|
||||
if (this.triggersPressed(controllerData) && otherModule.triggersPressed(controllerData)) {
|
||||
if (this.hand === dispatcherUtils.RIGHT_HAND) {
|
||||
var scalingCurrentDistance = Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position,
|
||||
var scalingCurrentDistance =
|
||||
Vec3.length(Vec3.subtract(controllerData.controllerLocations[this.hand].position,
|
||||
controllerData.controllerLocations[this.otherHand()].position));
|
||||
|
||||
var newAvatarScale = (scalingCurrentDistance / this.scalingStartDistance) * this.scalingStartAvatarScale;
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue