polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
119 lines (118 loc) • 4.14 kB
JavaScript
import {Matrix4 as Matrix42} from "three/src/math/Matrix4";
import {Vector3 as Vector32} from "three/src/math/Vector3";
import {CSS2DObject as CSS2DObject2} from "../objects/CSS2DObject";
import {CoreMath} from "../../../core/math/_Module";
export class CSS2DRenderer {
constructor() {
this._width = 0;
this._height = 0;
this._widthHalf = 0;
this._heightHalf = 0;
this.vector = new Vector32();
this.viewMatrix = new Matrix42();
this.viewProjectionMatrix = new Matrix42();
this.cache_distanceToCameraSquared = new WeakMap();
this.domElement = document.createElement("div");
this._sort_objects = false;
this._use_fog = false;
this._fog_near = 1;
this._fog_far = 100;
this.a = new Vector32();
this.b = new Vector32();
this.domElement.classList.add("polygonjs-CSS2DRenderer");
}
getSize() {
return {
width: this._width,
height: this._height
};
}
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";
}
renderObject(object, scene, camera) {
if (object instanceof CSS2DObject2) {
this.vector.setFromMatrixPosition(object.matrixWorld);
this.vector.applyMatrix4(this.viewProjectionMatrix);
var element = object.element;
var style = "translate(-50%,-50%) translate(" + (this.vector.x * this._widthHalf + this._widthHalf) + "px," + (-this.vector.y * this._heightHalf + this._heightHalf) + "px)";
element.style.webkitTransform = style;
element.style.transform = style;
element.style.display = object.visible && this.vector.z >= -1 && this.vector.z <= 1 ? "" : "none";
if (this._sort_objects || this._use_fog) {
const dist_to_squared = this.getDistanceToSquared(camera, object);
if (this._use_fog) {
const dist = Math.sqrt(dist_to_squared);
const dist_remapped = CoreMath.fit(dist, this._fog_near, this._fog_far, 0, 1);
const opacity = CoreMath.clamp(1 - dist_remapped, 0, 1);
element.style.opacity = `${opacity}`;
if (opacity == 0) {
element.style.display = "none";
}
}
this.cache_distanceToCameraSquared.set(object, dist_to_squared);
}
if (element.parentNode !== this.domElement) {
this.domElement.appendChild(element);
}
}
for (var i = 0, l = object.children.length; i < l; i++) {
this.renderObject(object.children[i], scene, camera);
}
}
getDistanceToSquared(object1, object2) {
this.a.setFromMatrixPosition(object1.matrixWorld);
this.b.setFromMatrixPosition(object2.matrixWorld);
return this.a.distanceToSquared(this.b);
}
filterAndFlatten(scene) {
const result = [];
scene.traverse(function(object) {
if (object instanceof CSS2DObject2)
result.push(object);
});
return result;
}
render(scene, camera) {
if (scene.autoUpdate === true)
scene.updateMatrixWorld();
if (camera.parent === null)
camera.updateMatrixWorld();
this.viewMatrix.copy(camera.matrixWorldInverse);
this.viewProjectionMatrix.multiplyMatrices(camera.projectionMatrix, this.viewMatrix);
this.renderObject(scene, scene, camera);
if (this._sort_objects) {
this.zOrder(scene);
}
}
set_sorting(state) {
this._sort_objects = state;
}
zOrder(scene) {
const sorted = this.filterAndFlatten(scene).sort((a, b) => {
const distanceA = this.cache_distanceToCameraSquared.get(a);
const distanceB = this.cache_distanceToCameraSquared.get(b);
if (distanceA != null && distanceB != null) {
return distanceA - distanceB;
} else {
return 0;
}
});
const zMax = sorted.length;
for (let i = 0, l = sorted.length; i < l; i++) {
sorted[i].element.style.zIndex = `${zMax - i}`;
}
}
set_use_fog(state) {
this._use_fog = state;
}
set_fog_range(near, far) {
this._fog_near = near;
this._fog_far = far;
}
}