@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
135 lines (134 loc) • 6.05 kB
JavaScript
"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);
}
}
}