@polygonjs/polygonjs
Version:
node-based WebGL 3D engine https://polygonjs.com
190 lines (189 loc) • 7.64 kB
JavaScript
"use strict";
import {
InstancedBufferAttribute,
InstancedBufferGeometry,
Matrix4,
Quaternion,
Vector2,
Vector3
} from "three";
import { isNumber } from "../Type";
import { Attribute } from "./Attribute";
const DEFAULT = {
SCALE: new Vector3(1, 1, 1),
PSCALE: 1,
EYE: new Vector3(0, 0, 0),
UP: new Vector3(0, 1, 0)
};
const DEFAULT_COLOR = new Vector3(1, 1, 1);
const DEFAULT_UV = new Vector2(0, 0);
const _position = new Vector3();
const _instancePts = [];
export var InstanceAttrib = /* @__PURE__ */ ((InstanceAttrib2) => {
InstanceAttrib2["POSITION"] = "instancePosition";
InstanceAttrib2["SCALE"] = "instanceScale";
InstanceAttrib2["QUATERNION"] = "instanceQuaternion";
InstanceAttrib2["COLOR"] = "instanceColor";
InstanceAttrib2["UV"] = "instanceUv";
return InstanceAttrib2;
})(InstanceAttrib || {});
const ATTRIB_NAME_MAP = {
P: "instancePosition" /* POSITION */,
N: "instanceQuaternion" /* QUATERNION */,
up: "instanceQuaternion" /* QUATERNION */,
Cd: "instanceColor" /* COLOR */,
[Attribute.COLOR]: "instanceColor" /* COLOR */,
[Attribute.NORMAL]: "instanceQuaternion" /* QUATERNION */,
[Attribute.POSITION]: "instancePosition" /* POSITION */,
[Attribute.PSCALE]: "instanceScale" /* SCALE */,
[Attribute.SCALE]: "instanceScale" /* SCALE */
};
const _CoreInstancer = class {
constructor(_coreGroup) {
this._coreGroup = _coreGroup;
this._is_pscale_present = false;
this._is_scale_present = false;
this._is_normal_present = false;
this._is_up_present = false;
this._do_rotate_matrices = false;
// private _matrices: PolyDictionary<Matrix4> = {};
this._matrixT = new Matrix4();
this._matrixR = new Matrix4();
this._matrixS = new Matrix4();
this._pointScale = new Vector3();
this._pointNormal = new Vector3();
this._pointUp = new Vector3();
if (_coreGroup) {
this.setCoreGroup(_coreGroup);
}
}
static remapName(name) {
return ATTRIB_NAME_MAP[name] || name;
}
setCoreGroup(coreGroup) {
this._coreGroup = coreGroup;
this._is_pscale_present = this._coreGroup.hasPointAttrib(Attribute.PSCALE);
this._is_scale_present = this._coreGroup.hasPointAttrib(Attribute.SCALE);
this._is_normal_present = this._coreGroup.hasPointAttrib(Attribute.NORMAL);
this._is_up_present = this._coreGroup.hasPointAttrib(Attribute.UP);
this._do_rotate_matrices = this._is_normal_present;
}
// private _point_m = new Matrix4()
matrixFromPoint(point, targetMatrix) {
targetMatrix.identity();
point.position(_position);
if (this._is_scale_present) {
point.attribValue(Attribute.SCALE, this._pointScale);
} else {
this._pointScale.copy(DEFAULT.SCALE);
}
const pscale = this._is_pscale_present ? point.attribValue(Attribute.PSCALE) : DEFAULT.PSCALE;
this._pointScale.multiplyScalar(pscale);
const scale_matrix = this._matrixS;
scale_matrix.makeScale(this._pointScale.x, this._pointScale.y, this._pointScale.z);
const translate_matrix = this._matrixT;
translate_matrix.makeTranslation(_position.x, _position.y, _position.z);
targetMatrix.multiply(translate_matrix);
if (this._do_rotate_matrices) {
const rotate_matrix = this._matrixR;
const eye = DEFAULT.EYE;
point.attribValue(Attribute.NORMAL, this._pointNormal);
this._pointNormal.multiplyScalar(-1);
if (this._is_up_present) {
point.attribValue(Attribute.UP, this._pointUp);
} else {
this._pointUp.copy(DEFAULT.UP);
}
this._pointUp.normalize();
rotate_matrix.lookAt(eye, this._pointNormal, this._pointUp);
targetMatrix.multiply(rotate_matrix);
}
targetMatrix.multiply(scale_matrix);
}
static updateTransformInstanceAttributes(instancePts, templateCoreGroup, geometry) {
const instancesCount = instancePts.length;
const positions = new Float32Array(instancesCount * 3);
const scales = new Float32Array(instancesCount * 3);
const quaternions = new Float32Array(instancesCount * 4);
const instancer = new _CoreInstancer(templateCoreGroup);
let i = 0;
for (const instancePt of instancePts) {
instancer.matrixFromPoint(instancePt, this._tmpMatrix);
const index3 = i * 3;
const index4 = i * 4;
this._tmpMatrix.decompose(this._position, this._quaternion, this._scale);
this._position.toArray(positions, index3);
this._quaternion.toArray(quaternions, index4);
this._scale.toArray(scales, index3);
i++;
}
const instancePosition = new InstancedBufferAttribute(positions, 3);
const instanceQuaternion = new InstancedBufferAttribute(quaternions, 4);
const instanceScale = new InstancedBufferAttribute(scales, 3);
geometry.setAttribute("instancePosition" /* POSITION */, instancePosition);
geometry.setAttribute("instanceQuaternion" /* QUATERNION */, instanceQuaternion);
geometry.setAttribute("instanceScale" /* SCALE */, instanceScale);
}
static updateColorInstanceAttribute(instancePts, templateCoreGroup, geometry) {
const instancesCount = instancePts.length;
const colors = new Float32Array(instancesCount * 3);
const hasColor = templateCoreGroup.hasPointAttrib(Attribute.COLOR);
let i = 0;
for (const instancePt of instancePts) {
const color = hasColor ? instancePt.attribValue(Attribute.COLOR, this._point_color) : DEFAULT_COLOR;
color.toArray(colors, i * 3);
i++;
}
geometry.setAttribute("instanceColor" /* COLOR */, new InstancedBufferAttribute(colors, 3));
}
static createInstanceBufferGeometry(geometryToInstance, templateCoreGroup, attributesToCopy) {
templateCoreGroup.points(_instancePts);
const geometry = new InstancedBufferGeometry();
geometry.copy(geometryToInstance);
geometry.instanceCount = Infinity;
const instancesCount = _instancePts.length;
const hasUV = templateCoreGroup.hasPointAttrib(Attribute.UV);
if (hasUV) {
const uvs = new Float32Array(instancesCount * 2);
let i = 0;
for (const instancePt of _instancePts) {
const index2 = i * 2;
const uv = hasUV ? instancePt.attribValue(Attribute.UV, this._point_uv) : DEFAULT_UV;
uv.toArray(uvs, index2);
i++;
}
geometry.setAttribute("instanceUv" /* UV */, new InstancedBufferAttribute(uvs, 2));
}
this.updateTransformInstanceAttributes(_instancePts, templateCoreGroup, geometry);
this.updateColorInstanceAttribute(_instancePts, templateCoreGroup, geometry);
const attribNames = templateCoreGroup.pointAttribNamesMatchingMask(attributesToCopy);
for (const attribName of attribNames) {
const attribSize = templateCoreGroup.pointAttribSize(attribName);
const values = new Float32Array(instancesCount * attribSize);
let i = 0;
for (const pt of _instancePts) {
const value = pt.attribValue(attribName);
if (isNumber(value)) {
values[i] = value;
} else {
value.toArray(values, i * attribSize);
}
i++;
}
geometry.setAttribute(attribName, new InstancedBufferAttribute(values, attribSize));
}
return geometry;
}
};
export let CoreInstancer = _CoreInstancer;
CoreInstancer.transformAttributeNames = [
"instancePosition" /* POSITION */,
"instanceQuaternion" /* QUATERNION */,
"instanceScale" /* SCALE */
];
CoreInstancer._point_color = new Vector3();
CoreInstancer._point_uv = new Vector2();
CoreInstancer._position = new Vector3(0, 0, 0);
CoreInstancer._quaternion = new Quaternion();
CoreInstancer._scale = new Vector3(1, 1, 1);
CoreInstancer._tmpMatrix = new Matrix4();