It's working!!

This commit is contained in:
Zach Fox 2018-04-30 12:00:39 -07:00
parent 1b29946a48
commit a2b84c0fbb
9 changed files with 174 additions and 49 deletions

View file

@ -7278,9 +7278,9 @@ void Application::takeSecondaryCameraSnapshot(const QString& filename) {
});
}
void Application::takeSecondaryCamera360Snapshot(const QString& filename) {
postLambdaEvent([filename, this] {
Snapshot::save360Snapshot(filename);
void Application::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const QString& filename) {
postLambdaEvent([filename, cameraPosition, this] {
Snapshot::save360Snapshot(cameraPosition, filename);
});
}

View file

@ -273,7 +273,7 @@ public:
void takeSnapshot(bool notify, bool includeAnimated = false, float aspectRatio = 0.0f, const QString& filename = QString());
void takeSecondaryCameraSnapshot(const QString& filename = QString());
void takeSecondaryCamera360Snapshot(const QString& filename = QString());
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const QString& filename = QString());
void shareSnapshot(const QString& filename, const QUrl& href = QUrl(""));

View file

@ -431,8 +431,8 @@ void WindowScriptingInterface::takeSecondaryCameraSnapshot(const QString& filena
qApp->takeSecondaryCameraSnapshot(filename);
}
void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const QString& filename) {
qApp->takeSecondaryCamera360Snapshot(filename);
void WindowScriptingInterface::takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const QString& filename) {
qApp->takeSecondaryCamera360Snapshot(cameraPosition, filename);
}
void WindowScriptingInterface::shareSnapshot(const QString& path, const QUrl& href) {

View file

@ -376,7 +376,7 @@ public slots:
*
* var filename = QString();
*/
void takeSecondaryCamera360Snapshot(const QString& filename = QString());
void takeSecondaryCamera360Snapshot(const glm::vec3& cameraPosition, const QString& filename = QString());
/**jsdoc
* Emit a {@link Window.connectionAdded|connectionAdded} or a {@link Window.connectionError|connectionError} signal that
@ -586,6 +586,16 @@ signals:
*/
void stillSnapshotTaken(const QString& pathStillSnapshot, bool notify);
/**jsdoc
* Triggered when a still equirectangular snapshot has been taken by calling {@link Window.take360Snapshot|take360Snapshot}
* @function Window.equirectangularSnapshotTaken
* @param {string} pathStillSnapshot - The path and name of the snapshot image file.
* @param {boolean} notify - The value of the <code>notify</code> parameter that {@link Window.take360Snapshot|take360Snapshot}
* was called with.
* @returns {Signal}
*/
void equirectangularSnapshotTaken(const QString& pathEquirectangularSnapshot, bool notify);
/**jsdoc
* Triggered when a snapshot submitted via {@link Window.shareSnapshot|shareSnapshot} is ready for sharing. The snapshot
* may then be shared via the {@link Account.metaverseServerURL} Web API.

View file

@ -20,6 +20,7 @@
#include <QtCore/QJsonArray>
#include <QtNetwork/QHttpMultiPart>
#include <QtGui/QImage>
#include <QtConcurrent/QtConcurrentRun>
#include <AccountManager.h>
#include <AddressManager.h>
@ -91,57 +92,66 @@ QString Snapshot::saveSnapshot(QImage image, const QString& filename) {
return snapshotPath;
}
void Snapshot::save360Snapshot(const QString& filename) {
qint16 Snapshot::snapshotIndex = 0;
QVariant Snapshot::oldAttachedEntityId = 0;
QVariant Snapshot::oldOrientation = 0;
QVariant Snapshot::oldvFoV = 0;
QVariant Snapshot::oldNearClipPlaneDistance = 0;
QVariant Snapshot::oldFarClipPlaneDistance = 0;
QImage Snapshot::downImage;
QImage Snapshot::frontImage;
QImage Snapshot::leftImage;
QImage Snapshot::backImage;
QImage Snapshot::rightImage;
QImage Snapshot::upImage;
void Snapshot::save360Snapshot(const glm::vec3& cameraPosition, const QString& filename) {
SecondaryCameraJobConfig* secondaryCameraRenderConfig = static_cast<SecondaryCameraJobConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera"));
// Save initial values of secondary camera render config
auto oldAttachedEntityId = secondaryCameraRenderConfig->property("attachedEntityId");
auto oldOrientation = secondaryCameraRenderConfig->property("orientation");
auto oldvFoV = secondaryCameraRenderConfig->property("vFoV");
auto oldNearClipPlaneDistance = secondaryCameraRenderConfig->property("nearClipPlaneDistance");
auto oldFarClipPlaneDistance = secondaryCameraRenderConfig->property("farClipPlaneDistance");
oldAttachedEntityId = secondaryCameraRenderConfig->property("attachedEntityId");
oldOrientation = secondaryCameraRenderConfig->property("orientation");
oldvFoV = secondaryCameraRenderConfig->property("vFoV");
oldNearClipPlaneDistance = secondaryCameraRenderConfig->property("nearClipPlaneDistance");
oldFarClipPlaneDistance = secondaryCameraRenderConfig->property("farClipPlaneDistance");
// Initialize some secondary camera render config options for 360 snapshot capture
secondaryCameraRenderConfig->resetSizeSpectatorCamera(2048, 2048);
secondaryCameraRenderConfig->setProperty("attachedEntityId", "");
secondaryCameraRenderConfig->setPosition(cameraPosition);
secondaryCameraRenderConfig->setProperty("vFoV", 90.0f);
secondaryCameraRenderConfig->setProperty("nearClipPlaneDistance", 0.5f);
secondaryCameraRenderConfig->setProperty("farClipPlaneDistance", 1000.0f);
secondaryCameraRenderConfig->setProperty("nearClipPlaneDistance", 0.3f);
secondaryCameraRenderConfig->setProperty("farClipPlaneDistance", 5000.0f);
secondaryCameraRenderConfig->setOrientation(glm::quat(glm::radians(glm::vec3(-90.0f, 0.0f, 0.0f))));
qint16 snapshotIndex = 0;
snapshotIndex = 0;
QTimer* snapshotTimer = new QTimer();
snapshotTimer->setSingleShot(false);
snapshotTimer->setInterval(200);
snapshotTimer->setInterval(250);
connect(snapshotTimer, &QTimer::timeout, [&] {
SecondaryCameraJobConfig* config = static_cast<SecondaryCameraJobConfig*>(qApp->getRenderEngine()->getConfiguration()->getConfig("SecondaryCamera"));
qDebug() << "ZRF HERE" << snapshotIndex;
if (snapshotIndex == 0) {
QImage downImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
Snapshot::saveSnapshot(downImage, "down");
downImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
config->setOrientation(glm::quat(glm::radians(glm::vec3(0.0f, 0.0f, 0.0f))));
} else if (snapshotIndex == 1) {
QImage frontImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
Snapshot::saveSnapshot(frontImage, "front");
frontImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
config->setOrientation(glm::quat(glm::radians(glm::vec3(0.0f, 90.0f, 0.0f))));
} else if (snapshotIndex == 2) {
QImage leftImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
Snapshot::saveSnapshot(leftImage, "left");
leftImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
config->setOrientation(glm::quat(glm::radians(glm::vec3(0.0f, 180.0f, 0.0f))));
} else if (snapshotIndex == 3) {
QImage backImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
Snapshot::saveSnapshot(backImage, "back");
backImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
config->setOrientation(glm::quat(glm::radians(glm::vec3(0.0f, 270.0f, 0.0f))));
} else if (snapshotIndex == 4) {
QImage rightImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
Snapshot::saveSnapshot(rightImage, "right");
rightImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
config->setOrientation(glm::quat(glm::radians(glm::vec3(90.0f, 0.0f, 0.0f))));
} else if (snapshotIndex == 5) {
QImage upImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
Snapshot::saveSnapshot(upImage, "up");
} else if (snapshotIndex == 6) {
upImage = qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot();
} else {
// Reset secondary camera render config
config->resetSizeSpectatorCamera(qApp->getWindow()->geometry().width(), qApp->getWindow()->geometry().height());
config->setProperty("attachedEntityId", oldAttachedEntityId);
@ -149,25 +159,97 @@ void Snapshot::save360Snapshot(const QString& filename) {
config->setProperty("nearClipPlaneDistance", oldNearClipPlaneDistance);
config->setProperty("farClipPlaneDistance", oldFarClipPlaneDistance);
QFile* snapshotFile = savedFileForSnapshot(qApp->getActiveDisplayPlugin()->getSecondaryCameraScreenshot(), false, filename);
// we don't need the snapshot file, so close it, grab its filename and delete it
snapshotFile->close();
QString snapshotPath = QFileInfo(*snapshotFile).absoluteFilePath();
delete snapshotFile;
// Process six QImages
QtConcurrent::run(convertToEquirectangular);
snapshotTimer->stop();
snapshotTimer->deleteLater();
emit DependencyManager::get<WindowScriptingInterface>()->stillSnapshotTaken(snapshotPath, true);
}
snapshotIndex++;
});
snapshotTimer->start();
}
void Snapshot::convertToEquirectangular() {
float outputImageWidth = 8192.0f;
float outputImageHeight = 4096.0f;
QImage outputImage(outputImageWidth, outputImageHeight, QImage::Format_RGB32);
outputImage.fill(0);
QRgb sourceColorValue;
float phi, theta;
int cubeFaceWidth = 2048.0f;
int cubeFaceHeight = 2048.0f;
for (int j = 0; j < outputImageHeight; j++) {
theta = (1.0f - ((float)j / outputImageHeight)) * PI;
for (int i = 0; i < outputImageWidth; i++) {
phi = ((float)i / outputImageWidth) * 2.0f * PI;
float x, y, z;
x = glm::sin(phi) * glm::sin(theta) * -1.0f;
y = glm::cos(theta);
z = glm::cos(phi) * glm::sin(theta) * -1.0f;
float xa, ya, za;
float a;
a = std::max(std::max(std::abs(x), std::abs(y)), std::abs(z));
xa = x / a;
ya = y / a;
za = z / a;
// Pixel in the source images
int xPixel, yPixel;
QImage sourceImage;
if (xa == 1) {
// Right image
xPixel = (int)((((za + 1.0f) / 2.0f) - 1.0f) * cubeFaceWidth);
yPixel = (int)((((ya + 1.0f) / 2.0f)) * cubeFaceHeight);
sourceImage = rightImage;
} else if (xa == -1) {
// Left image
xPixel = (int)((((za + 1.0f) / 2.0f)) * cubeFaceWidth);
yPixel = (int)((((ya + 1.0f) / 2.0f)) * cubeFaceHeight);
sourceImage = leftImage;
} else if (ya == 1) {
// Down image
xPixel = (int)((((xa + 1.0f) / 2.0f)) * cubeFaceWidth);
yPixel = (int)((((za + 1.0f) / 2.0f) - 1.0f) * cubeFaceHeight);
sourceImage = downImage;
} else if (ya == -1) {
// Up image
xPixel = (int)((((xa + 1.0f) / 2.0f)) * cubeFaceWidth);
yPixel = (int)((((za + 1.0f) / 2.0f)) * cubeFaceHeight);
sourceImage = upImage;
} else if (za == 1) {
// Front image
xPixel = (int)((((xa + 1.0f) / 2.0f)) * cubeFaceWidth);
yPixel = (int)((((ya + 1.0f) / 2.0f)) * cubeFaceHeight);
sourceImage = frontImage;
} else if (za == -1) {
// Back image
xPixel = (int)((((xa + 1.0f) / 2.0f) - 1.0f) * cubeFaceWidth);
yPixel = (int)((((ya + 1.0f) / 2.0f)) * cubeFaceHeight);
sourceImage = backImage;
} else {
qDebug() << "Unknown face encountered when processing 360 Snapshot";
xPixel = 0;
yPixel = 0;
}
xPixel = std::min(std::abs(xPixel), 2047);
yPixel = std::min(std::abs(yPixel), 2047);
sourceColorValue = sourceImage.pixel(xPixel, yPixel);
outputImage.setPixel(i, j, sourceColorValue);
}
}
emit DependencyManager::get<WindowScriptingInterface>()->equirectangularSnapshotTaken(saveSnapshot(outputImage, QString()), true);
}
QTemporaryFile* Snapshot::saveTempSnapshot(QImage image) {
// return whatever we get back from saved file for snapshot

View file

@ -38,7 +38,7 @@ class Snapshot : public QObject, public Dependency {
SINGLETON_DEPENDENCY
public:
static QString saveSnapshot(QImage image, const QString& filename);
static void save360Snapshot(const QString& filename);
static void save360Snapshot(const glm::vec3& cameraPosition, const QString& filename);
static QTemporaryFile* saveTempSnapshot(QImage image);
static SnapshotMetaData* parseSnapshotData(QString snapshotPath);
@ -53,6 +53,20 @@ public slots:
Q_INVOKABLE void setSnapshotsLocation(const QString& location);
private:
static QFile* savedFileForSnapshot(QImage & image, bool isTemporary, const QString& userSelectedFilename = QString());
static qint16 snapshotIndex;
static QVariant oldAttachedEntityId;
static QVariant oldOrientation;
static QVariant oldvFoV;
static QVariant oldNearClipPlaneDistance;
static QVariant oldFarClipPlaneDistance;
static QImage downImage;
static QImage frontImage;
static QImage leftImage;
static QImage backImage;
static QImage rightImage;
static QImage upImage;
static void convertToEquirectangular();
};
#endif // hifi_Snapshot_h

View file

@ -672,6 +672,7 @@
Menu.menuItemEvent.connect(menuItemEvent);
Window.domainConnectionRefused.connect(onDomainConnectionRefused);
Window.stillSnapshotTaken.connect(onSnapshotTaken);
Window.equirectangularSnapshotTaken.connect(onSnapshotTaken);
Window.processingGifStarted.connect(processingGif);
Window.connectionAdded.connect(connectionAdded);
Window.connectionError.connect(connectionError);

View file

@ -239,7 +239,7 @@ Rectangle {
// Instructions (visible when display texture isn't set)
HifiStylesUit.FiraSansRegular {
id: spectatorCameraInstructions;
text: "Turn on Spectator Camera for a preview\nof what your monitor shows.";
text: "Turn on Spectator Camera for a preview\nof " + (HMD.active ? "what your monitor shows." : "the camera's view.");
size: 16;
color: hifi.colors.lightGrayText;
visible: !cameraToggleButton.camIsOn;
@ -252,7 +252,7 @@ Rectangle {
Hifi.ResourceImageItem {
id: spectatorCameraPreview;
visible: cameraToggleButton.camIsOn;
url: monitorShowsSwitch.checked ? "resource://spectatorCameraFrame" : "resource://hmdPreviewFrame";
url: monitorShowsSwitch.checked || !HMD.active ? "resource://spectatorCameraFrame" : "resource://hmdPreviewFrame";
ready: cameraToggleButton.camIsOn;
mirrorVertically: true;
anchors.fill: parent;
@ -267,6 +267,7 @@ Rectangle {
// "Monitor Shows" Switch Label Glyph
HifiStylesUit.HiFiGlyphs {
id: monitorShowsSwitchLabelGlyph;
visible: HMD.active;
text: hifi.glyphs.screen;
size: 32;
color: hifi.colors.blueHighlight;
@ -277,6 +278,7 @@ Rectangle {
// "Monitor Shows" Switch Label
HifiStylesUit.RalewayLight {
id: monitorShowsSwitchLabel;
visible: HMD.active;
text: "MONITOR SHOWS:";
anchors.top: spectatorCameraImageContainer.bottom;
anchors.topMargin: 20;
@ -291,6 +293,7 @@ Rectangle {
// "Monitor Shows" Switch
HifiControlsUit.Switch {
id: monitorShowsSwitch;
visible: HMD.active;
height: 30;
anchors.left: parent.left;
anchors.right: parent.right;
@ -307,6 +310,7 @@ Rectangle {
// "Switch View From Controller" Checkbox
HifiControlsUit.CheckBox {
id: switchViewFromControllerCheckBox;
visible: HMD.active;
colorScheme: hifi.colorSchemes.dark;
anchors.left: parent.left;
anchors.top: monitorShowsSwitch.bottom;
@ -335,15 +339,18 @@ Rectangle {
HifiControlsUit.Button {
id: take360SnapshotButton;
text: "Take 360 Snapshot"
text: "Take 360 Snapshot";
enabled: cameraToggleButton.camIsOn;
colorScheme: hifi.colorSchemes.dark;
color: hifi.buttons.blue;
anchors.top: takeSnapshotFromControllerCheckBox.visible ? takeSnapshotFromControllerCheckBox.bottom : switchViewFromControllerCheckBox.bottom;
anchors.top: takeSnapshotFromControllerCheckBox.visible ? takeSnapshotFromControllerCheckBox.bottom : spectatorCameraImageContainer.bottom;
anchors.topMargin: 8;
anchors.left: parent.left;
anchors.right: parent.right;
height: 40;
onClicked: {
take360SnapshotButton.enabled = false;
take360SnapshotButton.text = "360 SNAPSHOT PROCESSING...";
sendToScript({method: 'takeSecondaryCamera360Snapshot'});
}
}
@ -400,6 +407,10 @@ Rectangle {
spectatorCameraPreview.url = message.url;
spectatorCameraPreview.visible = message.setting;
break;
case 'enable360SnapshotButton':
take360SnapshotButton.text = "Take 360 Snapshot";
take360SnapshotButton.enabled = cameraToggleButton.camIsOn;
break;
default:
console.log('Unrecognized message from spectatorCamera.js:', JSON.stringify(message));
}

View file

@ -68,8 +68,8 @@
spectatorCameraConfig.resetSizeSpectatorCamera(Window.innerWidth, Window.innerHeight);
cameraRotation = Quat.multiply(MyAvatar.orientation, Quat.fromPitchYawRollDegrees(15, -155, 0)), cameraPosition = inFrontOf(0.85, Vec3.sum(MyAvatar.position, { x: 0, y: 0.28, z: 0 }));
camera = Entities.addEntity({
"angularDamping": 0.8,
"damping": 0.8,
"angularDamping": 0.95,
"damping": 0.95,
"collidesWith": "static,dynamic,kinematic,",
"collisionMask": 7,
"dynamic": true,
@ -193,6 +193,7 @@
tablet.screenChanged.connect(onTabletScreenChanged);
Window.domainChanged.connect(onDomainChanged);
Window.geometryChanged.connect(resizeViewFinderOverlay);
Window.equirectangularSnapshotTaken.connect(onEquirectangularSnapshotTaken);
Controller.keyPressEvent.connect(keyPressEvent);
HMD.displayModeChanged.connect(onHMDChanged);
viewFinderOverlay = false;
@ -403,6 +404,11 @@
Window.takeSecondaryCameraSnapshot();
}
}
function onEquirectangularSnapshotTaken() {
sendToQml({
method: 'enable360SnapshotButton'
});
}
function maybeTake360Snapshot() {
if (camera) {
Audio.playSound(SNAPSHOT_SOUND, {
@ -410,7 +416,7 @@
localOnly: true,
volume: 1.0
});
Window.takeSecondaryCamera360Snapshot();
Window.takeSecondaryCamera360Snapshot(Entities.getEntityProperties(camera, ["positon"]).position);
}
}
function registerTakeSnapshotControllerMapping() {
@ -583,6 +589,7 @@
spectatorCameraOff();
Window.domainChanged.disconnect(onDomainChanged);
Window.geometryChanged.disconnect(resizeViewFinderOverlay);
Window.equirectangularSnapshotTaken.disconnect(onEquirectangularSnapshotTaken);
addOrRemoveButton(true);
if (tablet) {
tablet.screenChanged.disconnect(onTabletScreenChanged);