UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

120 lines (93 loc) 3.9 kB
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); }