UNPKG

polygonjs-engine

Version:

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

143 lines (142 loc) 6.26 kB
import {Vector3 as Vector32} from "three/src/math/Vector3"; import {Vector2 as Vector22} from "three/src/math/Vector2"; import {Quaternion as Quaternion2} from "three/src/math/Quaternion"; import {Matrix4 as Matrix42} from "three/src/math/Matrix4"; import {InstancedBufferGeometry as InstancedBufferGeometry2} from "three/src/core/InstancedBufferGeometry"; import {InstancedBufferAttribute as InstancedBufferAttribute2} from "three/src/core/InstancedBufferAttribute"; import {CoreGeometry} from "./Geometry"; import {CoreType} from "../Type"; const DEFAULT = { SCALE: new Vector32(1, 1, 1), PSCALE: 1, EYE: new Vector32(0, 0, 0), UP: new Vector32(0, 1, 0) }; const SCALE_ATTRIB_NAME = "scale"; const PSCALE_ATTRIB_NAME = "pscale"; const NORMAL_ATTRIB_NAME = "normal"; const UP_ATTRIB_NAME = "up"; const MATRIX_T = "translate"; const MATRIX_R = "rotate"; const MATRIX_S = "scale"; const DEFAULT_COLOR = new Vector32(1, 1, 1); const DEFAULT_UV = new Vector22(0, 0); const ATTRIB_NAME_UV = "uv"; const ATTRIB_NAME_COLOR = "color"; const CoreInstancer2 = class { constructor(_group_wrapper) { this._group_wrapper = _group_wrapper; this._matrices = {}; this._point_scale = new Vector32(); this._point_normal = new Vector32(); this._point_up = new Vector32(); this._is_pscale_present = this._group_wrapper.hasAttrib("pscale"); this._is_scale_present = this._group_wrapper.hasAttrib("scale"); this._is_normal_present = this._group_wrapper.hasAttrib("normal"); this._is_up_present = this._group_wrapper.hasAttrib("up"); this._do_rotate_matrices = this._is_normal_present; } matrices() { this._matrices = {}; this._matrices[MATRIX_T] = new Matrix42(); this._matrices[MATRIX_R] = new Matrix42(); this._matrices[MATRIX_S] = new Matrix42(); return this._group_wrapper.points().map((point) => { const matrix = new Matrix42(); this._matrix_from_point(point, matrix); return matrix; }); } _matrix_from_point(point, matrix) { const t = point.position(); if (this._is_scale_present) { point.attribValue(SCALE_ATTRIB_NAME, this._point_scale); } else { this._point_scale.copy(DEFAULT.SCALE); } const pscale = this._is_pscale_present ? point.attribValue(PSCALE_ATTRIB_NAME) : DEFAULT.PSCALE; this._point_scale.multiplyScalar(pscale); const scale_matrix = this._matrices[MATRIX_S]; scale_matrix.makeScale(this._point_scale.x, this._point_scale.y, this._point_scale.z); const translate_matrix = this._matrices[MATRIX_T]; translate_matrix.makeTranslation(t.x, t.y, t.z); matrix.multiply(translate_matrix); if (this._do_rotate_matrices) { const rotate_matrix = this._matrices[MATRIX_R]; const eye = DEFAULT.EYE; point.attribValue(NORMAL_ATTRIB_NAME, this._point_normal); this._point_normal.multiplyScalar(-1); if (this._is_up_present) { point.attribValue(UP_ATTRIB_NAME, this._point_up); } else { this._point_up.copy(DEFAULT.UP); } this._point_up.normalize(); rotate_matrix.lookAt(eye, this._point_normal, this._point_up); matrix.multiply(rotate_matrix); } matrix.multiply(scale_matrix); } static create_instance_buffer_geo(geometry_to_instance, template_core_group, attributes_to_copy) { const instance_pts = template_core_group.points(); const geometry = new InstancedBufferGeometry2(); geometry.copy(geometry_to_instance); geometry.instanceCount = Infinity; const instances_count = instance_pts.length; const positions = new Float32Array(instances_count * 3); const colors = new Float32Array(instances_count * 3); const scales = new Float32Array(instances_count * 3); const orients = new Float32Array(instances_count * 4); const has_color = template_core_group.hasAttrib(ATTRIB_NAME_COLOR); const position = new Vector32(0, 0, 0); const quaternion = new Quaternion2(); const scale = new Vector32(1, 1, 1); const instancer = new CoreInstancer2(template_core_group); const instance_matrices = instancer.matrices(); instance_pts.forEach((instance_pt, i) => { const index3 = i * 3; const index4 = i * 4; const matrix = instance_matrices[i]; matrix.decompose(position, quaternion, scale); position.toArray(positions, index3); quaternion.toArray(orients, index4); scale.toArray(scales, index3); const color = has_color ? instance_pt.attribValue(ATTRIB_NAME_COLOR, this._point_color) : DEFAULT_COLOR; color.toArray(colors, index3); }); const has_uv = template_core_group.hasAttrib(ATTRIB_NAME_UV); if (has_uv) { const uvs = new Float32Array(instances_count * 2); instance_pts.forEach((instance_pt, i) => { const index2 = i * 2; const uv = has_uv ? instance_pt.attribValue(ATTRIB_NAME_UV, this._point_uv) : DEFAULT_UV; uv.toArray(uvs, index2); }); geometry.setAttribute("instanceUv", new InstancedBufferAttribute2(uvs, 2)); } geometry.setAttribute("instancePosition", new InstancedBufferAttribute2(positions, 3)); geometry.setAttribute("instanceScale", new InstancedBufferAttribute2(scales, 3)); geometry.setAttribute("instanceOrientation", new InstancedBufferAttribute2(orients, 4)); geometry.setAttribute("instanceColor", new InstancedBufferAttribute2(colors, 3)); const attrib_names = template_core_group.attribNamesMatchingMask(attributes_to_copy); attrib_names.forEach((attrib_name) => { const attrib_size = template_core_group.attribSize(attrib_name); const values = new Float32Array(instances_count * attrib_size); instance_pts.forEach((pt, i) => { const value = pt.attribValue(attrib_name); if (CoreType.isNumber(value)) { values[i] = value; } else { value.toArray(values, i * attrib_size); } }); geometry.setAttribute(attrib_name, new InstancedBufferAttribute2(values, attrib_size)); }); const core_geometry = new CoreGeometry(geometry); core_geometry.markAsInstance(); return geometry; } }; export let CoreInstancer = CoreInstancer2; CoreInstancer._point_color = new Vector32(); CoreInstancer._point_uv = new Vector22();