mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-08 19:23:28 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into perf/idle-event
This commit is contained in:
commit
65e81077cb
99 changed files with 1769 additions and 860 deletions
|
@ -44,7 +44,7 @@ else ()
|
|||
endif ()
|
||||
|
||||
find_package(Qt5 COMPONENTS
|
||||
Gui Multimedia Network OpenGL Qml Quick Script Svg
|
||||
Gui Multimedia Network OpenGL Qml Quick Script ScriptTools Svg
|
||||
WebChannel WebEngine WebEngineWidgets WebKitWidgets WebSockets)
|
||||
|
||||
# grab the ui files in resources/ui
|
||||
|
@ -201,7 +201,7 @@ include_directories("${PROJECT_SOURCE_DIR}/src")
|
|||
target_link_libraries(
|
||||
${TARGET_NAME}
|
||||
Qt5::Gui Qt5::Network Qt5::Multimedia Qt5::OpenGL
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::Svg
|
||||
Qt5::Qml Qt5::Quick Qt5::Script Qt5::ScriptTools Qt5::Svg
|
||||
Qt5::WebChannel Qt5::WebEngine Qt5::WebEngineWidgets Qt5::WebKitWidgets
|
||||
)
|
||||
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
{
|
||||
"name": "Vive to Standard",
|
||||
"channels": [
|
||||
{ "from": "Vive.LY", "when": "Vive.LS", "filters": "invert", "to": "Standard.LY" },
|
||||
{ "from": "Vive.LX", "when": "Vive.LS", "to": "Standard.LX" },
|
||||
{ "from": "Vive.LY", "when": "Vive.LS", "filters": ["invert" ,{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LY" },
|
||||
{ "from": "Vive.LX", "when": "Vive.LS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.LX" },
|
||||
|
||||
{ "from": "Vive.LT", "to": "Standard.LT" },
|
||||
{ "from": "Vive.LB", "to": "Standard.LB" },
|
||||
{ "from": "Vive.LeftGrip", "to": "Standard.LB" },
|
||||
{ "from": "Vive.LS", "to": "Standard.LS" },
|
||||
{ "from": "Vive.LSTouch", "to": "Standard.LSTouch" },
|
||||
|
||||
{ "from": "Vive.RY", "when": "Vive.RS", "filters": "invert", "to": "Standard.RY" },
|
||||
{ "from": "Vive.RX", "when": "Vive.RS", "to": "Standard.RX" },
|
||||
{ "from": "Vive.RY", "when": "Vive.RS", "filters": ["invert", { "type": "deadZone", "min": 0.6 }], "to": "Standard.RY" },
|
||||
{ "from": "Vive.RX", "when": "Vive.RS", "filters": [{ "type": "deadZone", "min": 0.6 }], "to": "Standard.RX" },
|
||||
|
||||
{ "from": "Vive.RT", "to": "Standard.RT" },
|
||||
{ "from": "Vive.RB", "to": "Standard.RB" },
|
||||
{ "from": "Vive.RightGrip", "to": "Standard.RB" },
|
||||
{ "from": "Vive.RS", "to": "Standard.RS" },
|
||||
{ "from": "Vive.RSTouch", "to": "Standard.RSTouch" },
|
||||
|
||||
{ "from": "Vive.LeftApplicationMenu", "to": "Standard.Back" },
|
||||
{ "from": "Vive.RightApplicationMenu", "to": "Standard.Start" },
|
||||
|
|
|
@ -45,11 +45,13 @@
|
|||
#include <ResourceScriptingInterface.h>
|
||||
#include <AccountManager.h>
|
||||
#include <AddressManager.h>
|
||||
#include <AnimDebugDraw.h>
|
||||
#include <BuildInfo.h>
|
||||
#include <AssetClient.h>
|
||||
#include <AutoUpdater.h>
|
||||
#include <AudioInjectorManager.h>
|
||||
#include <CursorManager.h>
|
||||
#include <DebugDraw.h>
|
||||
#include <DeferredLightingEffect.h>
|
||||
#include <display-plugins/DisplayPlugin.h>
|
||||
#include <EntityScriptingInterface.h>
|
||||
|
@ -101,7 +103,7 @@
|
|||
#include <Preferences.h>
|
||||
#include <display-plugins/CompositorHelper.h>
|
||||
|
||||
#include "AnimDebugDraw.h"
|
||||
|
||||
#include "AudioClient.h"
|
||||
#include "audio/AudioScope.h"
|
||||
#include "avatar/AvatarManager.h"
|
||||
|
@ -668,9 +670,6 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
// The value will be 0 if the user blew away settings this session, which is both a feature and a bug.
|
||||
UserActivityLogger::getInstance().launch(applicationVersion(), _previousSessionCrashed, sessionRunTime.get());
|
||||
|
||||
// once the event loop has started, check and signal for an access token
|
||||
QMetaObject::invokeMethod(&accountManager, "checkAndSignalForAccessToken", Qt::QueuedConnection);
|
||||
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
// use our MyAvatar position and quat for address manager path
|
||||
|
@ -1055,6 +1054,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
|
||||
connect(this, &Application::applicationStateChanged, this, &Application::activeChanged);
|
||||
qCDebug(interfaceapp, "Startup time: %4.2f seconds.", (double)startupTimer.elapsed() / 1000.0);
|
||||
|
||||
// After all of the constructor is completed, then set firstRun to false.
|
||||
Setting::Handle<bool> firstRun{ Settings::firstRun, true };
|
||||
firstRun.set(false);
|
||||
}
|
||||
|
||||
|
||||
|
@ -1281,8 +1284,6 @@ void Application::initializeGL() {
|
|||
|
||||
// update before the first render
|
||||
update(0);
|
||||
|
||||
InfoView::show(INFO_HELP_PATH, true);
|
||||
}
|
||||
|
||||
FrameTimingsScriptingInterface _frameTimingsScriptingInterface;
|
||||
|
@ -2941,7 +2942,21 @@ void Application::init() {
|
|||
addressLookupString = arguments().value(urlIndex + 1);
|
||||
}
|
||||
|
||||
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
|
||||
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
||||
if (addressLookupString.isEmpty() && firstRun.get()) {
|
||||
qDebug() << "First run and no URL passed... attempting to go to Home or Entry...";
|
||||
DependencyManager::get<AddressManager>()->ifLocalSandboxRunningElse([](){
|
||||
qDebug() << "Home sandbox appears to be running, going to Home.";
|
||||
DependencyManager::get<AddressManager>()->goToLocalSandbox();
|
||||
},
|
||||
[](){
|
||||
qDebug() << "Home sandbox does not appear to be running, going to Entry.";
|
||||
DependencyManager::get<AddressManager>()->goToEntry();
|
||||
});
|
||||
} else {
|
||||
qDebug() << "Not first run... going to" << qPrintable(addressLookupString.isEmpty() ? QString("previous location") : addressLookupString);
|
||||
DependencyManager::get<AddressManager>()->loadSettings(addressLookupString);
|
||||
}
|
||||
|
||||
qCDebug(interfaceapp) << "Loaded settings";
|
||||
|
||||
|
@ -3006,9 +3021,9 @@ void Application::updateLOD() const {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::pushPreRenderLambda(void* key, std::function<void()> func) {
|
||||
std::unique_lock<std::mutex> guard(_preRenderLambdasLock);
|
||||
_preRenderLambdas[key] = func;
|
||||
void Application::pushPostUpdateLambda(void* key, std::function<void()> func) {
|
||||
std::unique_lock<std::mutex> guard(_postUpdateLambdasLock);
|
||||
_postUpdateLambdas[key] = func;
|
||||
}
|
||||
|
||||
// Called during Application::update immediately before AvatarManager::updateMyAvatar, updating my data that is then sent to everyone.
|
||||
|
@ -3530,15 +3545,19 @@ void Application::update(float deltaTime) {
|
|||
}
|
||||
}
|
||||
|
||||
avatarManager->postUpdate(deltaTime);
|
||||
|
||||
{
|
||||
PROFILE_RANGE_EX("PreRenderLambdas", 0xffff0000, (uint64_t)0);
|
||||
|
||||
std::unique_lock<std::mutex> guard(_preRenderLambdasLock);
|
||||
for (auto& iter : _preRenderLambdas) {
|
||||
std::unique_lock<std::mutex> guard(_postUpdateLambdasLock);
|
||||
for (auto& iter : _postUpdateLambdas) {
|
||||
iter.second();
|
||||
}
|
||||
_preRenderLambdas.clear();
|
||||
_postUpdateLambdas.clear();
|
||||
}
|
||||
|
||||
AnimDebugDraw::getInstance().update();
|
||||
}
|
||||
|
||||
|
||||
|
@ -3960,13 +3979,10 @@ namespace render {
|
|||
|
||||
void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool selfAvatarOnly) {
|
||||
|
||||
// FIXME: This preRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||
// FIXME: This preDisplayRender call is temporary until we create a separate render::scene for the mirror rendering.
|
||||
// Then we can move this logic into the Avatar::simulate call.
|
||||
auto myAvatar = getMyAvatar();
|
||||
myAvatar->preRender(renderArgs);
|
||||
|
||||
// Update animation debug draw renderer
|
||||
AnimDebugDraw::getInstance().update();
|
||||
myAvatar->preDisplaySide(renderArgs);
|
||||
|
||||
activeRenderingThread = QThread::currentThread();
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
|
@ -4917,24 +4933,19 @@ qreal Application::getDevicePixelRatio() {
|
|||
return (_window && _window->windowHandle()) ? _window->windowHandle()->devicePixelRatio() : 1.0;
|
||||
}
|
||||
|
||||
DisplayPlugin* Application::getActiveDisplayPlugin() {
|
||||
DisplayPlugin* result = nullptr;
|
||||
if (QThread::currentThread() == thread()) {
|
||||
if (nullptr == _displayPlugin) {
|
||||
updateDisplayMode();
|
||||
Q_ASSERT(_displayPlugin);
|
||||
}
|
||||
result = _displayPlugin.get();
|
||||
} else {
|
||||
DisplayPluginPointer Application::getActiveDisplayPlugin() const {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
std::unique_lock<std::mutex> lock(_displayPluginLock);
|
||||
result = _displayPlugin.get();
|
||||
return _displayPlugin;
|
||||
}
|
||||
return result;
|
||||
|
||||
if (!_displayPlugin) {
|
||||
const_cast<Application*>(this)->updateDisplayMode();
|
||||
Q_ASSERT(_displayPlugin);
|
||||
}
|
||||
return _displayPlugin;
|
||||
}
|
||||
|
||||
const DisplayPlugin* Application::getActiveDisplayPlugin() const {
|
||||
return const_cast<Application*>(this)->getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
static void addDisplayPluginToMenu(DisplayPluginPointer displayPlugin, bool active = false) {
|
||||
auto menu = Menu::getInstance();
|
||||
|
|
|
@ -182,8 +182,7 @@ public:
|
|||
|
||||
void setActiveDisplayPlugin(const QString& pluginName);
|
||||
|
||||
DisplayPlugin* getActiveDisplayPlugin();
|
||||
const DisplayPlugin* getActiveDisplayPlugin() const;
|
||||
DisplayPluginPointer getActiveDisplayPlugin() const;
|
||||
|
||||
FileLogger* getLogger() const { return _logger; }
|
||||
|
||||
|
@ -217,7 +216,7 @@ public:
|
|||
render::EnginePointer getRenderEngine() override { return _renderEngine; }
|
||||
gpu::ContextPointer getGPUContext() const { return _gpuContext; }
|
||||
|
||||
virtual void pushPreRenderLambda(void* key, std::function<void()> func) override;
|
||||
virtual void pushPostUpdateLambda(void* key, std::function<void()> func) override;
|
||||
|
||||
const QRect& getMirrorViewRect() const { return _mirrorViewRect; }
|
||||
|
||||
|
@ -390,7 +389,7 @@ private:
|
|||
|
||||
OffscreenGLCanvas* _offscreenContext { nullptr };
|
||||
DisplayPluginPointer _displayPlugin;
|
||||
std::mutex _displayPluginLock;
|
||||
mutable std::mutex _displayPluginLock;
|
||||
InputPluginList _activeInputPlugins;
|
||||
|
||||
bool _activatingDisplayPlugin { false };
|
||||
|
@ -515,8 +514,8 @@ private:
|
|||
|
||||
QThread* _deadlockWatchdogThread;
|
||||
|
||||
std::map<void*, std::function<void()>> _preRenderLambdas;
|
||||
std::mutex _preRenderLambdasLock;
|
||||
std::map<void*, std::function<void()>> _postUpdateLambdas;
|
||||
std::mutex _postUpdateLambdasLock;
|
||||
|
||||
std::atomic<uint32_t> _fullSceneReceivedCounter { 0 }; // how many times have we received a full-scene octree stats packet
|
||||
uint32_t _fullSceneCounterAtLastPhysicsCheck { 0 }; // _fullSceneReceivedCounter last time we checked physics ready
|
||||
|
|
|
@ -480,10 +480,8 @@ Menu::Menu() {
|
|||
avatarManager.data(), SLOT(setShouldShowReceiveStats(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderBoundingCollisionShapes);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtVectors, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderLookAtTargets, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderFocusIndicator, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::ShowWhosLookingAtMe, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderMyLookAtVectors, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderOtherLookAtVectors, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::FixGaze, 0, false);
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::AnimDebugDrawDefaultPose, 0, false,
|
||||
avatar, SLOT(setEnableDebugDrawDefaultPose(bool)));
|
||||
|
|
|
@ -147,9 +147,8 @@ namespace MenuOption {
|
|||
const QString ReloadAllScripts = "Reload All Scripts";
|
||||
const QString ReloadContent = "Reload Content (Clears all caches)";
|
||||
const QString RenderBoundingCollisionShapes = "Show Bounding Collision Shapes";
|
||||
const QString RenderFocusIndicator = "Show Eye Focus";
|
||||
const QString RenderLookAtTargets = "Show Look-at Targets";
|
||||
const QString RenderLookAtVectors = "Show Look-at Vectors";
|
||||
const QString RenderMyLookAtVectors = "Show My Eye Vectors";
|
||||
const QString RenderOtherLookAtVectors = "Show Other Eye Vectors";
|
||||
const QString RenderMaxTextureMemory = "Maximum Texture Memory";
|
||||
const QString RenderMaxTextureAutomatic = "Automatic Texture Memory";
|
||||
const QString RenderMaxTexture64MB = "64 MB";
|
||||
|
@ -174,7 +173,6 @@ namespace MenuOption {
|
|||
const QString ShowDSConnectTable = "Show Domain Connection Timing";
|
||||
const QString ShowBordersEntityNodes = "Show Entity Nodes";
|
||||
const QString ShowRealtimeEntityStats = "Show Realtime Entity Stats";
|
||||
const QString ShowWhosLookingAtMe = "Show Who's Looking at Me";
|
||||
const QString StandingHMDSensorMode = "Standing HMD Sensor Mode";
|
||||
const QString SimulateEyeTracking = "Simulate";
|
||||
const QString SMIEyeTracking = "SMI Eye Tracking";
|
||||
|
|
|
@ -54,7 +54,7 @@ QOpenGLContext* PluginContainerProxy::getPrimaryContext() {
|
|||
return qApp->_glWidget->context()->contextHandle();
|
||||
}
|
||||
|
||||
const DisplayPlugin* PluginContainerProxy::getActiveDisplayPlugin() const {
|
||||
const DisplayPluginPointer PluginContainerProxy::getActiveDisplayPlugin() const {
|
||||
return qApp->getActiveDisplayPlugin();
|
||||
}
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class PluginContainerProxy : public QObject, PluginContainer {
|
|||
virtual ui::Menu* getPrimaryMenu() override;
|
||||
virtual QOpenGLContext* getPrimaryContext() override;
|
||||
virtual bool isForeground() override;
|
||||
virtual const DisplayPlugin* getActiveDisplayPlugin() const override;
|
||||
virtual const DisplayPluginPointer getActiveDisplayPlugin() const override;
|
||||
|
||||
friend class Application;
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include <SharedUtil.h>
|
||||
#include <TextRenderer3D.h>
|
||||
#include <TextureCache.h>
|
||||
#include <DebugDraw.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Avatar.h"
|
||||
|
@ -66,11 +67,6 @@ namespace render {
|
|||
}
|
||||
template <> void payloadRender(const AvatarSharedPointer& avatar, RenderArgs* args) {
|
||||
auto avatarPtr = static_pointer_cast<Avatar>(avatar);
|
||||
bool renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtVectors);
|
||||
avatarPtr->setDisplayingLookatVectors(renderLookAtVectors);
|
||||
bool renderLookAtTarget = Menu::getInstance()->isOptionChecked(MenuOption::RenderLookAtTargets);
|
||||
avatarPtr->setDisplayingLookatTarget(renderLookAtTarget);
|
||||
|
||||
if (avatarPtr->isInitialized() && args) {
|
||||
PROFILE_RANGE_BATCH(*args->_batch, "renderAvatarPayload");
|
||||
avatarPtr->render(args, qApp->getCamera()->getPosition());
|
||||
|
@ -323,6 +319,39 @@ void Avatar::updateRenderItem(render::PendingChanges& pendingChanges) {
|
|||
}
|
||||
}
|
||||
|
||||
void Avatar::postUpdate(float deltaTime) {
|
||||
|
||||
bool renderLookAtVectors;
|
||||
if (isMyAvatar()) {
|
||||
renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderMyLookAtVectors);
|
||||
} else {
|
||||
renderLookAtVectors = Menu::getInstance()->isOptionChecked(MenuOption::RenderOtherLookAtVectors);
|
||||
}
|
||||
|
||||
if (renderLookAtVectors) {
|
||||
const float EYE_RAY_LENGTH = 10.0;
|
||||
const glm::vec4 BLUE(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
const glm::vec4 RED(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
int leftEyeJoint = getJointIndex("LeftEye");
|
||||
glm::vec3 leftEyePosition;
|
||||
glm::quat leftEyeRotation;
|
||||
|
||||
if (_skeletonModel->getJointPositionInWorldFrame(leftEyeJoint, leftEyePosition) &&
|
||||
_skeletonModel->getJointRotationInWorldFrame(leftEyeJoint, leftEyeRotation)) {
|
||||
DebugDraw::getInstance().drawRay(leftEyePosition, leftEyePosition + leftEyeRotation * Vectors::UNIT_Z * EYE_RAY_LENGTH, BLUE);
|
||||
}
|
||||
|
||||
int rightEyeJoint = getJointIndex("RightEye");
|
||||
glm::vec3 rightEyePosition;
|
||||
glm::quat rightEyeRotation;
|
||||
if (_skeletonModel->getJointPositionInWorldFrame(rightEyeJoint, rightEyePosition) &&
|
||||
_skeletonModel->getJointRotationInWorldFrame(rightEyeJoint, rightEyeRotation)) {
|
||||
DebugDraw::getInstance().drawRay(rightEyePosition, rightEyePosition + rightEyeRotation * Vectors::UNIT_Z * EYE_RAY_LENGTH, RED);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
||||
auto& batch = *renderArgs->_batch;
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__);
|
||||
|
@ -402,22 +431,7 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
|||
float distanceToTarget = glm::length(toTarget);
|
||||
|
||||
{
|
||||
// glow when moving far away
|
||||
const float GLOW_DISTANCE = 20.0f;
|
||||
const float GLOW_MAX_LOUDNESS = 2500.0f;
|
||||
const float MAX_GLOW = 0.5f;
|
||||
|
||||
float GLOW_FROM_AVERAGE_LOUDNESS = ((this == DependencyManager::get<AvatarManager>()->getMyAvatar())
|
||||
? 0.0f
|
||||
: MAX_GLOW * getHeadData()->getAudioLoudness() / GLOW_MAX_LOUDNESS);
|
||||
GLOW_FROM_AVERAGE_LOUDNESS = 0.0f;
|
||||
|
||||
float glowLevel = _moving && distanceToTarget > GLOW_DISTANCE && renderArgs->_renderMode == RenderArgs::NORMAL_RENDER_MODE
|
||||
? 1.0f
|
||||
: GLOW_FROM_AVERAGE_LOUDNESS;
|
||||
|
||||
// render body
|
||||
renderBody(renderArgs, glowLevel);
|
||||
fixupModelsInScene();
|
||||
|
||||
if (renderArgs->_renderMode != RenderArgs::SHADOW_RENDER_MODE) {
|
||||
// add local lights
|
||||
|
@ -441,64 +455,6 @@ void Avatar::render(RenderArgs* renderArgs, const glm::vec3& cameraPosition) {
|
|||
const float BOUNDING_SHAPE_ALPHA = 0.7f;
|
||||
_skeletonModel->renderBoundingCollisionShapes(*renderArgs->_batch, getUniformScale(), BOUNDING_SHAPE_ALPHA);
|
||||
}
|
||||
|
||||
// If this is the avatar being looked at, render a little ball above their head
|
||||
if (_isLookAtTarget && Menu::getInstance()->isOptionChecked(MenuOption::RenderFocusIndicator)) {
|
||||
static const float INDICATOR_OFFSET = 0.22f;
|
||||
static const float INDICATOR_RADIUS = 0.03f;
|
||||
static const glm::vec4 LOOK_AT_INDICATOR_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
|
||||
glm::vec3 avatarPosition = getPosition();
|
||||
glm::vec3 position = glm::vec3(avatarPosition.x, getDisplayNamePosition().y + INDICATOR_OFFSET, avatarPosition.z);
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderFocusIndicator");
|
||||
Transform transform;
|
||||
transform.setTranslation(position);
|
||||
transform.postScale(INDICATOR_RADIUS);
|
||||
batch.setModelTransform(transform);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidSphereInstance(batch, LOOK_AT_INDICATOR_COLOR);
|
||||
}
|
||||
|
||||
// If the avatar is looking at me, indicate that they are
|
||||
if (getHead()->isLookingAtMe() && Menu::getInstance()->isOptionChecked(MenuOption::ShowWhosLookingAtMe)) {
|
||||
PROFILE_RANGE_BATCH(batch, __FUNCTION__":renderLookingAtMe");
|
||||
const glm::vec3 LOOKING_AT_ME_COLOR = { 1.0f, 1.0f, 1.0f };
|
||||
const float LOOKING_AT_ME_ALPHA_START = 0.8f;
|
||||
const float LOOKING_AT_ME_DURATION = 0.5f; // seconds
|
||||
quint64 now = usecTimestampNow();
|
||||
float alpha = LOOKING_AT_ME_ALPHA_START
|
||||
* (1.0f - ((float)(now - getHead()->getLookingAtMeStarted()))
|
||||
/ (LOOKING_AT_ME_DURATION * (float)USECS_PER_SECOND));
|
||||
if (alpha > 0.0f) {
|
||||
if (_skeletonModel->isLoaded()) {
|
||||
const auto& geometry = _skeletonModel->getFBXGeometry();
|
||||
const float DEFAULT_EYE_DIAMETER = 0.048f; // Typical human eye
|
||||
const float RADIUS_INCREMENT = 0.005f;
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
glm::vec3 position = getHead()->getLeftEyePosition();
|
||||
Transform transform;
|
||||
transform.setTranslation(position);
|
||||
float eyeDiameter = geometry.leftEyeSize;
|
||||
if (eyeDiameter == 0.0f) {
|
||||
eyeDiameter = DEFAULT_EYE_DIAMETER;
|
||||
}
|
||||
|
||||
batch.setModelTransform(Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT));
|
||||
DependencyManager::get<GeometryCache>()->renderSolidSphereInstance(batch,
|
||||
glm::vec4(LOOKING_AT_ME_COLOR, alpha));
|
||||
|
||||
position = getHead()->getRightEyePosition();
|
||||
transform.setTranslation(position);
|
||||
eyeDiameter = geometry.rightEyeSize;
|
||||
if (eyeDiameter == 0.0f) {
|
||||
eyeDiameter = DEFAULT_EYE_DIAMETER;
|
||||
}
|
||||
batch.setModelTransform(Transform(transform).postScale(eyeDiameter * getUniformScale() / 2.0f + RADIUS_INCREMENT));
|
||||
DependencyManager::get<GeometryCache>()->renderSolidSphereInstance(batch,
|
||||
glm::vec4(LOOKING_AT_ME_COLOR, alpha));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const float DISPLAYNAME_DISTANCE = 20.0f;
|
||||
|
@ -556,11 +512,6 @@ void Avatar::fixupModelsInScene() {
|
|||
scene->enqueuePendingChanges(pendingChanges);
|
||||
}
|
||||
|
||||
void Avatar::renderBody(RenderArgs* renderArgs, float glowLevel) {
|
||||
fixupModelsInScene();
|
||||
getHead()->renderLookAts(renderArgs);
|
||||
}
|
||||
|
||||
bool Avatar::shouldRenderHead(const RenderArgs* renderArgs) const {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -77,9 +77,9 @@ public:
|
|||
|
||||
void updateRenderItem(render::PendingChanges& pendingChanges);
|
||||
|
||||
virtual void postUpdate(float deltaTime);
|
||||
|
||||
//setters
|
||||
void setDisplayingLookatVectors(bool displayingLookatVectors) { getHead()->setRenderLookatVectors(displayingLookatVectors); }
|
||||
void setDisplayingLookatTarget(bool displayingLookatTarget) { getHead()->setRenderLookatTarget(displayingLookatTarget); }
|
||||
void setIsLookAtTarget(const bool isLookAtTarget) { _isLookAtTarget = isLookAtTarget; }
|
||||
bool getIsLookAtTarget() const { return _isLookAtTarget; }
|
||||
//getters
|
||||
|
@ -232,7 +232,6 @@ protected:
|
|||
|
||||
Transform calculateDisplayNameTransform(const ViewFrustum& view, const glm::vec3& textPosition) const;
|
||||
void renderDisplayName(gpu::Batch& batch, const ViewFrustum& view, const glm::vec3& textPosition) const;
|
||||
virtual void renderBody(RenderArgs* renderArgs, float glowLevel = 0.0f);
|
||||
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const;
|
||||
virtual void fixupModelsInScene();
|
||||
|
||||
|
@ -251,7 +250,7 @@ private:
|
|||
bool _initialized;
|
||||
bool _shouldAnimate { true };
|
||||
bool _shouldSkipRender { false };
|
||||
bool _isLookAtTarget;
|
||||
bool _isLookAtTarget { false };
|
||||
|
||||
float getBoundingRadius() const;
|
||||
|
||||
|
|
|
@ -156,6 +156,15 @@ void AvatarManager::updateOtherAvatars(float deltaTime) {
|
|||
simulateAvatarFades(deltaTime);
|
||||
}
|
||||
|
||||
void AvatarManager::postUpdate(float deltaTime) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
void AvatarManager::simulateAvatarFades(float deltaTime) {
|
||||
QVector<AvatarSharedPointer>::iterator fadingIterator = _avatarFades.begin();
|
||||
|
||||
|
|
|
@ -44,6 +44,8 @@ public:
|
|||
void updateMyAvatar(float deltaTime);
|
||||
void updateOtherAvatars(float deltaTime);
|
||||
|
||||
void postUpdate(float deltaTime);
|
||||
|
||||
void clearOtherAvatars();
|
||||
void clearAllAvatars();
|
||||
|
||||
|
|
|
@ -46,8 +46,6 @@ Head::Head(Avatar* owningAvatar) :
|
|||
_mouth3(0.0f),
|
||||
_mouth4(0.0f),
|
||||
_mouthTime(0.0f),
|
||||
_renderLookatVectors(false),
|
||||
_renderLookatTarget(false),
|
||||
_saccade(0.0f, 0.0f, 0.0f),
|
||||
_saccadeTarget(0.0f, 0.0f, 0.0f),
|
||||
_leftEyeBlinkVelocity(0.0f),
|
||||
|
@ -316,19 +314,6 @@ void Head::relaxLean(float deltaTime) {
|
|||
_deltaLeanForward *= relaxationFactor;
|
||||
}
|
||||
|
||||
void Head::renderLookAts(RenderArgs* renderArgs) {
|
||||
renderLookAts(renderArgs, _leftEyePosition, _rightEyePosition);
|
||||
}
|
||||
|
||||
void Head::renderLookAts(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition) {
|
||||
if (_renderLookatVectors) {
|
||||
renderLookatVectors(renderArgs, leftEyePosition, rightEyePosition, getCorrectedLookAtPosition());
|
||||
}
|
||||
if (_renderLookatTarget) {
|
||||
renderLookatTarget(renderArgs, getCorrectedLookAtPosition());
|
||||
}
|
||||
}
|
||||
|
||||
void Head::setScale (float scale) {
|
||||
if (_scale == scale) {
|
||||
return;
|
||||
|
@ -439,31 +424,3 @@ void Head::addLeanDeltas(float sideways, float forward) {
|
|||
_deltaLeanSideways += sideways;
|
||||
_deltaLeanForward += forward;
|
||||
}
|
||||
|
||||
void Head::renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition) {
|
||||
auto& batch = *renderArgs->_batch;
|
||||
auto transform = Transform{};
|
||||
batch.setModelTransform(transform);
|
||||
// FIXME: THe line width of 2.0f is not supported anymore, we ll need a workaround
|
||||
|
||||
glm::vec4 startColor(0.2f, 0.2f, 0.2f, 1.0f);
|
||||
glm::vec4 endColor(1.0f, 1.0f, 1.0f, 0.0f);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
geometryCache->bindSimpleProgram(batch);
|
||||
geometryCache->renderLine(batch, leftEyePosition, lookatPosition, startColor, endColor, _leftEyeLookAtID);
|
||||
geometryCache->renderLine(batch, rightEyePosition, lookatPosition, startColor, endColor, _rightEyeLookAtID);
|
||||
}
|
||||
|
||||
void Head::renderLookatTarget(RenderArgs* renderArgs, glm::vec3 lookatPosition) {
|
||||
auto& batch = *renderArgs->_batch;
|
||||
auto transform = Transform{};
|
||||
transform.setTranslation(lookatPosition);
|
||||
|
||||
auto geometryCache = DependencyManager::get<GeometryCache>();
|
||||
const float LOOK_AT_TARGET_RADIUS = 0.075f;
|
||||
transform.postScale(LOOK_AT_TARGET_RADIUS);
|
||||
const glm::vec4 LOOK_AT_TARGET_COLOR = { 0.8f, 0.0f, 0.0f, 0.75f };
|
||||
batch.setModelTransform(transform);
|
||||
geometryCache->renderSolidSphereInstance(batch, LOOK_AT_TARGET_COLOR);
|
||||
}
|
||||
|
|
|
@ -36,10 +36,6 @@ public:
|
|||
void setPosition(glm::vec3 position) { _position = position; }
|
||||
void setAverageLoudness(float averageLoudness) { _averageLoudness = averageLoudness; }
|
||||
void setReturnToCenter (bool returnHeadToCenter) { _returnHeadToCenter = returnHeadToCenter; }
|
||||
void setRenderLookatVectors(bool onOff) { _renderLookatVectors = onOff; }
|
||||
void setRenderLookatTarget(bool onOff) { _renderLookatTarget = onOff; }
|
||||
void renderLookAts(RenderArgs* renderArgs);
|
||||
void renderLookAts(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition);
|
||||
|
||||
/// \return orientationBase+Delta
|
||||
glm::quat getFinalOrientationInLocalFrame() const;
|
||||
|
@ -49,7 +45,7 @@ public:
|
|||
|
||||
/// \return orientationBody * orientationBasePitch
|
||||
glm::quat getCameraOrientation () const;
|
||||
|
||||
|
||||
void setCorrectedLookAtPosition(glm::vec3 correctedLookAtPosition);
|
||||
glm::vec3 getCorrectedLookAtPosition();
|
||||
void clearCorrectedLookAtPosition() { _isLookingAtMe = false; }
|
||||
|
@ -65,9 +61,9 @@ public:
|
|||
glm::vec3 getFrontDirection() const { return getOrientation() * IDENTITY_FRONT; }
|
||||
float getFinalLeanSideways() const { return _leanSideways + _deltaLeanSideways; }
|
||||
float getFinalLeanForward() const { return _leanForward + _deltaLeanForward; }
|
||||
|
||||
|
||||
glm::quat getEyeRotation(const glm::vec3& eyePosition) const;
|
||||
|
||||
|
||||
const glm::vec3& getRightEyePosition() const { return _rightEyePosition; }
|
||||
const glm::vec3& getLeftEyePosition() const { return _leftEyePosition; }
|
||||
glm::vec3 getRightEarPosition() const { return _rightEyePosition + (getRightDirection() * EYE_EAR_GAP) + (getFrontDirection() * -EYE_EAR_GAP); }
|
||||
|
@ -84,10 +80,10 @@ public:
|
|||
|
||||
void setDeltaYaw(float yaw) { _deltaYaw = yaw; }
|
||||
float getDeltaYaw() const { return _deltaYaw; }
|
||||
|
||||
|
||||
void setDeltaRoll(float roll) { _deltaRoll = roll; }
|
||||
float getDeltaRoll() const { return _deltaRoll; }
|
||||
|
||||
|
||||
virtual void setFinalYaw(float finalYaw);
|
||||
virtual void setFinalPitch(float finalPitch);
|
||||
virtual void setFinalRoll(float finalRoll);
|
||||
|
@ -99,7 +95,7 @@ public:
|
|||
void addLeanDeltas(float sideways, float forward);
|
||||
|
||||
float getTimeWithoutTalking() const { return _timeWithoutTalking; }
|
||||
|
||||
|
||||
private:
|
||||
glm::vec3 calculateAverageEyePosition() const { return _leftEyePosition + (_rightEyePosition - _leftEyePosition ) * 0.5f; }
|
||||
|
||||
|
@ -113,7 +109,7 @@ private:
|
|||
glm::vec3 _leftEyePosition;
|
||||
glm::vec3 _rightEyePosition;
|
||||
glm::vec3 _eyePosition;
|
||||
|
||||
|
||||
float _scale;
|
||||
float _lastLoudness;
|
||||
float _longTermAverageLoudness;
|
||||
|
@ -124,8 +120,7 @@ private:
|
|||
float _mouth3;
|
||||
float _mouth4;
|
||||
float _mouthTime;
|
||||
bool _renderLookatVectors;
|
||||
bool _renderLookatTarget;
|
||||
|
||||
glm::vec3 _saccade;
|
||||
glm::vec3 _saccadeTarget;
|
||||
float _leftEyeBlinkVelocity;
|
||||
|
@ -145,15 +140,13 @@ private:
|
|||
bool _isLookingAtMe;
|
||||
quint64 _lookingAtMeStarted;
|
||||
quint64 _wasLastLookingAtMe;
|
||||
|
||||
|
||||
glm::vec3 _correctedLookAtPosition;
|
||||
|
||||
int _leftEyeLookAtID;
|
||||
int _rightEyeLookAtID;
|
||||
|
||||
|
||||
// private methods
|
||||
void renderLookatVectors(RenderArgs* renderArgs, glm::vec3 leftEyePosition, glm::vec3 rightEyePosition, glm::vec3 lookatPosition);
|
||||
void renderLookatTarget(RenderArgs* renderArgs, glm::vec3 lookatPosition);
|
||||
void calculateMouthShapes();
|
||||
void applyEyelidOffset(glm::quat headOrientation);
|
||||
};
|
||||
|
|
|
@ -1270,35 +1270,6 @@ void MyAvatar::attach(const QString& modelURL, const QString& jointName,
|
|||
Avatar::attach(modelURL, jointName, translation, rotation, scale, isSoft, allowDuplicates, useSaved);
|
||||
}
|
||||
|
||||
void MyAvatar::renderBody(RenderArgs* renderArgs, float glowLevel) {
|
||||
|
||||
if (!_skeletonModel->isRenderable()) {
|
||||
return; // wait until all models are loaded
|
||||
}
|
||||
|
||||
fixupModelsInScene();
|
||||
|
||||
// This is drawing the lookat vectors from our avatar to wherever we're looking.
|
||||
if (qApp->isHMDMode()) {
|
||||
glm::vec3 cameraPosition = qApp->getCamera()->getPosition();
|
||||
|
||||
glm::mat4 headPose = qApp->getActiveDisplayPlugin()->getHeadPose();
|
||||
glm::mat4 leftEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Left);
|
||||
leftEyePose = leftEyePose * headPose;
|
||||
glm::vec3 leftEyePosition = extractTranslation(leftEyePose);
|
||||
glm::mat4 rightEyePose = qApp->getActiveDisplayPlugin()->getEyeToHeadTransform(Eye::Right);
|
||||
rightEyePose = rightEyePose * headPose;
|
||||
glm::vec3 rightEyePosition = extractTranslation(rightEyePose);
|
||||
glm::vec3 headPosition = extractTranslation(headPose);
|
||||
|
||||
getHead()->renderLookAts(renderArgs,
|
||||
cameraPosition + getOrientation() * (leftEyePosition - headPosition),
|
||||
cameraPosition + getOrientation() * (rightEyePosition - headPosition));
|
||||
} else {
|
||||
getHead()->renderLookAts(renderArgs);
|
||||
}
|
||||
}
|
||||
|
||||
void MyAvatar::setVisibleInSceneIfReady(Model* model, render::ScenePointer scene, bool visible) {
|
||||
if (model->isActive() && model->isRenderable()) {
|
||||
model->setVisibleInScene(visible, scene);
|
||||
|
@ -1355,10 +1326,11 @@ void MyAvatar::destroyAnimGraph() {
|
|||
_rig->destroyAnimGraph();
|
||||
}
|
||||
|
||||
void MyAvatar::preRender(RenderArgs* renderArgs) {
|
||||
void MyAvatar::postUpdate(float deltaTime) {
|
||||
|
||||
Avatar::postUpdate(deltaTime);
|
||||
|
||||
render::ScenePointer scene = qApp->getMain3DScene();
|
||||
|
||||
if (_skeletonModel->initWhenReady(scene)) {
|
||||
initHeadBones();
|
||||
_skeletonModel->setCauterizeBoneSet(_headBoneSet);
|
||||
|
@ -1408,7 +1380,12 @@ void MyAvatar::preRender(RenderArgs* renderArgs) {
|
|||
|
||||
DebugDraw::getInstance().updateMyAvatarPos(getPosition());
|
||||
DebugDraw::getInstance().updateMyAvatarRot(getOrientation());
|
||||
}
|
||||
|
||||
|
||||
void MyAvatar::preDisplaySide(RenderArgs* renderArgs) {
|
||||
|
||||
// toggle using the cauterizedBones depending on where the camera is and the rendering pass type.
|
||||
const bool shouldDrawHead = shouldRenderHead(renderArgs);
|
||||
if (shouldDrawHead != _prevShouldDrawHead) {
|
||||
_skeletonModel->setCauterizeBones(!shouldDrawHead);
|
||||
|
|
|
@ -96,7 +96,8 @@ public:
|
|||
|
||||
Q_INVOKABLE void reset(bool andRecenter = false);
|
||||
void update(float deltaTime);
|
||||
void preRender(RenderArgs* renderArgs);
|
||||
virtual void postUpdate(float deltaTime) override;
|
||||
void preDisplaySide(RenderArgs* renderArgs);
|
||||
|
||||
const glm::mat4& getHMDSensorMatrix() const { return _hmdSensorMatrix; }
|
||||
const glm::vec3& getHMDSensorPosition() const { return _hmdSensorPosition; }
|
||||
|
@ -310,7 +311,6 @@ private:
|
|||
void simulate(float deltaTime);
|
||||
void updateFromTrackers(float deltaTime);
|
||||
virtual void render(RenderArgs* renderArgs, const glm::vec3& cameraPositio) override;
|
||||
virtual void renderBody(RenderArgs* renderArgs, float glowLevel = 0.0f) override;
|
||||
virtual bool shouldRenderHead(const RenderArgs* renderArgs) const override;
|
||||
void setShouldRenderLocally(bool shouldRender) { _shouldRender = shouldRender; setEnableMeshVisible(shouldRender); }
|
||||
bool getShouldRenderLocally() const { return _shouldRender; }
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <QMultiMap>
|
||||
|
||||
#include <recording/Deck.h>
|
||||
#include <DebugDraw.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Avatar.h"
|
||||
|
@ -92,7 +93,6 @@ void SkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
|
|||
|
||||
Head* head = _owningAvatar->getHead();
|
||||
|
||||
|
||||
// make sure lookAt is not too close to face (avoid crosseyes)
|
||||
glm::vec3 lookAt = _owningAvatar->isMyAvatar() ? head->getLookAtPosition() : head->getCorrectedLookAtPosition();
|
||||
glm::vec3 focusOffset = lookAt - _owningAvatar->getHead()->getEyePosition();
|
||||
|
|
|
@ -11,8 +11,11 @@
|
|||
|
||||
#include "MenuScriptingInterface.h"
|
||||
|
||||
#include "Menu.h"
|
||||
#include <QtCore/QCoreApplication>
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <MenuItemProperties.h>
|
||||
#include "Menu.h"
|
||||
|
||||
MenuScriptingInterface* MenuScriptingInterface::getInstance() {
|
||||
static MenuScriptingInterface sharedInstance;
|
||||
|
@ -36,6 +39,9 @@ void MenuScriptingInterface::removeMenu(const QString& menu) {
|
|||
}
|
||||
|
||||
bool MenuScriptingInterface::menuExists(const QString& menu) {
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
return Menu::getInstance()->menuExists(menu);
|
||||
}
|
||||
bool result;
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "menuExists", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(bool, result),
|
||||
|
@ -76,11 +82,14 @@ void MenuScriptingInterface::removeMenuItem(const QString& menu, const QString&
|
|||
};
|
||||
|
||||
bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString& menuitem) {
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
return Menu::getInstance()->menuItemExists(menu, menuitem);
|
||||
}
|
||||
bool result;
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "menuItemExists", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(bool, result),
|
||||
Q_ARG(const QString&, menu),
|
||||
Q_ARG(const QString&, menuitem));
|
||||
Q_RETURN_ARG(bool, result),
|
||||
Q_ARG(const QString&, menu),
|
||||
Q_ARG(const QString&, menuitem));
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -101,6 +110,9 @@ void MenuScriptingInterface::removeActionGroup(const QString& groupName) {
|
|||
}
|
||||
|
||||
bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) {
|
||||
if (QThread::currentThread() == qApp->thread()) {
|
||||
return Menu::getInstance()->isOptionChecked(menuOption);
|
||||
}
|
||||
bool result;
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection,
|
||||
Q_RETURN_ARG(bool, result),
|
||||
|
@ -109,7 +121,7 @@ bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) {
|
|||
}
|
||||
|
||||
void MenuScriptingInterface::setIsOptionChecked(const QString& menuOption, bool isChecked) {
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked", Qt::BlockingQueuedConnection,
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "setIsOptionChecked",
|
||||
Q_ARG(const QString&, menuOption),
|
||||
Q_ARG(bool, isChecked));
|
||||
}
|
||||
|
|
|
@ -104,7 +104,7 @@ void Image3DOverlay::render(RenderArgs* args) {
|
|||
const render::ShapeKey Image3DOverlay::getShapeKey() {
|
||||
auto builder = render::ShapeKey::Builder().withoutCullFace().withDepthBias();
|
||||
if (_emissive) {
|
||||
builder.withEmissive();
|
||||
builder.withUnlit();
|
||||
}
|
||||
if (getAlpha() != 1.0f) {
|
||||
builder.withTranslucent();
|
||||
|
|
|
@ -1057,20 +1057,30 @@ void Rig::updateNeckJoint(int index, const HeadParameters& params) {
|
|||
}
|
||||
|
||||
void Rig::updateEyeJoint(int index, const glm::vec3& modelTranslation, const glm::quat& modelRotation, const glm::quat& worldHeadOrientation, const glm::vec3& lookAtSpot, const glm::vec3& saccade) {
|
||||
|
||||
// TODO: does not properly handle avatar scale.
|
||||
|
||||
if (isIndexValid(index)) {
|
||||
glm::mat4 rigToWorld = createMatFromQuatAndPos(modelRotation, modelTranslation);
|
||||
glm::mat4 worldToRig = glm::inverse(rigToWorld);
|
||||
glm::vec3 zAxis = glm::normalize(_internalPoseSet._absolutePoses[index].trans - transformPoint(worldToRig, lookAtSpot));
|
||||
glm::vec3 lookAtVector = glm::normalize(transformPoint(worldToRig, lookAtSpot) - _internalPoseSet._absolutePoses[index].trans);
|
||||
|
||||
glm::quat desiredQuat = rotationBetween(IDENTITY_FRONT, zAxis);
|
||||
glm::quat headQuat;
|
||||
int headIndex = indexOfJoint("Head");
|
||||
glm::quat headQuat;
|
||||
if (headIndex >= 0) {
|
||||
headQuat = _internalPoseSet._absolutePoses[headIndex].rot;
|
||||
}
|
||||
|
||||
glm::vec3 headUp = headQuat * Vectors::UNIT_Y;
|
||||
glm::vec3 z, y, x;
|
||||
generateBasisVectors(lookAtVector, headUp, z, y, x);
|
||||
glm::mat3 m(glm::cross(y, z), y, z);
|
||||
glm::quat desiredQuat = glm::normalize(glm::quat_cast(m));
|
||||
|
||||
glm::quat deltaQuat = desiredQuat * glm::inverse(headQuat);
|
||||
|
||||
// limit rotation
|
||||
// limit swing rotation of the deltaQuat by a 30 degree cone.
|
||||
// TODO: use swing twist decomposition constraint instead, for off axis rotation clamping.
|
||||
const float MAX_ANGLE = 30.0f * RADIANS_PER_DEGREE;
|
||||
if (fabsf(glm::angle(deltaQuat)) > MAX_ANGLE) {
|
||||
deltaQuat = glm::angleAxis(glm::clamp(glm::angle(deltaQuat), -MAX_ANGLE, MAX_ANGLE), glm::axis(deltaQuat));
|
||||
|
|
|
@ -58,7 +58,7 @@ controller::UserInputMapper::UserInputMapper() {
|
|||
|
||||
namespace controller {
|
||||
|
||||
|
||||
|
||||
UserInputMapper::~UserInputMapper() {
|
||||
}
|
||||
|
||||
|
@ -80,6 +80,7 @@ void UserInputMapper::registerDevice(InputDevice::Pointer device) {
|
|||
recordDeviceOfType(device->getName());
|
||||
|
||||
qCDebug(controllers) << "Registered input device <" << device->getName() << "> deviceID = " << deviceID;
|
||||
|
||||
for (const auto& inputMapping : device->getAvailableInputs()) {
|
||||
const auto& input = inputMapping.first;
|
||||
// Ignore aliases
|
||||
|
@ -102,6 +103,7 @@ void UserInputMapper::registerDevice(InputDevice::Pointer device) {
|
|||
}
|
||||
|
||||
_registeredDevices[deviceID] = device;
|
||||
|
||||
auto mapping = loadMappings(device->getDefaultMappingConfigs());
|
||||
if (mapping) {
|
||||
_mappingsByDevice[deviceID] = mapping;
|
||||
|
@ -111,15 +113,21 @@ void UserInputMapper::registerDevice(InputDevice::Pointer device) {
|
|||
emit hardwareChanged();
|
||||
}
|
||||
|
||||
// FIXME remove the associated device mappings
|
||||
void UserInputMapper::removeDevice(int deviceID) {
|
||||
|
||||
Locker locker(_lock);
|
||||
auto proxyEntry = _registeredDevices.find(deviceID);
|
||||
|
||||
if (_registeredDevices.end() == proxyEntry) {
|
||||
qCWarning(controllers) << "Attempted to remove unknown device " << deviceID;
|
||||
return;
|
||||
}
|
||||
auto proxy = proxyEntry->second;
|
||||
|
||||
auto device = proxyEntry->second;
|
||||
qCDebug(controllers) << "Unregistering input device <" << device->getName() << "> deviceID = " << deviceID;
|
||||
|
||||
unloadMappings(device->getDefaultMappingConfigs());
|
||||
|
||||
auto mappingsEntry = _mappingsByDevice.find(deviceID);
|
||||
if (_mappingsByDevice.end() != mappingsEntry) {
|
||||
disableMapping(mappingsEntry->second);
|
||||
|
@ -244,7 +252,7 @@ void UserInputMapper::update(float deltaTime) {
|
|||
for (auto& channel : _actionStates) {
|
||||
channel = 0.0f;
|
||||
}
|
||||
|
||||
|
||||
for (auto& channel : _poseStates) {
|
||||
channel = Pose();
|
||||
}
|
||||
|
@ -705,11 +713,10 @@ Mapping::Pointer UserInputMapper::loadMapping(const QString& jsonFile, bool enab
|
|||
return Mapping::Pointer();
|
||||
}
|
||||
// Each mapping only needs to be loaded once
|
||||
static QSet<QString> loaded;
|
||||
if (loaded.contains(jsonFile)) {
|
||||
if (_loadedRouteJsonFiles.contains(jsonFile)) {
|
||||
return Mapping::Pointer();
|
||||
}
|
||||
loaded.insert(jsonFile);
|
||||
_loadedRouteJsonFiles.insert(jsonFile);
|
||||
QString json;
|
||||
{
|
||||
QFile file(jsonFile);
|
||||
|
@ -741,6 +748,18 @@ MappingPointer UserInputMapper::loadMappings(const QStringList& jsonFiles) {
|
|||
return result;
|
||||
}
|
||||
|
||||
void UserInputMapper::unloadMappings(const QStringList& jsonFiles) {
|
||||
for (const QString& jsonFile : jsonFiles) {
|
||||
unloadMapping(jsonFile);
|
||||
}
|
||||
}
|
||||
|
||||
void UserInputMapper::unloadMapping(const QString& jsonFile) {
|
||||
auto entry = _loadedRouteJsonFiles.find(jsonFile);
|
||||
if (entry != _loadedRouteJsonFiles.end()) {
|
||||
_loadedRouteJsonFiles.erase(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static const QString JSON_NAME = QStringLiteral("name");
|
||||
static const QString JSON_CHANNELS = QStringLiteral("channels");
|
||||
|
|
|
@ -111,9 +111,18 @@ namespace controller {
|
|||
|
||||
void loadDefaultMapping(uint16 deviceID);
|
||||
void enableMapping(const QString& mappingName, bool enable = true);
|
||||
|
||||
void unloadMappings(const QStringList& jsonFiles);
|
||||
void unloadMapping(const QString& jsonFile);
|
||||
|
||||
float getValue(const Input& input) const;
|
||||
Pose getPose(const Input& input) const;
|
||||
|
||||
// perform an action when the UserInputMapper mutex is acquired.
|
||||
using Locker = std::unique_lock<std::recursive_mutex>;
|
||||
template <typename F>
|
||||
void withLock(F&& f) { Locker locker(_lock); f(); }
|
||||
|
||||
signals:
|
||||
void actionEvent(int action, float state);
|
||||
void inputEvent(int input, float state);
|
||||
|
@ -177,7 +186,7 @@ namespace controller {
|
|||
RouteList _deviceRoutes;
|
||||
RouteList _standardRoutes;
|
||||
|
||||
using Locker = std::unique_lock<std::recursive_mutex>;
|
||||
QSet<QString> _loadedRouteJsonFiles;
|
||||
|
||||
mutable std::recursive_mutex _lock;
|
||||
};
|
||||
|
|
|
@ -13,11 +13,12 @@
|
|||
|
||||
using namespace controller;
|
||||
float DeadZoneFilter::apply(float value) const {
|
||||
float scale = 1.0f / (1.0f - _min);
|
||||
if (std::abs(value) < _min) {
|
||||
float scale = ((value < 0.0f) ? -1.0f : 1.0f) / (1.0f - _min);
|
||||
float magnitude = std::abs(value);
|
||||
if (magnitude < _min) {
|
||||
return 0.0f;
|
||||
}
|
||||
return (value - _min) * scale;
|
||||
return (magnitude - _min) * scale;
|
||||
}
|
||||
|
||||
bool DeadZoneFilter::parseParameters(const QJsonValue& parameters) {
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
#include <QtWidgets/QApplication>
|
||||
#include <QtWidgets/QDesktopWidget>
|
||||
#include <glm/gtc/type_ptr.hpp>
|
||||
#include <QtGui/QWindow>
|
||||
#include <QQuickWindow>
|
||||
|
||||
#include <ui/Menu.h>
|
||||
#include <NumericalConstants.h>
|
||||
|
@ -256,7 +258,7 @@ glm::vec2 CompositorHelper::getReticlePosition() const {
|
|||
QMutexLocker locker(&_reticleLock);
|
||||
return _reticlePositionInHMD;
|
||||
}
|
||||
return toGlm(QCursor::pos());
|
||||
return toGlm(_renderingWidget->mapFromGlobal(QCursor::pos()));
|
||||
}
|
||||
|
||||
bool CompositorHelper::getReticleOverDesktop() const {
|
||||
|
@ -322,17 +324,8 @@ void CompositorHelper::setReticlePosition(const glm::vec2& position, bool sendFa
|
|||
sendFakeMouseEvent();
|
||||
}
|
||||
} else {
|
||||
// NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies,
|
||||
// remove it after we're done
|
||||
const float REASONABLE_CHANGE = 50.0f;
|
||||
glm::vec2 oldPos = toGlm(QCursor::pos());
|
||||
auto distance = glm::distance(oldPos, position);
|
||||
if (distance > REASONABLE_CHANGE) {
|
||||
qDebug() << "Contrller::ScriptingInterface ---- UNREASONABLE CHANGE! distance:" <<
|
||||
distance << " oldPos:" << oldPos.x << "," << oldPos.y << " newPos:" << position.x << "," << position.y;
|
||||
}
|
||||
|
||||
QCursor::setPos(position.x, position.y);
|
||||
const QPoint point(position.x, position.y);
|
||||
QCursor::setPos(_renderingWidget->mapToGlobal(point));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -210,7 +210,7 @@ void RenderableWebEntityItem::render(RenderArgs* args) {
|
|||
}
|
||||
|
||||
DependencyManager::get<GeometryCache>()->bindSimpleProgram(batch, textured, culled, emissive);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f));
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, topLeft, bottomRight, texMin, texMax, glm::vec4(1.0f, 1.0f, 1.0f, 0.0f));
|
||||
}
|
||||
|
||||
void RenderableWebEntityItem::setSourceUrl(const QString& value) {
|
||||
|
|
|
@ -892,7 +892,10 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
properties = true;
|
||||
propertyName = "P";
|
||||
index = 4;
|
||||
} else if (subobject.name == "ShadingModel") {
|
||||
material.shadingModel = subobject.properties.at(0).toString();
|
||||
}
|
||||
|
||||
if (properties) {
|
||||
std::vector<std::string> unknowns;
|
||||
foreach(const FBXNode& property, subobject.children) {
|
||||
|
@ -988,7 +991,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
QString propname = subobject.name.data();
|
||||
int unknown = 0;
|
||||
if ( (propname == "Version")
|
||||
||(propname == "ShadingModel")
|
||||
||(propname == "Multilayer")) {
|
||||
} else {
|
||||
unknown++;
|
||||
|
@ -1130,7 +1132,6 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
ambientTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if (type.contains("tex_ao_map")) {
|
||||
occlusionTextures.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
|
||||
} else if (type == "lcl rotation") {
|
||||
localRotations.insert(getID(connection.properties, 2), getID(connection.properties, 1));
|
||||
} else if (type == "lcl translation") {
|
||||
|
@ -1331,7 +1332,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
}
|
||||
|
||||
// NOTE: shapeVertices are in joint-frame
|
||||
QVector<ShapeVertices> shapeVertices;
|
||||
std::vector<ShapeVertices> shapeVertices;
|
||||
shapeVertices.resize(geometry.joints.size());
|
||||
|
||||
// find our special joints
|
||||
|
@ -1522,7 +1523,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
|
||||
float clusterScale = extractUniformScale(fbxCluster.inverseBindMatrix);
|
||||
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
|
||||
ShapeVertices& points = shapeVertices[jointIndex];
|
||||
ShapeVertices& points = shapeVertices.at(jointIndex);
|
||||
|
||||
float totalWeight = 0.0f;
|
||||
for (int j = 0; j < cluster.indices.size(); j++) {
|
||||
|
@ -1584,7 +1585,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
// transform cluster vertices to joint-frame and save for later
|
||||
float clusterScale = extractUniformScale(firstFBXCluster.inverseBindMatrix);
|
||||
glm::mat4 meshToJoint = glm::inverse(joint.bindTransform) * modelTransform;
|
||||
ShapeVertices& points = shapeVertices[jointIndex];
|
||||
ShapeVertices& points = shapeVertices.at(jointIndex);
|
||||
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {
|
||||
const glm::mat4 vertexTransform = meshToJoint * glm::translate(vertex);
|
||||
points.push_back(extractTranslation(vertexTransform) * clusterScale);
|
||||
|
@ -1625,7 +1626,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
|
|||
FBXJoint& joint = geometry.joints[i];
|
||||
|
||||
// NOTE: points are in joint-frame
|
||||
ShapeVertices& points = shapeVertices[i];
|
||||
ShapeVertices& points = shapeVertices.at(i);
|
||||
if (points.size() > 0) {
|
||||
// compute average point
|
||||
glm::vec3 avgPoint = glm::vec3(0.0f);
|
||||
|
|
|
@ -154,6 +154,7 @@ public:
|
|||
|
||||
QString materialID;
|
||||
QString name;
|
||||
QString shadingModel;
|
||||
model::MaterialPointer _material;
|
||||
|
||||
FBXTexture normalTexture;
|
||||
|
|
|
@ -72,6 +72,10 @@ void FBXReader::consolidateFBXMaterials() {
|
|||
// foreach (const QString& materialID, materials) {
|
||||
for (QHash<QString, FBXMaterial>::iterator it = _fbxMaterials.begin(); it != _fbxMaterials.end(); it++) {
|
||||
FBXMaterial& material = (*it);
|
||||
|
||||
// Maya is the exporting the shading model and we aretrying to use it
|
||||
bool isMaterialLambert = (material.shadingModel.toLower() == "lambert");
|
||||
|
||||
// the pure material associated with this part
|
||||
bool detectDifferentUVs = false;
|
||||
FBXTexture diffuseTexture;
|
||||
|
@ -171,6 +175,13 @@ void FBXReader::consolidateFBXMaterials() {
|
|||
emissiveTexture = getTexture(emissiveTextureID);
|
||||
detectDifferentUVs |= (emissiveTexture.texcoordSet != 0) || (!emissiveTexture.transform.isIdentity());
|
||||
material.emissiveTexture = emissiveTexture;
|
||||
|
||||
if (isMaterialLambert) {
|
||||
// If the emissiveTextureID comes from the Texture bound to Emissive when material is lambert, we know it s exported from maya
|
||||
// And the EMissiveColor is forced to 0.5 by Maya which is bad
|
||||
// So we need to force it to 1.0
|
||||
material.emissiveColor = vec3(1.0);
|
||||
}
|
||||
}
|
||||
|
||||
FBXTexture occlusionTexture;
|
||||
|
@ -198,7 +209,7 @@ void FBXReader::consolidateFBXMaterials() {
|
|||
material._material = std::make_shared<model::Material>();
|
||||
|
||||
// Emissive color is the mix of emissiveColor with emissiveFactor
|
||||
auto emissive = material.emissiveColor * material.emissiveFactor;
|
||||
auto emissive = material.emissiveColor * (isMaterialLambert ? 1.0f : material.emissiveFactor); // In lambert there is not emissiveFactor
|
||||
material._material->setEmissive(emissive);
|
||||
|
||||
// Final diffuse color is the mix of diffuseColor with diffuseFactor
|
||||
|
@ -212,6 +223,18 @@ void FBXReader::consolidateFBXMaterials() {
|
|||
material._material->setRoughness(model::Material::shininessToRoughness(material.shininess));
|
||||
float metallic = std::max(material.specularColor.x, std::max(material.specularColor.y, material.specularColor.z));
|
||||
material._material->setMetallic(metallic);
|
||||
|
||||
if (isMaterialLambert) {
|
||||
if (!material._material->getKey().isAlbedo()) {
|
||||
// switch emissive to material albedo as we tag the material to unlit
|
||||
material._material->setUnlit(true);
|
||||
material._material->setAlbedo(emissive);
|
||||
|
||||
if (!material.emissiveTexture.isNull()) {
|
||||
material.albedoTexture = material.emissiveTexture;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (material.opacity <= 0.0f) {
|
||||
|
|
|
@ -20,8 +20,12 @@
|
|||
|
||||
const QString KeyboardMouseDevice::NAME = "Keyboard/Mouse";
|
||||
|
||||
void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
|
||||
_inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured);
|
||||
void KeyboardMouseDevice::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
|
||||
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->withLock([&, this]() {
|
||||
_inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured);
|
||||
});
|
||||
|
||||
// For touch event, we need to check that the last event is not too long ago
|
||||
// Maybe it's a Qt issue, but the touch event sequence (begin, update, end) is not always called properly
|
||||
|
|
|
@ -74,6 +74,11 @@ void Material::setOpacity(float opacity) {
|
|||
_schemaBuffer.edit<Schema>()._opacity = opacity;
|
||||
}
|
||||
|
||||
void Material::setUnlit(bool value) {
|
||||
_key.setUnlit(value);
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
}
|
||||
|
||||
void Material::setAlbedo(const Color& albedo, bool isSRGB) {
|
||||
_key.setAlbedo(glm::any(glm::greaterThan(albedo, Color(0.0f))));
|
||||
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();
|
||||
|
|
|
@ -28,14 +28,15 @@ class MaterialKey {
|
|||
public:
|
||||
enum FlagBit {
|
||||
EMISSIVE_VAL_BIT = 0,
|
||||
UNLIT_VAL_BIT,
|
||||
ALBEDO_VAL_BIT,
|
||||
METALLIC_VAL_BIT,
|
||||
GLOSSY_VAL_BIT,
|
||||
OPACITY_VAL_BIT,
|
||||
OPACITY_MASK_MAP_BIT, // OPacity Map and Opacity MASK map are mutually exclusive
|
||||
OPACITY_MASK_MAP_BIT, // Opacity Map and Opacity MASK map are mutually exclusive
|
||||
OPACITY_TRANSLUCENT_MAP_BIT,
|
||||
|
||||
// THe map bits must be in the smae sequence as the enum names for the map channels
|
||||
// THe map bits must be in the same sequence as the enum names for the map channels
|
||||
EMISSIVE_MAP_BIT,
|
||||
ALBEDO_MAP_BIT,
|
||||
METALLIC_MAP_BIT,
|
||||
|
@ -74,9 +75,12 @@ public:
|
|||
MaterialKey build() const { return MaterialKey(_flags); }
|
||||
|
||||
Builder& withEmissive() { _flags.set(EMISSIVE_VAL_BIT); return (*this); }
|
||||
Builder& withUnlit() { _flags.set(UNLIT_VAL_BIT); return (*this); }
|
||||
|
||||
Builder& withAlbedo() { _flags.set(ALBEDO_VAL_BIT); return (*this); }
|
||||
Builder& withMetallic() { _flags.set(METALLIC_VAL_BIT); return (*this); }
|
||||
Builder& withGlossy() { _flags.set(GLOSSY_VAL_BIT); return (*this); }
|
||||
|
||||
Builder& withTranslucentFactor() { _flags.set(OPACITY_VAL_BIT); return (*this); }
|
||||
|
||||
Builder& withEmissiveMap() { _flags.set(EMISSIVE_MAP_BIT); return (*this); }
|
||||
|
@ -98,6 +102,9 @@ public:
|
|||
void setEmissive(bool value) { _flags.set(EMISSIVE_VAL_BIT, value); }
|
||||
bool isEmissive() const { return _flags[EMISSIVE_VAL_BIT]; }
|
||||
|
||||
void setUnlit(bool value) { _flags.set(UNLIT_VAL_BIT, value); }
|
||||
bool isUnlit() const { return _flags[UNLIT_VAL_BIT]; }
|
||||
|
||||
void setEmissiveMap(bool value) { _flags.set(EMISSIVE_MAP_BIT, value); }
|
||||
bool isEmissiveMap() const { return _flags[EMISSIVE_MAP_BIT]; }
|
||||
|
||||
|
@ -172,6 +179,9 @@ public:
|
|||
Builder& withoutEmissiveMap() { _value.reset(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT); return (*this); }
|
||||
Builder& withEmissiveMap() { _value.set(MaterialKey::EMISSIVE_MAP_BIT); _mask.set(MaterialKey::EMISSIVE_MAP_BIT); return (*this); }
|
||||
|
||||
Builder& withoutUnlit() { _value.reset(MaterialKey::UNLIT_VAL_BIT); _mask.set(MaterialKey::UNLIT_VAL_BIT); return (*this); }
|
||||
Builder& withUnlit() { _value.set(MaterialKey::UNLIT_VAL_BIT); _mask.set(MaterialKey::UNLIT_VAL_BIT); return (*this); }
|
||||
|
||||
Builder& withoutAlbedo() { _value.reset(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); }
|
||||
Builder& withAlbedo() { _value.set(MaterialKey::ALBEDO_VAL_BIT); _mask.set(MaterialKey::ALBEDO_VAL_BIT); return (*this); }
|
||||
|
||||
|
@ -250,6 +260,9 @@ public:
|
|||
void setOpacity(float opacity);
|
||||
float getOpacity() const { return _schemaBuffer.get<Schema>()._opacity; }
|
||||
|
||||
void setUnlit(bool value);
|
||||
bool isUnlit() const { return _key.isUnlit(); }
|
||||
|
||||
void setAlbedo(const Color& albedo, bool isSRGB = true);
|
||||
Color getAlbedo(bool SRGB = true) const { return (SRGB ? ColorUtils::tosRGBVec3(_schemaBuffer.get<Schema>()._albedo) : _schemaBuffer.get<Schema>()._albedo); }
|
||||
|
||||
|
|
|
@ -40,20 +40,21 @@ float getMaterialShininess(Material m) { return 1.0 - getMaterialRoughness(m); }
|
|||
int getMaterialKey(Material m) { return floatBitsToInt(m._spareKey.w); }
|
||||
|
||||
const int EMISSIVE_VAL_BIT = 0x00000001;
|
||||
const int ALBEDO_VAL_BIT = 0x00000002;
|
||||
const int METALLIC_VAL_BIT = 0x00000004;
|
||||
const int GLOSSY_VAL_BIT = 0x00000008;
|
||||
const int OPACITY_VAL_BIT = 0x00000010;
|
||||
const int OPACITY_MASK_MAP_BIT = 0x00000020;
|
||||
const int OPACITY_TRANSLUCENT_MAP_BIT = 0x00000040;
|
||||
const int UNLIT_VAL_BIT = 0x00000002;
|
||||
const int ALBEDO_VAL_BIT = 0x00000004;
|
||||
const int METALLIC_VAL_BIT = 0x00000008;
|
||||
const int GLOSSY_VAL_BIT = 0x00000010;
|
||||
const int OPACITY_VAL_BIT = 0x00000020;
|
||||
const int OPACITY_MASK_MAP_BIT = 0x00000040;
|
||||
const int OPACITY_TRANSLUCENT_MAP_BIT = 0x00000080;
|
||||
|
||||
const int EMISSIVE_MAP_BIT = 0x00000080;
|
||||
const int ALBEDO_MAP_BIT = 0x00000100;
|
||||
const int METALLIC_MAP_BIT = 0x00000200;
|
||||
const int ROUGHNESS_MAP_BIT = 0x00000400;
|
||||
const int NORMAL_MAP_BIT = 0x00000800;
|
||||
const int OCCLUSION_MAP_BIT = 0x00001000;
|
||||
const int LIGHTMAP_MAP_BIT = 0x00002000;
|
||||
const int EMISSIVE_MAP_BIT = 0x00000100;
|
||||
const int ALBEDO_MAP_BIT = 0x00000200;
|
||||
const int METALLIC_MAP_BIT = 0x00000400;
|
||||
const int ROUGHNESS_MAP_BIT = 0x00000800;
|
||||
const int NORMAL_MAP_BIT = 0x00001000;
|
||||
const int OCCLUSION_MAP_BIT = 0x00002000;
|
||||
const int LIGHTMAP_MAP_BIT = 0x00004000;
|
||||
|
||||
|
||||
<@endif@>
|
||||
|
|
|
@ -629,3 +629,32 @@ void AddressManager::addCurrentAddressToHistory(LookupTrigger trigger) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AddressManager::ifLocalSandboxRunningElse(std::function<void()> localSandboxRunningDoThis,
|
||||
std::function<void()> localSandboxNotRunningDoThat) {
|
||||
|
||||
QNetworkAccessManager& networkAccessManager = NetworkAccessManager::getInstance();
|
||||
QNetworkRequest sandboxStatus(SANDBOX_STATUS_URL);
|
||||
sandboxStatus.setHeader(QNetworkRequest::UserAgentHeader, HIGH_FIDELITY_USER_AGENT);
|
||||
QNetworkReply* reply = networkAccessManager.get(sandboxStatus);
|
||||
|
||||
connect(reply, &QNetworkReply::finished, this, [reply, localSandboxRunningDoThis, localSandboxNotRunningDoThat]() {
|
||||
auto statusData = reply->readAll();
|
||||
auto statusJson = QJsonDocument::fromJson(statusData);
|
||||
if (!statusJson.isEmpty()) {
|
||||
auto statusObject = statusJson.object();
|
||||
auto serversValue = statusObject.value("servers");
|
||||
if (!serversValue.isUndefined() && serversValue.isObject()) {
|
||||
auto serversObject = serversValue.toObject();
|
||||
auto serversCount = serversObject.size();
|
||||
const int MINIMUM_EXPECTED_SERVER_COUNT = 5;
|
||||
if (serversCount >= MINIMUM_EXPECTED_SERVER_COUNT) {
|
||||
localSandboxRunningDoThis();
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
localSandboxNotRunningDoThat();
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
|
||||
const QString HIFI_URL_SCHEME = "hifi";
|
||||
const QString DEFAULT_HIFI_ADDRESS = "hifi://entry";
|
||||
const QString SANDBOX_HIFI_ADDRESS = "hifi://localhost";
|
||||
const QString SANDBOX_STATUS_URL = "http://localhost:60332/status";
|
||||
const QString INDEX_PATH = "/";
|
||||
|
||||
const QString GET_PLACE = "/api/v1/places/%1";
|
||||
|
@ -65,6 +67,11 @@ public:
|
|||
const QStack<QUrl>& getBackStack() const { return _backStack; }
|
||||
const QStack<QUrl>& getForwardStack() const { return _forwardStack; }
|
||||
|
||||
/// determines if the local sandbox is likely running. It does not account for custom setups, and is only
|
||||
/// intended to detect the standard local sandbox install.
|
||||
void ifLocalSandboxRunningElse(std::function<void()> localSandboxRunningDoThis,
|
||||
std::function<void()> localSandboxNotRunningDoThat);
|
||||
|
||||
public slots:
|
||||
void handleLookupString(const QString& lookupString);
|
||||
|
||||
|
@ -74,6 +81,8 @@ public slots:
|
|||
|
||||
void goBack();
|
||||
void goForward();
|
||||
void goToLocalSandbox(LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(SANDBOX_HIFI_ADDRESS, trigger); }
|
||||
void goToEntry(LookupTrigger trigger = LookupTrigger::StartupFromSettings) { handleUrl(DEFAULT_HIFI_ADDRESS, trigger); }
|
||||
|
||||
void goToUser(const QString& username);
|
||||
|
||||
|
|
|
@ -64,7 +64,7 @@ public:
|
|||
virtual MainWindow* getPrimaryWindow() = 0;
|
||||
virtual QOpenGLContext* getPrimaryContext() = 0;
|
||||
virtual bool isForeground() = 0;
|
||||
virtual const DisplayPlugin* getActiveDisplayPlugin() const = 0;
|
||||
virtual const DisplayPluginPointer getActiveDisplayPlugin() const = 0;
|
||||
|
||||
/// settings interface
|
||||
bool getBoolSetting(const QString& settingName, bool defaultValue);
|
||||
|
|
|
@ -46,7 +46,7 @@ public:
|
|||
virtual render::ScenePointer getMain3DScene() = 0;
|
||||
virtual render::EnginePointer getRenderEngine() = 0;
|
||||
|
||||
virtual void pushPreRenderLambda(void* key, std::function<void()> func) = 0;
|
||||
virtual void pushPostUpdateLambda(void* key, std::function<void()> func) = 0;
|
||||
|
||||
// FIXME - we shouldn't assume that there's a single instance of an AbstractViewStateInterface
|
||||
static AbstractViewStateInterface* instance();
|
||||
|
|
|
@ -307,6 +307,16 @@ static void addLink(const AnimPose& rootPose, const AnimPose& pose, const AnimPo
|
|||
}
|
||||
}
|
||||
|
||||
static void addLine(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color, Vertex*& v) {
|
||||
uint32_t colorInt = toRGBA(color);
|
||||
v->pos = start;
|
||||
v->rgba = colorInt;
|
||||
v++;
|
||||
v->pos = end;
|
||||
v->rgba = colorInt;
|
||||
v++;
|
||||
}
|
||||
|
||||
void AnimDebugDraw::update() {
|
||||
|
||||
render::ScenePointer scene = AbstractViewStateInterface::instance()->getMain3DScene();
|
||||
|
@ -319,6 +329,7 @@ void AnimDebugDraw::update() {
|
|||
|
||||
const size_t VERTICES_PER_BONE = (6 + (NUM_CIRCLE_SLICES * 2) * 3);
|
||||
const size_t VERTICES_PER_LINK = 8 * 2;
|
||||
const size_t VERTICES_PER_RAY = 2;
|
||||
|
||||
const float BONE_RADIUS = 0.01f; // 1 cm
|
||||
const float POSE_RADIUS = 0.1f; // 10 cm
|
||||
|
@ -342,6 +353,7 @@ void AnimDebugDraw::update() {
|
|||
numVerts += (int)markerMap.size() * VERTICES_PER_BONE;
|
||||
auto myAvatarMarkerMap = DebugDraw::getInstance().getMyAvatarMarkerMap();
|
||||
numVerts += (int)myAvatarMarkerMap.size() * VERTICES_PER_BONE;
|
||||
numVerts += (int)DebugDraw::getInstance().getRays().size() * VERTICES_PER_RAY;
|
||||
|
||||
// allocate verts!
|
||||
data._vertexBuffer->resize(sizeof(Vertex) * numVerts);
|
||||
|
@ -390,6 +402,12 @@ void AnimDebugDraw::update() {
|
|||
addBone(myAvatarPose, AnimPose(glm::vec3(1), rot, pos), radius, v);
|
||||
}
|
||||
|
||||
// draw rays from shared DebugDraw singleton
|
||||
for (auto& iter : DebugDraw::getInstance().getRays()) {
|
||||
addLine(std::get<0>(iter), std::get<1>(iter), std::get<2>(iter), v);
|
||||
}
|
||||
DebugDraw::getInstance().clearRays();
|
||||
|
||||
assert(numVerts == (v - verts));
|
||||
|
||||
render::Item::Bound theBound;
|
||||
|
|
|
@ -90,14 +90,21 @@ static const std::string DEFAULT_OCCLUSION_SHADER{
|
|||
static const std::string DEFAULT_EMISSIVE_SHADER{
|
||||
"vec4 getFragmentColor() {"
|
||||
" DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);"
|
||||
" return (frag.mode != LIGHT_MAPPED ? vec4(pow(frag.emissive, vec3(1.0 / 2.2)), 1.0) : vec4(vec3(0.0), 1.0));"
|
||||
" return (frag.mode == FRAG_MODE_SHADED ? vec4(pow(frag.emissive, vec3(1.0 / 2.2)), 1.0) : vec4(vec3(0.0), 1.0));"
|
||||
" }"
|
||||
};
|
||||
|
||||
static const std::string DEFAULT_UNLIT_SHADER{
|
||||
"vec4 getFragmentColor() {"
|
||||
" DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);"
|
||||
" return (frag.mode == FRAG_MODE_UNLIT ? vec4(pow(frag.diffuse, vec3(1.0 / 2.2)), 1.0) : vec4(vec3(0.0), 1.0));"
|
||||
" }"
|
||||
};
|
||||
|
||||
static const std::string DEFAULT_LIGHTMAP_SHADER{
|
||||
"vec4 getFragmentColor() {"
|
||||
" DeferredFragment frag = unpackDeferredFragmentNoPosition(uv);"
|
||||
" return (frag.mode == LIGHT_MAPPED ? vec4(frag.emissive, 1.0) : vec4(vec3(0.0), 1.0));"
|
||||
" return (frag.mode == FRAG_MODE_LIGHTMAPPED ? vec4(pow(frag.emissive, vec3(1.0 / 2.2)), 1.0) : vec4(vec3(0.0), 1.0));"
|
||||
" }"
|
||||
};
|
||||
|
||||
|
@ -184,6 +191,8 @@ std::string DebugDeferredBuffer::getShaderSourceCode(Mode mode, std::string cust
|
|||
return DEFAULT_DEPTH_SHADER;
|
||||
case EmissiveMode:
|
||||
return DEFAULT_EMISSIVE_SHADER;
|
||||
case UnlitMode:
|
||||
return DEFAULT_UNLIT_SHADER;
|
||||
case OcclusionMode:
|
||||
return DEFAULT_OCCLUSION_SHADER;
|
||||
case LightmapMode:
|
||||
|
|
|
@ -53,6 +53,7 @@ protected:
|
|||
RoughnessMode,
|
||||
MetallicMode,
|
||||
EmissiveMode,
|
||||
UnlitMode,
|
||||
OcclusionMode,
|
||||
LightmapMode,
|
||||
LightingMode,
|
||||
|
|
|
@ -11,135 +11,44 @@
|
|||
<@if not DEFERRED_BUFFER_SLH@>
|
||||
<@def DEFERRED_BUFFER_SLH@>
|
||||
|
||||
// Unpack the metallic-mode value
|
||||
const float FRAG_PACK_SHADED_NON_METALLIC = 0.0;
|
||||
const float FRAG_PACK_SHADED_METALLIC = 0.1;
|
||||
const float FRAG_PACK_SHADED_RANGE_INV = 1.0 / (FRAG_PACK_SHADED_METALLIC - FRAG_PACK_SHADED_NON_METALLIC);
|
||||
|
||||
// the albedo texture
|
||||
uniform sampler2D albedoMap;
|
||||
const float FRAG_PACK_LIGHTMAPPED_NON_METALLIC = 0.2;
|
||||
const float FRAG_PACK_LIGHTMAPPED_METALLIC = 0.3;
|
||||
const float FRAG_PACK_LIGHTMAPPED_RANGE_INV = 1.0 / (FRAG_PACK_LIGHTMAPPED_METALLIC - FRAG_PACK_LIGHTMAPPED_NON_METALLIC);
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
const float FRAG_PACK_UNLIT = 0.5;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
const int FRAG_MODE_UNLIT = 0;
|
||||
const int FRAG_MODE_SHADED = 1;
|
||||
const int FRAG_MODE_LIGHTMAPPED = 2;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the obscurance texture
|
||||
uniform sampler2D obscuranceMap;
|
||||
|
||||
// the lighting texture
|
||||
uniform sampler2D lightingMap;
|
||||
|
||||
|
||||
struct DeferredTransform {
|
||||
mat4 projection;
|
||||
mat4 viewInverse;
|
||||
float stereoSide;
|
||||
vec3 _spareABC;
|
||||
};
|
||||
|
||||
layout(std140) uniform deferredTransformBuffer {
|
||||
DeferredTransform _deferredTransform;
|
||||
};
|
||||
DeferredTransform getDeferredTransform() {
|
||||
return _deferredTransform;
|
||||
}
|
||||
|
||||
bool getStereoMode(DeferredTransform deferredTransform) {
|
||||
return (deferredTransform.stereoSide != 0.0);
|
||||
}
|
||||
float getStereoSide(DeferredTransform deferredTransform) {
|
||||
return (deferredTransform.stereoSide);
|
||||
}
|
||||
|
||||
vec4 evalEyePositionFromZ(DeferredTransform deferredTransform, float depthVal, vec2 texcoord) {
|
||||
vec3 nPos = vec3(texcoord.xy * 2.0f - 1.0f, depthVal * 2.0f - 1.0f);
|
||||
|
||||
// compute the view space position using the depth
|
||||
// basically manually pick the proj matrix components to do the inverse
|
||||
float Ze = -deferredTransform.projection[3][2] / (nPos.z + deferredTransform.projection[2][2]);
|
||||
float Xe = (-Ze * nPos.x - Ze * deferredTransform.projection[2][0] - deferredTransform.projection[3][0]) / deferredTransform.projection[0][0];
|
||||
float Ye = (-Ze * nPos.y - Ze * deferredTransform.projection[2][1] - deferredTransform.projection[3][1]) / deferredTransform.projection[1][1];
|
||||
return vec4(Xe, Ye, Ze, 1.0f);
|
||||
}
|
||||
|
||||
struct DeferredFragment {
|
||||
vec4 normalVal;
|
||||
vec4 diffuseVal;
|
||||
vec4 specularVal;
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
float metallic;
|
||||
vec3 diffuse;
|
||||
float obscurance;
|
||||
vec3 specular;
|
||||
float roughness;
|
||||
vec3 emissive;
|
||||
int mode;
|
||||
float depthVal;
|
||||
};
|
||||
|
||||
const int LIGHT_MAPPED = 1;
|
||||
|
||||
vec4 unpackDeferredPosition(DeferredTransform deferredTransform, float depthValue, vec2 texcoord) {
|
||||
if (getStereoMode(deferredTransform)) {
|
||||
if (texcoord.x > 0.5) {
|
||||
texcoord.x -= 0.5;
|
||||
}
|
||||
texcoord.x *= 2.0;
|
||||
void unpackModeMetallic(float rawValue, out int mode, out float metallic) {
|
||||
if (rawValue <= FRAG_PACK_SHADED_METALLIC) {
|
||||
mode = FRAG_MODE_SHADED;
|
||||
metallic = clamp((rawValue - FRAG_PACK_SHADED_NON_METALLIC) * FRAG_PACK_SHADED_RANGE_INV, 0.0, 1.0);
|
||||
} else if (rawValue <= FRAG_PACK_LIGHTMAPPED_METALLIC) {
|
||||
mode = FRAG_MODE_LIGHTMAPPED;
|
||||
metallic = clamp((rawValue - FRAG_PACK_LIGHTMAPPED_NON_METALLIC) * FRAG_PACK_SHADED_RANGE_INV, 0.0, 1.0);
|
||||
} else if (rawValue >= FRAG_PACK_UNLIT) {
|
||||
mode = FRAG_MODE_UNLIT;
|
||||
metallic = 0.0;
|
||||
}
|
||||
return evalEyePositionFromZ(deferredTransform, depthValue, texcoord);
|
||||
}
|
||||
|
||||
DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) {
|
||||
|
||||
DeferredFragment frag;
|
||||
frag.depthVal = -1;
|
||||
frag.normalVal = texture(normalMap, texcoord);
|
||||
frag.diffuseVal = texture(albedoMap, texcoord);
|
||||
frag.specularVal = texture(specularMap, texcoord);
|
||||
frag.obscurance = texture(obscuranceMap, texcoord).x;
|
||||
|
||||
// Unpack the normal from the map
|
||||
frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0));
|
||||
|
||||
frag.mode = 0;
|
||||
frag.emissive = frag.specularVal.xyz;
|
||||
if (frag.normalVal.a < 0.5) {
|
||||
frag.mode = 0;
|
||||
frag.roughness = 2.0 * frag.normalVal.a;
|
||||
} else {
|
||||
frag.mode = LIGHT_MAPPED;
|
||||
frag.roughness = 2.0 * frag.normalVal.a - 1.0;
|
||||
}
|
||||
|
||||
frag.metallic = frag.diffuseVal.a;
|
||||
frag.diffuse = frag.diffuseVal.xyz;
|
||||
if (frag.metallic <= 0.5) {
|
||||
frag.metallic = 0.0;
|
||||
frag.specular = vec3(0.03); // Default Di-electric fresnel value
|
||||
} else {
|
||||
frag.specular = vec3(frag.diffuseVal.xyz);
|
||||
frag.metallic = 1.0;
|
||||
}
|
||||
frag.obscurance = min(frag.specularVal.w, frag.obscurance);
|
||||
|
||||
return frag;
|
||||
float packShadedMetallic(float metallic) {
|
||||
return mix(FRAG_PACK_SHADED_NON_METALLIC, FRAG_PACK_SHADED_METALLIC, metallic);
|
||||
}
|
||||
|
||||
DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec2 texcoord) {
|
||||
|
||||
float depthValue = texture(depthMap, texcoord).r;
|
||||
|
||||
DeferredFragment frag = unpackDeferredFragmentNoPosition(texcoord);
|
||||
|
||||
frag.depthVal = depthValue;
|
||||
frag.position = unpackDeferredPosition(deferredTransform, frag.depthVal, texcoord);
|
||||
|
||||
return frag;
|
||||
float packLightmappedMetallic(float metallic) {
|
||||
return mix(FRAG_PACK_LIGHTMAPPED_NON_METALLIC, FRAG_PACK_LIGHTMAPPED_METALLIC, metallic);
|
||||
}
|
||||
|
||||
|
||||
|
||||
float packUnlit() {
|
||||
return FRAG_PACK_UNLIT;
|
||||
}
|
||||
|
||||
<@endif@>
|
||||
|
|
140
libraries/render-utils/src/DeferredBufferRead.slh
Normal file
140
libraries/render-utils/src/DeferredBufferRead.slh
Normal file
|
@ -0,0 +1,140 @@
|
|||
<!
|
||||
// DeferredBufferRead.slh
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Sam Gateau on 5/4/16.
|
||||
// Copyright 2013 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
|
||||
!>
|
||||
<@if not DEFERRED_BUFFER_READ_SLH@>
|
||||
<@def DEFERRED_BUFFER_READ_SLH@>
|
||||
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
// the albedo texture
|
||||
uniform sampler2D albedoMap;
|
||||
|
||||
// the normal texture
|
||||
uniform sampler2D normalMap;
|
||||
|
||||
// the specular texture
|
||||
uniform sampler2D specularMap;
|
||||
|
||||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the obscurance texture
|
||||
uniform sampler2D obscuranceMap;
|
||||
|
||||
// the lighting texture
|
||||
uniform sampler2D lightingMap;
|
||||
|
||||
|
||||
struct DeferredTransform {
|
||||
mat4 projection;
|
||||
mat4 viewInverse;
|
||||
float stereoSide;
|
||||
vec3 _spareABC;
|
||||
};
|
||||
|
||||
layout(std140) uniform deferredTransformBuffer {
|
||||
DeferredTransform _deferredTransform;
|
||||
};
|
||||
DeferredTransform getDeferredTransform() {
|
||||
return _deferredTransform;
|
||||
}
|
||||
|
||||
bool getStereoMode(DeferredTransform deferredTransform) {
|
||||
return (deferredTransform.stereoSide != 0.0);
|
||||
}
|
||||
float getStereoSide(DeferredTransform deferredTransform) {
|
||||
return (deferredTransform.stereoSide);
|
||||
}
|
||||
|
||||
vec4 evalEyePositionFromZ(DeferredTransform deferredTransform, float depthVal, vec2 texcoord) {
|
||||
vec3 nPos = vec3(texcoord.xy * 2.0f - 1.0f, depthVal * 2.0f - 1.0f);
|
||||
|
||||
// compute the view space position using the depth
|
||||
// basically manually pick the proj matrix components to do the inverse
|
||||
float Ze = -deferredTransform.projection[3][2] / (nPos.z + deferredTransform.projection[2][2]);
|
||||
float Xe = (-Ze * nPos.x - Ze * deferredTransform.projection[2][0] - deferredTransform.projection[3][0]) / deferredTransform.projection[0][0];
|
||||
float Ye = (-Ze * nPos.y - Ze * deferredTransform.projection[2][1] - deferredTransform.projection[3][1]) / deferredTransform.projection[1][1];
|
||||
return vec4(Xe, Ye, Ze, 1.0f);
|
||||
}
|
||||
|
||||
struct DeferredFragment {
|
||||
vec4 normalVal;
|
||||
vec4 diffuseVal;
|
||||
vec4 specularVal;
|
||||
vec4 position;
|
||||
vec3 normal;
|
||||
float metallic;
|
||||
vec3 diffuse;
|
||||
float obscurance;
|
||||
vec3 specular;
|
||||
float roughness;
|
||||
vec3 emissive;
|
||||
int mode;
|
||||
float depthVal;
|
||||
};
|
||||
|
||||
vec4 unpackDeferredPosition(DeferredTransform deferredTransform, float depthValue, vec2 texcoord) {
|
||||
if (getStereoMode(deferredTransform)) {
|
||||
if (texcoord.x > 0.5) {
|
||||
texcoord.x -= 0.5;
|
||||
}
|
||||
texcoord.x *= 2.0;
|
||||
}
|
||||
return evalEyePositionFromZ(deferredTransform, depthValue, texcoord);
|
||||
}
|
||||
|
||||
DeferredFragment unpackDeferredFragmentNoPosition(vec2 texcoord) {
|
||||
|
||||
DeferredFragment frag;
|
||||
frag.depthVal = -1;
|
||||
frag.normalVal = texture(normalMap, texcoord);
|
||||
frag.diffuseVal = texture(albedoMap, texcoord);
|
||||
frag.specularVal = texture(specularMap, texcoord);
|
||||
frag.obscurance = texture(obscuranceMap, texcoord).x;
|
||||
|
||||
// Unpack the normal from the map
|
||||
frag.normal = normalize(frag.normalVal.xyz * 2.0 - vec3(1.0));
|
||||
frag.roughness = 2.0 * frag.normalVal.a;
|
||||
|
||||
// Diffuse color and unpack the mode and the metallicness
|
||||
frag.diffuse = frag.diffuseVal.xyz;
|
||||
unpackModeMetallic(frag.diffuseVal.w, frag.mode, frag.metallic);
|
||||
|
||||
|
||||
if (frag.metallic <= 0.5) {
|
||||
frag.metallic = 0.0;
|
||||
frag.specular = vec3(0.03); // Default Di-electric fresnel value
|
||||
} else {
|
||||
frag.specular = vec3(frag.diffuseVal.xyz);
|
||||
frag.metallic = 1.0;
|
||||
}
|
||||
|
||||
frag.emissive = frag.specularVal.xyz;
|
||||
frag.obscurance = min(frag.specularVal.w, frag.obscurance);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
DeferredFragment unpackDeferredFragment(DeferredTransform deferredTransform, vec2 texcoord) {
|
||||
|
||||
float depthValue = texture(depthMap, texcoord).r;
|
||||
|
||||
DeferredFragment frag = unpackDeferredFragmentNoPosition(texcoord);
|
||||
|
||||
frag.depthVal = depthValue;
|
||||
frag.position = unpackDeferredPosition(deferredTransform, frag.depthVal, texcoord);
|
||||
|
||||
return frag;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
<@endif@>
|
|
@ -11,6 +11,8 @@
|
|||
<@if not DEFERRED_BUFFER_WRITE_SLH@>
|
||||
<@def DEFERRED_BUFFER_WRITE_SLH@>
|
||||
|
||||
<@include DeferredBuffer.slh@>
|
||||
|
||||
layout(location = 0) out vec4 _fragColor0;
|
||||
layout(location = 1) out vec4 _fragColor1;
|
||||
layout(location = 2) out vec4 _fragColor2;
|
||||
|
@ -48,13 +50,12 @@ const vec3 DEFAULT_EMISSIVE = vec3(0.0);
|
|||
const float DEFAULT_OCCLUSION = 1.0;
|
||||
const vec3 DEFAULT_FRESNEL = DEFAULT_EMISSIVE;
|
||||
|
||||
|
||||
void packDeferredFragment(vec3 normal, float alpha, vec3 albedo, float roughness, float metallic, vec3 emissive, float occlusion) {
|
||||
if (alpha != 1.0) {
|
||||
discard;
|
||||
}
|
||||
_fragColor0 = vec4(albedo, metallic);
|
||||
_fragColor1 = vec4(bestFitNormal(normal), 0.5 * clamp(roughness, 0.0, 1.0));
|
||||
_fragColor0 = vec4(albedo, packShadedMetallic(metallic));
|
||||
_fragColor1 = vec4(bestFitNormal(normal), clamp(roughness, 0.0, 1.0));
|
||||
_fragColor2 = vec4(emissive, occlusion);
|
||||
}
|
||||
|
||||
|
@ -63,19 +64,25 @@ void packDeferredFragmentLightmap(vec3 normal, float alpha, vec3 albedo, float r
|
|||
if (alpha != 1.0) {
|
||||
discard;
|
||||
}
|
||||
_fragColor0 = vec4(albedo, metallic);
|
||||
_fragColor1 = vec4(bestFitNormal(normal), 0.5 + 0.5 * clamp(roughness, 0.0, 1.0));
|
||||
_fragColor0 = vec4(albedo, packLightmappedMetallic(metallic));
|
||||
_fragColor1 = vec4(bestFitNormal(normal), clamp(roughness, 0.0, 1.0));
|
||||
_fragColor2 = vec4(emissive, 1.0);
|
||||
}
|
||||
|
||||
void packDeferredFragmentUnlit(vec3 normal, float alpha, vec3 color) {
|
||||
if (alpha != 1.0) {
|
||||
discard;
|
||||
}
|
||||
_fragColor0 = vec4(color, packUnlit());
|
||||
_fragColor1 = vec4(bestFitNormal(normal), 1.0);
|
||||
//_fragColor2 = vec4(vec3(0.0), 1.0); // If unlit, do not worry about the emissive color target
|
||||
}
|
||||
|
||||
void packDeferredFragmentTranslucent(vec3 normal, float alpha, vec3 albedo, vec3 fresnel, float roughness) {
|
||||
if (alpha <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
}
|
||||
_fragColor0 = vec4(albedo.rgb, alpha);
|
||||
// _fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
// _fragColor2 = vec4(fresnel, roughness);
|
||||
}
|
||||
|
||||
<@endif@>
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
|
||||
#include "simple_vert.h"
|
||||
#include "simple_textured_frag.h"
|
||||
#include "simple_textured_emisive_frag.h"
|
||||
#include "simple_textured_unlit_frag.h"
|
||||
|
||||
#include "grid_frag.h"
|
||||
|
||||
|
@ -1687,7 +1687,7 @@ public:
|
|||
enum FlagBit {
|
||||
IS_TEXTURED_FLAG = 0,
|
||||
IS_CULLED_FLAG,
|
||||
IS_EMISSIVE_FLAG,
|
||||
IS_UNLIT_FLAG,
|
||||
HAS_DEPTH_BIAS_FLAG,
|
||||
|
||||
NUM_FLAGS,
|
||||
|
@ -1696,7 +1696,7 @@ public:
|
|||
enum Flag {
|
||||
IS_TEXTURED = (1 << IS_TEXTURED_FLAG),
|
||||
IS_CULLED = (1 << IS_CULLED_FLAG),
|
||||
IS_EMISSIVE = (1 << IS_EMISSIVE_FLAG),
|
||||
IS_UNLIT = (1 << IS_UNLIT_FLAG),
|
||||
HAS_DEPTH_BIAS = (1 << HAS_DEPTH_BIAS_FLAG),
|
||||
};
|
||||
typedef unsigned short Flags;
|
||||
|
@ -1705,7 +1705,7 @@ public:
|
|||
|
||||
bool isTextured() const { return isFlag(IS_TEXTURED); }
|
||||
bool isCulled() const { return isFlag(IS_CULLED); }
|
||||
bool isEmissive() const { return isFlag(IS_EMISSIVE); }
|
||||
bool isUnlit() const { return isFlag(IS_UNLIT); }
|
||||
bool hasDepthBias() const { return isFlag(HAS_DEPTH_BIAS); }
|
||||
|
||||
Flags _flags = 0;
|
||||
|
@ -1715,9 +1715,9 @@ public:
|
|||
|
||||
|
||||
SimpleProgramKey(bool textured = false, bool culled = true,
|
||||
bool emissive = false, bool depthBias = false) {
|
||||
bool unlit = false, bool depthBias = false) {
|
||||
_flags = (textured ? IS_TEXTURED : 0) | (culled ? IS_CULLED : 0) |
|
||||
(emissive ? IS_EMISSIVE : 0) | (depthBias ? HAS_DEPTH_BIAS : 0);
|
||||
(unlit ? IS_UNLIT : 0) | (depthBias ? HAS_DEPTH_BIAS : 0);
|
||||
}
|
||||
|
||||
SimpleProgramKey(int bitmask) : _flags(bitmask) {}
|
||||
|
@ -1731,8 +1731,8 @@ inline bool operator==(const SimpleProgramKey& a, const SimpleProgramKey& b) {
|
|||
return a.getRaw() == b.getRaw();
|
||||
}
|
||||
|
||||
void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool emissive, bool depthBiased) {
|
||||
batch.setPipeline(getSimplePipeline(textured, culled, emissive, depthBiased));
|
||||
void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool culled, bool unlit, bool depthBiased) {
|
||||
batch.setPipeline(getSimplePipeline(textured, culled, unlit, depthBiased));
|
||||
|
||||
// If not textured, set a default albedo map
|
||||
if (!textured) {
|
||||
|
@ -1744,23 +1744,23 @@ void GeometryCache::bindSimpleProgram(gpu::Batch& batch, bool textured, bool cul
|
|||
DependencyManager::get<TextureCache>()->getNormalFittingTexture());
|
||||
}
|
||||
|
||||
gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool culled, bool emissive, bool depthBiased) {
|
||||
SimpleProgramKey config{textured, culled, emissive, depthBiased};
|
||||
gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool culled, bool unlit, bool depthBiased) {
|
||||
SimpleProgramKey config{ textured, culled, unlit, depthBiased };
|
||||
|
||||
// Compile the shaders
|
||||
static std::once_flag once;
|
||||
std::call_once(once, [&]() {
|
||||
auto VS = gpu::Shader::createVertex(std::string(simple_vert));
|
||||
auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag));
|
||||
auto PSEmissive = gpu::Shader::createPixel(std::string(simple_textured_emisive_frag));
|
||||
auto PSUnlit = gpu::Shader::createPixel(std::string(simple_textured_unlit_frag));
|
||||
|
||||
_simpleShader = gpu::Shader::createProgram(VS, PS);
|
||||
_emissiveShader = gpu::Shader::createProgram(VS, PSEmissive);
|
||||
_unlitShader = gpu::Shader::createProgram(VS, PSUnlit);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("normalFittingMap"), render::ShapePipeline::Slot::MAP::NORMAL_FITTING));
|
||||
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
|
||||
gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
|
||||
gpu::Shader::makeProgram(*_unlitShader, slotBindings);
|
||||
});
|
||||
|
||||
// If the pipeline already exists, return it
|
||||
|
@ -1785,7 +1785,7 @@ gpu::PipelinePointer GeometryCache::getSimplePipeline(bool textured, bool culled
|
|||
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
|
||||
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
|
||||
|
||||
gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
|
||||
gpu::ShaderPointer program = (config.isUnlit()) ? _unlitShader : _simpleShader;
|
||||
gpu::PipelinePointer pipeline = gpu::Pipeline::create(program, state);
|
||||
_simplePrograms.insert(config, pipeline);
|
||||
return pipeline;
|
||||
|
|
|
@ -153,10 +153,10 @@ public:
|
|||
|
||||
// Bind the pipeline and get the state to render static geometry
|
||||
void bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
|
||||
bool emissive = false, bool depthBias = false);
|
||||
bool unlit = false, bool depthBias = false);
|
||||
// Get the pipeline to render static geometry
|
||||
gpu::PipelinePointer getSimplePipeline(bool textured = false, bool culled = true,
|
||||
bool emissive = false, bool depthBias = false);
|
||||
bool unlit = false, bool depthBias = false);
|
||||
render::ShapePipelinePointer getShapePipeline() { return GeometryCache::_simplePipeline; }
|
||||
|
||||
// Static (instanced) geometry
|
||||
|
@ -393,7 +393,7 @@ private:
|
|||
QHash<QUrl, QWeakPointer<NetworkGeometry> > _networkGeometry;
|
||||
|
||||
gpu::ShaderPointer _simpleShader;
|
||||
gpu::ShaderPointer _emissiveShader;
|
||||
gpu::ShaderPointer _unlitShader;
|
||||
static render::ShapePipelinePointer _simplePipeline;
|
||||
QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
|
||||
};
|
||||
|
|
|
@ -157,7 +157,7 @@ vec3 fetchLightmapMap(vec2 uv) {
|
|||
}
|
||||
<@endfunc@>
|
||||
|
||||
<@func $discardTransparent(opacity)@>
|
||||
<@func discardTransparent(opacity)@>
|
||||
{
|
||||
if (<$opacity$> < 1.0) {
|
||||
discard;
|
||||
|
|
|
@ -144,6 +144,11 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
|
|||
auto materialKey = _drawMaterial->getKey();
|
||||
auto textureMaps = _drawMaterial->getTextureMaps();
|
||||
|
||||
int numUnlit = 0;
|
||||
if (materialKey.isUnlit()) {
|
||||
numUnlit++;
|
||||
}
|
||||
|
||||
// Albedo
|
||||
if (materialKey.isAlbedoMap()) {
|
||||
auto albedoMap = textureMaps[model::MaterialKey::ALBEDO_MAP];
|
||||
|
@ -414,6 +419,7 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
|||
bool hasTangents = drawMaterialKey.isNormalMap() && !mesh.tangents.isEmpty();
|
||||
bool hasSpecular = drawMaterialKey.isMetallicMap();
|
||||
bool hasLightmap = drawMaterialKey.isLightmapMap();
|
||||
bool isUnlit = drawMaterialKey.isUnlit();
|
||||
|
||||
bool isSkinned = _isSkinned;
|
||||
bool wireframe = _model->isWireframe();
|
||||
|
@ -435,6 +441,9 @@ ShapeKey ModelMeshPartPayload::getShapeKey() const {
|
|||
if (hasLightmap) {
|
||||
builder.withLightmap();
|
||||
}
|
||||
if (isUnlit) {
|
||||
builder.withUnlit();
|
||||
}
|
||||
if (isSkinned) {
|
||||
builder.withSkinned();
|
||||
}
|
||||
|
|
|
@ -132,7 +132,7 @@ void Model::updateRenderItems() {
|
|||
// the application will ensure only the last lambda is actually invoked.
|
||||
void* key = (void*)this;
|
||||
std::weak_ptr<Model> weakSelf = shared_from_this();
|
||||
AbstractViewStateInterface::instance()->pushPreRenderLambda(key, [weakSelf]() {
|
||||
AbstractViewStateInterface::instance()->pushPostUpdateLambda(key, [weakSelf]() {
|
||||
|
||||
// do nothing, if the model has already been destroyed.
|
||||
auto self = weakSelf.lock();
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
#include "skin_model_normal_map_vert.h"
|
||||
|
||||
#include "model_frag.h"
|
||||
#include "model_emissive_frag.h"
|
||||
#include "model_unlit_frag.h"
|
||||
#include "model_shadow_frag.h"
|
||||
#include "model_normal_map_frag.h"
|
||||
#include "model_normal_specular_map_frag.h"
|
||||
|
@ -37,13 +37,13 @@
|
|||
#include "model_lightmap_normal_specular_map_frag.h"
|
||||
#include "model_lightmap_specular_map_frag.h"
|
||||
#include "model_translucent_frag.h"
|
||||
#include "model_translucent_emissive_frag.h"
|
||||
#include "model_translucent_unlit_frag.h"
|
||||
|
||||
#include "overlay3D_vert.h"
|
||||
#include "overlay3D_frag.h"
|
||||
#include "overlay3D_translucent_frag.h"
|
||||
#include "overlay3D_emissive_frag.h"
|
||||
#include "overlay3D_translucent_emissive_frag.h"
|
||||
#include "overlay3D_unlit_frag.h"
|
||||
#include "overlay3D_translucent_unlit_frag.h"
|
||||
|
||||
#include "drawOpaqueStencil_frag.h"
|
||||
|
||||
|
@ -102,13 +102,13 @@ void initOverlay3DPipelines(ShapePlumber& plumber) {
|
|||
auto vertex = gpu::Shader::createVertex(std::string(overlay3D_vert));
|
||||
auto pixel = gpu::Shader::createPixel(std::string(overlay3D_frag));
|
||||
auto pixelTranslucent = gpu::Shader::createPixel(std::string(overlay3D_translucent_frag));
|
||||
auto pixelEmissive = gpu::Shader::createPixel(std::string(overlay3D_emissive_frag));
|
||||
auto pixelTranslucentEmissive = gpu::Shader::createPixel(std::string(overlay3D_translucent_emissive_frag));
|
||||
auto pixelUnlit = gpu::Shader::createPixel(std::string(overlay3D_unlit_frag));
|
||||
auto pixelTranslucentUnlit = gpu::Shader::createPixel(std::string(overlay3D_translucent_unlit_frag));
|
||||
|
||||
auto opaqueProgram = gpu::Shader::createProgram(vertex, pixel);
|
||||
auto translucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucent);
|
||||
auto emissiveOpaqueProgram = gpu::Shader::createProgram(vertex, pixelEmissive);
|
||||
auto emissiveTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentEmissive);
|
||||
auto unlitOpaqueProgram = gpu::Shader::createProgram(vertex, pixelUnlit);
|
||||
auto unlitTranslucentProgram = gpu::Shader::createProgram(vertex, pixelTranslucentUnlit);
|
||||
|
||||
for (int i = 0; i < 8; i++) {
|
||||
bool isCulled = (i & 1);
|
||||
|
@ -138,9 +138,9 @@ void initOverlay3DPipelines(ShapePlumber& plumber) {
|
|||
isOpaque ? builder.withOpaque() : builder.withTranslucent();
|
||||
|
||||
auto simpleProgram = isOpaque ? opaqueProgram : translucentProgram;
|
||||
auto emissiveProgram = isOpaque ? emissiveOpaqueProgram : emissiveTranslucentProgram;
|
||||
plumber.addPipeline(builder.withoutEmissive().build(), simpleProgram, state, &lightBatchSetter);
|
||||
plumber.addPipeline(builder.withEmissive().build(), emissiveProgram, state, &batchSetter);
|
||||
auto unlitProgram = isOpaque ? unlitOpaqueProgram : unlitTranslucentProgram;
|
||||
plumber.addPipeline(builder.withoutUnlit().build(), simpleProgram, state, &lightBatchSetter);
|
||||
plumber.addPipeline(builder.withUnlit().build(), unlitProgram, state, &batchSetter);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,12 +201,12 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
|
|||
|
||||
// Pixel shaders
|
||||
auto modelPixel = gpu::Shader::createPixel(std::string(model_frag));
|
||||
auto modelEmissivePixel = gpu::Shader::createPixel(std::string(model_emissive_frag));
|
||||
auto modelUnlitPixel = gpu::Shader::createPixel(std::string(model_unlit_frag));
|
||||
auto modelNormalMapPixel = gpu::Shader::createPixel(std::string(model_normal_map_frag));
|
||||
auto modelSpecularMapPixel = gpu::Shader::createPixel(std::string(model_specular_map_frag));
|
||||
auto modelNormalSpecularMapPixel = gpu::Shader::createPixel(std::string(model_normal_specular_map_frag));
|
||||
auto modelTranslucentPixel = gpu::Shader::createPixel(std::string(model_translucent_frag));
|
||||
auto modelTranslucentEmissivePixel = gpu::Shader::createPixel(std::string(model_translucent_emissive_frag));
|
||||
auto modelTranslucentUnlitPixel = gpu::Shader::createPixel(std::string(model_translucent_unlit_frag));
|
||||
auto modelShadowPixel = gpu::Shader::createPixel(std::string(model_shadow_frag));
|
||||
auto modelLightmapPixel = gpu::Shader::createPixel(std::string(model_lightmap_frag));
|
||||
auto modelLightmapNormalMapPixel = gpu::Shader::createPixel(std::string(model_lightmap_normal_map_frag));
|
||||
|
@ -219,8 +219,8 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
|
|||
Key::Builder(),
|
||||
modelVertex, modelPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withEmissive(),
|
||||
modelVertex, modelEmissivePixel);
|
||||
Key::Builder().withUnlit(),
|
||||
modelVertex, modelUnlitPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTangents(),
|
||||
modelNormalMapVertex, modelNormalMapPixel);
|
||||
|
@ -235,8 +235,8 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
|
|||
Key::Builder().withTranslucent(),
|
||||
modelVertex, modelTranslucentPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTranslucent().withEmissive(),
|
||||
modelVertex, modelTranslucentEmissivePixel);
|
||||
Key::Builder().withTranslucent().withUnlit(),
|
||||
modelVertex, modelTranslucentUnlitPixel);
|
||||
addPipeline(
|
||||
Key::Builder().withTranslucent().withTangents(),
|
||||
modelNormalMapVertex, modelTranslucentPixel);
|
||||
|
@ -296,4 +296,5 @@ void initDeferredPipelines(render::ShapePlumber& plumber) {
|
|||
addPipeline(
|
||||
Key::Builder().withSkinned().withDepthOnly(),
|
||||
skinModelShadowVertex, modelShadowPixel);
|
||||
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
|
||||
uniform sampler2D pyramidMap;
|
||||
uniform sampler2D occlusionMap;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalLightmappedColor()$>
|
||||
|
@ -27,7 +27,9 @@ void main(void) {
|
|||
|
||||
float shadowAttenuation = 1.0;
|
||||
|
||||
if (frag.mode == LIGHT_MAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
_fragColor = vec4(frag.diffuse, 1.0);
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
vec3 color = evalLightmappedColor(
|
||||
deferredTransform.viewInverse,
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
|
||||
<@include Shadow.slh@>
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalLightmappedColor()$>
|
||||
|
@ -29,7 +29,9 @@ void main(void) {
|
|||
vec4 worldPos = deferredTransform.viewInverse * vec4(frag.position.xyz, 1.0);
|
||||
float shadowAttenuation = evalShadowAttenuation(worldPos);
|
||||
|
||||
if (frag.mode == LIGHT_MAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
_fragColor = vec4(frag.diffuse, 1.0);
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
vec3 color = evalLightmappedColor(
|
||||
deferredTransform.viewInverse,
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalLightmappedColor()$>
|
||||
|
@ -28,7 +28,9 @@ void main(void) {
|
|||
float shadowAttenuation = 1.0;
|
||||
|
||||
// Light mapped or not ?
|
||||
if (frag.mode == LIGHT_MAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
_fragColor = vec4(frag.diffuse, 1.0);
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
vec3 color = evalLightmappedColor(
|
||||
deferredTransform.viewInverse,
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
|
||||
<@include Shadow.slh@>
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalLightmappedColor()$>
|
||||
|
@ -30,7 +30,9 @@ void main(void) {
|
|||
float shadowAttenuation = evalShadowAttenuation(worldPos);
|
||||
|
||||
// Light mapped or not ?
|
||||
if (frag.mode == LIGHT_MAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
_fragColor = vec4(frag.diffuse, 1.0);
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
vec3 color = evalLightmappedColor(
|
||||
deferredTransform.viewInverse,
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalLightmappedColor()$>
|
||||
|
@ -28,7 +28,9 @@ void main(void) {
|
|||
float shadowAttenuation = 1.0;
|
||||
|
||||
// Light mapped or not ?
|
||||
if (frag.mode == LIGHT_MAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
_fragColor = vec4(frag.diffuse, 1.0);
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
vec3 color = evalLightmappedColor(
|
||||
deferredTransform.viewInverse,
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
//!>
|
||||
|
||||
<@include Shadow.slh@>
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
<@include DeferredGlobalLight.slh@>
|
||||
|
||||
<$declareEvalLightmappedColor()$>
|
||||
|
@ -30,7 +30,9 @@ void main(void) {
|
|||
float shadowAttenuation = evalShadowAttenuation(worldPos);
|
||||
|
||||
// Light mapped or not ?
|
||||
if (frag.mode == LIGHT_MAPPED) {
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
_fragColor = vec4(frag.diffuse, 1.0);
|
||||
} else if (frag.mode == FRAG_MODE_LIGHTMAPPED) {
|
||||
vec3 color = evalLightmappedColor(
|
||||
deferredTransform.viewInverse,
|
||||
shadowAttenuation,
|
||||
|
|
|
@ -30,7 +30,7 @@ void main(void) {
|
|||
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$>
|
||||
|
||||
float opacity = 1.0;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
|
|
|
@ -1,39 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// model_emissive.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Zach Pomerantz on 2/3/2016.
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
<@include model/Material.slh@>
|
||||
|
||||
uniform sampler2D albedoMap;
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
void main(void) {
|
||||
vec4 texel = texture(albedoMap, _texCoord0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
vec3 fragColor = getMaterialAlbedo(mat) * texel.rgb * _color;
|
||||
|
||||
packDeferredFragmentLightmap(
|
||||
normalize(_normal),
|
||||
texel.a,
|
||||
vec3(1.0),
|
||||
getMaterialRoughness(mat),
|
||||
getMaterialMetallic(mat),
|
||||
getMaterialFresnel(mat),
|
||||
fragColor);
|
||||
}
|
|
@ -31,7 +31,7 @@ void main(void) {
|
|||
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, normalTex, _SCRIBE_NULL, emissiveTex, occlusionTex)$>
|
||||
|
||||
float opacity = 1.0;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
|
|
|
@ -31,7 +31,7 @@ void main(void) {
|
|||
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, metallicTex, emissiveTex, occlusionTex)$>
|
||||
|
||||
float opacity = 1.0;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
|
|
|
@ -38,8 +38,7 @@ void main(void) {
|
|||
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, roughnessTex, _SCRIBE_NULL, _SCRIBE_NULL, emissiveTex, occlusionTex)$>
|
||||
|
||||
float opacity = getMaterialOpacity(mat) * _alpha;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)&>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// model_translucent_emissive.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Zach Pomerantz on 2/3/2016.
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
<@include model/Material.slh@>
|
||||
|
||||
uniform sampler2D albedoMap;
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
vec4 albedo = texture(albedoMap, _texCoord0);
|
||||
|
||||
Material mat = getMaterial();
|
||||
vec3 fragColor = getMaterialAlbedo(mat) * albedo.rgb * _color;
|
||||
float fragOpacity = getMaterialOpacity(mat) * albedo.a * _alpha;
|
||||
|
||||
_fragColor = vec4(fragColor, fragOpacity);
|
||||
}
|
39
libraries/render-utils/src/model_translucent_unlit.slf
Normal file
39
libraries/render-utils/src/model_translucent_unlit.slf
Normal file
|
@ -0,0 +1,39 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// model_translucent_unlit.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Zach Pomerantz on 2/3/2016.
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
<@include model/Material.slh@>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTextures(ALBEDO, ROUGHNESS, _SCRIBE_NULL, _SCRIBE_NULL, EMISSIVE, OCCLUSION)$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
out vec4 _fragColor;
|
||||
|
||||
void main(void) {
|
||||
Material mat = getMaterial();
|
||||
int matKey = getMaterialKey(mat);
|
||||
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$>
|
||||
|
||||
float opacity = getMaterialOpacity(mat) * _alpha;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
albedo *= _color;
|
||||
|
||||
_fragColor = vec4(albedo, opacity);
|
||||
}
|
44
libraries/render-utils/src/model_unlit.slf
Normal file
44
libraries/render-utils/src/model_unlit.slf
Normal file
|
@ -0,0 +1,44 @@
|
|||
<@include gpu/Config.slh@>
|
||||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// material_opaque_unlit.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Sam Gateau on 5/5/2016.
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
<@include model/Material.slh@>
|
||||
|
||||
<@include MaterialTextures.slh@>
|
||||
<$declareMaterialTextures(ALBEDO, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$>
|
||||
|
||||
in vec2 _texCoord0;
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in float _alpha;
|
||||
|
||||
void main(void) {
|
||||
|
||||
Material mat = getMaterial();
|
||||
int matKey = getMaterialKey(mat);
|
||||
<$fetchMaterialTextures(matKey, _texCoord0, albedoTex, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL, _SCRIBE_NULL)$>
|
||||
|
||||
float opacity = 1.0;
|
||||
<$evalMaterialOpacity(albedoTex.a, opacity, matKey, opacity)$>;
|
||||
<$discardTransparent(opacity)$>;
|
||||
|
||||
vec3 albedo = getMaterialAlbedo(mat);
|
||||
<$evalMaterialAlbedo(albedoTex, albedo, matKey, albedo)$>;
|
||||
albedo *= _color;
|
||||
|
||||
packDeferredFragmentUnlit(
|
||||
normalize(_normal),
|
||||
opacity,
|
||||
albedo);
|
||||
}
|
|
@ -71,6 +71,7 @@ void main(void) {
|
|||
fragRoughness,
|
||||
fragOpacity);
|
||||
|
||||
|
||||
// Apply standard tone mapping
|
||||
_fragColor = vec4(pow(color.xyz, vec3(1.0 / 2.2)), color.w);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// overlay3D_translucent_emissive.frag
|
||||
// overlay3D_translucent_unlit.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Zach Pomerantz on 2/2/2016.
|
|
@ -2,7 +2,7 @@
|
|||
<$VERSION_HEADER$>
|
||||
// Generated on <$_SCRIBE_DATE$>
|
||||
//
|
||||
// overlay3D_emissive.frag
|
||||
// overlay3D_unlit.frag
|
||||
// fragment shader
|
||||
//
|
||||
// Created by Zach Pomerantz on 2/2/2016.
|
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
|
||||
//Everything about deferred lighting
|
||||
<@include DeferredLighting.slh@>
|
||||
|
@ -32,6 +32,10 @@ void main(void) {
|
|||
vec2 texCoord = _texCoord0.st / _texCoord0.q;
|
||||
DeferredFragment frag = unpackDeferredFragment(deferredTransform, texCoord);
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
}
|
||||
|
||||
mat4 invViewMat = deferredTransform.viewInverse;
|
||||
|
||||
// Kill if in front of the light volume
|
||||
|
|
|
@ -20,12 +20,12 @@
|
|||
// the interpolated normal
|
||||
out vec3 _normal;
|
||||
out vec3 _modelNormal;
|
||||
out vec3 _color;
|
||||
out vec4 _color;
|
||||
out vec2 _texCoord0;
|
||||
out vec4 _position;
|
||||
|
||||
void main(void) {
|
||||
_color = colorToLinearRGB(inColor.rgb);
|
||||
_color = colorToLinearRGBA(inColor);
|
||||
_texCoord0 = inTexCoord0.st;
|
||||
_position = inPosition;
|
||||
_modelNormal = inNormal.xyz;
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
<@include model/Material.slh@>
|
||||
|
||||
|
@ -20,13 +21,14 @@ uniform sampler2D originalTexture;
|
|||
|
||||
// the interpolated normal
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in vec4 _color;
|
||||
in vec2 _texCoord0;
|
||||
|
||||
void main(void) {
|
||||
Material material = getMaterial();
|
||||
vec4 texel = texture(originalTexture, _texCoord0);
|
||||
|
||||
if (_color.a <= 0.0) {
|
||||
texel = colorToLinearRGBA(texel);
|
||||
}
|
||||
packDeferredFragment(
|
||||
normalize(_normal.xyz),
|
||||
texel.a,
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<@include DeferredBufferWrite.slh@>
|
||||
|
||||
// the albedo texture
|
||||
|
@ -19,18 +20,17 @@ uniform sampler2D originalTexture;
|
|||
|
||||
// the interpolated normal
|
||||
in vec3 _normal;
|
||||
in vec3 _color;
|
||||
in vec4 _color;
|
||||
in vec2 _texCoord0;
|
||||
|
||||
void main(void) {
|
||||
vec4 texel = texture(originalTexture, _texCoord0.st);
|
||||
|
||||
packDeferredFragmentLightmap(
|
||||
if (_color.a <= 0.0) {
|
||||
texel = colorToLinearRGBA(texel);
|
||||
}
|
||||
|
||||
packDeferredFragmentUnlit(
|
||||
normalize(_normal),
|
||||
texel.a,
|
||||
_color.rgb,
|
||||
DEFAULT_ROUGHNESS,
|
||||
DEFAULT_METALLIC,
|
||||
DEFAULT_SPECULAR,
|
||||
texel.rgb);
|
||||
_color.rgb * texel.rgb);
|
||||
}
|
|
@ -13,7 +13,7 @@
|
|||
//
|
||||
|
||||
// Everything about deferred buffer
|
||||
<@include DeferredBuffer.slh@>
|
||||
<@include DeferredBufferRead.slh@>
|
||||
|
||||
//Everything about deferred lighting
|
||||
<@include DeferredLighting.slh@>
|
||||
|
@ -32,6 +32,10 @@ void main(void) {
|
|||
vec2 texCoord = _texCoord0.st / _texCoord0.q;
|
||||
DeferredFragment frag = unpackDeferredFragment(deferredTransform, texCoord);
|
||||
|
||||
if (frag.mode == FRAG_MODE_UNLIT) {
|
||||
discard;
|
||||
}
|
||||
|
||||
mat4 invViewMat = deferredTransform.viewInverse;
|
||||
|
||||
// Kill if in front of the light volume
|
||||
|
|
|
@ -26,7 +26,7 @@ public:
|
|||
LIGHTMAP,
|
||||
TANGENTS,
|
||||
SPECULAR,
|
||||
EMISSIVE,
|
||||
UNLIT,
|
||||
SKINNED,
|
||||
STEREO,
|
||||
DEPTH_ONLY,
|
||||
|
@ -57,7 +57,7 @@ public:
|
|||
Builder& withLightmap() { _flags.set(LIGHTMAP); return (*this); }
|
||||
Builder& withTangents() { _flags.set(TANGENTS); return (*this); }
|
||||
Builder& withSpecular() { _flags.set(SPECULAR); return (*this); }
|
||||
Builder& withEmissive() { _flags.set(EMISSIVE); return (*this); }
|
||||
Builder& withUnlit() { _flags.set(UNLIT); return (*this); }
|
||||
Builder& withSkinned() { _flags.set(SKINNED); return (*this); }
|
||||
Builder& withStereo() { _flags.set(STEREO); return (*this); }
|
||||
Builder& withDepthOnly() { _flags.set(DEPTH_ONLY); return (*this); }
|
||||
|
@ -101,8 +101,8 @@ public:
|
|||
Builder& withSpecular() { _flags.set(SPECULAR); _mask.set(SPECULAR); return (*this); }
|
||||
Builder& withoutSpecular() { _flags.reset(SPECULAR); _mask.set(SPECULAR); return (*this); }
|
||||
|
||||
Builder& withEmissive() { _flags.set(EMISSIVE); _mask.set(EMISSIVE); return (*this); }
|
||||
Builder& withoutEmissive() { _flags.reset(EMISSIVE); _mask.set(EMISSIVE); return (*this); }
|
||||
Builder& withUnlit() { _flags.set(UNLIT); _mask.set(UNLIT); return (*this); }
|
||||
Builder& withoutUnlit() { _flags.reset(UNLIT); _mask.set(UNLIT); return (*this); }
|
||||
|
||||
Builder& withSkinned() { _flags.set(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||
Builder& withoutSkinned() { _flags.reset(SKINNED); _mask.set(SKINNED); return (*this); }
|
||||
|
@ -137,7 +137,7 @@ public:
|
|||
bool hasLightmap() const { return _flags[LIGHTMAP]; }
|
||||
bool hasTangents() const { return _flags[TANGENTS]; }
|
||||
bool hasSpecular() const { return _flags[SPECULAR]; }
|
||||
bool hasEmissive() const { return _flags[EMISSIVE]; }
|
||||
bool isUnlit() const { return _flags[UNLIT]; }
|
||||
bool isTranslucent() const { return _flags[TRANSLUCENT]; }
|
||||
bool isSkinned() const { return _flags[SKINNED]; }
|
||||
bool isStereo() const { return _flags[STEREO]; }
|
||||
|
@ -173,7 +173,7 @@ inline QDebug operator<<(QDebug debug, const ShapeKey& key) {
|
|||
<< "hasLightmap:" << key.hasLightmap()
|
||||
<< "hasTangents:" << key.hasTangents()
|
||||
<< "hasSpecular:" << key.hasSpecular()
|
||||
<< "hasEmissive:" << key.hasEmissive()
|
||||
<< "isUnlit:" << key.isUnlit()
|
||||
<< "isTranslucent:" << key.isTranslucent()
|
||||
<< "isSkinned:" << key.isSkinned()
|
||||
<< "isStereo:" << key.isStereo()
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
set(TARGET_NAME script-engine)
|
||||
setup_hifi_library(Gui Network Script WebSockets Widgets)
|
||||
setup_hifi_library(Gui Network Script ScriptTools WebSockets Widgets)
|
||||
link_hifi_libraries(shared networking octree gpu ui procedural model model-networking recording avatars fbx entities controllers animation audio physics)
|
||||
|
|
|
@ -17,12 +17,18 @@
|
|||
#include <QtCore/QFileInfo>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtCore/QThread>
|
||||
#include <QtCore/QRegularExpression>
|
||||
|
||||
#include <QtWidgets/QMainWindow>
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <QtNetwork/QNetworkRequest>
|
||||
#include <QtNetwork/QNetworkReply>
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <QtScript/QScriptValue>
|
||||
#include <QtScript/QScriptValueIterator>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include <QtScriptTools/QScriptEngineDebugger>
|
||||
|
||||
#include <AudioConstants.h>
|
||||
#include <AudioEffectOptions.h>
|
||||
|
@ -34,6 +40,7 @@
|
|||
#include <NodeList.h>
|
||||
#include <udt/PacketHeaders.h>
|
||||
#include <UUID.h>
|
||||
#include <ui/Menu.h>
|
||||
|
||||
#include <controllers/ScriptingInterface.h>
|
||||
#include <AnimationObject.h>
|
||||
|
@ -169,6 +176,93 @@ void ScriptEngine::disconnectNonEssentialSignals() {
|
|||
}
|
||||
}
|
||||
|
||||
void ScriptEngine::runDebuggable() {
|
||||
static QMenuBar* menuBar { nullptr };
|
||||
static QMenu* scriptDebugMenu { nullptr };
|
||||
static size_t scriptMenuCount { 0 };
|
||||
if (!scriptDebugMenu) {
|
||||
for (auto window : qApp->topLevelWidgets()) {
|
||||
auto mainWindow = qobject_cast<QMainWindow*>(window);
|
||||
if (mainWindow) {
|
||||
menuBar = mainWindow->menuBar();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (menuBar) {
|
||||
scriptDebugMenu = menuBar->addMenu("Script Debug");
|
||||
}
|
||||
}
|
||||
|
||||
init();
|
||||
_isRunning = true;
|
||||
_debuggable = true;
|
||||
_debugger = new QScriptEngineDebugger(this);
|
||||
_debugger->attachTo(this);
|
||||
|
||||
QMenu* parentMenu = scriptDebugMenu;
|
||||
QMenu* scriptMenu { nullptr };
|
||||
if (parentMenu) {
|
||||
++scriptMenuCount;
|
||||
scriptMenu = parentMenu->addMenu(_fileNameString);
|
||||
scriptMenu->addMenu(_debugger->createStandardMenu(qApp->activeWindow()));
|
||||
} else {
|
||||
qWarning() << "Unable to add script debug menu";
|
||||
}
|
||||
|
||||
QScriptValue result = evaluate(_scriptContents, _fileNameString);
|
||||
|
||||
_lastUpdate = usecTimestampNow();
|
||||
QTimer* timer = new QTimer(this);
|
||||
connect(this, &ScriptEngine::finished, [this, timer, parentMenu, scriptMenu] {
|
||||
if (scriptMenu) {
|
||||
parentMenu->removeAction(scriptMenu->menuAction());
|
||||
--scriptMenuCount;
|
||||
if (0 == scriptMenuCount) {
|
||||
menuBar->removeAction(scriptDebugMenu->menuAction());
|
||||
scriptDebugMenu = nullptr;
|
||||
}
|
||||
}
|
||||
disconnect(timer);
|
||||
});
|
||||
|
||||
connect(timer, &QTimer::timeout, [this, timer] {
|
||||
if (_isFinished) {
|
||||
if (!_isRunning) {
|
||||
return;
|
||||
}
|
||||
stopAllTimers(); // make sure all our timers are stopped if the script is ending
|
||||
if (_wantSignals) {
|
||||
emit scriptEnding();
|
||||
emit finished(_fileNameString, this);
|
||||
}
|
||||
_isRunning = false;
|
||||
if (_wantSignals) {
|
||||
emit runningStateChanged();
|
||||
emit doneRunning();
|
||||
}
|
||||
timer->deleteLater();
|
||||
return;
|
||||
}
|
||||
|
||||
qint64 now = usecTimestampNow();
|
||||
// we check for 'now' in the past in case people set their clock back
|
||||
if (_lastUpdate < now) {
|
||||
float deltaTime = (float)(now - _lastUpdate) / (float)USECS_PER_SECOND;
|
||||
if (!_isFinished) {
|
||||
if (_wantSignals) {
|
||||
emit update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
_lastUpdate = now;
|
||||
// Debug and clear exceptions
|
||||
hadUncaughtExceptions(*this, _fileNameString);
|
||||
});
|
||||
|
||||
timer->start(10);
|
||||
}
|
||||
|
||||
|
||||
void ScriptEngine::runInThread() {
|
||||
Q_ASSERT_X(!_isThreaded, "ScriptEngine::runInThread()", "runInThread should not be called more than once");
|
||||
|
||||
|
@ -260,6 +354,10 @@ void ScriptEngine::loadURL(const QUrl& scriptURL, bool reload) {
|
|||
// FIXME - switch this to the new model of ScriptCache callbacks
|
||||
void ScriptEngine::scriptContentsAvailable(const QUrl& url, const QString& scriptContents) {
|
||||
_scriptContents = scriptContents;
|
||||
static const QString DEBUG_FLAG("#debug");
|
||||
if (QRegularExpression(DEBUG_FLAG).match(scriptContents).hasMatch()) {
|
||||
_debuggable = true;
|
||||
}
|
||||
if (_wantSignals) {
|
||||
emit scriptLoaded(url.toString());
|
||||
}
|
||||
|
@ -723,7 +821,7 @@ void ScriptEngine::run() {
|
|||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
auto entityScriptingInterface = DependencyManager::get<EntityScriptingInterface>();
|
||||
|
||||
qint64 lastUpdate = usecTimestampNow();
|
||||
_lastUpdate = usecTimestampNow();
|
||||
|
||||
// TODO: Integrate this with signals/slots instead of reimplementing throttling for ScriptEngine
|
||||
while (!_isFinished) {
|
||||
|
@ -771,15 +869,15 @@ void ScriptEngine::run() {
|
|||
qint64 now = usecTimestampNow();
|
||||
|
||||
// we check for 'now' in the past in case people set their clock back
|
||||
if (lastUpdate < now) {
|
||||
float deltaTime = (float) (now - lastUpdate) / (float) USECS_PER_SECOND;
|
||||
if (_lastUpdate < now) {
|
||||
float deltaTime = (float) (now - _lastUpdate) / (float) USECS_PER_SECOND;
|
||||
if (!_isFinished) {
|
||||
if (_wantSignals) {
|
||||
emit update(deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
lastUpdate = now;
|
||||
_lastUpdate = now;
|
||||
|
||||
// Debug and clear exceptions
|
||||
hadUncaughtExceptions(*this, _fileNameString);
|
||||
|
|
|
@ -18,9 +18,10 @@
|
|||
#include <QtCore/QUrl>
|
||||
#include <QtCore/QSet>
|
||||
#include <QtCore/QWaitCondition>
|
||||
#include <QtScript/QScriptEngine>
|
||||
#include <QtCore/QStringList>
|
||||
|
||||
#include <QtScript/QScriptEngine>
|
||||
|
||||
#include <AnimationCache.h>
|
||||
#include <AnimVariant.h>
|
||||
#include <AvatarData.h>
|
||||
|
@ -39,6 +40,8 @@
|
|||
#include "ScriptUUID.h"
|
||||
#include "Vec3.h"
|
||||
|
||||
class QScriptEngineDebugger;
|
||||
|
||||
static const QString NO_SCRIPT("");
|
||||
|
||||
static const int SCRIPT_FPS = 60;
|
||||
|
@ -75,6 +78,8 @@ public:
|
|||
/// services before calling this.
|
||||
void runInThread();
|
||||
|
||||
void runDebuggable();
|
||||
|
||||
/// run the script in the callers thread, exit when stop() is called.
|
||||
void run();
|
||||
|
||||
|
@ -140,6 +145,8 @@ public:
|
|||
bool isFinished() const { return _isFinished; } // used by Application and ScriptWidget
|
||||
bool isRunning() const { return _isRunning; } // used by ScriptWidget
|
||||
|
||||
bool isDebuggable() const { return _debuggable; }
|
||||
|
||||
void disconnectNonEssentialSignals();
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -187,6 +194,9 @@ protected:
|
|||
bool _wantSignals { true };
|
||||
QHash<EntityItemID, EntityScriptDetails> _entityScripts;
|
||||
bool _isThreaded { false };
|
||||
QScriptEngineDebugger* _debugger { nullptr };
|
||||
bool _debuggable { false };
|
||||
qint64 _lastUpdate;
|
||||
|
||||
void init();
|
||||
QString getFilename() const;
|
||||
|
|
|
@ -9,7 +9,8 @@
|
|||
#include "ScriptEngines.h"
|
||||
|
||||
#include <QtCore/QStandardPaths>
|
||||
#include <QtCore/QCoreApplication>
|
||||
|
||||
#include <QtWidgets/QApplication>
|
||||
|
||||
#include <SettingHandle.h>
|
||||
#include <UserActivityLogger.h>
|
||||
|
@ -270,12 +271,12 @@ void ScriptEngines::loadOneScript(const QString& scriptFilename) {
|
|||
|
||||
void ScriptEngines::loadScripts() {
|
||||
// check first run...
|
||||
if (_firstRun.get()) {
|
||||
Setting::Handle<bool> firstRun { Settings::firstRun, true };
|
||||
if (firstRun.get()) {
|
||||
qCDebug(scriptengine) << "This is a first run...";
|
||||
// clear the scripts, and set out script to our default scripts
|
||||
clearScripts();
|
||||
loadDefaultScripts();
|
||||
_firstRun.set(false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -490,7 +491,12 @@ void ScriptEngines::launchScriptEngine(ScriptEngine* scriptEngine) {
|
|||
for (auto initializer : _scriptInitializers) {
|
||||
initializer(scriptEngine);
|
||||
}
|
||||
scriptEngine->runInThread();
|
||||
|
||||
if (scriptEngine->isDebuggable() || (qApp->queryKeyboardModifiers() & Qt::ShiftModifier)) {
|
||||
scriptEngine->runDebuggable();
|
||||
} else {
|
||||
scriptEngine->runInThread();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -87,8 +87,6 @@ protected:
|
|||
void onScriptEngineError(const QString& scriptFilename);
|
||||
void launchScriptEngine(ScriptEngine* engine);
|
||||
|
||||
|
||||
Setting::Handle<bool> _firstRun { "firstRun", true };
|
||||
QReadWriteLock _scriptEnginesHashLock;
|
||||
QHash<QUrl, ScriptEngine*> _scriptEnginesHash;
|
||||
QSet<ScriptEngine*> _allKnownScriptEngines;
|
||||
|
|
|
@ -23,6 +23,11 @@ DebugDraw::~DebugDraw() {
|
|||
|
||||
}
|
||||
|
||||
// world space line, drawn only once
|
||||
void DebugDraw::drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color) {
|
||||
_rays.push_back(Ray(start, end, color));
|
||||
}
|
||||
|
||||
void DebugDraw::addMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color) {
|
||||
_markers[key] = MarkerInfo(rotation, position, color);
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#include <unordered_map>
|
||||
#include <tuple>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
|
@ -23,16 +24,21 @@ public:
|
|||
DebugDraw();
|
||||
~DebugDraw();
|
||||
|
||||
// world space maker
|
||||
// world space line, drawn only once
|
||||
void drawRay(const glm::vec3& start, const glm::vec3& end, const glm::vec4& color);
|
||||
|
||||
// world space maker, marker drawn every frame until it is removed.
|
||||
void addMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color);
|
||||
void removeMarker(const std::string& key);
|
||||
|
||||
// myAvatar relative marker
|
||||
// myAvatar relative marker, maker is drawn every frame until it is removed.
|
||||
void addMyAvatarMarker(const std::string& key, const glm::quat& rotation, const glm::vec3& position, const glm::vec4& color);
|
||||
void removeMyAvatarMarker(const std::string& key);
|
||||
|
||||
using MarkerInfo = std::tuple<glm::quat, glm::vec3, glm::vec4>;
|
||||
using MarkerMap = std::unordered_map<std::string, MarkerInfo>;
|
||||
using Ray = std::tuple<glm::vec3, glm::vec3, glm::vec4>;
|
||||
using Rays = std::vector<Ray>;
|
||||
|
||||
//
|
||||
// accessors used by renderer
|
||||
|
@ -44,12 +50,15 @@ public:
|
|||
const glm::vec3& getMyAvatarPos() const { return _myAvatarPos; }
|
||||
void updateMyAvatarRot(const glm::quat& rot) { _myAvatarRot = rot; }
|
||||
const glm::quat& getMyAvatarRot() const { return _myAvatarRot; }
|
||||
const Rays getRays() const { return _rays; }
|
||||
void clearRays() { _rays.clear(); }
|
||||
|
||||
protected:
|
||||
MarkerMap _markers;
|
||||
MarkerMap _myAvatarMarkers;
|
||||
glm::quat _myAvatarRot;
|
||||
glm::vec3 _myAvatarPos;
|
||||
Rays _rays;
|
||||
};
|
||||
|
||||
#endif // hifi_DebugDraw_h
|
||||
|
|
|
@ -431,13 +431,27 @@ glm::vec3 transformVectorFull(const glm::mat4& m, const glm::vec3& v) {
|
|||
void generateBasisVectors(const glm::vec3& primaryAxis, const glm::vec3& secondaryAxis,
|
||||
glm::vec3& uAxisOut, glm::vec3& vAxisOut, glm::vec3& wAxisOut) {
|
||||
|
||||
// primaryAxis & secondaryAxis must not be zero.
|
||||
#ifndef NDEBUG
|
||||
const float MIN_LENGTH_SQUARED = 1.0e-6f;
|
||||
#endif
|
||||
assert(fabsf(glm::length2(primaryAxis) > MIN_LENGTH_SQUARED));
|
||||
assert(fabsf(glm::length2(secondaryAxis) > MIN_LENGTH_SQUARED));
|
||||
|
||||
uAxisOut = glm::normalize(primaryAxis);
|
||||
wAxisOut = glm::cross(uAxisOut, secondaryAxis);
|
||||
if (glm::length(wAxisOut) > 0.0f) {
|
||||
wAxisOut = glm::normalize(wAxisOut);
|
||||
} else {
|
||||
wAxisOut = glm::normalize(glm::cross(uAxisOut, glm::vec3(0, 1, 0)));
|
||||
glm::vec3 normSecondary = glm::normalize(secondaryAxis);
|
||||
|
||||
// if secondaryAxis is parallel with the primaryAxis, pick another axis.
|
||||
const float EPSILON = 1.0e-4f;
|
||||
if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) {
|
||||
// pick a better secondaryAxis.
|
||||
normSecondary = glm::vec3(1.0f, 0.0f, 0.0f);
|
||||
if (fabsf(fabsf(glm::dot(uAxisOut, secondaryAxis)) - 1.0f) > EPSILON) {
|
||||
normSecondary = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
}
|
||||
}
|
||||
|
||||
wAxisOut = glm::normalize(glm::cross(uAxisOut, secondaryAxis));
|
||||
vAxisOut = glm::cross(wAxisOut, uAxisOut);
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <math.h>
|
||||
|
||||
const QString Settings::firstRun { "firstRun" };
|
||||
|
||||
void Settings::getFloatValueIfValid(const QString& name, float& floatValue) {
|
||||
const QVariant badDefaultValue = NAN;
|
||||
|
|
|
@ -26,6 +26,8 @@
|
|||
// TODO: remove
|
||||
class Settings : public QSettings {
|
||||
public:
|
||||
static const QString firstRun;
|
||||
|
||||
void getFloatValueIfValid(const QString& name, float& floatValue);
|
||||
void getBoolValue(const QString& name, bool& boolValue);
|
||||
|
||||
|
|
|
@ -509,7 +509,12 @@ void NeuronPlugin::pluginUpdate(float deltaTime, const controller::InputCalibrat
|
|||
std::lock_guard<std::mutex> guard(_jointsMutex);
|
||||
joints = _joints;
|
||||
}
|
||||
_inputDevice->update(deltaTime, inputCalibrationData, joints, _prevJoints);
|
||||
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->withLock([&, this]() {
|
||||
_inputDevice->update(deltaTime, inputCalibrationData, joints, _prevJoints);
|
||||
});
|
||||
|
||||
_prevJoints = joints;
|
||||
}
|
||||
|
||||
|
|
|
@ -136,7 +136,12 @@ void SixenseManager::setSixenseFilter(bool filter) {
|
|||
|
||||
void SixenseManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
|
||||
BAIL_IF_NOT_LOADED
|
||||
_inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured);
|
||||
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
userInputMapper->withLock([&, this]() {
|
||||
_inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured);
|
||||
});
|
||||
|
||||
if (_inputDevice->_requestReset) {
|
||||
_container->requestReset();
|
||||
_inputDevice->_requestReset = false;
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include "ViveControllerManager.h"
|
||||
|
||||
#include <QtCore/QProcessEnvironment>
|
||||
|
||||
#include <PerfStat.h>
|
||||
#include <PathUtils.h>
|
||||
#include <GeometryCache.h>
|
||||
|
@ -48,9 +50,11 @@ static const QString MENU_PATH = MENU_PARENT + ">" + MENU_NAME;
|
|||
static const QString RENDER_CONTROLLERS = "Render Hand Controllers";
|
||||
|
||||
const QString ViveControllerManager::NAME = "OpenVR";
|
||||
static const QString DEBUG_FLAG("HIFI_DEBUG_OPENVR");
|
||||
static bool enableDebugOpenVR = QProcessEnvironment::systemEnvironment().contains(DEBUG_FLAG);
|
||||
|
||||
bool ViveControllerManager::isSupported() const {
|
||||
return !isOculusPresent() && vr::VR_IsHmdPresent();
|
||||
return (enableDebugOpenVR || !isOculusPresent()) && vr::VR_IsHmdPresent();
|
||||
}
|
||||
|
||||
bool ViveControllerManager::activate() {
|
||||
|
@ -211,9 +215,13 @@ void ViveControllerManager::renderHand(const controller::Pose& pose, gpu::Batch&
|
|||
|
||||
|
||||
void ViveControllerManager::pluginUpdate(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, bool jointsCaptured) {
|
||||
_inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured);
|
||||
auto userInputMapper = DependencyManager::get<controller::UserInputMapper>();
|
||||
|
||||
// because update mutates the internal state we need to lock
|
||||
userInputMapper->withLock([&, this]() {
|
||||
_inputDevice->update(deltaTime, inputCalibrationData, jointsCaptured);
|
||||
});
|
||||
|
||||
if (_inputDevice->_trackedControllers == 0 && _registeredWithInputMapper) {
|
||||
userInputMapper->removeDevice(_inputDevice->_deviceID);
|
||||
_registeredWithInputMapper = false;
|
||||
|
@ -270,7 +278,8 @@ void ViveControllerManager::InputDevice::handleHandController(float deltaTime, u
|
|||
for (uint32_t i = 0; i < vr::k_EButton_Max; ++i) {
|
||||
auto mask = vr::ButtonMaskFromId((vr::EVRButtonId)i);
|
||||
bool pressed = 0 != (controllerState.ulButtonPressed & mask);
|
||||
handleButtonEvent(deltaTime, i, pressed, isLeftHand);
|
||||
bool touched = 0 != (controllerState.ulButtonTouched & mask);
|
||||
handleButtonEvent(deltaTime, i, pressed, touched, isLeftHand);
|
||||
}
|
||||
|
||||
// process each axis
|
||||
|
@ -314,20 +323,26 @@ enum ViveButtonChannel {
|
|||
|
||||
|
||||
// These functions do translation from the Steam IDs to the standard controller IDs
|
||||
void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand) {
|
||||
if (!pressed) {
|
||||
return;
|
||||
}
|
||||
void ViveControllerManager::InputDevice::handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool touched, bool isLeftHand) {
|
||||
|
||||
using namespace controller;
|
||||
if (button == vr::k_EButton_ApplicationMenu) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LEFT_APP_MENU : RIGHT_APP_MENU);
|
||||
} else if (button == vr::k_EButton_Grip) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LB : RB);
|
||||
} else if (button == vr::k_EButton_SteamVR_Trigger) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LT : RT);
|
||||
} else if (button == vr::k_EButton_SteamVR_Touchpad) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LS : RS);
|
||||
|
||||
if (pressed) {
|
||||
if (button == vr::k_EButton_ApplicationMenu) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LEFT_APP_MENU : RIGHT_APP_MENU);
|
||||
} else if (button == vr::k_EButton_Grip) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LEFT_GRIP : RIGHT_GRIP);
|
||||
} else if (button == vr::k_EButton_SteamVR_Trigger) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LT : RT);
|
||||
} else if (button == vr::k_EButton_SteamVR_Touchpad) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LS : RS);
|
||||
}
|
||||
}
|
||||
|
||||
if (touched) {
|
||||
if (button == vr::k_EButton_SteamVR_Touchpad) {
|
||||
_buttonPressedMap.insert(isLeftHand ? LS_TOUCH : RS_TOUCH);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -424,18 +439,28 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI
|
|||
makePair(LY, "LY"),
|
||||
makePair(RX, "RX"),
|
||||
makePair(RY, "RY"),
|
||||
// trigger analogs
|
||||
|
||||
// capacitive touch on the touch pad
|
||||
makePair(LS_TOUCH, "LSTouch"),
|
||||
makePair(RS_TOUCH, "RSTouch"),
|
||||
|
||||
// touch pad press
|
||||
makePair(LS, "LS"),
|
||||
makePair(RS, "RS"),
|
||||
|
||||
// triggers
|
||||
makePair(LT, "LT"),
|
||||
makePair(RT, "RT"),
|
||||
|
||||
makePair(LB, "LB"),
|
||||
makePair(RB, "RB"),
|
||||
// low profile side grip button.
|
||||
makePair(LEFT_GRIP, "LeftGrip"),
|
||||
makePair(RIGHT_GRIP, "RightGrip"),
|
||||
|
||||
makePair(LS, "LS"),
|
||||
makePair(RS, "RS"),
|
||||
// 3d location of controller
|
||||
makePair(LEFT_HAND, "LeftHand"),
|
||||
makePair(RIGHT_HAND, "RightHand"),
|
||||
|
||||
// app button above trackpad.
|
||||
Input::NamedPair(Input(_deviceID, LEFT_APP_MENU, ChannelType::BUTTON), "LeftApplicationMenu"),
|
||||
Input::NamedPair(Input(_deviceID, RIGHT_APP_MENU, ChannelType::BUTTON), "RightApplicationMenu"),
|
||||
};
|
||||
|
|
|
@ -59,7 +59,7 @@ private:
|
|||
virtual void focusOutEvent() override;
|
||||
|
||||
void handleHandController(float deltaTime, uint32_t deviceIndex, const controller::InputCalibrationData& inputCalibrationData, bool isLeftHand);
|
||||
void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool isLeftHand);
|
||||
void handleButtonEvent(float deltaTime, uint32_t button, bool pressed, bool touched, bool isLeftHand);
|
||||
void handleAxisEvent(float deltaTime, uint32_t axis, float x, float y, bool isLeftHand);
|
||||
void handlePoseEvent(float deltaTime, const controller::InputCalibrationData& inputCalibrationData, const mat4& mat,
|
||||
const vec3& linearVelocity, const vec3& angularVelocity, bool isLeftHand);
|
||||
|
|
|
@ -17,7 +17,7 @@ Script.load("system/edit.js");
|
|||
Script.load("system/selectAudioDevice.js");
|
||||
Script.load("system/notifications.js");
|
||||
Script.load("system/controllers/handControllerGrab.js");
|
||||
Script.load("system/controllers/handControllerPointer.js");
|
||||
Script.load("system/controllers/squeezeHands.js");
|
||||
Script.load("system/controllers/grab.js");
|
||||
Script.load("system/dialTone.js");
|
||||
Script.load("system/depthReticle.js");
|
79
scripts/developer/tests/viveTouchpadTest.js
Normal file
79
scripts/developer/tests/viveTouchpadTest.js
Normal file
|
@ -0,0 +1,79 @@
|
|||
//
|
||||
// viveTouchpadTest.js
|
||||
//
|
||||
// Anthony J. Thibault
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// An example of reading touch and move events from the vive controller touch pad.
|
||||
//
|
||||
// It will spawn a gray cube in front of you, then as you use the right touch pad,
|
||||
// the cube should turn green and respond to the motion of your thumb on the pad.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
var GRAY = {red: 57, green: 57, blue: 57};
|
||||
var GREEN = {red: 0, green: 255, blue: 0};
|
||||
var ZERO = {x: 0, y: 0, z: 0};
|
||||
var Y_AXIS = {x: 0, y: 1, x: 0};
|
||||
var ROT_Y_90 = Quat.angleAxis(Y_AXIS, 90.0);
|
||||
|
||||
var boxEntity;
|
||||
var boxPosition;
|
||||
var boxZAxis, boxYAxis;
|
||||
var prevThumbDown = false;
|
||||
|
||||
function init() {
|
||||
boxPosition = Vec3.sum(MyAvatar.position, Vec3.multiply(3, Quat.getFront(Camera.getOrientation())));
|
||||
var front = Quat.getFront(Camera.getOrientation());
|
||||
boxZAxis = Vec3.normalize(Vec3.cross(front, Y_AXIS));
|
||||
boxYAxis = Vec3.normalize(Vec3.cross(boxZAxis, front));
|
||||
|
||||
boxEntity = Entities.addEntity({
|
||||
type: "Box",
|
||||
position: boxPosition,
|
||||
dimentions: {x: 0.25, y: 0.25, z: 0.25},
|
||||
color: GRAY,
|
||||
gravity: ZERO,
|
||||
visible: true,
|
||||
locked: false,
|
||||
lifetime: 60000
|
||||
});
|
||||
}
|
||||
|
||||
function shutdown() {
|
||||
Entities.deleteEntity(boxEntity);
|
||||
}
|
||||
Script.scriptEnding.connect(shutdown);
|
||||
|
||||
function viveIsConnected() {
|
||||
return Controller.Hardware.Vive;
|
||||
}
|
||||
|
||||
function update(dt) {
|
||||
if (viveIsConnected()) {
|
||||
var thumbDown = Controller.getValue(Controller.Hardware.Vive.RSTouch);
|
||||
if (thumbDown) {
|
||||
var x = Controller.getValue(Controller.Hardware.Vive.RX);
|
||||
var y = Controller.getValue(Controller.Hardware.Vive.RY);
|
||||
var xOffset = Vec3.multiply(boxZAxis, x);
|
||||
var yOffset = Vec3.multiply(boxYAxis, y);
|
||||
var offset = Vec3.sum(xOffset, yOffset);
|
||||
Entities.editEntity(boxEntity, {position: Vec3.sum(boxPosition, offset)});
|
||||
}
|
||||
if (thumbDown && !prevThumbDown) {
|
||||
Entities.editEntity(boxEntity, {color: GREEN});
|
||||
}
|
||||
if (!thumbDown && prevThumbDown) {
|
||||
Entities.editEntity(boxEntity, {color: GRAY});
|
||||
}
|
||||
prevThumbDown = thumbDown;
|
||||
}
|
||||
}
|
||||
|
||||
Script.update.connect(update);
|
||||
|
||||
init();
|
||||
|
||||
|
||||
|
|
@ -33,6 +33,7 @@ Column {
|
|||
"Roughness",
|
||||
"Metallic",
|
||||
"Emissive",
|
||||
"Shaded/Lightmapped/Unlit",
|
||||
"Occlusion",
|
||||
"Lightmap",
|
||||
"Lighting",
|
||||
|
|
|
@ -739,6 +739,9 @@ function MyController(hand) {
|
|||
};
|
||||
|
||||
this.propsArePhysical = function(props) {
|
||||
if (!props.dynamic) {
|
||||
return false;
|
||||
}
|
||||
var isPhysical = (props.shapeType && props.shapeType != 'none');
|
||||
return isPhysical;
|
||||
}
|
||||
|
|
456
scripts/system/controllers/handControllerPointer.js
Normal file
456
scripts/system/controllers/handControllerPointer.js
Normal file
|
@ -0,0 +1,456 @@
|
|||
"use strict";
|
||||
/*jslint vars: true, plusplus: true*/
|
||||
/*globals Script, Overlays, Controller, Reticle, HMD, Camera, Entities, MyAvatar, Settings, Menu, ScriptDiscoveryService, Window, Vec3, Quat, print */
|
||||
|
||||
//
|
||||
// handControllerPointer.js
|
||||
// examples/controllers
|
||||
//
|
||||
// Created by Howard Stearns on 2016/04/22
|
||||
// Copyright 2016 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
|
||||
//
|
||||
|
||||
// Control the "mouse" using hand controller. (HMD and desktop.)
|
||||
// For now:
|
||||
// Hydra thumb button 3 is left-mouse, button 4 is right-mouse.
|
||||
// A click in the center of the vive thumb pad is left mouse. Vive menu button is context menu (right mouse).
|
||||
// First-person only.
|
||||
// Starts right handed, but switches to whichever is free: Whichever hand was NOT most recently squeezed.
|
||||
// (For now, the thumb buttons on both controllers are always on.)
|
||||
// When over a HUD element, the reticle is shown where the active hand controller beam intersects the HUD.
|
||||
// Otherwise, the active hand controller shows a red ball where a click will act.
|
||||
//
|
||||
// Bugs:
|
||||
// On Windows, the upper left corner of Interface must be in the upper left corner of the screen, and the title bar must be 50px high. (System bug.)
|
||||
// While hardware mouse move switches to mouse move, hardware mouse click (without amove) does not.
|
||||
|
||||
|
||||
// UTILITIES -------------
|
||||
//
|
||||
|
||||
// Utility to make it easier to setup and disconnect cleanly.
|
||||
function setupHandler(event, handler) {
|
||||
event.connect(handler);
|
||||
Script.scriptEnding.connect(function () {
|
||||
event.disconnect(handler);
|
||||
});
|
||||
}
|
||||
// If some capability is not available until expiration milliseconds after the last update.
|
||||
function TimeLock(expiration) {
|
||||
var last = 0;
|
||||
this.update = function (optionalNow) {
|
||||
last = optionalNow || Date.now();
|
||||
};
|
||||
this.expired = function (optionalNow) {
|
||||
return ((optionalNow || Date.now()) - last) > expiration;
|
||||
};
|
||||
}
|
||||
var handControllerLockOut = new TimeLock(2000);
|
||||
|
||||
// Calls onFunction() or offFunction() when swtich(on), but only if it is to a new value.
|
||||
function LatchedToggle(onFunction, offFunction, state) {
|
||||
this.getState = function () {
|
||||
return state;
|
||||
};
|
||||
this.setState = function (on) {
|
||||
if (state === on) {
|
||||
return;
|
||||
}
|
||||
state = on;
|
||||
if (on) {
|
||||
onFunction();
|
||||
} else {
|
||||
offFunction();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// VERTICAL FIELD OF VIEW ---------
|
||||
//
|
||||
// Cache the verticalFieldOfView setting and update it every so often.
|
||||
var verticalFieldOfView, DEFAULT_VERTICAL_FIELD_OF_VIEW = 45; // degrees
|
||||
function updateFieldOfView() {
|
||||
verticalFieldOfView = Settings.getValue('fieldOfView') || DEFAULT_VERTICAL_FIELD_OF_VIEW;
|
||||
}
|
||||
|
||||
// SHIMS ----------
|
||||
//
|
||||
var weMovedReticle = false;
|
||||
function ignoreMouseActivity() {
|
||||
// If we're paused, or if change in cursor position is from this script, not the hardware mouse.
|
||||
if (!Reticle.allowMouseCapture) {
|
||||
return true;
|
||||
}
|
||||
// Only we know if we moved it, which is why this script has to replace depthReticle.js
|
||||
if (!weMovedReticle) {
|
||||
return false;
|
||||
}
|
||||
weMovedReticle = false;
|
||||
return true;
|
||||
}
|
||||
var setReticlePosition = function (point2d) {
|
||||
weMovedReticle = true;
|
||||
Reticle.setPosition(point2d);
|
||||
};
|
||||
|
||||
// Generalizations of utilities that work with system and overlay elements.
|
||||
function findRayIntersection(pickRay) {
|
||||
// Check 3D overlays and entities. Argument is an object with origin and direction.
|
||||
var result = Overlays.findRayIntersection(pickRay);
|
||||
if (!result.intersects) {
|
||||
result = Entities.findRayIntersection(pickRay, true);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
function isPointingAtOverlay(optionalHudPosition2d) {
|
||||
return Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(optionalHudPosition2d || Reticle.position);
|
||||
}
|
||||
|
||||
// Generalized HUD utilities, with or without HMD:
|
||||
// These two "vars" are for documentation. Do not change their values!
|
||||
var SPHERICAL_HUD_DISTANCE = 1; // meters.
|
||||
var PLANAR_PERPENDICULAR_HUD_DISTANCE = SPHERICAL_HUD_DISTANCE;
|
||||
function calculateRayUICollisionPoint(position, direction) {
|
||||
// Answer the 3D intersection of the HUD by the given ray, or falsey if no intersection.
|
||||
if (HMD.active) {
|
||||
return HMD.calculateRayUICollisionPoint(position, direction);
|
||||
}
|
||||
// interect HUD plane, 1m in front of camera, using formula:
|
||||
// scale = hudNormal dot (hudPoint - position) / hudNormal dot direction
|
||||
// intersection = postion + scale*direction
|
||||
var hudNormal = Quat.getFront(Camera.getOrientation());
|
||||
var hudPoint = Vec3.sum(Camera.getPosition(), hudNormal); // must also scale if PLANAR_PERPENDICULAR_HUD_DISTANCE!=1
|
||||
var denominator = Vec3.dot(hudNormal, direction);
|
||||
if (denominator === 0) {
|
||||
return null;
|
||||
} // parallel to plane
|
||||
var numerator = Vec3.dot(hudNormal, Vec3.subtract(hudPoint, position));
|
||||
var scale = numerator / denominator;
|
||||
return Vec3.sum(position, Vec3.multiply(scale, direction));
|
||||
}
|
||||
var DEGREES_TO_HALF_RADIANS = Math.PI / 360;
|
||||
function overlayFromWorldPoint(point) {
|
||||
// Answer the 2d pixel-space location in the HUD that covers the given 3D point.
|
||||
// REQUIRES: that the 3d point be on the hud surface!
|
||||
// Note that this is based on the Camera, and doesn't know anything about any
|
||||
// ray that may or may not have been used to compute the point. E.g., the
|
||||
// overlay point is NOT the intersection of some non-camera ray with the HUD.
|
||||
if (HMD.active) {
|
||||
return HMD.overlayFromWorldPoint(point);
|
||||
}
|
||||
var cameraToPoint = Vec3.subtract(point, Camera.getPosition());
|
||||
var cameraX = Vec3.dot(cameraToPoint, Quat.getRight(Camera.getOrientation()));
|
||||
var cameraY = Vec3.dot(cameraToPoint, Quat.getUp(Camera.getOrientation()));
|
||||
var size = Controller.getViewportDimensions();
|
||||
var hudHeight = 2 * Math.tan(verticalFieldOfView * DEGREES_TO_HALF_RADIANS); // must adjust if PLANAR_PERPENDICULAR_HUD_DISTANCE!=1
|
||||
var hudWidth = hudHeight * size.x / size.y;
|
||||
var horizontalFraction = (cameraX / hudWidth + 0.5);
|
||||
var verticalFraction = 1 - (cameraY / hudHeight + 0.5);
|
||||
var horizontalPixels = size.x * horizontalFraction;
|
||||
var verticalPixels = size.y * verticalFraction;
|
||||
return { x: horizontalPixels, y: verticalPixels };
|
||||
}
|
||||
|
||||
// MOUSE ACTIVITY --------
|
||||
//
|
||||
var isSeeking = false;
|
||||
var averageMouseVelocity = 0, lastIntegration = 0, lastMouse;
|
||||
var WEIGHTING = 1 / 20; // simple moving average over last 20 samples
|
||||
var ONE_MINUS_WEIGHTING = 1 - WEIGHTING;
|
||||
var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 20;
|
||||
function isShakingMouse() { // True if the person is waving the mouse around trying to find it.
|
||||
var now = Date.now(), mouse = Reticle.position, isShaking = false;
|
||||
if (lastIntegration && (lastIntegration !== now)) {
|
||||
var velocity = Vec3.length(Vec3.subtract(mouse, lastMouse)) / (now - lastIntegration);
|
||||
averageMouseVelocity = (ONE_MINUS_WEIGHTING * averageMouseVelocity) + (WEIGHTING * velocity);
|
||||
if (averageMouseVelocity > AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO) {
|
||||
isShaking = true;
|
||||
}
|
||||
}
|
||||
lastIntegration = now;
|
||||
lastMouse = mouse;
|
||||
return isShaking;
|
||||
}
|
||||
var NON_LINEAR_DIVISOR = 2;
|
||||
var MINIMUM_SEEK_DISTANCE = 0.01;
|
||||
function updateSeeking() {
|
||||
if (!Reticle.visible || isShakingMouse()) {
|
||||
isSeeking = true;
|
||||
} // e.g., if we're about to turn it on with first movement.
|
||||
if (!isSeeking) {
|
||||
return;
|
||||
}
|
||||
averageMouseVelocity = lastIntegration = 0;
|
||||
var lookAt2D = HMD.getHUDLookAtPosition2D();
|
||||
if (!lookAt2D) {
|
||||
print('Cannot seek without lookAt position');
|
||||
return;
|
||||
} // E.g., if parallel to location in HUD
|
||||
var copy = Reticle.position;
|
||||
function updateDimension(axis) {
|
||||
var distanceBetween = lookAt2D[axis] - Reticle.position[axis];
|
||||
var move = distanceBetween / NON_LINEAR_DIVISOR;
|
||||
if (Math.abs(move) < MINIMUM_SEEK_DISTANCE) {
|
||||
return false;
|
||||
}
|
||||
copy[axis] += move;
|
||||
return true;
|
||||
}
|
||||
var okX = !updateDimension('x'), okY = !updateDimension('y'); // Evaluate both. Don't short-circuit.
|
||||
if (okX && okY) {
|
||||
isSeeking = false;
|
||||
} else {
|
||||
Reticle.setPosition(copy); // Not setReticlePosition
|
||||
}
|
||||
}
|
||||
|
||||
var mouseCursorActivity = new TimeLock(5000);
|
||||
var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant
|
||||
function updateMouseActivity(isClick) {
|
||||
if (ignoreMouseActivity()) {
|
||||
return;
|
||||
}
|
||||
var now = Date.now();
|
||||
mouseCursorActivity.update(now);
|
||||
if (isClick) {
|
||||
return;
|
||||
} // Bug: mouse clicks should keep going. Just not hand controller clicks
|
||||
handControllerLockOut.update(now);
|
||||
Reticle.visible = true;
|
||||
}
|
||||
function expireMouseCursor(now) {
|
||||
if (!isPointingAtOverlay() && mouseCursorActivity.expired(now)) {
|
||||
Reticle.visible = false;
|
||||
}
|
||||
}
|
||||
function onMouseMove() {
|
||||
// Display cursor at correct depth (as in depthReticle.js), and updateMouseActivity.
|
||||
if (ignoreMouseActivity()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (HMD.active) { // set depth
|
||||
updateSeeking();
|
||||
if (isPointingAtOverlay()) {
|
||||
Reticle.setDepth(SPHERICAL_HUD_DISTANCE); // NOT CORRECT IF WE SWITCH TO OFFSET SPHERE!
|
||||
} else {
|
||||
var result = findRayIntersection(Camera.computePickRay(Reticle.position.x, Reticle.position.y));
|
||||
var depth = result.intersects ? result.distance : APPARENT_MAXIMUM_DEPTH;
|
||||
Reticle.setDepth(depth);
|
||||
}
|
||||
}
|
||||
updateMouseActivity(); // After the above, just in case the depth movement is awkward when becoming visible.
|
||||
}
|
||||
function onMouseClick() {
|
||||
updateMouseActivity(true);
|
||||
}
|
||||
setupHandler(Controller.mouseMoveEvent, onMouseMove);
|
||||
setupHandler(Controller.mousePressEvent, onMouseClick);
|
||||
setupHandler(Controller.mouseDoublePressEvent, onMouseClick);
|
||||
|
||||
// CONTROLLER MAPPING ---------
|
||||
//
|
||||
|
||||
var activeHand = Controller.Standard.RightHand;
|
||||
function toggleHand() {
|
||||
if (activeHand === Controller.Standard.RightHand) {
|
||||
activeHand = Controller.Standard.LeftHand;
|
||||
} else {
|
||||
activeHand = Controller.Standard.RightHand;
|
||||
}
|
||||
}
|
||||
|
||||
// Create clickMappings as needed, on demand.
|
||||
var clickMappings = {}, clickMapping, clickMapToggle;
|
||||
var hardware; // undefined
|
||||
function checkHardware() {
|
||||
var newHardware = Controller.Hardware.Hydra ? 'Hydra' : (Controller.Hardware.Vive ? 'Vive' : null); // not undefined
|
||||
if (hardware === newHardware) {
|
||||
return;
|
||||
}
|
||||
print('Setting mapping for new controller hardware:', newHardware);
|
||||
if (clickMapToggle) {
|
||||
clickMapToggle.setState(false);
|
||||
}
|
||||
hardware = newHardware;
|
||||
if (clickMappings[hardware]) {
|
||||
clickMapping = clickMappings[hardware];
|
||||
} else {
|
||||
clickMapping = Controller.newMapping(Script.resolvePath('') + '-click-' + hardware);
|
||||
Script.scriptEnding.connect(clickMapping.disable);
|
||||
function mapToAction(button, action) {
|
||||
clickMapping.from(Controller.Hardware[hardware][button]).peek().to(Controller.Actions[action]);
|
||||
}
|
||||
function makeHandToggle(button, hand, optionalWhen) {
|
||||
var whenThunk = optionalWhen || function () {
|
||||
return true;
|
||||
};
|
||||
function maybeToggle() {
|
||||
if (activeHand !== Controller.Standard[hand]) {
|
||||
toggleHand();
|
||||
}
|
||||
|
||||
}
|
||||
clickMapping.from(Controller.Hardware[hardware][button]).peek().when(whenThunk).to(maybeToggle);
|
||||
}
|
||||
function makeViveWhen(click, x, y) {
|
||||
var viveClick = Controller.Hardware.Vive[click],
|
||||
viveX = Controller.Standard[x], // Standard after filtering by mapping
|
||||
viveY = Controller.Standard[y];
|
||||
return function () {
|
||||
var clickValue = Controller.getValue(viveClick);
|
||||
var xValue = Controller.getValue(viveX);
|
||||
var yValue = Controller.getValue(viveY);
|
||||
return clickValue && !xValue && !yValue;
|
||||
};
|
||||
}
|
||||
switch (hardware) {
|
||||
case 'Hydra':
|
||||
makeHandToggle('R3', 'RightHand');
|
||||
makeHandToggle('L3', 'LeftHand');
|
||||
|
||||
mapToAction('R3', 'ReticleClick');
|
||||
mapToAction('L3', 'ReticleClick');
|
||||
mapToAction('R4', 'ContextMenu');
|
||||
mapToAction('L4', 'ContextMenu');
|
||||
break;
|
||||
case 'Vive':
|
||||
// When touchpad click is NOT treated as movement, treat as left click
|
||||
makeHandToggle('RS', 'RightHand', makeViveWhen('RS', 'RX', 'RY'));
|
||||
makeHandToggle('LS', 'LeftHand', makeViveWhen('LS', 'LX', 'LY'));
|
||||
clickMapping.from(Controller.Hardware.Vive.RS).when(makeViveWhen('RS', 'RX', 'RY')).to(Controller.Actions.ReticleClick);
|
||||
clickMapping.from(Controller.Hardware.Vive.LS).when(makeViveWhen('LS', 'LX', 'LY')).to(Controller.Actions.ReticleClick);
|
||||
mapToAction('RightApplicationMenu', 'ContextMenu');
|
||||
mapToAction('LeftApplicationMenu', 'ContextMenu');
|
||||
break;
|
||||
}
|
||||
clickMappings[hardware] = clickMapping;
|
||||
}
|
||||
clickMapToggle = new LatchedToggle(clickMapping.enable, clickMapping.disable);
|
||||
clickMapToggle.setState(true);
|
||||
}
|
||||
checkHardware();
|
||||
|
||||
// VISUAL AID -----------
|
||||
// Same properties as handControllerGrab search sphere
|
||||
var BALL_SIZE = 0.011;
|
||||
var BALL_ALPHA = 0.5;
|
||||
var fakeProjectionBall = Overlays.addOverlay("sphere", {
|
||||
size: 5 * BALL_SIZE,
|
||||
color: {red: 255, green: 10, blue: 10},
|
||||
ignoreRayIntersection: true,
|
||||
alpha: BALL_ALPHA,
|
||||
visible: false,
|
||||
solid: true,
|
||||
drawInFront: true // Even when burried inside of something, show it.
|
||||
});
|
||||
var overlays = [fakeProjectionBall]; // If we want to try showing multiple balls and lasers.
|
||||
Script.scriptEnding.connect(function () {
|
||||
overlays.forEach(Overlays.deleteOverlay);
|
||||
});
|
||||
var visualizationIsShowing = false; // Not whether it desired, but simply whether it is. Just an optimziation.
|
||||
function turnOffVisualization(optionalEnableClicks) { // because we're showing cursor on HUD
|
||||
if (!optionalEnableClicks) {
|
||||
expireMouseCursor();
|
||||
}
|
||||
if (!visualizationIsShowing) {
|
||||
return;
|
||||
}
|
||||
visualizationIsShowing = false;
|
||||
overlays.forEach(function (overlay) {
|
||||
Overlays.editOverlay(overlay, {visible: false});
|
||||
});
|
||||
}
|
||||
var MAX_RAY_SCALE = 32000; // Anything large. It's a scale, not a distance.
|
||||
function updateVisualization(controllerPosition, controllerDirection, hudPosition3d, hudPosition2d) {
|
||||
// Show an indication of where the cursor will appear when crossing a HUD element,
|
||||
// and where in-world clicking will occur.
|
||||
//
|
||||
// There are a number of ways we could do this, but for now, it's a blue sphere that rolls along
|
||||
// the HUD surface, and a red sphere that rolls along the 3d objects that will receive the click.
|
||||
// We'll leave it to other scripts (like handControllerGrab) to show a search beam when desired.
|
||||
|
||||
function intersection3d(position, direction) {
|
||||
// Answer in-world intersection (entity or 3d overlay), or way-out point
|
||||
var pickRay = {origin: position, direction: direction};
|
||||
var result = findRayIntersection(pickRay);
|
||||
return result.intersects ? result.intersection : Vec3.sum(position, Vec3.multiply(MAX_RAY_SCALE, direction));
|
||||
}
|
||||
|
||||
visualizationIsShowing = true;
|
||||
// We'd rather in-world interactions be done at the termination of the hand beam
|
||||
// -- intersection3d(controllerPosition, controllerDirection). Maybe have handControllerGrab
|
||||
// direclty manipulate both entity and 3d overlay objects.
|
||||
// For now, though, we present a false projection of the cursor onto whatever is below it. This is
|
||||
// different from the hand beam termination because the false projection is from the camera, while
|
||||
// the hand beam termination is from the hand.
|
||||
var eye = Camera.getPosition();
|
||||
var falseProjection = intersection3d(eye, Vec3.subtract(hudPosition3d, eye));
|
||||
Overlays.editOverlay(fakeProjectionBall, {visible: true, position: falseProjection});
|
||||
Reticle.visible = false;
|
||||
|
||||
return visualizationIsShowing; // In case we change caller to act conditionally.
|
||||
}
|
||||
|
||||
// MAIN OPERATIONS -----------
|
||||
//
|
||||
function update() {
|
||||
var now = Date.now();
|
||||
if (!handControllerLockOut.expired(now)) {
|
||||
return turnOffVisualization();
|
||||
} // Let them use mouse it in peace.
|
||||
if (!Menu.isOptionChecked("First Person")) {
|
||||
return turnOffVisualization();
|
||||
} // What to do? menus can be behind hand!
|
||||
var controllerPose = Controller.getPoseValue(activeHand);
|
||||
// Vive is effectively invalid when not in HMD
|
||||
if (!controllerPose.valid || ((hardware === 'Vive') && !HMD.active)) {
|
||||
return turnOffVisualization();
|
||||
} // Controller is cradled.
|
||||
var controllerPosition = Vec3.sum(Vec3.multiplyQbyV(MyAvatar.orientation, controllerPose.translation),
|
||||
MyAvatar.position);
|
||||
// This gets point direction right, but if you want general quaternion it would be more complicated:
|
||||
var controllerDirection = Quat.getUp(Quat.multiply(MyAvatar.orientation, controllerPose.rotation));
|
||||
|
||||
var hudPoint3d = calculateRayUICollisionPoint(controllerPosition, controllerDirection);
|
||||
if (!hudPoint3d) {
|
||||
print('Controller is parallel to HUD');
|
||||
return turnOffVisualization();
|
||||
}
|
||||
var hudPoint2d = overlayFromWorldPoint(hudPoint3d);
|
||||
|
||||
// We don't know yet if we'll want to make the cursor visble, but we need to move it to see if
|
||||
// it's pointing at a QML tool (aka system overlay).
|
||||
setReticlePosition(hudPoint2d);
|
||||
// If there's a HUD element at the (newly moved) reticle, just make it visible and bail.
|
||||
if (isPointingAtOverlay(hudPoint2d)) {
|
||||
if (HMD.active) { // Doesn't hurt anything without the guard, but consider it documentation.
|
||||
Reticle.depth = SPHERICAL_HUD_DISTANCE; // NOT CORRECT IF WE SWITCH TO OFFSET SPHERE!
|
||||
}
|
||||
Reticle.visible = true;
|
||||
return turnOffVisualization(true);
|
||||
}
|
||||
// We are not pointing at a HUD element (but it could be a 3d overlay).
|
||||
updateVisualization(controllerPosition, controllerDirection, hudPoint3d, hudPoint2d);
|
||||
}
|
||||
|
||||
var UPDATE_INTERVAL = 20; // milliseconds. Script.update is too frequent.
|
||||
var updater = Script.setInterval(update, UPDATE_INTERVAL);
|
||||
Script.scriptEnding.connect(function () {
|
||||
Script.clearInterval(updater);
|
||||
});
|
||||
|
||||
// Check periodically for changes to setup.
|
||||
var SETTINGS_CHANGE_RECHECK_INTERVAL = 10 * 1000; // milliseconds
|
||||
function checkSettings() {
|
||||
updateFieldOfView();
|
||||
checkHardware();
|
||||
}
|
||||
checkSettings();
|
||||
var settingsChecker = Script.setInterval(checkSettings, SETTINGS_CHANGE_RECHECK_INTERVAL);
|
||||
Script.scriptEnding.connect(function () {
|
||||
Script.clearInterval(settingsChecker);
|
||||
});
|
|
@ -1,185 +0,0 @@
|
|||
// depthReticle.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2/23/16.
|
||||
// Copyright 2016 High Fidelity, Inc.
|
||||
//
|
||||
// When used in HMD, this script will make the reticle depth track to any clickable item in view.
|
||||
// This script also handles auto-hiding the reticle after inactivity, as well as having the reticle
|
||||
// seek the look at position upon waking up.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var APPARENT_2D_OVERLAY_DEPTH = 1.0;
|
||||
var APPARENT_MAXIMUM_DEPTH = 100.0; // this is a depth at which things all seem sufficiently distant
|
||||
var lastDepthCheckTime = Date.now();
|
||||
var desiredDepth = APPARENT_2D_OVERLAY_DEPTH;
|
||||
var TIME_BETWEEN_DEPTH_CHECKS = 100;
|
||||
var MINIMUM_DEPTH_ADJUST = 0.01;
|
||||
var NON_LINEAR_DIVISOR = 2;
|
||||
var MINIMUM_SEEK_DISTANCE = 0.01;
|
||||
|
||||
var lastMouseMoveOrClick = Date.now();
|
||||
var lastMouseX = Reticle.position.x;
|
||||
var lastMouseY = Reticle.position.y;
|
||||
var HIDE_STATIC_MOUSE_AFTER = 3000; // 3 seconds
|
||||
var shouldSeekToLookAt = false;
|
||||
var fastMouseMoves = 0;
|
||||
var averageMouseVelocity = 0;
|
||||
var WEIGHTING = 1/20; // simple moving average over last 20 samples
|
||||
var ONE_MINUS_WEIGHTING = 1 - WEIGHTING;
|
||||
var AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO = 50;
|
||||
|
||||
function showReticleOnMouseClick() {
|
||||
Reticle.visible = true;
|
||||
lastMouseMoveOrClick = Date.now(); // move or click
|
||||
}
|
||||
|
||||
Controller.mousePressEvent.connect(showReticleOnMouseClick);
|
||||
Controller.mouseDoublePressEvent.connect(showReticleOnMouseClick);
|
||||
|
||||
Controller.mouseMoveEvent.connect(function(mouseEvent) {
|
||||
var now = Date.now();
|
||||
|
||||
// if the reticle is hidden, and we're not in away mode...
|
||||
if (!Reticle.visible && Reticle.allowMouseCapture) {
|
||||
Reticle.visible = true;
|
||||
if (HMD.active) {
|
||||
shouldSeekToLookAt = true;
|
||||
}
|
||||
} else {
|
||||
// even if the reticle is visible, if we're in HMD mode, and the person is moving their mouse quickly (shaking it)
|
||||
// then they are probably looking for it, and we should move into seekToLookAt mode
|
||||
if (HMD.active && !shouldSeekToLookAt && Reticle.allowMouseCapture) {
|
||||
var dx = Reticle.position.x - lastMouseX;
|
||||
var dy = Reticle.position.y - lastMouseY;
|
||||
var dt = Math.max(1, (now - lastMouseMoveOrClick)); // mSecs since last mouse move
|
||||
var mouseMoveDistance = Math.sqrt((dx*dx) + (dy*dy));
|
||||
var mouseVelocity = mouseMoveDistance / dt;
|
||||
averageMouseVelocity = (ONE_MINUS_WEIGHTING * averageMouseVelocity) + (WEIGHTING * mouseVelocity);
|
||||
if (averageMouseVelocity > AVERAGE_MOUSE_VELOCITY_FOR_SEEK_TO) {
|
||||
shouldSeekToLookAt = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
lastMouseMoveOrClick = now;
|
||||
lastMouseX = mouseEvent.x;
|
||||
lastMouseY = mouseEvent.y;
|
||||
});
|
||||
|
||||
function seekToLookAt() {
|
||||
// if we're currently seeking the lookAt move the mouse toward the lookat
|
||||
if (shouldSeekToLookAt) {
|
||||
averageMouseVelocity = 0; // reset this, these never count for movement...
|
||||
var lookAt2D = HMD.getHUDLookAtPosition2D();
|
||||
var currentReticlePosition = Reticle.position;
|
||||
var distanceBetweenX = lookAt2D.x - Reticle.position.x;
|
||||
var distanceBetweenY = lookAt2D.y - Reticle.position.y;
|
||||
var moveX = distanceBetweenX / NON_LINEAR_DIVISOR;
|
||||
var moveY = distanceBetweenY / NON_LINEAR_DIVISOR;
|
||||
var newPosition = { x: Reticle.position.x + moveX, y: Reticle.position.y + moveY };
|
||||
var closeEnoughX = false;
|
||||
var closeEnoughY = false;
|
||||
if (moveX < MINIMUM_SEEK_DISTANCE) {
|
||||
newPosition.x = lookAt2D.x;
|
||||
closeEnoughX = true;
|
||||
}
|
||||
if (moveY < MINIMUM_SEEK_DISTANCE) {
|
||||
newPosition.y = lookAt2D.y;
|
||||
closeEnoughY = true;
|
||||
}
|
||||
Reticle.position = newPosition;
|
||||
if (closeEnoughX && closeEnoughY) {
|
||||
shouldSeekToLookAt = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function autoHideReticle() {
|
||||
var now = Date.now();
|
||||
|
||||
// sometimes we don't actually get mouse move messages (for example, if the focus has been set
|
||||
// to an overlay or web page 'overlay') in but the mouse can still be moving, and we don't want
|
||||
// to autohide in these cases, so we will take this opportunity to also check if the reticle
|
||||
// position has changed.
|
||||
if (lastMouseX != Reticle.position.x || lastMouseY != Reticle.position.y) {
|
||||
lastMouseMoveOrClick = now;
|
||||
lastMouseX = Reticle.position.x;
|
||||
lastMouseY = Reticle.position.y;
|
||||
}
|
||||
|
||||
// if we haven't moved in a long period of time, and we're not pointing at some
|
||||
// system overlay (like a window), then hide the reticle
|
||||
if (Reticle.visible && !Reticle.pointingAtSystemOverlay) {
|
||||
var timeSinceLastMouseMove = now - lastMouseMoveOrClick;
|
||||
if (timeSinceLastMouseMove > HIDE_STATIC_MOUSE_AFTER) {
|
||||
Reticle.visible = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function checkReticleDepth() {
|
||||
var now = Date.now();
|
||||
var timeSinceLastDepthCheck = now - lastDepthCheckTime;
|
||||
if (timeSinceLastDepthCheck > TIME_BETWEEN_DEPTH_CHECKS && Reticle.visible) {
|
||||
var newDesiredDepth = desiredDepth;
|
||||
lastDepthCheckTime = now;
|
||||
var reticlePosition = Reticle.position;
|
||||
|
||||
// first check the 2D Overlays
|
||||
if (Reticle.pointingAtSystemOverlay || Overlays.getOverlayAtPoint(reticlePosition)) {
|
||||
newDesiredDepth = APPARENT_2D_OVERLAY_DEPTH;
|
||||
} else {
|
||||
var pickRay = Camera.computePickRay(reticlePosition.x, reticlePosition.y);
|
||||
|
||||
// Then check the 3D overlays
|
||||
var result = Overlays.findRayIntersection(pickRay);
|
||||
|
||||
if (!result.intersects) {
|
||||
// finally check the entities
|
||||
result = Entities.findRayIntersection(pickRay, true);
|
||||
}
|
||||
|
||||
// If either the overlays or entities intersect, then set the reticle depth to
|
||||
// the distance of intersection
|
||||
if (result.intersects) {
|
||||
newDesiredDepth = result.distance;
|
||||
} else {
|
||||
// if nothing intersects... set the depth to some sufficiently large depth
|
||||
newDesiredDepth = APPARENT_MAXIMUM_DEPTH;
|
||||
}
|
||||
}
|
||||
|
||||
// If the desired depth has changed, reset our fade start time
|
||||
if (desiredDepth != newDesiredDepth) {
|
||||
desiredDepth = newDesiredDepth;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function moveToDesiredDepth() {
|
||||
// move the reticle toward the desired depth
|
||||
if (desiredDepth != Reticle.depth) {
|
||||
|
||||
// cut distance between desiredDepth and current depth in half until we're close enough
|
||||
var distanceToAdjustThisCycle = (desiredDepth - Reticle.depth) / NON_LINEAR_DIVISOR;
|
||||
if (Math.abs(distanceToAdjustThisCycle) < MINIMUM_DEPTH_ADJUST) {
|
||||
newDepth = desiredDepth;
|
||||
} else {
|
||||
newDepth = Reticle.depth + distanceToAdjustThisCycle;
|
||||
}
|
||||
Reticle.setDepth(newDepth);
|
||||
}
|
||||
}
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
autoHideReticle(); // auto hide reticle for desktop or HMD mode
|
||||
if (HMD.active) {
|
||||
seekToLookAt(); // handle moving the reticle toward the look at
|
||||
checkReticleDepth(); // make sure reticle is at correct depth
|
||||
moveToDesiredDepth(); // move the fade the reticle to the desired depth
|
||||
}
|
||||
});
|
|
@ -91,7 +91,7 @@ public:
|
|||
virtual QOpenGLContext* getPrimaryContext() override { return nullptr; }
|
||||
virtual ui::Menu* getPrimaryMenu() { return nullptr; }
|
||||
virtual bool isForeground() override { return true; }
|
||||
virtual const DisplayPlugin* getActiveDisplayPlugin() const override { return nullptr; }
|
||||
virtual const DisplayPluginPointer getActiveDisplayPlugin() const override { return DisplayPluginPointer(); }
|
||||
};
|
||||
|
||||
class MyControllerScriptingInterface : public controller::ScriptingInterface {
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <render-utils/simple_vert.h>
|
||||
#include <render-utils/simple_frag.h>
|
||||
#include <render-utils/simple_textured_frag.h>
|
||||
#include <render-utils/simple_textured_emisive_frag.h>
|
||||
#include <render-utils/simple_textured_unlit_frag.h>
|
||||
|
||||
#include <render-utils/deferred_light_vert.h>
|
||||
#include <render-utils/deferred_light_limited_vert.h>
|
||||
|
@ -160,7 +160,7 @@ void QTestWindow::draw() {
|
|||
testShaderBuild(skybox_vert, skybox_frag);
|
||||
testShaderBuild(simple_vert, simple_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_emisive_frag);
|
||||
testShaderBuild(simple_vert, simple_textured_unlit_frag);
|
||||
testShaderBuild(deferred_light_vert, directional_light_frag);
|
||||
testShaderBuild(deferred_light_vert, directional_ambient_light_frag);
|
||||
testShaderBuild(deferred_light_vert, directional_skybox_light_frag);
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
#include "TextTemplate.h"
|
||||
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <ctime>
|
||||
#include <chrono>
|
||||
|
||||
|
@ -168,7 +169,7 @@ int main (int argc, char** argv) {
|
|||
auto scribe = std::make_shared<TextTemplate>(srcFilename, config);
|
||||
|
||||
// ready to parse and generate
|
||||
std::ostringstream destStringStream;
|
||||
std::stringstream destStringStream;
|
||||
int numErrors = scribe->scribe(destStringStream, srcStream, vars);
|
||||
if (numErrors) {
|
||||
cerr << "Scribe " << srcFilename << "> failed: " << numErrors << " errors." << endl;
|
||||
|
@ -187,14 +188,38 @@ int main (int argc, char** argv) {
|
|||
|
||||
std::ostringstream targetStringStream;
|
||||
if (makeCPlusPlus) {
|
||||
// Because there is a maximum size for literal strings declared in source we need to partition the
|
||||
// full source string stream into pages that seems to be around that value...
|
||||
const int MAX_STRING_LITERAL = 10000;
|
||||
std::string lineToken;
|
||||
auto pageSize = lineToken.length();
|
||||
std::vector<std::shared_ptr<std::stringstream>> pages(1, std::make_shared<std::stringstream>());
|
||||
while (!destStringStream.eof()) {
|
||||
std::getline(destStringStream, lineToken);
|
||||
auto lineSize = lineToken.length() + 1;
|
||||
|
||||
if (pageSize + lineSize > MAX_STRING_LITERAL) {
|
||||
pages.push_back(std::make_shared<std::stringstream>());
|
||||
// reset pageStringStream
|
||||
pageSize = 0;
|
||||
}
|
||||
|
||||
(*pages.back()) << lineToken << std::endl;
|
||||
pageSize += lineSize;
|
||||
}
|
||||
|
||||
targetStringStream << "// File generated by Scribe " << vars["_SCRIBE_DATE"] << std::endl;
|
||||
targetStringStream << "#ifndef scribe_" << targetName << "_h" << std::endl;
|
||||
targetStringStream << "#define scribe_" << targetName << "_h" << std::endl << std::endl;
|
||||
|
||||
// targetStringStream << "const char " << targetName << "[] = R\"XXXX(" << destStringStream.str() << ")XXXX\";";
|
||||
targetStringStream << "const char " << targetName << "[] = R\"SCRIBE(";
|
||||
targetStringStream << destStringStream.str();
|
||||
targetStringStream << "\n)SCRIBE\";\n\n";
|
||||
targetStringStream << "const char " << targetName << "[] = \n";
|
||||
|
||||
// Write the pages content
|
||||
for (auto page : pages) {
|
||||
targetStringStream << "R\"SCRIBE(\n" << page->str() << "\n)SCRIBE\"\n";
|
||||
}
|
||||
targetStringStream << ";\n" << std::endl << std::endl;
|
||||
|
||||
targetStringStream << "#endif" << std::endl;
|
||||
} else {
|
||||
targetStringStream << destStringStream.str();
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
var MINUTE_HAND_CLOCK_SCRIPT_URL = Script.resolvePath("cuckooClockMinuteHandEntityScript.js" )
|
||||
var MINUTE_HAND_CLOCK_SCRIPT_URL = Script.resolvePath("cuckooClockMinuteHandEntityScript.js")
|
||||
var CLOCK_BODY_URL = "atp:/cuckooClock/cuckoo2_BODY.fbx";
|
||||
var CLOCK_BODY_COLLISION_HULL_URL = "atp:/cuckooClock/clockHull.obj";
|
||||
var CLOCK_FACE_URL = "atp:/cuckooClock/cuckooClock2_FACE.fbx";
|
||||
|
@ -38,11 +38,11 @@ MyCuckooClock = function(spawnPosition, spawnRotation) {
|
|||
},
|
||||
position: spawnPosition,
|
||||
rotation: clockRotation,
|
||||
dimensions: {
|
||||
dimensions: Vec3.multiply(0.5, {
|
||||
x: 0.8181,
|
||||
y: 1.3662,
|
||||
z: 0.8181
|
||||
},
|
||||
}),
|
||||
userData: JSON.stringify({
|
||||
hifiHomeKey: {
|
||||
reset: true
|
||||
|
@ -50,9 +50,9 @@ MyCuckooClock = function(spawnPosition, spawnRotation) {
|
|||
})
|
||||
})
|
||||
|
||||
var forwardOffset = -0.13
|
||||
var upOffset = 0.255;
|
||||
var sideOffset = -0.03;
|
||||
var forwardOffset = 0.5 * -0.13;
|
||||
var upOffset = 0.5 * 0.255;
|
||||
var sideOffset = 0.5 * -0.03;
|
||||
var clockFacePosition = spawnPosition;
|
||||
clockFacePosition = Vec3.sum(clockFacePosition, Vec3.multiply(Quat.getFront(clockRotation), forwardOffset));
|
||||
clockFacePosition = Vec3.sum(clockFacePosition, Vec3.multiply(Quat.getUp(clockRotation), upOffset));
|
||||
|
@ -65,11 +65,11 @@ MyCuckooClock = function(spawnPosition, spawnRotation) {
|
|||
name: "home_model_clockFace",
|
||||
modelURL: CLOCK_FACE_URL,
|
||||
position: clockFacePosition,
|
||||
dimensions: {
|
||||
dimensions: Vec3.multiply(0.5, {
|
||||
x: 0.2397,
|
||||
y: 0.2402,
|
||||
z: 0.0212
|
||||
},
|
||||
}),
|
||||
userData: JSON.stringify({
|
||||
hifiHomeKey: {
|
||||
reset: true
|
||||
|
@ -86,7 +86,7 @@ MyCuckooClock = function(spawnPosition, spawnRotation) {
|
|||
|
||||
var myDate = new Date()
|
||||
// HOUR HAND *************************
|
||||
var clockHandForwardOffset = -0.017;
|
||||
var clockHandForwardOffset = (0.5 * -0.017);
|
||||
|
||||
|
||||
var hourHandPosition = Vec3.sum(clockFacePosition, Vec3.multiply(Quat.getFront(clockRotation), clockHandForwardOffset));
|
||||
|
@ -118,11 +118,11 @@ MyCuckooClock = function(spawnPosition, spawnRotation) {
|
|||
rotation: worldClockHandRotation,
|
||||
angularDamping: 0,
|
||||
angularVelocity: worldAngularVelocity,
|
||||
dimensions: {
|
||||
dimensions: Vec3.multiply(0.5, {
|
||||
x: 0.0263,
|
||||
y: 0.0982,
|
||||
z: 0.0024
|
||||
},
|
||||
}),
|
||||
userData: JSON.stringify({
|
||||
hifiHomeKey: {
|
||||
reset: true
|
||||
|
@ -150,11 +150,11 @@ MyCuckooClock = function(spawnPosition, spawnRotation) {
|
|||
modelURL: CLOCK_SECOND_HAND_URL,
|
||||
name: "home_model_clockSecondHand",
|
||||
position: hourHandPosition,
|
||||
dimensions: {
|
||||
dimensions: Vec3.multiply(0.5, {
|
||||
x: 0.0043,
|
||||
y: 0.1117,
|
||||
z: 0.0008
|
||||
},
|
||||
}),
|
||||
color: {
|
||||
red: 200,
|
||||
green: 10,
|
||||
|
@ -202,14 +202,14 @@ MyCuckooClock = function(spawnPosition, spawnRotation) {
|
|||
y: 0.05,
|
||||
z: 0.5
|
||||
},
|
||||
rotation:worldClockHandRotation,
|
||||
rotation: worldClockHandRotation,
|
||||
angularDamping: 0,
|
||||
angularVelocity: worldAngularVelocity,
|
||||
dimensions: {
|
||||
dimensions: Vec3.multiply(0.5, {
|
||||
x: 0.0251,
|
||||
y: 0.1179,
|
||||
z: 0.0032
|
||||
},
|
||||
}),
|
||||
script: MINUTE_HAND_CLOCK_SCRIPT_URL,
|
||||
userData: JSON.stringify({
|
||||
clockBody: clockBody,
|
||||
|
|
165
unpublishedScripts/DomainContent/Home/firePit/fire.js
Normal file
165
unpublishedScripts/DomainContent/Home/firePit/fire.js
Normal file
|
@ -0,0 +1,165 @@
|
|||
// this script turns an entity into an exploder -- anything that collides with it will be vaporized!
|
||||
//
|
||||
//
|
||||
|
||||
(function() {
|
||||
|
||||
var _this = this;
|
||||
|
||||
function Fire() {
|
||||
_this = this;
|
||||
}
|
||||
|
||||
var RED = {
|
||||
red: 255,
|
||||
green: 0,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var ORANGE = {
|
||||
red: 255,
|
||||
green: 165,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var YELLOW = {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var GREEN = {
|
||||
red: 0,
|
||||
green: 255,
|
||||
blue: 0
|
||||
};
|
||||
|
||||
var BLUE = {
|
||||
red: 0,
|
||||
green: 0,
|
||||
blue: 255
|
||||
};
|
||||
|
||||
var INDIGO = {
|
||||
red: 128,
|
||||
green: 0,
|
||||
blue: 128
|
||||
};
|
||||
|
||||
var VIOLET = {
|
||||
red: 75,
|
||||
green: 0,
|
||||
blue: 130
|
||||
};
|
||||
|
||||
var colors = [RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET];
|
||||
|
||||
Fire.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.EXPLOSION_SOUND = SoundCache.getSound("atp:/firepit/fire_burst.wav");
|
||||
|
||||
},
|
||||
collisionWithEntity: function(myID, otherID, collisionInfo) {
|
||||
var otherProps = Entities.getEntityProperties(otherID);
|
||||
var data = null;
|
||||
try {
|
||||
data = JSON.parse(otherProps.userData)
|
||||
} catch (err) {
|
||||
print('ERROR GETTING USERDATA!');
|
||||
}
|
||||
if (data === null || "") {
|
||||
return;
|
||||
} else {
|
||||
if (data.hasOwnProperty('hifiHomeKey')) {
|
||||
if (data.hifiHomeKey.reset === true) {
|
||||
print('FLAMMABLE THING, EXPLODE IT!');
|
||||
_this.playSoundAtCurrentPosition();
|
||||
_this.explodeWithColor();
|
||||
_this.smokePuff();
|
||||
Entities.deleteEntity(otherID)
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
explodeWithColor: function() {
|
||||
print('EXPLODE!')
|
||||
var myProps = Entities.getEntityProperties(this.entityID);
|
||||
var color = colors[Math.floor(Math.random() * colors.length)];
|
||||
var explosionParticleProperties = {
|
||||
"color": color,
|
||||
"isEmitting": 1,
|
||||
"maxParticles": 1000,
|
||||
"lifespan": 0.25,
|
||||
"emitRate": 1,
|
||||
"emitSpeed": 0.1,
|
||||
"speedSpread": 1,
|
||||
"emitOrientation": Quat.getUp(myProps.rotation),
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"polarStart": 0,
|
||||
"polarFinish": 0,
|
||||
"azimuthStart": 0,
|
||||
"azimuthFinish": 0,
|
||||
"emitAcceleration": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.829,
|
||||
"radiusSpread": 0,
|
||||
"radiusStart": 0.361,
|
||||
"radiusFinish": 0.294,
|
||||
"colorSpread": {
|
||||
"red": 0,
|
||||
"green": 0,
|
||||
"blue": 0
|
||||
},
|
||||
"colorStart": {
|
||||
"red": 255,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
},
|
||||
"colorFinish": {
|
||||
"red": 255,
|
||||
"green": 255,
|
||||
"blue": 255
|
||||
},
|
||||
"alpha": 1,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": -0.2,
|
||||
"alphaFinish": 0.5,
|
||||
"emitterShouldTrail": 0,
|
||||
"textures": "atp:/firepit/explode.png",
|
||||
"type": "ParticleEffect",
|
||||
lifetime: 1,
|
||||
position: myProps.position
|
||||
};
|
||||
|
||||
var explosion = Entities.addEntity(explosionParticleProperties);
|
||||
print('explosion is: ' + explosion)
|
||||
},
|
||||
smokePuff: function() {
|
||||
//smoke puff here
|
||||
},
|
||||
playSoundAtCurrentPosition: function() {
|
||||
|
||||
var audioProperties = {
|
||||
volume: 0.5,
|
||||
position: Entities.getEntityProperties(this.entityID).position
|
||||
};
|
||||
|
||||
Audio.playSound(this.EXPLOSION_SOUND, audioProperties);
|
||||
},
|
||||
}
|
||||
|
||||
return new Fire();
|
||||
});
|
51
unpublishedScripts/DomainContent/Home/firePit/flicker.js
Normal file
51
unpublishedScripts/DomainContent/Home/firePit/flicker.js
Normal file
|
@ -0,0 +1,51 @@
|
|||
(function() {
|
||||
|
||||
var MINIMUM_LIGHT_INTENSITY = 50.0;
|
||||
var MAXIMUM_LIGHT_INTENSITY = 200.0;
|
||||
var LIGHT_FALLOFF_RADIUS = 0.1;
|
||||
var LIGHT_INTENSITY_RANDOMNESS = 0.1;
|
||||
|
||||
function randFloat(low, high) {
|
||||
return low + Math.random() * (high - low);
|
||||
}
|
||||
|
||||
var _this;
|
||||
|
||||
function FlickeringFlame() {
|
||||
_this = this;
|
||||
}
|
||||
|
||||
var totalTime = 0;
|
||||
var spacer = 2;
|
||||
FlickeringFlame.prototype = {
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
Script.update.connect(this.update);
|
||||
},
|
||||
update: function(deltaTime) {
|
||||
|
||||
totalTime += deltaTime;
|
||||
if (totalTime > spacer) {
|
||||
var howManyAvatars = AvatarList.getAvatarIdentifiers().length;
|
||||
var intensity = (MINIMUM_LIGHT_INTENSITY + (MAXIMUM_LIGHT_INTENSITY + (Math.sin(totalTime) * MAXIMUM_LIGHT_INTENSITY)));
|
||||
intensity += randFloat(-LIGHT_INTENSITY_RANDOMNESS, LIGHT_INTENSITY_RANDOMNESS);
|
||||
|
||||
Entities.editEntity(_this.entityID, {
|
||||
intensity: intensity
|
||||
});
|
||||
|
||||
spacer = Math.random(0, 100) * (2 / howManyAvatars);
|
||||
totalTime = 0;
|
||||
} else {
|
||||
//just keep counting
|
||||
}
|
||||
},
|
||||
unload: function() {
|
||||
Script.update.disconnect(this.update)
|
||||
}
|
||||
}
|
||||
|
||||
return new FlickeringFlame
|
||||
|
||||
|
||||
});
|
|
@ -37,14 +37,10 @@
|
|||
|
||||
var whiteboardPath = Script.resolvePath("atp:/whiteboard/wrapper.js");
|
||||
|
||||
var plantPath = Script.resolvePath("atp:/growingPlant/wrapper.js");
|
||||
|
||||
var cuckooClockPath = Script.resolvePath("atp:/cuckooClock/wrapper.js");
|
||||
|
||||
var pingPongGunPath = Script.resolvePath("atp:/pingPongGun/wrapper.js");
|
||||
|
||||
var musicBoxPath = Script.resolvePath("musicBox/wrapper.js?" + Math.random());
|
||||
|
||||
var transformerPath = Script.resolvePath("atp:/dressingRoom/wrapper.js");
|
||||
|
||||
Script.include(utilsPath);
|
||||
|
@ -54,10 +50,8 @@
|
|||
Script.include(fishTankPath);
|
||||
Script.include(tiltMazePath);
|
||||
Script.include(whiteboardPath);
|
||||
Script.include(plantPath);
|
||||
Script.include(cuckooClockPath);
|
||||
Script.include(pingPongGunPath);
|
||||
// Script.include(musicBoxPath);
|
||||
Script.include(transformerPath);
|
||||
|
||||
var TRANSFORMER_URL_ROBOT = 'atp:/dressingRoom/simple_robot.fbx';
|
||||
|
@ -204,23 +198,13 @@
|
|||
});
|
||||
|
||||
var whiteboard = new Whiteboard({
|
||||
x: 1104,
|
||||
y: 460.5,
|
||||
z: -77
|
||||
x: 1105.0955,
|
||||
y: 460.5000,
|
||||
z: -77.4409
|
||||
}, {
|
||||
x: 0,
|
||||
y: -133,
|
||||
z: 0
|
||||
});
|
||||
|
||||
var myPlant = new Plant({
|
||||
x: 1099.8785,
|
||||
y: 460.3115,
|
||||
z: -84.7736
|
||||
}, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
x: -0.0013,
|
||||
y: -133.0056,
|
||||
z: -0.0013
|
||||
});
|
||||
|
||||
var pingPongGun = new HomePingPongGun({
|
||||
|
@ -234,16 +218,15 @@
|
|||
});
|
||||
|
||||
var cuckooClock = new MyCuckooClock({
|
||||
x: 1105.267,
|
||||
y: 461.44,
|
||||
z: -81.9495
|
||||
x: 1105.5237,
|
||||
y: 461.4826,
|
||||
z: -81.7524
|
||||
}, {
|
||||
x: 0,
|
||||
y: -57,
|
||||
z: 0
|
||||
x: -0.0013,
|
||||
y: -57.0089,
|
||||
z: -0.0013
|
||||
});
|
||||
|
||||
// var musicBox = new MusicBox();
|
||||
print('HOME after creating scripted entities')
|
||||
|
||||
},
|
||||
|
|
Loading…
Reference in a new issue