UNPKG

@polygonjs/polygonjs

Version:

node-based WebGL 3D engine https://polygonjs.com

135 lines (134 loc) 6.05 kB
"use strict"; import { Matrix4, Quaternion, Vector3 } from "three"; const _position = new Vector3(); const _quaternion = new Quaternion(); const _scale = new Vector3(); const _matrix = new Matrix4(); const _matrix2 = new Matrix4(); function epsilon(value) { return Math.abs(value) < 1e-10 ? 0 : value; } function getObjectCSSMatrix(matrix) { const elements = matrix.elements; const matrix3d = "matrix3d(" + epsilon(elements[0]) + "," + epsilon(elements[1]) + "," + epsilon(elements[2]) + "," + epsilon(elements[3]) + "," + epsilon(-elements[4]) + "," + epsilon(-elements[5]) + "," + epsilon(-elements[6]) + "," + epsilon(-elements[7]) + "," + epsilon(elements[8]) + "," + epsilon(elements[9]) + "," + epsilon(elements[10]) + "," + epsilon(elements[11]) + "," + epsilon(elements[12]) + "," + epsilon(elements[13]) + "," + epsilon(elements[14]) + "," + epsilon(elements[15]) + ")"; return "translate(-50%,-50%)" + matrix3d; } function getCameraCSSMatrix(matrix) { const elements = matrix.elements; return "matrix3d(" + epsilon(elements[0]) + "," + epsilon(-elements[1]) + "," + epsilon(elements[2]) + "," + epsilon(elements[3]) + "," + epsilon(elements[4]) + "," + epsilon(-elements[5]) + "," + epsilon(elements[6]) + "," + epsilon(elements[7]) + "," + epsilon(elements[8]) + "," + epsilon(-elements[9]) + "," + epsilon(elements[10]) + "," + epsilon(elements[11]) + "," + epsilon(elements[12]) + "," + epsilon(-elements[13]) + "," + epsilon(elements[14]) + "," + epsilon(elements[15]) + ")"; } export class CSS3DRenderer { constructor(parameters = {}) { this._width = 0; this._height = 0; this._widthHalf = 0; this._heightHalf = 0; this.cache = { camera: { style: "" }, objects: /* @__PURE__ */ new WeakMap() }; this.appendedObjects = /* @__PURE__ */ new Set(); this.objectsToRender = /* @__PURE__ */ new Set(); this.objectsToRemove = /* @__PURE__ */ new Set(); const domElement = parameters.element !== void 0 ? parameters.element : document.createElement("div"); domElement.style.overflow = "hidden"; this.domElement = domElement; this.cameraElement = document.createElement("div"); this.cameraElement.style.transformStyle = "preserve-3d"; this.cameraElement.style.pointerEvents = "none"; domElement.appendChild(this.cameraElement); } getSize() { return { width: this._width, height: this._height }; } render(scene, camera) { const fov = camera.projectionMatrix.elements[5] * this._heightHalf; let tx = 0; let ty = 0; if (camera.isOrthographicCamera) { tx = -(camera.right + camera.left) / 2; ty = (camera.top + camera.bottom) / 2; } const cameraCSSMatrix = camera.isOrthographicCamera ? "scale(" + fov + ")translate(" + epsilon(tx) + "px," + epsilon(ty) + "px)" + getCameraCSSMatrix(camera.matrixWorldInverse) : "translateZ(" + fov + "px)" + getCameraCSSMatrix(camera.matrixWorldInverse); const perspective = camera.isPerspectiveCamera ? "perspective(" + fov + "px) " : ""; const style = perspective + cameraCSSMatrix + "translate(" + this._widthHalf + "px," + this._heightHalf + "px)"; if (this.cache.camera.style !== style) { this.cameraElement.style.transform = style; this.cache.camera.style = style; } this.removeElementsDeletedFromSceneGraph(scene); this.renderObject(scene, scene, camera, cameraCSSMatrix); } removeElementsDeletedFromSceneGraph(scene) { this.objectsToRender.clear(); scene.traverse((object) => { if (object.isCSS3DObject) { this.objectsToRender.add(object); } }); this.objectsToRemove.clear(); this.appendedObjects.forEach((appendedObject) => { if (!this.objectsToRender.has(appendedObject)) { this.objectsToRemove.add(appendedObject); } }); this.objectsToRemove.forEach((object) => { this.cameraElement.removeChild(object.element); this.appendedObjects.delete(object); }); } setSize(width, height) { this._width = width; this._height = height; this._widthHalf = this._width / 2; this._heightHalf = this._height / 2; this.domElement.style.width = width + "px"; this.domElement.style.height = height + "px"; this.cameraElement.style.width = width + "px"; this.cameraElement.style.height = height + "px"; } renderObject(object, scene, camera, cameraCSSMatrix) { if (object.isCSS3DObject) { const visible = object.visible === true && object.layers.test(camera.layers) === true; object.element.style.display = visible === true ? "" : "none"; if (visible === true) { object.onBeforeRender(this, scene, camera); let style; if (object.isCSS3DSprite) { _matrix.copy(camera.matrixWorldInverse); _matrix.transpose(); if (object.rotation2D !== 0) _matrix.multiply(_matrix2.makeRotationZ(object.rotation2D)); object.matrixWorld.decompose(_position, _quaternion, _scale); _matrix.setPosition(_position); _matrix.scale(_scale); _matrix.elements[3] = 0; _matrix.elements[7] = 0; _matrix.elements[11] = 0; _matrix.elements[15] = 1; style = getObjectCSSMatrix(_matrix); } else { style = getObjectCSSMatrix(object.matrixWorld); } const element = object.element; const cachedObject = this.cache.objects.get(object); if (cachedObject === void 0 || cachedObject.style !== style) { element.style.transform = style; const objectData = { style }; this.cache.objects.set(object, objectData); } if (element.parentNode !== this.cameraElement) { this.cameraElement.appendChild(element); this.appendedObjects.add(object); } object.onAfterRender(this, scene, camera); } } for (let i = 0, l = object.children.length; i < l; i++) { this.renderObject(object.children[i], scene, camera, cameraCSSMatrix); } } }