mirror of
https://github.com/Comfy-Org/ComfyUI_frontend.git
synced 2026-04-29 18:52:19 +00:00
[3d] performance improvement by using threejs setViewport (#4079)
This commit is contained in:
@@ -160,22 +160,48 @@ class Load3d {
|
|||||||
this.viewHelperManager.update(delta)
|
this.viewHelperManager.update(delta)
|
||||||
this.controlsManager.update()
|
this.controlsManager.update()
|
||||||
|
|
||||||
|
this.renderMainScene()
|
||||||
|
|
||||||
|
if (this.previewManager.showPreview) {
|
||||||
|
this.renderPreviewScene()
|
||||||
|
}
|
||||||
|
|
||||||
|
this.resetViewport()
|
||||||
|
|
||||||
|
if (this.viewHelperManager.viewHelper.render) {
|
||||||
|
this.viewHelperManager.viewHelper.render(this.renderer)
|
||||||
|
}
|
||||||
|
|
||||||
|
this.INITIAL_RENDER_DONE = true
|
||||||
|
}
|
||||||
|
|
||||||
|
renderMainScene(): void {
|
||||||
|
const width = this.renderer.domElement.clientWidth
|
||||||
|
const height = this.renderer.domElement.clientHeight
|
||||||
|
|
||||||
|
this.renderer.setViewport(0, 0, width, height)
|
||||||
|
this.renderer.setScissor(0, 0, width, height)
|
||||||
|
this.renderer.setScissorTest(true)
|
||||||
|
|
||||||
this.renderer.clear()
|
this.renderer.clear()
|
||||||
this.sceneManager.renderBackground()
|
this.sceneManager.renderBackground()
|
||||||
this.renderer.render(
|
this.renderer.render(
|
||||||
this.sceneManager.scene,
|
this.sceneManager.scene,
|
||||||
this.cameraManager.activeCamera
|
this.cameraManager.activeCamera
|
||||||
)
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (this.viewHelperManager.viewHelper.render) {
|
renderPreviewScene(): void {
|
||||||
this.viewHelperManager.viewHelper.render(this.renderer)
|
this.previewManager.renderPreview()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.previewManager.showPreview) {
|
resetViewport(): void {
|
||||||
this.previewManager.updatePreviewRender()
|
const width = this.renderer.domElement.clientWidth
|
||||||
}
|
const height = this.renderer.domElement.clientHeight
|
||||||
|
|
||||||
this.INITIAL_RENDER_DONE = true
|
this.renderer.setViewport(0, 0, width, height)
|
||||||
|
this.renderer.setScissor(0, 0, width, height)
|
||||||
|
this.renderer.setScissorTest(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private getActiveCamera(): THREE.Camera {
|
private getActiveCamera(): THREE.Camera {
|
||||||
@@ -198,20 +224,17 @@ class Load3d {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.previewManager.showPreview) {
|
|
||||||
this.previewManager.updatePreviewRender()
|
|
||||||
}
|
|
||||||
|
|
||||||
const delta = this.clock.getDelta()
|
const delta = this.clock.getDelta()
|
||||||
this.viewHelperManager.update(delta)
|
this.viewHelperManager.update(delta)
|
||||||
this.controlsManager.update()
|
this.controlsManager.update()
|
||||||
|
|
||||||
this.renderer.clear()
|
this.renderMainScene()
|
||||||
this.sceneManager.renderBackground()
|
|
||||||
this.renderer.render(
|
if (this.previewManager.showPreview) {
|
||||||
this.sceneManager.scene,
|
this.renderPreviewScene()
|
||||||
this.cameraManager.activeCamera
|
}
|
||||||
)
|
|
||||||
|
this.resetViewport()
|
||||||
|
|
||||||
if (this.viewHelperManager.viewHelper.render) {
|
if (this.viewHelperManager.viewHelper.render) {
|
||||||
this.viewHelperManager.viewHelper.render(this.renderer)
|
this.viewHelperManager.viewHelper.render(this.renderer)
|
||||||
@@ -304,11 +327,9 @@ class Load3d {
|
|||||||
async setBackgroundImage(uploadPath: string): Promise<void> {
|
async setBackgroundImage(uploadPath: string): Promise<void> {
|
||||||
await this.sceneManager.setBackgroundImage(uploadPath)
|
await this.sceneManager.setBackgroundImage(uploadPath)
|
||||||
|
|
||||||
if (this.previewManager.previewRenderer) {
|
this.previewManager.updateBackgroundTexture(
|
||||||
this.previewManager.updateBackgroundTexture(
|
this.sceneManager.backgroundTexture
|
||||||
this.sceneManager.backgroundTexture
|
)
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
this.forceRender()
|
this.forceRender()
|
||||||
}
|
}
|
||||||
@@ -316,10 +337,7 @@ class Load3d {
|
|||||||
removeBackgroundImage(): void {
|
removeBackgroundImage(): void {
|
||||||
this.sceneManager.removeBackgroundImage()
|
this.sceneManager.removeBackgroundImage()
|
||||||
|
|
||||||
if (
|
if (this.previewManager.previewCamera) {
|
||||||
this.previewManager.previewRenderer &&
|
|
||||||
this.previewManager.previewCamera
|
|
||||||
) {
|
|
||||||
this.previewManager.updateBackgroundTexture(null)
|
this.previewManager.updateBackgroundTexture(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,10 +42,6 @@ class Load3dAnimation extends Load3d {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.previewManager.showPreview) {
|
|
||||||
this.previewManager.updatePreviewRender()
|
|
||||||
}
|
|
||||||
|
|
||||||
const delta = this.clock.getDelta()
|
const delta = this.clock.getDelta()
|
||||||
|
|
||||||
this.animationManager.update(delta)
|
this.animationManager.update(delta)
|
||||||
@@ -54,12 +50,13 @@ class Load3dAnimation extends Load3d {
|
|||||||
|
|
||||||
this.controlsManager.update()
|
this.controlsManager.update()
|
||||||
|
|
||||||
this.renderer.clear()
|
this.renderMainScene()
|
||||||
this.sceneManager.renderBackground()
|
|
||||||
this.renderer.render(
|
if (this.previewManager.showPreview) {
|
||||||
this.sceneManager.scene,
|
this.renderPreviewScene()
|
||||||
this.cameraManager.activeCamera
|
}
|
||||||
)
|
|
||||||
|
this.resetViewport()
|
||||||
|
|
||||||
if (this.viewHelperManager.viewHelper.render) {
|
if (this.viewHelperManager.viewHelper.render) {
|
||||||
this.viewHelperManager.viewHelper.render(this.renderer)
|
this.viewHelperManager.viewHelper.render(this.renderer)
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
|
|||||||
import { EventManagerInterface, PreviewManagerInterface } from './interfaces'
|
import { EventManagerInterface, PreviewManagerInterface } from './interfaces'
|
||||||
|
|
||||||
export class PreviewManager implements PreviewManagerInterface {
|
export class PreviewManager implements PreviewManagerInterface {
|
||||||
previewRenderer: THREE.WebGLRenderer | null = null
|
|
||||||
previewCamera: THREE.Camera
|
previewCamera: THREE.Camera
|
||||||
previewContainer: HTMLDivElement = {} as HTMLDivElement
|
previewContainer: HTMLDivElement = {} as HTMLDivElement
|
||||||
showPreview: boolean = true
|
showPreview: boolean = true
|
||||||
@@ -17,7 +16,6 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
private getControls: () => OrbitControls
|
private getControls: () => OrbitControls
|
||||||
private eventManager: EventManagerInterface
|
private eventManager: EventManagerInterface
|
||||||
|
|
||||||
// @ts-expect-error unused variable
|
|
||||||
private getRenderer: () => THREE.WebGLRenderer
|
private getRenderer: () => THREE.WebGLRenderer
|
||||||
|
|
||||||
private previewBackgroundScene: THREE.Scene
|
private previewBackgroundScene: THREE.Scene
|
||||||
@@ -25,6 +23,8 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
private previewBackgroundMesh: THREE.Mesh | null = null
|
private previewBackgroundMesh: THREE.Mesh | null = null
|
||||||
private previewBackgroundTexture: THREE.Texture | null = null
|
private previewBackgroundTexture: THREE.Texture | null = null
|
||||||
|
|
||||||
|
private previewBackgroundColor: THREE.Color = new THREE.Color(0x282828)
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
scene: THREE.Scene,
|
scene: THREE.Scene,
|
||||||
getActiveCamera: () => THREE.Camera,
|
getActiveCamera: () => THREE.Camera,
|
||||||
@@ -61,18 +61,6 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
init(): void {}
|
init(): void {}
|
||||||
|
|
||||||
dispose(): void {
|
dispose(): void {
|
||||||
if (this.previewRenderer) {
|
|
||||||
this.previewRenderer.forceContextLoss()
|
|
||||||
const canvas = this.previewRenderer.domElement
|
|
||||||
const event = new Event('webglcontextlost', {
|
|
||||||
bubbles: true,
|
|
||||||
cancelable: true
|
|
||||||
})
|
|
||||||
canvas.dispatchEvent(event)
|
|
||||||
|
|
||||||
this.previewRenderer.dispose()
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.previewBackgroundTexture) {
|
if (this.previewBackgroundTexture) {
|
||||||
this.previewBackgroundTexture.dispose()
|
this.previewBackgroundTexture.dispose()
|
||||||
}
|
}
|
||||||
@@ -84,17 +72,6 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
createCapturePreview(container: Element | HTMLElement): void {
|
createCapturePreview(container: Element | HTMLElement): void {
|
||||||
this.previewRenderer = new THREE.WebGLRenderer({
|
|
||||||
alpha: true,
|
|
||||||
antialias: true,
|
|
||||||
preserveDrawingBuffer: true
|
|
||||||
})
|
|
||||||
|
|
||||||
this.previewRenderer.setSize(this.targetWidth, this.targetHeight)
|
|
||||||
this.previewRenderer.setClearColor(0x282828)
|
|
||||||
this.previewRenderer.autoClear = false
|
|
||||||
this.previewRenderer.outputColorSpace = THREE.SRGBColorSpace
|
|
||||||
|
|
||||||
this.previewContainer = document.createElement('div')
|
this.previewContainer = document.createElement('div')
|
||||||
this.previewContainer.style.cssText = `
|
this.previewContainer.style.cssText = `
|
||||||
position: absolute;
|
position: absolute;
|
||||||
@@ -104,7 +81,6 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
display: block;
|
display: block;
|
||||||
transition: border-color 0.1s ease;
|
transition: border-color 0.1s ease;
|
||||||
`
|
`
|
||||||
this.previewContainer.appendChild(this.previewRenderer.domElement)
|
|
||||||
|
|
||||||
const MIN_PREVIEW_WIDTH = 120
|
const MIN_PREVIEW_WIDTH = 120
|
||||||
const MAX_PREVIEW_WIDTH = 240
|
const MAX_PREVIEW_WIDTH = 240
|
||||||
@@ -131,7 +107,6 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.updatePreviewSize()
|
this.updatePreviewSize()
|
||||||
this.updatePreviewRender()
|
|
||||||
})
|
})
|
||||||
|
|
||||||
this.previewContainer.style.display = this.showPreview ? 'block' : 'none'
|
this.previewContainer.style.display = this.showPreview ? 'block' : 'none'
|
||||||
@@ -159,13 +134,48 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
|
|
||||||
const previewHeight =
|
const previewHeight =
|
||||||
(this.previewWidth * this.targetHeight) / this.targetWidth
|
(this.previewWidth * this.targetHeight) / this.targetWidth
|
||||||
this.previewRenderer?.setSize(this.previewWidth, previewHeight, false)
|
|
||||||
|
this.previewContainer.style.width = `${this.previewWidth}px`
|
||||||
|
this.previewContainer.style.height = `${previewHeight}px`
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreviewViewport(): {
|
||||||
|
left: number
|
||||||
|
bottom: number
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
} | null {
|
||||||
|
if (!this.showPreview || !this.previewContainer) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const renderer = this.getRenderer()
|
||||||
|
const canvas = renderer.domElement
|
||||||
|
|
||||||
|
const containerRect = this.previewContainer.getBoundingClientRect()
|
||||||
|
const canvasRect = canvas.getBoundingClientRect()
|
||||||
|
|
||||||
|
if (
|
||||||
|
containerRect.bottom < canvasRect.top ||
|
||||||
|
containerRect.top > canvasRect.bottom ||
|
||||||
|
containerRect.right < canvasRect.left ||
|
||||||
|
containerRect.left > canvasRect.right
|
||||||
|
) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
const width = parseFloat(this.previewContainer.style.width)
|
||||||
|
const height = parseFloat(this.previewContainer.style.height)
|
||||||
|
|
||||||
|
const left = this.getRenderer().domElement.clientWidth - width
|
||||||
|
|
||||||
|
const bottom = 0
|
||||||
|
|
||||||
|
return { left, bottom, width, height }
|
||||||
}
|
}
|
||||||
|
|
||||||
syncWithMainCamera(): void {
|
syncWithMainCamera(): void {
|
||||||
if (!this.previewRenderer || !this.previewContainer || !this.showPreview) {
|
if (!this.showPreview) return
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
this.previewCamera = this.getActiveCamera().clone()
|
this.previewCamera = this.getActiveCamera().clone()
|
||||||
|
|
||||||
@@ -203,85 +213,73 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.previewCamera.lookAt(this.getControls().target)
|
this.previewCamera.lookAt(this.getControls().target)
|
||||||
|
|
||||||
this.updatePreviewRender()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updatePreviewRender(): void {
|
renderPreview(): void {
|
||||||
if (!this.previewRenderer || !this.previewContainer || !this.showPreview)
|
const viewport = this.getPreviewViewport()
|
||||||
return
|
if (!viewport) return
|
||||||
|
|
||||||
if (
|
const renderer = this.getRenderer()
|
||||||
!this.previewCamera ||
|
|
||||||
(this.getActiveCamera() instanceof THREE.PerspectiveCamera &&
|
|
||||||
!(this.previewCamera instanceof THREE.PerspectiveCamera)) ||
|
|
||||||
(this.getActiveCamera() instanceof THREE.OrthographicCamera &&
|
|
||||||
!(this.previewCamera instanceof THREE.OrthographicCamera))
|
|
||||||
) {
|
|
||||||
this.previewCamera = this.getActiveCamera().clone()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.previewCamera.position.copy(this.getActiveCamera().position)
|
const originalClearColor = renderer.getClearColor(new THREE.Color())
|
||||||
this.previewCamera.rotation.copy(this.getActiveCamera().rotation)
|
const originalClearAlpha = renderer.getClearAlpha()
|
||||||
|
|
||||||
const aspect = this.targetWidth / this.targetHeight
|
this.syncWithMainCamera()
|
||||||
|
|
||||||
if (this.getActiveCamera() instanceof THREE.OrthographicCamera) {
|
renderer.setViewport(
|
||||||
const activeOrtho = this.getActiveCamera() as THREE.OrthographicCamera
|
viewport.left,
|
||||||
const previewOrtho = this.previewCamera as THREE.OrthographicCamera
|
viewport.bottom,
|
||||||
|
viewport.width,
|
||||||
|
viewport.height
|
||||||
|
)
|
||||||
|
renderer.setScissor(
|
||||||
|
viewport.left,
|
||||||
|
viewport.bottom,
|
||||||
|
viewport.width,
|
||||||
|
viewport.height
|
||||||
|
)
|
||||||
|
|
||||||
const frustumHeight =
|
renderer.setClearColor(this.previewBackgroundColor, 1.0)
|
||||||
(activeOrtho.top - activeOrtho.bottom) / activeOrtho.zoom
|
renderer.clear()
|
||||||
|
|
||||||
const frustumWidth = frustumHeight * aspect
|
|
||||||
|
|
||||||
previewOrtho.top = frustumHeight / 2
|
|
||||||
previewOrtho.left = -frustumWidth / 2
|
|
||||||
previewOrtho.right = frustumWidth / 2
|
|
||||||
previewOrtho.bottom = -frustumHeight / 2
|
|
||||||
previewOrtho.zoom = 1
|
|
||||||
|
|
||||||
previewOrtho.updateProjectionMatrix()
|
|
||||||
} else {
|
|
||||||
;(this.previewCamera as THREE.PerspectiveCamera).aspect = aspect
|
|
||||||
;(this.previewCamera as THREE.PerspectiveCamera).fov = (
|
|
||||||
this.getActiveCamera() as THREE.PerspectiveCamera
|
|
||||||
).fov
|
|
||||||
;(this.previewCamera as THREE.PerspectiveCamera).updateProjectionMatrix()
|
|
||||||
}
|
|
||||||
|
|
||||||
this.previewCamera.lookAt(this.getControls().target)
|
|
||||||
|
|
||||||
const previewHeight =
|
|
||||||
(this.previewWidth * this.targetHeight) / this.targetWidth
|
|
||||||
this.previewRenderer.setSize(this.previewWidth, previewHeight, false)
|
|
||||||
this.previewRenderer.outputColorSpace = THREE.SRGBColorSpace
|
|
||||||
this.previewRenderer.clear()
|
|
||||||
|
|
||||||
if (this.previewBackgroundMesh && this.previewBackgroundTexture) {
|
if (this.previewBackgroundMesh && this.previewBackgroundTexture) {
|
||||||
const material = this.previewBackgroundMesh
|
const material = this.previewBackgroundMesh
|
||||||
.material as THREE.MeshBasicMaterial
|
.material as THREE.MeshBasicMaterial
|
||||||
if (material.map) {
|
if (material.map) {
|
||||||
const currentToneMapping = this.previewRenderer.toneMapping
|
const currentToneMapping = renderer.toneMapping
|
||||||
const currentExposure = this.previewRenderer.toneMappingExposure
|
const currentExposure = renderer.toneMappingExposure
|
||||||
|
|
||||||
this.previewRenderer.toneMapping = THREE.NoToneMapping
|
renderer.toneMapping = THREE.NoToneMapping
|
||||||
this.previewRenderer.render(
|
renderer.render(
|
||||||
this.previewBackgroundScene,
|
this.previewBackgroundScene,
|
||||||
this.previewBackgroundCamera
|
this.previewBackgroundCamera
|
||||||
)
|
)
|
||||||
|
|
||||||
this.previewRenderer.toneMapping = currentToneMapping
|
renderer.toneMapping = currentToneMapping
|
||||||
this.previewRenderer.toneMappingExposure = currentExposure
|
renderer.toneMappingExposure = currentExposure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.previewRenderer.render(this.scene, this.previewCamera)
|
renderer.render(this.scene, this.previewCamera)
|
||||||
|
|
||||||
|
renderer.setClearColor(originalClearColor, originalClearAlpha)
|
||||||
|
}
|
||||||
|
|
||||||
|
setPreviewBackgroundColor(color: string | number): void {
|
||||||
|
this.previewBackgroundColor.set(color)
|
||||||
|
}
|
||||||
|
|
||||||
|
getPreviewBackgroundColor(): THREE.Color {
|
||||||
|
return this.previewBackgroundColor.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
updatePreviewRender(): void {
|
||||||
|
this.syncWithMainCamera()
|
||||||
}
|
}
|
||||||
|
|
||||||
togglePreview(showPreview: boolean): void {
|
togglePreview(showPreview: boolean): void {
|
||||||
if (this.previewRenderer) {
|
this.showPreview = showPreview
|
||||||
this.showPreview = showPreview
|
if (this.previewContainer) {
|
||||||
this.previewContainer.style.display = this.showPreview ? 'block' : 'none'
|
this.previewContainer.style.display = this.showPreview ? 'block' : 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -306,7 +304,7 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.previewRenderer && this.previewCamera) {
|
if (this.previewCamera) {
|
||||||
if (this.previewCamera instanceof THREE.PerspectiveCamera) {
|
if (this.previewCamera instanceof THREE.PerspectiveCamera) {
|
||||||
this.previewCamera.aspect = width / height
|
this.previewCamera.aspect = width / height
|
||||||
this.previewCamera.updateProjectionMatrix()
|
this.previewCamera.updateProjectionMatrix()
|
||||||
@@ -322,7 +320,6 @@ export class PreviewManager implements PreviewManagerInterface {
|
|||||||
|
|
||||||
handleResize(): void {
|
handleResize(): void {
|
||||||
this.updatePreviewSize()
|
this.updatePreviewSize()
|
||||||
this.updatePreviewRender()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
updateBackgroundTexture(texture: THREE.Texture | null): void {
|
updateBackgroundTexture(texture: THREE.Texture | null): void {
|
||||||
|
|||||||
@@ -100,7 +100,6 @@ export interface ViewHelperManagerInterface extends BaseManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface PreviewManagerInterface extends BaseManager {
|
export interface PreviewManagerInterface extends BaseManager {
|
||||||
previewRenderer: THREE.WebGLRenderer | null
|
|
||||||
previewCamera: THREE.Camera
|
previewCamera: THREE.Camera
|
||||||
previewContainer: HTMLDivElement
|
previewContainer: HTMLDivElement
|
||||||
showPreview: boolean
|
showPreview: boolean
|
||||||
@@ -112,6 +111,14 @@ export interface PreviewManagerInterface extends BaseManager {
|
|||||||
setTargetSize(width: number, height: number): void
|
setTargetSize(width: number, height: number): void
|
||||||
handleResize(): void
|
handleResize(): void
|
||||||
updateBackgroundTexture(texture: THREE.Texture | null): void
|
updateBackgroundTexture(texture: THREE.Texture | null): void
|
||||||
|
getPreviewViewport(): {
|
||||||
|
left: number
|
||||||
|
bottom: number
|
||||||
|
width: number
|
||||||
|
height: number
|
||||||
|
} | null
|
||||||
|
renderPreview(): void
|
||||||
|
syncWithMainCamera(): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface EventManagerInterface {
|
export interface EventManagerInterface {
|
||||||
|
|||||||
Reference in New Issue
Block a user