UNPKG

@polygonjs/polygonjs

Version:

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

241 lines (210 loc) 7.77 kB
import { BufferGeometry, InstancedBufferAttribute, InstancedBufferGeometry, Matrix4, Quaternion, Vector2, Vector3, } from 'three'; import {BaseCorePoint, CorePoint} from './entities/point/CorePoint'; import {CoreGroup} from './Group'; // import {CoreGeometry} from './Geometry'; import {isNumber} from '../Type'; import {Attribute} from './Attribute'; import {PolyDictionary} from '../../types/GlobalTypes'; import {CoreObjectType} from './ObjectContent'; 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: CorePoint<CoreObjectType>[] = []; export enum InstanceAttrib { POSITION = 'instancePosition', SCALE = 'instanceScale', QUATERNION = 'instanceQuaternion', COLOR = 'instanceColor', UV = 'instanceUv', } const ATTRIB_NAME_MAP: PolyDictionary<string> = { P: InstanceAttrib.POSITION, N: InstanceAttrib.QUATERNION, up: InstanceAttrib.QUATERNION, Cd: InstanceAttrib.COLOR, [Attribute.COLOR]: InstanceAttrib.COLOR, [Attribute.NORMAL]: InstanceAttrib.QUATERNION, [Attribute.POSITION]: InstanceAttrib.POSITION, [Attribute.PSCALE]: InstanceAttrib.SCALE, [Attribute.SCALE]: InstanceAttrib.SCALE, }; export class CoreInstancer { private _is_pscale_present: boolean = false; private _is_scale_present: boolean = false; private _is_normal_present: boolean = false; private _is_up_present: boolean = false; private _do_rotate_matrices: boolean = false; // private _matrices: PolyDictionary<Matrix4> = {}; private _matrixT = new Matrix4(); private _matrixR = new Matrix4(); private _matrixS = new Matrix4(); static transformAttributeNames: string[] = [ InstanceAttrib.POSITION, InstanceAttrib.QUATERNION, InstanceAttrib.SCALE, ]; static remapName(name: string): string { return ATTRIB_NAME_MAP[name] || name; } constructor(private _coreGroup?: CoreGroup) { if (_coreGroup) { this.setCoreGroup(_coreGroup); } } setCoreGroup(coreGroup: 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; //&& this._is_up_present; } private _pointScale = new Vector3(); private _pointNormal = new Vector3(); private _pointUp = new Vector3(); // private _point_m = new Matrix4() matrixFromPoint(point: BaseCorePoint, targetMatrix: Matrix4) { targetMatrix.identity(); point.position(_position); //r = new Vector3(0,0,0) if (this._is_scale_present) { point.attribValue(Attribute.SCALE, this._pointScale); } else { this._pointScale.copy(DEFAULT.SCALE); } const pscale: number = this._is_pscale_present ? (point.attribValue(Attribute.PSCALE) as number) : DEFAULT.PSCALE; this._pointScale.multiplyScalar(pscale); //matrix = #Core.Transform.matrix(t, r, s, scale) // matrix.identity(); 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); } private static _point_color = new Vector3(); private static _point_uv = new Vector2(); private static _position = new Vector3(0, 0, 0); private static _quaternion = new Quaternion(); private static _scale = new Vector3(1, 1, 1); private static _tmpMatrix = new Matrix4(); static updateTransformInstanceAttributes( instancePts: BaseCorePoint[], templateCoreGroup: CoreGroup, geometry: InstancedBufferGeometry ) { 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(InstanceAttrib.POSITION, instancePosition); geometry.setAttribute(InstanceAttrib.QUATERNION, instanceQuaternion); geometry.setAttribute(InstanceAttrib.SCALE, instanceScale); } static updateColorInstanceAttribute( instancePts: BaseCorePoint[], templateCoreGroup: CoreGroup, geometry: InstancedBufferGeometry ) { 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) as Vector3) : DEFAULT_COLOR; color.toArray(colors, i * 3); i++; } geometry.setAttribute(InstanceAttrib.COLOR, new InstancedBufferAttribute(colors, 3)); } static createInstanceBufferGeometry( geometryToInstance: BufferGeometry, templateCoreGroup: CoreGroup, attributesToCopy: string ) { templateCoreGroup.points(_instancePts); const geometry = new InstancedBufferGeometry(); geometry.copy(geometryToInstance as InstancedBufferGeometry); 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) as Vector2) : DEFAULT_UV; uv.toArray(uvs, index2); i++; } geometry.setAttribute(InstanceAttrib.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 as Vector3).toArray(values, i * attribSize); } i++; } geometry.setAttribute(attribName, new InstancedBufferAttribute(values, attribSize)); } return geometry; } }