Merge branch 'master' of https://github.com/highfidelity/hifi into red

This commit is contained in:
samcake 2016-03-10 18:14:22 -08:00
commit 24d712b7b4
14 changed files with 197 additions and 111 deletions

View file

@ -4880,7 +4880,10 @@ void Application::updateDisplayMode() {
} }
} }
emit activeDisplayPluginChanged(); emit activeDisplayPluginChanged();
resetSensors();
// reset the avatar, to set head and hand palms back to a resonable default pose.
getMyAvatar()->reset(false);
Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin"); Q_ASSERT_X(_displayPlugin, "Application::updateDisplayMode", "could not find an activated display plugin");
} }

View file

@ -464,6 +464,8 @@ Menu::Menu() {
avatar, SLOT(setUseAnimPreAndPostRotations(bool))); avatar, SLOT(setUseAnimPreAndPostRotations(bool)));
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableInverseKinematics, 0, true, addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::EnableInverseKinematics, 0, true,
avatar, SLOT(setEnableInverseKinematics(bool))); avatar, SLOT(setEnableInverseKinematics(bool)));
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSensorToWorldMatrix, 0, false,
avatar, SLOT(setEnableDebugDrawSensorToWorldMatrix(bool)));
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::KeyboardMotorControl, addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::KeyboardMotorControl,
Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehaviorFromMenu()), Qt::CTRL | Qt::SHIFT | Qt::Key_K, true, avatar, SLOT(updateMotionBehaviorFromMenu()),

View file

@ -144,6 +144,7 @@ namespace MenuOption {
const QString RenderResolutionHalf = "1/2"; const QString RenderResolutionHalf = "1/2";
const QString RenderResolutionThird = "1/3"; const QString RenderResolutionThird = "1/3";
const QString RenderResolutionQuarter = "1/4"; const QString RenderResolutionQuarter = "1/4";
const QString RenderSensorToWorldMatrix = "Show SensorToWorld Matrix";
const QString ResetAvatarSize = "Reset Avatar Size"; const QString ResetAvatarSize = "Reset Avatar Size";
const QString ResetSensors = "Reset Sensors"; const QString ResetSensors = "Reset Sensors";
const QString RunningScripts = "Running Scripts..."; const QString RunningScripts = "Running Scripts...";

View file

@ -444,6 +444,10 @@ void MyAvatar::updateSensorToWorldMatrix() {
lateUpdatePalms(); lateUpdatePalms();
if (_enableDebugDrawSensorToWorldMatrix) {
DebugDraw::getInstance().addMarker("sensorToWorldMatrix", glmExtractRotation(_sensorToWorldMatrix), extractTranslation(_sensorToWorldMatrix), glm::vec4(1));
}
_sensorToWorldMatrixCache.set(_sensorToWorldMatrix); _sensorToWorldMatrixCache.set(_sensorToWorldMatrix);
} }
@ -698,6 +702,14 @@ void MyAvatar::setEnableDebugDrawPosition(bool isEnabled) {
} }
} }
void MyAvatar::setEnableDebugDrawSensorToWorldMatrix(bool isEnabled) {
_enableDebugDrawSensorToWorldMatrix = isEnabled;
if (!isEnabled) {
DebugDraw::getInstance().removeMarker("sensorToWorldMatrix");
}
}
void MyAvatar::setEnableMeshVisible(bool isEnabled) { void MyAvatar::setEnableMeshVisible(bool isEnabled) {
render::ScenePointer scene = qApp->getMain3DScene(); render::ScenePointer scene = qApp->getMain3DScene();
_skeletonModel.setVisibleInScene(isEnabled, scene); _skeletonModel.setVisibleInScene(isEnabled, scene);

View file

@ -271,6 +271,7 @@ public slots:
void setEnableDebugDrawDefaultPose(bool isEnabled); void setEnableDebugDrawDefaultPose(bool isEnabled);
void setEnableDebugDrawAnimPose(bool isEnabled); void setEnableDebugDrawAnimPose(bool isEnabled);
void setEnableDebugDrawPosition(bool isEnabled); void setEnableDebugDrawPosition(bool isEnabled);
void setEnableDebugDrawSensorToWorldMatrix(bool isEnabled);
bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); } bool getEnableMeshVisible() const { return _skeletonModel.isVisible(); }
void setEnableMeshVisible(bool isEnabled); void setEnableMeshVisible(bool isEnabled);
void setUseAnimPreAndPostRotations(bool isEnabled); void setUseAnimPreAndPostRotations(bool isEnabled);
@ -434,6 +435,7 @@ private:
bool _enableDebugDrawDefaultPose { false }; bool _enableDebugDrawDefaultPose { false };
bool _enableDebugDrawAnimPose { false }; bool _enableDebugDrawAnimPose { false };
bool _enableDebugDrawSensorToWorldMatrix { false };
AudioListenerMode _audioListenerMode; AudioListenerMode _audioListenerMode;
glm::vec3 _customListenPosition; glm::vec3 _customListenPosition;

