From 0498e27d1f2a98c914b13c89eb13eb177ac6f6e6 Mon Sep 17 00:00:00 2001 From: "Mr.doob" Date: Wed, 28 Feb 2024 20:23:22 +0900 Subject: [PATCH] Editor: Added Image render section (Realistic shading not ready yet). --- editor/js/Sidebar.Project.Image.js | 155 +++++++++++++++++++++++++++++ editor/js/Sidebar.Project.js | 3 + editor/js/Strings.js | 9 ++ editor/sw.js | 1 + 4 files changed, 168 insertions(+) create mode 100644 editor/js/Sidebar.Project.Image.js diff --git a/editor/js/Sidebar.Project.Image.js b/editor/js/Sidebar.Project.Image.js new file mode 100644 index 00000000000000..8785ccd753fd26 --- /dev/null +++ b/editor/js/Sidebar.Project.Image.js @@ -0,0 +1,155 @@ +import * as THREE from 'three'; + +import { UIBreak, UIButton, UIInteger, UIPanel, UIRow, UISelect, UIText } from './libs/ui.js'; + +import { ViewportPathtracer } from './Viewport.Pathtracer.js'; + +function SidebarProjectImage( editor ) { + + const strings = editor.strings; + + const container = new UIPanel(); + container.setId( 'render' ); + + // Image + + container.add( new UIText( strings.getKey( 'sidebar/project/image' ) ).setTextTransform( 'uppercase' ) ); + container.add( new UIBreak(), new UIBreak() ); + + // Shading + + const shadingRow = new UIRow(); + // container.add( shadingRow ); + + shadingRow.add( new UIText( strings.getKey( 'sidebar/project/shading' ) ).setClass( 'Label' ) ); + + const shadingTypeSelect = new UISelect().setOptions( { + 0: 'Solid', + 1: 'Realistic' + } ).setWidth( '125px' ); + shadingTypeSelect.setValue( 0 ); + shadingRow.add( shadingTypeSelect ); + + // Resolution + + const resolutionRow = new UIRow(); + container.add( resolutionRow ); + + resolutionRow.add( new UIText( strings.getKey( 'sidebar/project/resolution' ) ).setClass( 'Label' ) ); + + const imageWidth = new UIInteger( 1024 ).setTextAlign( 'center' ).setWidth( '28px' ); + resolutionRow.add( imageWidth ); + + resolutionRow.add( new UIText( '×' ).setTextAlign( 'center' ).setFontSize( '12px' ).setWidth( '12px' ) ); + + const imageHeight = new UIInteger( 1024 ).setTextAlign( 'center' ).setWidth( '28px' ); + resolutionRow.add( imageHeight ); + + // Render + + const renderButton = new UIButton( strings.getKey( 'sidebar/project/render' ) ); + renderButton.setWidth( '170px' ); + renderButton.setMarginLeft( '120px' ); + renderButton.onClick( async () => { + + const json = editor.toJSON(); + const project = json.project; + + // + + const loader = new THREE.ObjectLoader(); + + const camera = loader.parse( json.camera ); + camera.aspect = imageWidth.getValue() / imageHeight.getValue(); + camera.updateProjectionMatrix(); + camera.updateMatrixWorld(); + + const scene = loader.parse( json.scene ); + + const renderer = new THREE.WebGLRenderer( { antialias: true } ); + renderer.setSize( imageWidth.getValue(), imageHeight.getValue() ); + + if ( project.shadows !== undefined ) renderer.shadowMap.enabled = project.shadows; + if ( project.shadowType !== undefined ) renderer.shadowMap.type = project.shadowType; + if ( project.toneMapping !== undefined ) renderer.toneMapping = project.toneMapping; + if ( project.toneMappingExposure !== undefined ) renderer.toneMappingExposure = project.toneMappingExposure; + + // popup + + const width = imageWidth.getValue() / window.devicePixelRatio; + const height = imageHeight.getValue() / window.devicePixelRatio; + + const left = ( screen.width - width ) / 2; + const top = ( screen.height - height ) / 2; + + const output = window.open( '', '_blank', `location=no,left=${left},top=${top},width=${width},height=${height}` ); + + const meta = document.createElement( 'meta' ); + meta.name = 'viewport'; + meta.content = 'width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0'; + output.document.head.appendChild( meta ); + + output.document.body.style.background = '#000'; + output.document.body.style.margin = '0px'; + output.document.body.style.overflow = 'hidden'; + + const canvas = renderer.domElement; + canvas.style.width = width + 'px'; + canvas.style.height = height + 'px'; + output.document.body.appendChild( canvas ); + + // + + switch ( Number( shadingTypeSelect.getValue() ) ) { + + case 0: // SOLID + + renderer.render( scene, camera ); + renderer.dispose(); + + break; + /* + case 1: // REALISTIC + + const status = document.createElement( 'div' ); + status.style.position = 'absolute'; + status.style.top = '10px'; + status.style.left = '10px'; + status.style.color = 'white'; + status.style.fontFamily = 'system-ui'; + status.style.fontSize = '12px'; + output.document.body.appendChild( status ); + + const pathtracer = new ViewportPathtracer( renderer ); + pathtracer.init( scene, camera ); + pathtracer.setSize( imageWidth.getValue(), imageHeight.getValue()); + + function animate() { + + if ( output.closed === true ) return; + + requestAnimationFrame( animate ); + + pathtracer.update(); + + // status.textContent = Math.floor( samples ); + + } + + animate(); + + break; + */ + + } + + } ); + container.add( renderButton ); + + // + + return container; + +} + +export { SidebarProjectImage }; diff --git a/editor/js/Sidebar.Project.js b/editor/js/Sidebar.Project.js index 2091d62f734f97..ae9039f97b13ec 100644 --- a/editor/js/Sidebar.Project.js +++ b/editor/js/Sidebar.Project.js @@ -3,6 +3,7 @@ import { UISpan } from './libs/ui.js'; import { SidebarProjectApp } from './Sidebar.Project.App.js'; /* import { SidebarProjectMaterials } from './Sidebar.Project.Materials.js'; */ import { SidebarProjectRenderer } from './Sidebar.Project.Renderer.js'; +import { SidebarProjectImage } from './Sidebar.Project.Image.js'; import { SidebarProjectVideo } from './Sidebar.Project.Video.js'; function SidebarProject( editor ) { @@ -15,6 +16,8 @@ function SidebarProject( editor ) { container.add( new SidebarProjectApp( editor ) ); + container.add( new SidebarProjectImage( editor ) ); + if ( 'SharedArrayBuffer' in window ) { container.add( new SidebarProjectVideo( editor ) ); diff --git a/editor/js/Strings.js b/editor/js/Strings.js index b9dc5e239808aa..95a13930c0fb88 100644 --- a/editor/js/Strings.js +++ b/editor/js/Strings.js @@ -318,7 +318,10 @@ function Strings( config ) { 'sidebar/project/app/editable': 'Editable', 'sidebar/project/app/publish': 'Publish', + 'sidebar/project/image': 'Image', 'sidebar/project/video': 'Video', + + 'sidebar/project/shading': 'Shading', 'sidebar/project/resolution': 'Resolution', 'sidebar/project/duration': 'Duration', 'sidebar/project/render': 'Render', @@ -664,7 +667,10 @@ function Strings( config ) { 'sidebar/project/app/editable': 'Modifiable', 'sidebar/project/app/publish': 'Publier', + 'sidebar/project/image': 'Image', 'sidebar/project/video': 'Video', + + 'sidebar/project/shading': 'Shading', 'sidebar/project/resolution': 'Resolution', 'sidebar/project/duration': 'Duration', 'sidebar/project/render': 'Render', @@ -1010,7 +1016,10 @@ function Strings( config ) { 'sidebar/project/app/editable': '编辑性', 'sidebar/project/app/publish': '发布', + 'sidebar/project/image': 'Image', 'sidebar/project/video': '视频', + + 'sidebar/project/shading': 'Shading', 'sidebar/project/resolution': '分辨率', 'sidebar/project/duration': '时长', 'sidebar/project/render': '渲染', diff --git a/editor/sw.js b/editor/sw.js index 4d30f92a608eee..9447e6f5a1110f 100644 --- a/editor/sw.js +++ b/editor/sw.js @@ -149,6 +149,7 @@ const assets = [ './js/Sidebar.Project.Renderer.js', './js/Sidebar.Project.Materials.js', './js/Sidebar.Project.App.js', + './js/Sidebar.Project.Image.js', './js/Sidebar.Project.Video.js', './js/Sidebar.Settings.js', './js/Sidebar.Settings.History.js',