import { Camera, Color, OffscreenCanvas, PCFSoftShadowMap, Scene, sRGBEncoding, TextureEncoding, ToneMapping, WebGLRenderer, WebGLRendererParameters, } from 'three' import { Ref } from 'vue' import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls.js' import { normalizeColor } from '/@/utils' export interface RendererOptions { renderer: Partial shadows: boolean controls: boolean physicallyCorrectLights?: boolean outputEncoding?: TextureEncoding toneMapping?: ToneMapping } const experience: Ref = ref(null) let renderer: WebGLRenderer let controls: OrbitControls export const useRenderer = () => { const { width, height } = useWindowSize() const aspectRatio = computed(() => width.value / height.value) watch(aspectRatio, updateRenderer) function initRenderer(camera: Camera, options: RendererOptions) { if (experience.value) { renderer = new WebGLRenderer({ canvas: experience.value, ...options.renderer, }) if (options.shadows) setRealisticShadows() if (options.controls) initControls(camera) renderer.physicallyCorrectLights = options.physicallyCorrectLights || false if (options.outputEncoding) renderer.outputEncoding = options.outputEncoding renderer.outputEncoding = sRGBEncoding if (options.toneMapping) { renderer.toneMapping = options.toneMapping renderer.toneMappingExposure = 1 } return { renderer, controls, } } } function initControls(camera: Camera) { controls = new OrbitControls(camera, renderer.domElement) controls.enableDamping = true } function setRealisticShadows() { renderer.shadowMap.enabled = true renderer.shadowMap.type = PCFSoftShadowMap } function updateRenderer() { if (renderer) { renderer.setSize(width.value, height.value) renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2)) } } function setClearColor(color: Color | string | number) { if (renderer) { renderer.setClearColor(normalizeColor(color)) } } function renderScene(scene: Scene, camera: Camera) { if (renderer) { renderer.render(scene, camera) } } function updateControls() { if (controls) { controls.update() } } function disposeRenderer() { if (renderer) { renderer.dispose() } } return { experience, controls, aspectRatio, initRenderer, updateRenderer, setClearColor, renderScene, updateControls, disposeRenderer, } }