UNPKG

@polygonjs/polygonjs

Version:

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

190 lines (189 loc) 7.64 kB
"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();