From fd50434d869d1103a47dc10b3f04a1c76461f507 Mon Sep 17 00:00:00 2001 From: Zach Fox Date: Thu, 8 Jun 2017 14:36:38 -0700 Subject: [PATCH] New camera model; Cleanup; Bashing head :against desk --- interface/src/SecondaryCamera.cpp | 73 +++++++++++-------- interface/src/SecondaryCamera.h | 15 +++- .../src/model-networking/TextureCache.cpp | 37 +++++----- .../src/model-networking/TextureCache.h | 8 +- scripts/system/spectatorCamera.js | 52 +++++++++---- 5 files changed, 113 insertions(+), 72 deletions(-) diff --git a/interface/src/SecondaryCamera.cpp b/interface/src/SecondaryCamera.cpp index 4603a4be79..0af51bb2c4 100644 --- a/interface/src/SecondaryCamera.cpp +++ b/interface/src/SecondaryCamera.cpp @@ -1,8 +1,20 @@ +// +// SecondaryCamera.cpp +// interface/src +// +// Created by Samuel Gateau, Howard Stearns, and Zach Fox on 2017-06-08. +// 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 +// #include "SecondaryCamera.h" - +#include #include +using RenderArgsPointer = std::shared_ptr; + void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render::Varying& outputs, render::CullFunctor cullFunctor, bool isDeferred) { task.addJob("RenderShadowTask", cullFunctor); @@ -15,19 +27,18 @@ void MainRenderTask::build(JobModel& task, const render::Varying& inputs, render } } - -#include - -using RenderArgsPointer = std::shared_ptr; - -void SecondaryCameraRenderTaskConfig::resetSize(int width, int height) { // Carefully adjust the framebuffer / texture. +void SecondaryCameraRenderTaskConfig::resetSize(int width, int height) { // FIXME: Add an arg here for "destinationFramebuffer" bool wasEnabled = isEnabled(); setEnabled(false); auto textureCache = DependencyManager::get(); - textureCache->resetSpectatorCameraFramebuffer(width, height); + textureCache->resetSpectatorCameraFramebuffer(width, height); // FIXME: Call the correct reset function based on the "destinationFramebuffer" arg setEnabled(wasEnabled); } +void SecondaryCameraRenderTaskConfig::resetSizeSpectatorCamera(int width, int height) { // Carefully adjust the framebuffer / texture. + resetSize(width, height); +} + class BeginSecondaryCameraFrame { // Changes renderContext for our framebuffer and and view. glm::vec3 _position{}; glm::quat _orientation{}; @@ -39,36 +50,36 @@ public: } void configure(const Config& config) { - // Why does this run all the time, even when not enabled? Should we check and bail? - //qDebug() << "FIXME pos" << config.position << "orient" << config.orientation; - _position = config.position; - _orientation = config.orientation; + if (config.enabled || config.alwaysEnabled) { + _position = config.position; + _orientation = config.orientation; + } } void run(const render::RenderContextPointer& renderContext, RenderArgsPointer& cachedArgs) { auto args = renderContext->args; auto textureCache = DependencyManager::get(); - auto destFramebuffer = textureCache->getSpectatorCameraFramebuffer(); - // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? - _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; - _cachedArgsPointer->_viewport = args->_viewport; - _cachedArgsPointer->_displayMode = args->_displayMode; - args->_blitFramebuffer = destFramebuffer; - args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); - args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); - args->_displayMode = RenderArgs::MONO; + gpu::FramebufferPointer destFramebuffer; + destFramebuffer = textureCache->getSpectatorCameraFramebuffer(); // FIXME: Change the destination based on some unimplemented config var + if (destFramebuffer) { + // Caching/restoring the old values doesn't seem to be needed. Is it because we happen to be last in the pipeline (which would be a bug waiting to happen)? + _cachedArgsPointer->_blitFramebuffer = args->_blitFramebuffer; + _cachedArgsPointer->_viewport = args->_viewport; + _cachedArgsPointer->_displayMode = args->_displayMode; + args->_blitFramebuffer = destFramebuffer; + args->_viewport = glm::ivec4(0, 0, destFramebuffer->getWidth(), destFramebuffer->getHeight()); + args->_displayMode = RenderArgs::MONO; - gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { - batch.disableContextStereo(); - }); + gpu::doInBatch(args->_context, [&](gpu::Batch& batch) { + batch.disableContextStereo(); + }); - auto srcViewFrustum = args->getViewFrustum(); - srcViewFrustum.setPosition(_position); - srcViewFrustum.setOrientation(_orientation); - //srcViewFrustum.calculate(); // do we need this? I don't think so - //qDebug() << "FIXME pos" << _position << "orient" << _orientation << "frust pos" << srcViewFrustum.getPosition() << "orient" << srcViewFrustum.getOrientation() << "direct" << srcViewFrustum.getDirection(); - args->pushViewFrustum(srcViewFrustum); - cachedArgs = _cachedArgsPointer; + auto srcViewFrustum = args->getViewFrustum(); + srcViewFrustum.setPosition(_position); + srcViewFrustum.setOrientation(_orientation); + args->pushViewFrustum(srcViewFrustum); + cachedArgs = _cachedArgsPointer; + } } protected: diff --git a/interface/src/SecondaryCamera.h b/interface/src/SecondaryCamera.h index f68a65dd12..1abb2952aa 100644 --- a/interface/src/SecondaryCamera.h +++ b/interface/src/SecondaryCamera.h @@ -1,3 +1,14 @@ +// +// SecondaryCamera.h +// interface/src +// +// Created by Samuel Gateau, Howard Stearns, and Zach Fox on 2017-06-08. +// 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 +// + #pragma once #ifndef hifi_SecondaryCamera_h #define hifi_SecondaryCamera_h @@ -34,10 +45,12 @@ class SecondaryCameraRenderTaskConfig : public render::Task::Config { Q_OBJECT public: SecondaryCameraRenderTaskConfig() : render::Task::Config(false) {} +private: + void resetSize(int width, int height); signals: void dirty(); public slots: - void resetSize(int width, int height); + void resetSizeSpectatorCamera(int width, int height); }; class SecondaryCameraRenderTask { diff --git a/libraries/model-networking/src/model-networking/TextureCache.cpp b/libraries/model-networking/src/model-networking/TextureCache.cpp index 69eede0cc2..0ecd8e8aab 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.cpp +++ b/libraries/model-networking/src/model-networking/TextureCache.cpp @@ -50,7 +50,8 @@ Q_LOGGING_CATEGORY(trace_resource_parse_image_ktx, "trace.resource.parse.image.k const std::string TextureCache::KTX_DIRNAME { "ktx_cache" }; const std::string TextureCache::KTX_EXT { "ktx" }; -const std::string TextureCache::SPECTATOR_CAMERA_FRAME_URL { "resource://spectatorCameraFrame" }; +static const QString RESOURCE_SCHEME = "resource"; +static const QUrl SPECTATOR_CAMERA_FRAME_URL("resource://spectatorCameraFrame"); static const float SKYBOX_LOAD_PRIORITY { 10.0f }; // Make sure skybox loads first static const float HIGH_MIPS_LOAD_PRIORITY { 9.0f }; // Make sure high mips loads after skybox but before models @@ -182,9 +183,8 @@ ScriptableResource* TextureCache::prefetch(const QUrl& url, int type, int maxNum } NetworkTexturePointer TextureCache::getTexture(const QUrl& url, image::TextureUsage::Type type, const QByteArray& content, int maxNumPixels) { - if (url == QUrl(SPECTATOR_CAMERA_FRAME_URL.c_str())) { - - return getSpectatorCameraNetworkTexture(); + if (url.scheme() == RESOURCE_SCHEME) { + return getResourceTexture(url); } TextureExtra extra = { type, content, maxNumPixels }; return ResourceCache::getResource(url, QUrl(), &extra).staticCast(); @@ -885,31 +885,30 @@ void ImageReader::read() { } -NetworkTexturePointer TextureCache::getSpectatorCameraNetworkTexture() { - if (!_spectatorCameraNetworkTexture) { - _spectatorCameraNetworkTexture.reset(new NetworkTexture(QUrl(SPECTATOR_CAMERA_FRAME_URL.c_str()))); - auto texture = getSpectatorCameraTexture(); - _spectatorCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); +NetworkTexturePointer TextureCache::getResourceTexture(QUrl resourceTextureUrl) { + gpu::TexturePointer texture; + if (resourceTextureUrl == SPECTATOR_CAMERA_FRAME_URL) { + if (!_spectatorCameraNetworkTexture) { + _spectatorCameraNetworkTexture.reset(new NetworkTexture(resourceTextureUrl)); + } + texture = _spectatorCameraFramebuffer->getRenderBuffer(0); + if (texture) { + _spectatorCameraNetworkTexture->setImage(texture, texture->getWidth(), texture->getHeight()); + return _spectatorCameraNetworkTexture; + } } - return _spectatorCameraNetworkTexture; - } -const gpu::TexturePointer& TextureCache::getSpectatorCameraTexture() { - if (!_spectatorCameraTexture) { - getSpectatorCameraFramebuffer(); - } - return _spectatorCameraTexture; + return NetworkTexturePointer(); } + const gpu::FramebufferPointer& TextureCache::getSpectatorCameraFramebuffer() { if (!_spectatorCameraFramebuffer) { resetSpectatorCameraFramebuffer(2048, 1024); } - return _spectatorCameraFramebuffer; } void TextureCache::resetSpectatorCameraFramebuffer(int width, int height) { - _spectatorCameraFramebuffer.reset(gpu::Framebuffer::create("spectatorCamera", gpu::Element::COLOR_SRGBA_32, 2048, 1024)); - _spectatorCameraTexture = _spectatorCameraFramebuffer->getRenderBuffer(0); + _spectatorCameraFramebuffer.reset(gpu::Framebuffer::create("spectatorCamera", gpu::Element::COLOR_SRGBA_32, width, height)); _spectatorCameraNetworkTexture.reset(); } diff --git a/libraries/model-networking/src/model-networking/TextureCache.h b/libraries/model-networking/src/model-networking/TextureCache.h index 38cb8e1982..c7bb34068d 100644 --- a/libraries/model-networking/src/model-networking/TextureCache.h +++ b/libraries/model-networking/src/model-networking/TextureCache.h @@ -171,8 +171,7 @@ public: /// SpectatorCamera rendering targets. - NetworkTexturePointer getSpectatorCameraNetworkTexture(); - const gpu::TexturePointer& getSpectatorCameraTexture(); + NetworkTexturePointer getResourceTexture(QUrl resourceTextureUrl); const gpu::FramebufferPointer& getSpectatorCameraFramebuffer(); void resetSpectatorCameraFramebuffer(int width, int height); @@ -193,7 +192,6 @@ private: static const std::string KTX_DIRNAME; static const std::string KTX_EXT; - static const std::string SPECTATOR_CAMERA_FRAME_URL; KTXCache _ktxCache; // Map from image hashes to texture weak pointers @@ -206,10 +204,8 @@ private: gpu::TexturePointer _blueTexture; gpu::TexturePointer _blackTexture; - - gpu::FramebufferPointer _spectatorCameraFramebuffer; - gpu::TexturePointer _spectatorCameraTexture; NetworkTexturePointer _spectatorCameraNetworkTexture; + gpu::FramebufferPointer _spectatorCameraFramebuffer; }; #endif // hifi_TextureCache_h diff --git a/scripts/system/spectatorCamera.js b/scripts/system/spectatorCamera.js index 051741d55f..6e3d032e31 100644 --- a/scripts/system/spectatorCamera.js +++ b/scripts/system/spectatorCamera.js @@ -28,7 +28,7 @@ // Spectator camera utility functions and variables. // function inFrontOf(distance, position, orientation) { - return Vec3.sum(position || MyAvatar.position, + return Vec3.sum(position || Vec3.sum(MyAvatar.position, { x: 0, y: 0.3, z: 0 }), Vec3.multiply(distance, Quat.getForward(orientation || MyAvatar.orientation))); } var aroundY = Quat.fromPitchYawRollDegrees(0, 180, 0); @@ -46,6 +46,8 @@ // camera: The in-world entity that corresponds to the spectator camera. // cameraIsDynamic: "false" for now while we figure out why dynamic, parented overlays // drift with respect to their parent + // lastCameraPosition: Holds the last known camera position + // lastCameraRotation: Holds the last known camera rotation // // Arguments: // None @@ -59,11 +61,18 @@ var viewFinderOverlay = false; var camera = false; var cameraIsDynamic = false; + var lastCameraPosition = false; + var lastCameraRotation = false; function updateRenderFromCamera() { var cameraData = Entities.getEntityProperties(camera, ['position', 'rotation']); - // FIXME: don't muck with config if properties haven't changed. - beginSpectatorFrameRenderConfig.position = cameraData.position; - beginSpectatorFrameRenderConfig.orientation = cameraData.rotation; + if (JSON.stringify(lastCameraPosition) !== JSON.stringify(cameraData.position)) { + lastCameraPosition = cameraData.position; + beginSpectatorFrameRenderConfig.position = lastCameraPosition; + } + if (JSON.stringify(lastCameraRotation) !== JSON.stringify(cameraData.rotation)) { + lastCameraRotation = cameraData.rotation; + beginSpectatorFrameRenderConfig.orientation = lastCameraRotation; + } if (cameraIsDynamic) { // BUG: image3d overlays don't retain their locations properly when parented to a dynamic object Overlays.editOverlay(viewFinderOverlay, { orientation: flip(cameraData.rotation) }); @@ -88,33 +97,46 @@ function spectatorCameraOn() { // Set the special texture size based on the window in which it will eventually be displayed. var size = Controller.getViewportDimensions(); // FIXME: Need a signal to hook into when the dimensions change. - spectatorFrameRenderConfig.resetSize(size.x, size.y); + spectatorFrameRenderConfig.resetSizeSpectatorCamera(size.x, size.y); spectatorFrameRenderConfig.enabled = beginSpectatorFrameRenderConfig.enabled = true; var cameraRotation = MyAvatar.orientation, cameraPosition = inFrontOf(2); Script.update.connect(updateRenderFromCamera); isUpdateRenderWired = true; camera = Entities.addEntity({ - type: 'Box', - dimensions: { x: 0.4, y: 0.2, z: 0.4 }, - userData: '{"grabbableKey":{"grabbable":true}}', - dynamic: cameraIsDynamic, - color: { red: 255, green: 0, blue: 0 }, - name: 'SpectatorCamera', - position: cameraPosition, // Put the camera in front of me so that I can find it. - rotation: cameraRotation + "angularDamping": 0.98000001907348633, + "collisionsWillMove": 1, + "damping": 0.98000001907348633, + "dimensions": { + "x": 0.2338641881942749, + "y": 0.407032310962677, + "z": 0.38702544569969177 + }, + "dynamic": cameraIsDynamic, + "modelURL": "http://hifi-content.s3.amazonaws.com/alan/dev/spectator-camera.fbx", + "queryAACube": { + "scale": 0.60840487480163574, + "x": -0.30420243740081787, + "y": -0.30420243740081787, + "z": -0.30420243740081787 + }, + "rotation": cameraRotation, + "position": cameraPosition, + "shapeType": "simple-compound", + "type": "Model", + "userData": "{\"grabbableKey\":{\"grabbable\":true}}" }, true); // Put an image3d overlay on the near face, as a viewFinder. viewFinderOverlay = Overlays.addOverlay("image3d", { url: "resource://spectatorCameraFrame", parentID: camera, alpha: 1, - position: inFrontOf(-0.25, cameraPosition, cameraRotation), + position: inFrontOf(0, Vec3.sum(cameraPosition, { x: 0, y: 0.15, z: 0 }), cameraRotation), // FIXME: We shouldn't need the flip and the negative scale. // e.g., This isn't necessary using an ordinary .jpg with lettering, above. // Must be something about the view frustum projection matrix? // But don't go changing that in (c++ code) without getting all the way to a desktop display! orientation: flip(cameraRotation), - scale: -0.35, + scale: -0.16, }); setDisplay(monitorShowsCameraView); }