UNPKG

polygonjs-engine

Version:

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

232 lines (212 loc) 6.93 kB
import {NumericAttribValue} from '../../types/GlobalTypes'; import {Vector3} from 'three/src/math/Vector3'; import {Vector2} from 'three/src/math/Vector2'; import {Triangle} from 'three/src/math/Triangle'; import {BufferGeometry} from 'three/src/core/BufferGeometry'; import {BufferAttribute} from 'three/src/core/BufferAttribute'; import {CorePoint} from './Point'; import {CoreGeometry} from './Geometry'; import {CoreMath} from '../math/_Module'; import {ArrayUtils} from '../ArrayUtils'; interface FaceLike { a: number; b: number; c: number; } type CorePointArray3 = [CorePoint, CorePoint, CorePoint]; type Vector3Array2 = [Vector3, Vector3]; type Vector3Array3 = [Vector3, Vector3, Vector3]; export class CoreFace { _geometry: BufferGeometry; _points: CorePointArray3 | undefined; _triangle: Triangle | undefined; _positions: Vector3Array3 | undefined; _deltas: Vector3Array2 | undefined; constructor(private _core_geometry: CoreGeometry, private _index: number) { this._geometry = this._core_geometry.geometry(); } index() { return this._index; } points() { return (this._points = this._points || this._get_points()); } private _get_points(): CorePointArray3 { const index_array = this._geometry.index?.array || []; const start = this._index * 3; return [ new CorePoint(this._core_geometry, index_array[start + 0]), new CorePoint(this._core_geometry, index_array[start + 1]), new CorePoint(this._core_geometry, index_array[start + 2]), ]; } positions() { return (this._positions = this._positions || this._get_positions()); } private _get_positions(): Vector3Array3 { const points = this.points(); return [points[0].position(), points[1].position(), points[2].position()]; } triangle() { return (this._triangle = this._triangle || this._get_triangle()); } private _get_triangle(): Triangle { const positions = this.positions(); return new Triangle(positions[0], positions[1], positions[2]); } deltas() { return (this._deltas = this._deltas || this._get_deltas()); } private _get_deltas(): Vector3Array2 { const positions = this.positions(); return [positions[1].clone().sub(positions[0]), positions[2].clone().sub(positions[0])]; } area(): number { return this.triangle().getArea(); } center(target: Vector3) { const positions = this.positions(); target.x = (positions[0].x + positions[1].x + positions[2].x) / 3; target.y = (positions[0].y + positions[1].y + positions[2].y) / 3; target.z = (positions[0].z + positions[1].z + positions[2].z) / 3; return target; } random_position(seed: number) { let weights = [CoreMath.rand_float(seed), CoreMath.rand_float(seed * 6541)]; if (weights[0] + weights[1] > 1) { weights[0] = 1 - weights[0]; weights[1] = 1 - weights[1]; } return this.positions()[0] .clone() .add(this.deltas()[0].clone().multiplyScalar(weights[0])) .add(this.deltas()[1].clone().multiplyScalar(weights[1])); } // random_position(seed: number){ // let weights = [ // CoreMath.rand_float(seed), // CoreMath.rand_float(seed*524), // CoreMath.rand_float(seed*4631) // ] // const sum = ArrayUtils.sum(weights) // weights = weights.map(w=>w/sum) // const pos = new Vector3() // let positions = this.positions().map((p,i)=> p.multiplyScalar(weights[i])) // positions.forEach(p=>{ // pos.add(p) // }) // return pos // } attrib_value_at_position(attrib_name: string, position: Vector3) { // const weights = CoreInterpolate._weights_from_3(position, this._positions) const barycentric_coordinates = new Vector3(); this.triangle().getBarycoord(position, barycentric_coordinates); const weights = barycentric_coordinates.toArray(); const attrib = this._geometry.attributes[attrib_name]; const attrib_size = attrib.itemSize; const point_values = this.points().map((point) => point.attribValue(attrib_name)); let new_attrib_value; let sum; let index = 0; switch (attrib_size) { case 1: { sum = 0; for (let point_value of point_values as number[]) { sum += point_value * weights[index]; index++; } new_attrib_value = sum; break; } default: { for (let point_value of point_values as Vector3[]) { const weighted_value = point_value.multiplyScalar(weights[index]); if (sum) { sum.add(weighted_value); } else { sum = weighted_value; } index++; } new_attrib_value = sum; } } return new_attrib_value; } static interpolated_value( geometry: BufferGeometry, face: FaceLike, intersect_point: Vector3, attrib: BufferAttribute ) { // let point_index, i, sum const point_indices = [face.a, face.b, face.c]; const position_attrib = geometry.getAttribute('position'); const position_attrib_array = position_attrib.array; const point_positions = point_indices.map( (point_index) => new Vector3( position_attrib_array[point_index * 3 + 0], position_attrib_array[point_index * 3 + 1], position_attrib_array[point_index * 3 + 2] ) ); const attrib_size = attrib.itemSize; const attrib_array = attrib.array; let attrib_values: NumericAttribValue[] = []; switch (attrib_size) { case 1: attrib_values = point_indices.map((point_index) => attrib_array[point_index]); break; case 2: attrib_values = point_indices.map( (point_index) => new Vector2(attrib_array[point_index * 2 + 0], attrib_array[point_index * 2 + 1]) ); break; case 3: attrib_values = point_indices.map( (point_index) => new Vector3( attrib_array[point_index * 3 + 0], attrib_array[point_index * 3 + 1], attrib_array[point_index * 3 + 2] ) ); break; } const dist_to_points = point_indices.map((point_index, i) => intersect_point.distanceTo(point_positions[i])); // https://math.stackexchange.com/questions/1336386/weighted-average-distance-between-3-or-more-points // TODO: replace this with Core.Math.Interpolate const distance_total = ArrayUtils.sum([ dist_to_points[0] * dist_to_points[1], dist_to_points[0] * dist_to_points[2], dist_to_points[1] * dist_to_points[2], ]); const weights = [ (dist_to_points[1] * dist_to_points[2]) / distance_total, (dist_to_points[0] * dist_to_points[2]) / distance_total, (dist_to_points[0] * dist_to_points[1]) / distance_total, ]; let new_attrib_value; switch (attrib_size) { case 1: new_attrib_value = ArrayUtils.sum( point_indices.map((point_indx, i) => weights[i] * (attrib_values[i] as number)) ); break; default: var values = point_indices.map((point_index, i) => (attrib_values[i] as Vector3).multiplyScalar(weights[i]) ); new_attrib_value = null; for (let value of values) { if (new_attrib_value) { new_attrib_value.add(value); } else { new_attrib_value = value; } } } return new_attrib_value; } }