Skip to content

Commit

Permalink
Add ScenePreviewCameraNode
Browse files Browse the repository at this point in the history
  • Loading branch information
robertlong committed Aug 3, 2020
1 parent 4f48879 commit bd2b001
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 30 deletions.
7 changes: 3 additions & 4 deletions src/api/Api.js
Original file line number Diff line number Diff line change
Expand Up @@ -557,7 +557,7 @@ export default class Project extends EventEmitter {
throw new Error("Save project aborted");
}

const { blob: thumbnailBlob } = await editor.takeScreenshot(512, 320);
const thumbnailBlob = await editor.takeScreenshot(512, 320);

if (signal.aborted) {
throw new Error("Save project aborted");
Expand Down Expand Up @@ -711,7 +711,7 @@ export default class Project extends EventEmitter {
await new Promise(resolve => setTimeout(resolve, 5));

// Take a screenshot of the scene from the current camera position to use as the thumbnail
const { blob: screenshotBlob, cameraTransform: screenshotCameraTransform } = await editor.takeScreenshot();
const screenshotBlob = await editor.takeScreenshot();
screenshotUrl = URL.createObjectURL(screenshotBlob);

if (signal.aborted) {
Expand Down Expand Up @@ -767,8 +767,7 @@ export default class Project extends EventEmitter {
name: publishParams.name,
creatorAttribution: publishParams.creatorAttribution,
allowRemixing: publishParams.allowRemixing,
allowPromotion: publishParams.allowPromotion,
previewCameraTransform: screenshotCameraTransform
allowPromotion: publishParams.allowPromotion
});

// Save the creatorAttribution to localStorage so that the user doesn't have to input it again
Expand Down
3 changes: 3 additions & 0 deletions src/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ import SimpleWaterNode from "./editor/nodes/SimpleWaterNode";
import SimpleWaterNodeEditor from "./ui/properties/SimpleWaterNodeEditor";
import AudioNode from "./editor/nodes/AudioNode";
import AudioNodeEditor from "./ui/properties/AudioNodeEditor";
import ScenePreviewCameraNode from "./editor/nodes/ScenePreviewCameraNode";
import ScenePreviewCameraNodeEditor from "./ui/properties/ScenePreviewCameraNodeEditor";

import SketchfabSource from "./ui/assets/sources/SketchfabSource";
import PolySource from "./ui/assets/sources/PolySource";
Expand Down Expand Up @@ -84,6 +86,7 @@ export function createEditor(api, settings) {
editor.registerNode(ParticleEmitterNode, ParticleEmitterNodeEditor);
editor.registerNode(KitPieceNode, KitPieceNodeEditor);
editor.registerNode(SimpleWaterNode, SimpleWaterNodeEditor);
editor.registerNode(ScenePreviewCameraNode, ScenePreviewCameraNodeEditor);

editor.registerSource(new ElementsSource(editor));
editor.registerSource(new MyAssetsSource(editor));
Expand Down
12 changes: 2 additions & 10 deletions src/editor/Editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ export default class Editor extends EventEmitter {
async exportScene(signal, options = {}) {
const { combineMeshes, removeUnusedObjects } = Object.assign({}, Editor.DefaultExportOptions, options);

this.deselectAll(false);

const scene = this.scene;

const floorPlanNode = scene.findNodeByType(FloorPlanNode);
Expand Down Expand Up @@ -387,16 +389,6 @@ export default class Editor extends EventEmitter {
clonedScene.removeUnusedObjects();
}

// Add a preview camera to the exported GLB if there is a transform in the metadata.
const previewCamera = this.camera.clone();
previewCamera.name = "scene-preview-camera";
previewCamera.userData.gltfExtensions = {
MOZ_hubs_components: {
"scene-preview-camera": {}
}
};
clonedScene.add(previewCamera);

const exporter = new GLTFExporter({
mode: "glb",
onlyVisible: false,
Expand Down
49 changes: 49 additions & 0 deletions src/editor/nodes/ScenePreviewCameraNode.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Matrix4, PerspectiveCamera, CameraHelper } from "three";
import EditorNodeMixin from "./EditorNodeMixin";

export default class ScenePreviewCameraNode extends EditorNodeMixin(PerspectiveCamera) {
static legacyComponentName = "scene-preview-camera";

static nodeName = "Scene Preview Camera";

static canAddNode(editor) {
return editor.scene.findNodeByType(ScenePreviewCameraNode) === null;
}

constructor(editor) {
super(editor, 80, 16 / 9, 0.2, 8000);

const cameraHelper = new CameraHelper(this);
cameraHelper.layers.set(1);
this.helper = cameraHelper;
}

setFromViewport() {
const matrix = new Matrix4().getInverse(this.parent.matrixWorld).multiply(this.editor.camera.matrixWorld);
matrix.decompose(this.position, this.rotation, this.scale);
this.editor.emit("objectsChanged", [this]);
this.editor.emit("selectionChanged");
}

onSelect() {
this.editor.scene.add(this.helper);
this.helper.update();
}

onDeselect() {
this.editor.scene.remove(this.helper);
}

serialize() {
return super.serialize({ "scene-preview-camera": {} });
}

prepareForExport() {
super.prepareForExport();
// This name is required in the current Hubs client.
// It's possible to migrate to the scene-preview-camera component in the future.
this.name = "scene-preview-camera";
this.addGLTFComponent("scene-preview-camera");
this.replaceObject();
}
}
35 changes: 20 additions & 15 deletions src/editor/renderer/Renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import OutlinePass from "./OutlinePass";
import { getCanvasBlob } from "../utils/thumbnails";
import makeRenderer from "./makeRenderer";
import SpokeBatchRawUniformGroup from "./SpokeBatchRawUniformGroup";
import ScenePreviewCameraNode from "../nodes/ScenePreviewCameraNode";

/**
* @author mrdoob / http://mrdoob.com/
Expand Down Expand Up @@ -272,15 +273,23 @@ export default class Renderer {
this.renderer = screenshotRenderer;

this.editor.disableUpdate = true;
const prevAspect = camera.aspect;
camera.aspect = width / height;
camera.updateProjectionMatrix();

camera.layers.disable(1);
let scenePreviewCamera = this.editor.scene.findNodeByType(ScenePreviewCameraNode);

screenshotRenderer.setSize(width, height, true);
if (!scenePreviewCamera) {
scenePreviewCamera = new ScenePreviewCameraNode(this.editor);
camera.matrix.decompose(scenePreviewCamera.position, scenePreviewCamera.rotation, scenePreviewCamera.scale);
this.editor.addObject(scenePreviewCamera);
}

const prevAspect = scenePreviewCamera.aspect;
scenePreviewCamera.aspect = width / height;

scenePreviewCamera.updateProjectionMatrix();

screenshotRenderer.render(this.editor.scene, camera);
scenePreviewCamera.layers.disable(1);

screenshotRenderer.setSize(width, height, true);

this.editor.scene.traverse(child => {
if (child.isNode) {
Expand All @@ -292,17 +301,13 @@ export default class Renderer {
this.shadowsRenderMode.onSceneSet();
}

this.screenshotRenderer.render(this.editor.scene, camera);

camera.layers.enable(1);

camera.updateMatrixWorld();
const cameraTransform = camera.matrixWorld.clone();
screenshotRenderer.render(this.editor.scene, scenePreviewCamera);

const blob = await getCanvasBlob(screenshotRenderer.domElement);

camera.aspect = prevAspect;
camera.updateProjectionMatrix();
scenePreviewCamera.aspect = prevAspect;
scenePreviewCamera.updateProjectionMatrix();
scenePreviewCamera.layers.enable(1);
this.editor.disableUpdate = false;

this.renderer = originalRenderer;
Expand All @@ -315,7 +320,7 @@ export default class Renderer {
}
});

return { blob, cameraTransform };
return blob;
};

dispose() {
Expand Down
2 changes: 1 addition & 1 deletion src/ui/EditorContainer.js
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ class EditorContainer extends Component {
// Wait for 5ms so that the ProgressDialog shows up.
await new Promise(resolve => setTimeout(resolve, 5));

const { blob } = await editor.takeScreenshot(512, 320);
const blob = await editor.takeScreenshot(512, 320);

const result = await new Promise(resolve => {
this.showDialog(SaveNewProjectDialog, {
Expand Down
29 changes: 29 additions & 0 deletions src/ui/properties/ScenePreviewCameraNodeEditor.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import React, { Component } from "react";
import PropTypes from "prop-types";
import NodeEditor from "./NodeEditor";
import { Camera } from "styled-icons/fa-solid/Camera";
import { PropertiesPanelButton } from "../inputs/Button";

export default class ScenePreviewCameraNodeEditor extends Component {
static propTypes = {
editor: PropTypes.object,
node: PropTypes.object
};

static iconComponent = Camera;

static description =
"The camera used to generate the thumbnail for your scene and the starting position for the preview camera in Hubs.";

onSetFromViewport = () => {
this.props.node.setFromViewport();
};

render() {
return (
<NodeEditor {...this.props} description={ScenePreviewCameraNodeEditor.description}>
<PropertiesPanelButton onClick={this.onSetFromViewport}>Set From Viewport</PropertiesPanelButton>
</NodeEditor>
);
}
}

0 comments on commit bd2b001

Please sign in to comment.