UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

86 lines (59 loc) 2.52 kB
import { query_edge_is_boundary } from "../../../../core/geom/3d/topology/query/query_edge_is_boundary.js"; import { query_edge_other_vertex } from "../../../../core/geom/3d/topology/query/query_edge_other_vertex.js"; import { TopoMesh } from "../../../../core/geom/3d/topology/struct/TopoMesh.js"; /** * Move UVs to reduce stretching * * @param {Float64Array|Float32Array|number[]} positions * @param {Float64Array|Float32Array|number[]} uvs * @param {Uint16Array|Uint32Array|number[]|undefined} faces * @param {number} [steps] Number of optimization passes to perform */ export function geometry_optimize_uv_tension( positions, uvs, faces, steps = 3 ) { // Build topology from the data, we need to know which faces are connected to each vertex const topo = new TopoMesh(); topo.build(positions, faces); topo.computeEdgeSquaredLengths(); const vertex_count = positions.length / 3; for (let i = 0; i < steps; i++) { loop_vertices: for (let j = 0; j < vertex_count; j++) { const v0 = topo.vertices[j]; // 1) get attached edges const attached_edges = v0.edges; const attached_edge_count = attached_edges.length; if (attached_edge_count === 0) { continue; } // Compute neighbour UV weight based on edge length let sum_u = 0; let sum_v = 0; let weight_sum = 0; for (let k = 0; k < attached_edge_count; k++) { const edge = attached_edges[k]; if (query_edge_is_boundary(edge)) { // edge vertex, no adjustment possible continue loop_vertices; } const v1 = query_edge_other_vertex(edge, v0); const other_uv_address = v1.index * 2; const u = uvs[other_uv_address]; const v = uvs[other_uv_address + 1]; const weight = 1 / edge.lengthSqr; sum_u += u * weight; sum_v += v * weight; weight_sum += weight; } // compute new UV position to equalize the vertex distance const u = sum_u / weight_sum; const v = sum_v / weight_sum; const uv_address = v0.index * 2; uvs[uv_address] = u; uvs[uv_address + 1] = v; } } }