React-360 原始碼閱讀【5】
今天我們看下 360/tree/master/React360/js/Compositor" rel="nofollow,noindex" target="_blank">compositor 。顧名思義,compositor 應該是你第一個接觸到的 訪問屬性,我們不妨回顧下官方程式碼 Client 裡面的內容:
function init(bundle, parent, options = {}) { const r360 = new ReactInstance(bundle, parent, { // Add custom options here fullScreen: true, ...options, }); // Render your app content to the default cylinder surface r360.renderToSurface( r360.createRoot('hello_360', { /* initial props */ }), r360.getDefaultSurface() ); // Load the initial environment r360.compositor.setBackground(r360.getAssetURL('360_world.jpg')); } window.React360 = {init};
大概這裡我們可以看到 r360.compositor
這麼一個東西,大概我們所處理 React-360 背景的音樂,圖片都是在這裡完成初始化和操作的。
這其中最核心的是 Compositor.js ,裡面對外暴露了我們經常需要呼叫的方法;
import * as THREE from 'three'; import {type Quaternion, type Ray, type Vec3} from '../Controls/Types'; import createRemoteImageManager from '../Utils/createRemoteImageManager'; import type ResourceManager from '../Utils/ResourceManager'; import Cursor from './Cursor'; import Environment, {type PanoOptions} from './Environment/Environment'; import Surface from './Surface'; import type {VideoPlayer} from './Video/Types'; import VideoPlayerManager from './Video/VideoPlayerManager'; const LEFT = 'left'; const RIGHT = 'right'; // 用於 VR 裝置中的左右眼模式 const leftCamera = new THREE.PerspectiveCamera(); leftCamera.matrixAutoUpdate = false; const rightCamera = new THREE.PerspectiveCamera(); rightCamera.matrixAutoUpdate = false; export default class Compositor { _camera: THREE.Camera; _canvas: HTMLCanvasElement; _cursor: Cursor; _cursorVisibility: string; _defaultSurface: ?Surface; _environment: Environment; _frame: HTMLElement; _isMouseCursorActive: boolean; _renderer: THREE.WebGLRenderer; _scene: THREE.Scene; _surfaceRoot: THREE.Object3D; _surfaces: {[name: string]: Surface}; _resourceManager: ResourceManager<Image>; _videoPlayers: VideoPlayerManager; constructor(frame: HTMLElement, scene: THREE.Scene) { this._frame = frame; this._cursorVisibility = 'auto'; this._isMouseCursorActive = false; this._defaultSurface = null; this._surfaces = {}; this._resourceManager = createRemoteImageManager(); // 用於對視訊播放器進行控制 this._videoPlayers = new VideoPlayerManager(); // 設定 three.js 的相機配置 this._camera = new THREE.PerspectiveCamera( 60, frame.clientWidth / frame.clientHeight, 0.1, 2000, ); // 設定 render 這些都是最基礎 three.js 建立的物件 this._renderer = new THREE.WebGLRenderer({ antialias: true, }); this._canvas = this._renderer.domElement; // 設定裝置的畫素比 this._renderer.setPixelRatio(window.devicePixelRatio); this._renderer.setSize(frame.clientWidth, frame.clientHeight); // 將 canvas 新增到容器中 frame.appendChild(this._renderer.domElement); // 在之前 ReactInstance.js 中建立的 scene this._scene = scene; // 獲取環境狀態 this._environment = new Environment( this._resourceManager, this._videoPlayers, ); // 將用於背景的全景Node新增到場景中進行渲染 scene.add(this._environment.getPanoNode()); this._surfaceRoot = new THREE.Object3D(); scene.add(this._surfaceRoot); this._cursor = new Cursor(); // 將用於滑鼠顯示的影象新增進來 scene.add(this._cursor.getMesh()); } setCursorVisibility(vis: string) { this._cursorVisibility = vis; } // 設定背景的全景圖 setBackground(src: string, options: PanoOptions = {}): Promise<void> { return this._environment.setSource(src, options); } // 設定背景的視訊 setBackgroundVideo(handle: string, options: PanoOptions = {}): Promise<void> { return this._environment.setVideoSource(handle, options); } // 建立 視訊播放器 createVideoPlayer(handle: string): VideoPlayer { return this._videoPlayers.createPlayer(handle); } getVideoPlayerManager(): VideoPlayerManager { return this._videoPlayers; } // 訪問環境狀態 getEnvironment(): Environment { return this._environment; } getCursorVisibility(): string { return this._cursorVisibility; } // 設定滑鼠與當前場景的互動 setMouseCursorActive(active: boolean) { if (this._isMouseCursorActive !== active) { this._isMouseCursorActive = active; this._frame.style.cursor = active ? 'pointer' : 'inherit'; } } // 新增表面紋理 addSurface(name: string, surface: Surface) { if (this._surfaces[name]) { throw new Error( `Cannot add Surface with tag '${name}', a Surface with that name already exists.`, ); } this._surfaces[name] = surface; } showSurface(surface: Surface) { this._surfaceRoot.add(surface.getNode()); } getSurface(name: string): ?Surface { return this._surfaces[name]; } getDefaultSurface(): Surface { if (!this._defaultSurface) { this._defaultSurface = new Surface(1000, 600); } return this._defaultSurface; } // 獲取 Canvas 元素 getCanvas(): HTMLCanvasElement { return this._canvas; } // 獲取 Camera 物件 getCamera(): THREE.Camera { return this._camera; } // 獲取 three.js 渲染物件 getRenderer(): THREE.WebGLRenderer { return this._renderer; } // 重新設定當前畫布的大小 resize(width: number, height: number, pixelRatio: number = 1) { this._renderer.setPixelRatio(pixelRatio); this._renderer.setSize(width, height, false); } resizeCanvas(width: number, height: number) { this._camera.aspect = width / height; this._camera.updateProjectionMatrix(); this._renderer.setSize(width, height, true); } prepareForRender(eye: ?string) { this._environment.prepareForRender(eye); } // 每一幀的回撥函式 frame(delta: number) { this._environment.frame(delta); this._videoPlayers.frame(); } // 更新滑鼠軌跡 updateCursor(rays: ?Array<Ray>, depth: number) { if (!rays || rays.length < 1) { this._cursor.hide(); return; } // TODO: extend to multiple rays if (!rays[0].drawsCursor) { this._cursor.hide(); return; } this._cursor.show(); const origin = rays[0].origin; const direction = rays[0].direction; const cameraToCursorX = origin[0] + direction[0] * depth; const cameraToCursorY = origin[1] + direction[1] * depth; const cameraToCursorZ = origin[2] + direction[2] * depth; this._cursor.setPosition(cameraToCursorX, cameraToCursorY, cameraToCursorZ); } // 開始只想渲染 render(position: Vec3, quat: Quaternion) { this.prepareForRender(null); this._camera.position.set(position[0], position[1], position[2]); this._camera.quaternion.set(quat[0], quat[1], quat[2], quat[3]); this._renderer.render(this._scene, this._camera); } renderSurface(surface: Surface) { this._renderer.render(surface.getScene(), surface.getCamera()); } // 渲染 VR 模式 renderVR(display: VRDisplay, frameData: VRFrameData) { const preserveAutoUpdate = this._scene.autoUpdate; if (preserveAutoUpdate) { this._scene.updateMatrixWorld(); this._scene.autoUpdate = false; } const size = this._renderer.getSize(); this._renderer.setScissorTest(true); this._camera.updateMatrixWorld(); leftCamera.matrixWorldInverse.fromArray(frameData.leftViewMatrix); rightCamera.matrixWorldInverse.fromArray(frameData.rightViewMatrix); leftCamera.matrixWorld.getInverse(leftCamera.matrixWorldInverse); rightCamera.matrixWorld.getInverse(rightCamera.matrixWorldInverse); leftCamera.projectionMatrix.fromArray(frameData.leftProjectionMatrix); rightCamera.projectionMatrix.fromArray(frameData.rightProjectionMatrix); let x = 0; const y = 0; const w = 0.5 * size.width; const h = size.height; this.prepareForRender(LEFT); this._renderer.setViewport(x, y, w, h); this._renderer.setScissor(x, y, w, h); this._renderer.render(this._scene, leftCamera); x = w; this.prepareForRender(RIGHT); this._renderer.setViewport(x, y, w, h); this._renderer.setScissor(x, y, w, h); this._renderer.render(this._scene, rightCamera); this._renderer.setViewport(0, 0, size.width, size.height); this._renderer.setScissorTest(false); if (preserveAutoUpdate) { this._scene.autoUpdate = true; } display.submitFrame(); } }
大概通過這些方法你可以非常方便的進行全景圖的設定和視訊的設定。同時你也可以獲取 three.js 的一些基本物件比如 Camera, Renderer 等。