Fix and enable 3D viewer: #4035

Fix 3d viewer styles

Fix minor warnings from three.js

Remove deprecated themes

Fix #4074
This commit is contained in:
btzr-io 2020-04-25 03:24:42 -05:00 committed by Sean Yesmunt
parent ae3c8d5221
commit e4d822f818
6 changed files with 79 additions and 154 deletions

View file

@ -2,6 +2,7 @@
import React, { useState, useEffect } from 'react';
import FileRender from 'component/fileRender';
import LoadingScreen from 'component/common/loading-screen';
import { NON_STREAM_MODES } from 'constants/file_render_modes';
type Props = {
isPlaying: boolean,
@ -14,9 +15,18 @@ type Props = {
};
export default function FileRenderInline(props: Props) {
const { isPlaying, fileInfo, uri, streamingUrl, triggerAnalyticsView, claimRewards } = props;
const { isPlaying, fileInfo, uri, streamingUrl, triggerAnalyticsView, claimRewards, renderMode } = props;
const [playTime, setPlayTime] = useState();
const isReadyToPlay = streamingUrl || (fileInfo && fileInfo.completed);
const isReadyToView = fileInfo && fileInfo.completed;
const isReadyToPlay = streamingUrl || isReadyToView;
// Render if any source is ready
let renderContent = isReadyToPlay;
// Force non-streaming content to wait for download
if (NON_STREAM_MODES.includes(renderMode)) {
renderContent = isReadyToView;
}
useEffect(() => {
if (isPlaying) {
@ -39,5 +49,5 @@ export default function FileRenderInline(props: Props) {
return null;
}
return isReadyToPlay ? <FileRender uri={uri} /> : <LoadingScreen status={__('Preparing your content')} />;
return renderContent ? <FileRender uri={uri} /> : <LoadingScreen status={__('Preparing your content')} />;
}

View file

@ -1,7 +1,6 @@
// @flow
import * as React from 'react';
import * as dat from 'dat.gui';
import classNames from 'classnames';
import LoadingScreen from 'component/common/loading-screen';
// ThreeJS
@ -52,14 +51,13 @@ const ThreeLoader = ({ fileType = null, downloadPath = null }, renderModel, mana
};
type viewerTheme = {
gridColor: string,
groundColor: string,
backgroundColor: string,
centerLineColor: string,
showFog: boolean,
gridColor: number,
backgroundColor: number,
centerLineColor: number,
};
type Props = {
theme: string,
source: {
fileType: string,
downloadPath: string,
@ -131,26 +129,15 @@ class ThreeViewer extends React.PureComponent<Props, State> {
constructor(props: Props) {
super(props);
const { theme } = this.props;
// Object defualt color
this.materialColor = '#44b098';
// Viewer themes
this.themes = {
dark: {
gridColor: '#414e5c',
groundColor: '#13233C',
backgroundColor: '#13233C',
centerLineColor: '#7f8c8d',
},
light: {
gridColor: '#7f8c8d',
groundColor: '#DDD',
backgroundColor: '#EEE',
centerLineColor: '#2F2F2F',
},
this.materialColor = 0xffffff;
// Default viewer Theme
this.theme = {
showFog: true,
gridColor: 0x414e5c,
centerLineColor: 0x7f8c8d,
backgroundColor: 0x0b0c0d,
};
// Select current theme
this.theme = this.themes[theme] || this.themes.light;
// State
this.state = {
error: null,
@ -212,29 +199,27 @@ class ThreeViewer extends React.PureComponent<Props, State> {
});
// Clean up controls
if (this.controls) this.controls.dispose();
// It's unclear if we need this:
// Clean up scene
if (this.scene) this.scene.dispose();
if (this.renderer) {
this.renderer.context = null;
this.renderer.domElement = null;
this.renderer.renderLists.dispose();
this.renderer.forceContextLoss();
this.renderer.dispose();
this.renderer = null;
}
// Stop animation
cancelAnimationFrame(this.frameID);
// Destroy GUI Controls
if (this.gui) this.gui.destroy();
// Empty objects
this.grid = null;
this.mesh = null;
this.renderer = null;
this.material = null;
this.geometry = null;
this.bufferGeometry = null;
}
}
// Define component types
theme: viewerTheme;
themes: { dark: viewerTheme, light: viewerTheme };
materialColor: string;
materialColor: number;
// Refs
viewer: ?HTMLElement;
guiContainer: ?HTMLElement;
@ -265,10 +250,10 @@ class ThreeViewer extends React.PureComponent<Props, State> {
transformGroup(group: any) {
ThreeViewer.fitMeshToCamera(group);
if (!this.targetCenter) {
const box = new Box3();
this.targetCenter = box.setFromObject(this.mesh).getCenter();
const center = new Vector3();
this.targetCenter = box.setFromObject(this.mesh).getCenter(center);
}
this.updateControlsTarget(this.targetCenter);
}
@ -452,10 +437,7 @@ class ThreeViewer extends React.PureComponent<Props, State> {
gammaCorrection: true,
});
this.scene = ThreeScene({
showFog: true,
...this.theme,
});
this.scene = ThreeScene(this.theme);
const canvas = this.renderer.domElement;
const { offsetWidth: width, offsetHeight: height } = this.viewer || {};
@ -473,7 +455,7 @@ class ThreeViewer extends React.PureComponent<Props, State> {
// Set viewer size
this.renderer.setSize(width, height);
// Create model material
// Create material
this.material = new MeshPhongMaterial({
depthWrite: true,
flatShading: true,
@ -501,26 +483,21 @@ class ThreeViewer extends React.PureComponent<Props, State> {
}
render() {
const { theme } = this.props;
const { error, isReady, isLoading } = this.state;
const loadingMessage = __('Loading 3D model.');
const showViewer = isReady && !error;
const showLoading = isLoading && !error;
// Adaptive theme for gui controls
const containerClass = classNames('gui-container', { light: theme === 'light' });
const showLoading = isLoading && !error && !isReady;
const containerClass = 'gui-container';
return (
<React.Fragment>
<>
<div className="file-render__viewer file-render__viewer--three">
<div ref={element => (this.guiContainer = element)} className={containerClass} />
<div className="three-viewer" ref={viewer => (this.viewer = viewer)}>
{error && <LoadingScreen status={error} spinner={false} />}
{showLoading && <LoadingScreen status={loadingMessage} spinner />}
<div ref={element => (this.guiContainer = element)} className={containerClass} />
<div
style={{ opacity: showViewer ? 1 : 0 }}
className="three-viewer file-render__viewer"
ref={viewer => (this.viewer = viewer)}
/>
</React.Fragment>
</div>
</div>
</>
);
}
}

View file

@ -21,17 +21,18 @@ const addLights = (scene, color, groundColor) => {
scene.add(shadowLight);
};
const ViewerScene = ({ backgroundColor, groundColor, showFog }) => {
// Convert color
const bgColor = new Color(backgroundColor);
const ViewerScene = ({ backgroundColor, showFog }) => {
// New scene
const bg = new Color(backgroundColor);
const scene = new Scene();
// Background color
scene.background = bgColor;
// Fog effect
scene.fog = showFog === true ? new Fog(bgColor, 1, 95) : null;
// Transparent background
scene.background = bg;
// Add fog
if (showFog) {
scene.fog = new Fog(bg, 1, 54);
}
// Add basic lights
addLights(scene, '#FFFFFF', groundColor);
addLights(scene, 0xffffff, bg);
// Return new three scene
return scene;
};

View file

@ -16,7 +16,10 @@ export const IMAGE = 'image';
export const CAD = 'cad';
export const COMIC = 'comic';
export const AUTO_RENDER_MODES = [IMAGE, CAD, COMIC].concat(TEXT_MODES); // these types will render (and thus download) automatically (if free)
// These types can only be render if download completed
export const NON_STREAM_MODES = [CAD, COMIC];
export const AUTO_RENDER_MODES = [IMAGE].concat(TEXT_MODES);
export const WEB_SHAREABLE_MODES = AUTO_RENDER_MODES.concat(FLOATING_MODES);
export const DOWNLOAD = 'download';
@ -25,7 +28,7 @@ export const UNSUPPORTED = 'unsupported';
// PDFs disabled on desktop until we update Electron: https://github.com/electron/electron/issues/12337
// Comics disabled because nothing is actually reporting as a comic type
export const UNSUPPORTED_IN_THIS_APP = IS_WEB ? [CAD, COMIC, APPLICATION] : [CAD, APPLICATION, PDF];
export const UNSUPPORTED_IN_THIS_APP = IS_WEB ? [CAD, COMIC, APPLICATION] : [APPLICATION, PDF];
export const UNRENDERABLE_MODES = Array.from(
new Set(UNSUPPORTED_IN_THIS_APP.concat([DOWNLOAD, APPLICATION, UNSUPPORTED]))

View file

@ -3,101 +3,26 @@
.gui-container {
top: 0;
right: 0;
position: absolute;
z-index: 2;
.dg.main {
margin: 0;
padding: 0;
overflow: inherit;
}
// Light theme:
// https://github.com/liabru/dat-gui-light-theme
&.light {
.dg.main.taller-than-window .close-button {
border-top: 1px solid #ddd;
}
.dg.main .close-button {
&:not(:hover) {
background-color: #e8e8e8;
}
&:hover {
background-color: #ddd;
}
}
.dg {
color: #555;
text-shadow: none !important;
&.main {
&::-webkit-scrollbar {
background-color: #fafafa;
}
&::-webkit-scrollbar-thumb {
background-color: #bbb;
}
}
li {
&:not(.folder) {
background-color: #fafafa;
border-bottom: 1px solid #ddd;
margin: 0;
}
&.save-row .button {
text-shadow: none !important;
}
&.title {
background: #e8e8e8
url('data:image/gif;base64,R0lGODlhBQAFAJEAAP////Pz8////////yH5BAEAAAIALAAAAAAFAAUAAAIIlI+hKgFxoCgAOw==')
6px 10px no-repeat;
}
}
.cr {
&.function:hover,
&.boolean:hover {
background-color: white;
}
}
.c {
input {
&[type='text'] {
&:not(:focus),
&:not(:hover) {
background-color: #e9e9e9;
height: initial;
}
&:focus,
&:hover {
background-color: #eee;
}
&:focus {
color: #555;
}
}
}
.slider {
&:not(:hover) {
background-color: #e9e9e9;
}
&:hover {
background-color: #eee;
}
}
}
input[type='checkbox'] {
height: 12px;
width: 12px;
padding: 0;
margin: 0;
}
}
}

View file

@ -119,6 +119,15 @@
}
}
.file-render__viewer--three {
position: relative;
overflow: hidden;
.three-viewer {
height: calc(100vh - var(--header-height) - var(--spacing-medium) * 2);
}
}
.file-render__content {
width: 100%;
height: 100%;