polygonjs-engine
Version:
node-based webgl 3D engine https://polygonjs.com
201 lines (168 loc) • 6.87 kB
text/typescript
import {Vector3} from 'three/src/math/Vector3';
import {Vector2} from 'three/src/math/Vector2';
import {Quaternion} from 'three/src/math/Quaternion';
import {Matrix4} from 'three/src/math/Matrix4';
import {InstancedBufferGeometry} from 'three/src/core/InstancedBufferGeometry';
import {InstancedBufferAttribute} from 'three/src/core/InstancedBufferAttribute';
import {CorePoint} from './Point';
import {CoreGroup} from './Group';
import {CoreGeometry} from './Geometry';
import {BufferGeometry} from 'three/src/core/BufferGeometry';
import {CoreType} from '../Type';
import {PolyDictionary} from '../../types/GlobalTypes';
const DEFAULT = {
SCALE: new Vector3(1, 1, 1),
PSCALE: 1,
EYE: new Vector3(0, 0, 0),
UP: new Vector3(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 Vector3(1, 1, 1);
const DEFAULT_UV = new Vector2(0, 0);
const ATTRIB_NAME_UV = 'uv';
const ATTRIB_NAME_COLOR = 'color';
export class CoreInstancer {
private _is_pscale_present: boolean;
private _is_scale_present: boolean;
private _is_normal_present: boolean;
private _is_up_present: boolean;
private _do_rotate_matrices: boolean;
private _matrices: PolyDictionary<Matrix4> = {};
constructor(private _group_wrapper: CoreGroup) {
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; //&& this._is_up_present;
}
matrices() {
this._matrices = {};
this._matrices[MATRIX_T] = new Matrix4();
this._matrices[MATRIX_R] = new Matrix4();
this._matrices[MATRIX_S] = new Matrix4();
return this._group_wrapper.points().map((point) => {
const matrix = new Matrix4();
this._matrix_from_point(point, matrix);
return matrix;
});
}
private _point_scale = new Vector3();
private _point_normal = new Vector3();
private _point_up = new Vector3();
// private _point_m = new Matrix4()
_matrix_from_point(point: CorePoint, matrix: Matrix4) {
const t = point.position();
//r = new Vector3(0,0,0)
if (this._is_scale_present) {
point.attribValue(SCALE_ATTRIB_NAME, this._point_scale);
} else {
this._point_scale.copy(DEFAULT.SCALE);
}
const pscale: number = this._is_pscale_present
? (point.attribValue(PSCALE_ATTRIB_NAME) as number)
: DEFAULT.PSCALE;
this._point_scale.multiplyScalar(pscale);
//matrix = #Core.Transform.matrix(t, r, s, scale)
// matrix.identity();
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);
}
private static _point_color = new Vector3();
private static _point_uv = new Vector2();
static create_instance_buffer_geo(
geometry_to_instance: BufferGeometry,
template_core_group: CoreGroup,
attributes_to_copy: string
) {
const instance_pts = template_core_group.points();
// geometry_to_instance = new BoxBufferGeometry( 2, 2, 2 )
// geometry = new InstancedBufferGeometry()
// geometry.index = geometry_to_instance.index
// geometry.attributes.position = geometry_to_instance.attributes.position
// geometry.attributes.uv = geometry_to_instance.attributes.uv
const geometry = new InstancedBufferGeometry();
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 Vector3(0, 0, 0);
const quaternion = new Quaternion();
const scale = new Vector3(1, 1, 1);
const instancer = new CoreInstancer(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) as Vector3)
: DEFAULT_COLOR;
color.toArray(colors, index3);
});
// if(this._param_add_uv_offset){
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) as Vector2) : DEFAULT_UV;
uv.toArray(uvs, index2);
});
geometry.setAttribute('instanceUv', new InstancedBufferAttribute(uvs, 2));
}
// }
geometry.setAttribute('instancePosition', new InstancedBufferAttribute(positions, 3));
geometry.setAttribute('instanceScale', new InstancedBufferAttribute(scales, 3));
geometry.setAttribute('instanceOrientation', new InstancedBufferAttribute(orients, 4));
geometry.setAttribute('instanceColor', new InstancedBufferAttribute(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 as Vector3).toArray(values, i * attrib_size);
}
});
geometry.setAttribute(attrib_name, new InstancedBufferAttribute(values, attrib_size));
});
const core_geometry = new CoreGeometry(geometry);
core_geometry.markAsInstance();
return geometry;
}
}