View file

@ -341,12 +341,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
static QString userData; static QString userData;
if (userData != zone->getUserData()) { if (userData != zone->getUserData()) {
userData = zone->getUserData(); userData = zone->getUserData();
auto procedural = std::make_shared<Procedural>(userData); skybox->parse(userData);
if (procedural->_enabled) {
skybox->setProcedural(procedural);
} else {
skybox->setProcedural(ProceduralPointer());
}
} }
if (zone->getSkyboxProperties().getURL().isEmpty()) { if (zone->getSkyboxProperties().getURL().isEmpty()) {
skybox->setCubemap(gpu::TexturePointer()); skybox->setCubemap(gpu::TexturePointer());

View file

@ -31,7 +31,9 @@ EntityItemPointer RenderableBoxEntityItem::factory(const EntityItemID& entityID,
void RenderableBoxEntityItem::setUserData(const QString& value) { void RenderableBoxEntityItem::setUserData(const QString& value) {
if (value != getUserData()) { if (value != getUserData()) {
BoxEntityItem::setUserData(value); BoxEntityItem::setUserData(value);
_procedural.reset(); if (_procedural) {
_procedural->parse(value);
}
} }
} }
@ -40,7 +42,6 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
Q_ASSERT(getType() == EntityTypes::Box); Q_ASSERT(getType() == EntityTypes::Box);
Q_ASSERT(args->_batch); Q_ASSERT(args->_batch);
if (!_procedural) { if (!_procedural) {
_procedural.reset(new Procedural(this->getUserData())); _procedural.reset(new Procedural(this->getUserData()));
_procedural->_vertexSource = simple_vert; _procedural->_vertexSource = simple_vert;
@ -62,7 +63,7 @@ void RenderableBoxEntityItem::render(RenderArgs* args) {
} }
batch.setModelTransform(transToCenter); // we want to include the scale as well batch.setModelTransform(transToCenter); // we want to include the scale as well
if (_procedural && _procedural->ready()) { if (_procedural->ready()) {
_procedural->prepare(batch, getPosition(), getDimensions()); _procedural->prepare(batch, getPosition(), getDimensions());
auto color = _procedural->getColor(cubeColor); auto color = _procedural->getColor(cubeColor);
batch._glColor4f(color.r, color.g, color.b, color.a); batch._glColor4f(color.r, color.g, color.b, color.a);

View file

@ -36,7 +36,9 @@ EntityItemPointer RenderableSphereEntityItem::factory(const EntityItemID& entity
void RenderableSphereEntityItem::setUserData(const QString& value) { void RenderableSphereEntityItem::setUserData(const QString& value) {
if (value != getUserData()) { if (value != getUserData()) {
SphereEntityItem::setUserData(value); SphereEntityItem::setUserData(value);
_procedural.reset(); if (_procedural) {
_procedural->parse(value);
}
} }
} }

View file

@ -62,6 +62,9 @@ QJsonValue Procedural::getProceduralData(const QString& proceduralJson) {
return doc.object()[PROCEDURAL_USER_DATA_KEY]; return doc.object()[PROCEDURAL_USER_DATA_KEY];
} }
Procedural::Procedural() {
_state = std::make_shared<gpu::State>();
}
Procedural::Procedural(const QString& userDataJson) { Procedural::Procedural(const QString& userDataJson) {
parse(userDataJson); parse(userDataJson);
@ -69,74 +72,110 @@ Procedural::Procedural(const QString& userDataJson) {
} }
void Procedural::parse(const QString& userDataJson) { void Procedural::parse(const QString& userDataJson) {
_enabled = false;
auto proceduralData = getProceduralData(userDataJson); auto proceduralData = getProceduralData(userDataJson);
if (proceduralData.isObject()) { // Instead of parsing, prep for a parse on the rendering thread
parse(proceduralData.toObject()); // This will be called by Procedural::ready
std::lock_guard<std::mutex> lock(_proceduralDataMutex);
_proceduralData = proceduralData.toObject();
_proceduralDataDirty = true;
}
bool Procedural::parseVersion(const QJsonValue& version) {
if (version.isDouble()) {
_version = (uint8_t)(floor(version.toDouble()));
} else {
// All unversioned shaders default to V1
_version = 1;
} }
return (_version == 1 || _version == 2);
}
bool Procedural::parseUrl(const QUrl& shaderUrl) {
if (!shaderUrl.isValid()) {
qWarning() << "Invalid shader URL: " << shaderUrl;
return false;
}
if (_shaderUrl == shaderUrl) {
return true;
}
_shaderUrl = shaderUrl;
if (_shaderUrl.isLocalFile()) {
_shaderPath = _shaderUrl.toLocalFile();
qDebug() << "Shader path: " << _shaderPath;
if (!QFile(_shaderPath).exists()) {
return false;;
}
} else {
qDebug() << "Shader url: " << _shaderUrl;
_networkShader = ShaderCache::instance().getShader(_shaderUrl);
}
return true;
}
bool Procedural::parseUniforms(const QJsonObject& uniforms) {
if (_parsedUniforms != uniforms) {
_parsedUniforms = uniforms;
_uniformsDirty = true;
}
return true;
}
bool Procedural::parseTextures(const QJsonArray& channels) {
if (_parsedChannels != channels) {
_parsedChannels = channels;
auto textureCache = DependencyManager::get<TextureCache>();
size_t channelCount = std::min(MAX_PROCEDURAL_TEXTURE_CHANNELS, (size_t)_parsedChannels.size());
for (size_t i = 0; i < channelCount; ++i) {
QString url = _parsedChannels.at((int)i).toString();
_channels[i] = textureCache->getTexture(QUrl(url));
}
_channelsDirty = true;
}
return true;
} }
void Procedural::parse(const QJsonObject& proceduralData) { void Procedural::parse(const QJsonObject& proceduralData) {
// grab the version number _enabled = false;
{
auto version = proceduralData[VERSION_KEY]; if (proceduralData.isEmpty()) {
if (version.isDouble()) { return;
_version = (uint8_t)(floor(version.toDouble()));
}
} }
// Get the path to the shader auto version = proceduralData[VERSION_KEY];
{ auto shaderUrl = proceduralData[URL_KEY].toString();
QString shaderUrl = proceduralData[URL_KEY].toString(); shaderUrl = ResourceManager::normalizeURL(shaderUrl);
shaderUrl = ResourceManager::normalizeURL(shaderUrl); auto uniforms = proceduralData[UNIFORMS_KEY].toObject();
_shaderUrl = QUrl(shaderUrl); auto channels = proceduralData[CHANNELS_KEY].toArray();
if (!_shaderUrl.isValid()) {
qWarning() << "Invalid shader URL: " << shaderUrl;
return;
}
if (_shaderUrl.isLocalFile()) { if (parseVersion(version) &&
_shaderPath = _shaderUrl.toLocalFile(); parseUrl(shaderUrl) &&
qDebug() << "Shader path: " << _shaderPath; parseUniforms(uniforms) &&
if (!QFile(_shaderPath).exists()) { parseTextures(channels)) {
return; _enabled = true;
}
} else {
qDebug() << "Shader url: " << _shaderUrl;
_networkShader = ShaderCache::instance().getShader(_shaderUrl);
}
} }
// Grab any custom uniforms
{
auto uniforms = proceduralData[UNIFORMS_KEY];
if (uniforms.isObject()) {
_parsedUniforms = uniforms.toObject();
}
}
// Grab any textures
{
auto channels = proceduralData[CHANNELS_KEY];
if (channels.isArray()) {
auto textureCache = DependencyManager::get<TextureCache>();
_parsedChannels = channels.toArray();
size_t channelCount = std::min(MAX_PROCEDURAL_TEXTURE_CHANNELS, (size_t)_parsedChannels.size());
for (size_t i = 0; i < channelCount; ++i) {
QString url = _parsedChannels.at((int)i).toString();
_channels[i] = textureCache->getTexture(QUrl(url));
}
}
}
_enabled = true;
} }
bool Procedural::ready() { bool Procedural::ready() {
// Load any changes to the procedural
if (_proceduralDataDirty) {
std::lock_guard<std::mutex> lock(_proceduralDataMutex);
parse(_proceduralData);
_proceduralDataDirty = false;
}
if (!_enabled) { if (!_enabled) {
return false; return false;
} }
// Do we have a network or local shader // Do we have a network or local shader, and if so, is it loaded?
if (_shaderPath.isEmpty() && (!_networkShader || !_networkShader->isLoaded())) { if (_shaderPath.isEmpty() && (!_networkShader || !_networkShader->isLoaded())) {
return false; return false;
} }
@ -160,15 +199,14 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
QFile file(_shaderPath); QFile file(_shaderPath);
file.open(QIODevice::ReadOnly); file.open(QIODevice::ReadOnly);
_shaderSource = QTextStream(&file).readAll(); _shaderSource = QTextStream(&file).readAll();
_pipelineDirty = true; _shaderDirty = true;
_shaderModified = lastModified; _shaderModified = lastModified;
} }
} else if (_networkShader && _networkShader->isLoaded()) { } else if (_networkShader && _networkShader->isLoaded()) {
_shaderSource = _networkShader->_source; _shaderSource = _networkShader->_source;
} }
if (!_pipeline || _pipelineDirty) { if (!_pipeline || _shaderDirty) {
_pipelineDirty = true;
if (!_vertexShader) { if (!_vertexShader) {
_vertexShader = gpu::Shader::createVertex(_vertexSource); _vertexShader = gpu::Shader::createVertex(_vertexSource);
} }
@ -214,11 +252,15 @@ void Procedural::prepare(gpu::Batch& batch, const glm::vec3& position, const glm
batch.setPipeline(_pipeline); batch.setPipeline(_pipeline);
if (_pipelineDirty) { if (_shaderDirty || _uniformsDirty) {
_pipelineDirty = false;
setupUniforms(); setupUniforms();
} }
if (_shaderDirty || _uniformsDirty || _channelsDirty) {
setupChannels(_shaderDirty || _uniformsDirty);
}
_shaderDirty = _uniformsDirty = _channelsDirty = false;
for (auto lambda : _uniforms) { for (auto lambda : _uniforms) {
lambda(batch); lambda(batch);
@ -359,8 +401,14 @@ void Procedural::setupUniforms() {
batch._glUniform(_standardUniformSlots[POSITION], _entityPosition); batch._glUniform(_standardUniformSlots[POSITION], _entityPosition);
}); });
} }
}
void Procedural::setupChannels(bool shouldCreate) {
if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[CHANNEL_RESOLUTION]) { if (gpu::Shader::INVALID_LOCATION != _standardUniformSlots[CHANNEL_RESOLUTION]) {
if (!shouldCreate) {
// Instead of modifying the last element, just remove and recreate it.
_uniforms.pop_back();
}
_uniforms.push_back([=](gpu::Batch& batch) { _uniforms.push_back([=](gpu::Batch& batch) {
vec3 channelSizes[MAX_PROCEDURAL_TEXTURE_CHANNELS]; vec3 channelSizes[MAX_PROCEDURAL_TEXTURE_CHANNELS];
for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) { for (size_t i = 0; i < MAX_PROCEDURAL_TEXTURE_CHANNELS; ++i) {

View file

@ -28,27 +28,24 @@ const size_t MAX_PROCEDURAL_TEXTURE_CHANNELS{ 4 };
// FIXME better encapsulation // FIXME better encapsulation
// FIXME better mechanism for extending to things rendered using shaders other than simple.slv // FIXME better mechanism for extending to things rendered using shaders other than simple.slv
struct Procedural { struct Procedural {
public:
static QJsonValue getProceduralData(const QString& proceduralJson); static QJsonValue getProceduralData(const QString& proceduralJson);
Procedural();
Procedural(const QString& userDataJson); Procedural(const QString& userDataJson);
void parse(const QString& userDataJson); void parse(const QString& userDataJson);
void parse(const QJsonObject&);
bool ready(); bool ready();
void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size); void prepare(gpu::Batch& batch, const glm::vec3& position, const glm::vec3& size);
void setupUniforms();
glm::vec4 getColor(const glm::vec4& entityColor); glm::vec4 getColor(const glm::vec4& entityColor);
bool _enabled{ false }; uint8_t _version { 1 };
uint8_t _version{ 1 };
std::string _vertexSource; std::string _vertexSource;
std::string _fragmentSource; std::string _fragmentSource;
QString _shaderSource; gpu::StatePointer _state;
QString _shaderPath;
QUrl _shaderUrl;
quint64 _shaderModified{ 0 };
bool _pipelineDirty{ true };
enum StandardUniforms { enum StandardUniforms {
DATE, DATE,
@ -60,23 +57,50 @@ struct Procedural {
NUM_STANDARD_UNIFORMS NUM_STANDARD_UNIFORMS
}; };
int32_t _standardUniformSlots[NUM_STANDARD_UNIFORMS]; protected:
// Procedural metadata
bool _enabled { false };
uint64_t _start { 0 };
int32_t _frameCount { 0 };
uint64_t _start{ 0 }; // Rendering object descriptions, from userData
int32_t _frameCount{ 0 }; QJsonObject _proceduralData;
std::mutex _proceduralDataMutex;
QString _shaderSource;
QString _shaderPath;
QUrl _shaderUrl;
quint64 _shaderModified { 0 };
NetworkShaderPointer _networkShader; NetworkShaderPointer _networkShader;
QJsonObject _parsedUniforms; QJsonObject _parsedUniforms;
QJsonArray _parsedChannels; QJsonArray _parsedChannels;
bool _proceduralDataDirty { true };
bool _shaderDirty { true };
bool _uniformsDirty { true };
bool _channelsDirty { true };
// Rendering objects
UniformLambdas _uniforms; UniformLambdas _uniforms;
int32_t _standardUniformSlots[NUM_STANDARD_UNIFORMS];
NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS]; NetworkTexturePointer _channels[MAX_PROCEDURAL_TEXTURE_CHANNELS];
gpu::PipelinePointer _pipeline; gpu::PipelinePointer _pipeline;
gpu::ShaderPointer _vertexShader; gpu::ShaderPointer _vertexShader;
gpu::ShaderPointer _fragmentShader; gpu::ShaderPointer _fragmentShader;
gpu::ShaderPointer _shader; gpu::ShaderPointer _shader;
gpu::StatePointer _state;
// Entity metadata
glm::vec3 _entityDimensions; glm::vec3 _entityDimensions;
glm::vec3 _entityPosition; glm::vec3 _entityPosition;
private:
// This should only be called from the render thread, as it shares data with Procedural::prepare
void parse(const QJsonObject&);
bool parseVersion(const QJsonValue& version);
bool parseUrl(const QUrl& url);
bool parseUniforms(const QJsonObject& uniforms);
bool parseTextures(const QJsonArray& channels);
void setupUniforms();
void setupChannels(bool shouldCreate);
}; };
#endif #endif

View file

@ -19,22 +19,10 @@
#include "ProceduralSkybox_frag.h" #include "ProceduralSkybox_frag.h"
ProceduralSkybox::ProceduralSkybox() : model::Skybox() { ProceduralSkybox::ProceduralSkybox() : model::Skybox() {
} _procedural._vertexSource = ProceduralSkybox_vert;
_procedural._fragmentSource = ProceduralSkybox_frag;
ProceduralSkybox::ProceduralSkybox(const ProceduralSkybox& skybox) : // Adjust the pipeline state for background using the stencil test
model::Skybox(skybox), _procedural._state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
_procedural(skybox._procedural) {
}
void ProceduralSkybox::setProcedural(const ProceduralPointer& procedural) {
_procedural = procedural;
if (_procedural) {
_procedural->_vertexSource = ProceduralSkybox_vert;
_procedural->_fragmentSource = ProceduralSkybox_frag;
// Adjust the pipeline state for background using the stencil test
_procedural->_state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
}
} }
void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& frustum) const { void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& frustum) const {
@ -42,12 +30,10 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& frustum) con
} }
void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const ProceduralSkybox& skybox) { void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum, const ProceduralSkybox& skybox) {
if (!(skybox._procedural)) { if (!(skybox._procedural.ready())) {
skybox.updateDataBuffer(); skybox.updateDataBuffer();
Skybox::render(batch, viewFrustum, skybox); Skybox::render(batch, viewFrustum, skybox);
} } else {
if (skybox._procedural && skybox._procedural->_enabled && skybox._procedural->ready()) {
gpu::TexturePointer skymap = skybox.getCubemap(); gpu::TexturePointer skymap = skybox.getCubemap();
// FIXME: skymap->isDefined may not be threadsafe // FIXME: skymap->isDefined may not be threadsafe
assert(skymap && skymap->isDefined()); assert(skymap && skymap->isDefined());
@ -62,8 +48,7 @@ void ProceduralSkybox::render(gpu::Batch& batch, const ViewFrustum& viewFrustum,
batch.setModelTransform(Transform()); // only for Mac batch.setModelTransform(Transform()); // only for Mac
batch.setResourceTexture(0, skybox.getCubemap()); batch.setResourceTexture(0, skybox.getCubemap());
skybox._procedural->prepare(batch, glm::vec3(0), glm::vec3(1)); skybox._procedural.prepare(batch, glm::vec3(0), glm::vec3(1));
batch.draw(gpu::TRIANGLE_STRIP, 4); batch.draw(gpu::TRIANGLE_STRIP, 4);
} }
} }

View file

@ -17,22 +17,18 @@
#include "Procedural.h" #include "Procedural.h"
typedef std::shared_ptr<Procedural> ProceduralPointer;
class ProceduralSkybox: public model::Skybox { class ProceduralSkybox: public model::Skybox {
public: public:
ProceduralSkybox(); ProceduralSkybox();
ProceduralSkybox(const ProceduralSkybox& skybox);
ProceduralSkybox& operator= (const ProceduralSkybox& skybox);
virtual ~ProceduralSkybox() {}; virtual ~ProceduralSkybox() {};
void setProcedural(const ProceduralPointer& procedural); void parse(const QString& userData) { _procedural.parse(userData); }
virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const; virtual void render(gpu::Batch& batch, const ViewFrustum& frustum) const;
static void render(gpu::Batch& batch, const ViewFrustum& frustum, const ProceduralSkybox& skybox); static void render(gpu::Batch& batch, const ViewFrustum& frustum, const ProceduralSkybox& skybox);
protected: protected:
ProceduralPointer _procedural; mutable Procedural _procedural;
}; };
typedef std::shared_ptr< ProceduralSkybox > ProceduralSkyboxPointer; typedef std::shared_ptr< ProceduralSkybox > ProceduralSkyboxPointer;

View file

@ -78,7 +78,7 @@ public:
// WARNING, There is No check on the validity of the ID, so this could return a bad Item // WARNING, There is No check on the validity of the ID, so this could return a bad Item
const Item& getItem(const ItemID& id) const { return _items[id]; } const Item& getItem(const ItemID& id) const { return _items[id]; }
// Access the spatialized items // Access the spatialized items
const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; } const ItemSpatialTree& getSpatialTree() const { return _masterSpatialTree; }
// Access non-spatialized items (overlays, backgrounds) // Access non-spatialized items (overlays, backgrounds)

View file

@ -68,6 +68,21 @@ void OpenVrDisplayPlugin::activate() {
_compositor = vr::VRCompositor(); _compositor = vr::VRCompositor();
Q_ASSERT(_compositor); Q_ASSERT(_compositor);
HmdDisplayPlugin::activate(); HmdDisplayPlugin::activate();
// set up default sensor space such that the UI overlay will align with the front of the room.
auto chaperone = vr::VRChaperone();
if (chaperone) {
float const UI_RADIUS = 1.0f;
float const UI_HEIGHT = 1.6f;
float const UI_Z_OFFSET = 0.5;
float xSize, zSize;
chaperone->GetPlayAreaSize(&xSize, &zSize);
glm::vec3 uiPos(0.0f, UI_HEIGHT, UI_RADIUS - (0.5f * zSize) - UI_Z_OFFSET);
_sensorResetMat = glm::inverse(createMatFromQuatAndPos(glm::quat(), uiPos));
} else {
qDebug() << "OpenVR: error could not get chaperone pointer";
}
} }
void OpenVrDisplayPlugin::deactivate() { void OpenVrDisplayPlugin::deactivate() {
@ -115,7 +130,7 @@ glm::mat4 OpenVrDisplayPlugin::getHeadPose(uint32_t frameIndex) const {
#endif #endif
vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount]; vr::TrackedDevicePose_t predictedTrackedDevicePose[vr::k_unMaxTrackedDeviceCount];
_system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseSeated, predictedSecondsFromNow, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount); _system->GetDeviceToAbsoluteTrackingPose(vr::TrackingUniverseStanding, predictedSecondsFromNow, predictedTrackedDevicePose, vr::k_unMaxTrackedDeviceCount);
// copy and process predictedTrackedDevicePoses // copy and process predictedTrackedDevicePoses
for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) { for (int i = 0; i < vr::k_unMaxTrackedDeviceCount; i++) {