@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
86 lines (59 loc) • 2.52 kB
JavaScript
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;
}
}
}