@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
120 lines (93 loc) • 3.9 kB
JavaScript
import { Uint32Heap } from "../../../../collection/heap/Uint32Heap.js";
import { build_vertex_quadratics } from "./quadratic/build_vertex_quadratics.js";
import {
compute_edge_collapse_cost,
decimate_edge_collapse_snap,
edge_collapse_pick_target_vertex
} from "./decimate_edge_collapse_snap.js";
import { max2 } from "../../../../math/max2.js";
/**
*
* @param {Iterable<TopoEdge>} edges
* @param {Set<number>} restricted_vertices
* @param {Uint32Heap} heap
* @param {Map<number, Quadratic3>} vertex_quadratics
* @param {Map<number,TopoEdge>} edge_lookup
*/
export function edge_collapse_populate_heap(edges, restricted_vertices, heap, vertex_quadratics, edge_lookup) {
const edge_array = Array.from(edges);
const total_edge_count = edge_array.length;
for (let i = 0; i < total_edge_count; i++) {
const edge = edge_array[i];
if (
restricted_vertices.has(edge.v0.index)
&& restricted_vertices.has(edge.v1.index)
) {
// both vertices are fixed, can't simplify the edge
continue;
}
heap.insert(edge.index, compute_edge_collapse_cost(edge, vertex_quadratics, restricted_vertices));
edge_lookup.set(edge.index, edge);
}
}
/**
*
* @param {TopoMesh} mesh
* @param {number} num_faces_to_remove
* @param {Uint32Heap} heap
* @param {Map<number,TopoEdge>} edge_lookup
* @param {Set<number>} restricted_vertices
* @param {Map<number, Quadratic3>} vertex_quadratics
*/
export function edge_collapse_reduce_face_count(mesh, num_faces_to_remove, heap, edge_lookup, restricted_vertices, vertex_quadratics) {
const mesh_faces = mesh.getFaces();
const target_face_count = max2(0, mesh_faces.size - num_faces_to_remove);
let cycle_count = 0;
let cycle_limit = max2(heap.size, num_faces_to_remove * 10) + 10;
while (
!heap.is_empty()
&& mesh_faces.size > target_face_count
&& cycle_count < cycle_limit
) {
const edge_index = heap.pop_min();
const edge = edge_lookup.get(edge_index);
let target;
target = edge_collapse_pick_target_vertex(edge, restricted_vertices);
if (target === undefined) {
// invalid collapse
continue;
}
decimate_edge_collapse_snap(mesh, edge, target, vertex_quadratics, heap, restricted_vertices);
cycle_count++;
}
}
/**
* Simplifies a given topology mesh by reducing number of faces. Preserves original vertices
* NOTE: preserves outline of the mesh, that is the open edge
* NOTE: assumes that face normals are set
* @param {TopoMesh} mesh
* @param {number} num_faces_to_remove desired number of faces to remove
* @param {Set<number>} [restricted_vertices] vertices that are not allowed to be removed
*/
export function simplifyTopoMesh2(mesh, num_faces_to_remove, restricted_vertices = new Set()) {
const mesh_faces = mesh.getFaces();
const face_count = mesh_faces.size;
if (num_faces_to_remove <= 0 || face_count <= 0) {
// we're already at the target
return;
}
const heap = new Uint32Heap(mesh.getEdges().size);
/**
*
* @type {Map<number, Quadratic3>}
*/
const vertex_quadratics = new Map();
build_vertex_quadratics({ mesh: mesh, quadratics: vertex_quadratics });
const edge_lookup = new Map();
edge_collapse_populate_heap(mesh.getEdges(), restricted_vertices, heap, vertex_quadratics, edge_lookup);
edge_collapse_reduce_face_count(mesh, num_faces_to_remove, heap, edge_lookup, restricted_vertices, vertex_quadratics);
// debugValidateMesh(mesh);
// get rid of degenerate edges
// collapse_all_degenerate_edges(mesh.getEdges(), mesh);
// debugValidateMesh(mesh);
}