Hello, I am trying to simplify the meshes in the threeJs scene using meshoptimizer library.
I am facing some difficulties while creating a new vertex attribute after the compactMesh
function is called. I also took some references from gltf-transform library and wrote similar methods which does same functionality on typedArray instead of a mesh primitive.
Here is my code
import {MeshoptSimplifier} from 'meshoptimizer'
function createIndices(count: number, maxIndex = count): Uint16Array | Uint32Array {
const array = maxIndex <= 65534 ? new Uint16Array(count) : new Uint32Array(count);
for (let i = 0; i < array.length; i++) array[i] = i;
return array;
}
function cleanIndexArray(indexArray : Uint16Array | Uint32Array, maxIndex : number){
const srcIndicesArray = indexArray;
const dstIndicesArray = []
const component_type = maxIndex <= 65534 ? '5123' : '5125';
let maxIndex1 = -Infinity;
for (let i = 0, il = srcIndicesArray.length; i < il; i += 3) {
const a = srcIndicesArray[i];
const b = srcIndicesArray[i + 1];
const c = srcIndicesArray[i + 2];
if (a === b || a === c || b === c) continue;
dstIndicesArray.push(a, b, c);
maxIndex = Math.max(maxIndex1, a, b, c);
}
const TypedArray = ComponentTypeToTypedArray[component_type]
return new TypedArray(dstIndicesArray)
}
function remapGeometries(geometry: THREE.BufferGeometry, remap : TypedArray, dstVertexCount: number){
// Remap Indices
const srcVertexCount = geometry.attributes.position.count
const srcIndices = geometry.index
const srcIndicesArray = srcIndices ? srcIndices.array : null;
const dstIndicesCount = srcIndices ? srcIndices.count : srcVertexCount;
const dstIndicesArray = createIndices(dstIndicesCount, dstVertexCount);
for (let i = 0; i < dstIndicesCount; i++) {
dstIndicesArray[i] = remap[srcIndicesArray ? srcIndicesArray[i] : i];
}
// Remap Vertices
const elementSize = geometry.attributes.position.itemSize
const srcCount = srcVertexCount
const srcArray = geometry.attributes.position.array
const dstArray = srcArray.slice(0, dstVertexCount * elementSize)
const done = new Uint8Array(dstVertexCount)
for (let srcIndex = 0; srcIndex < srcCount; srcIndex++) {
const dstIndex = remap[srcIndex];
if (done[dstIndex]) continue;
for (let j = 0; j < elementSize; j++) {
dstArray[dstIndex * elementSize + j] = srcArray[srcIndex * elementSize + j];
}
done[dstIndex] = 1;
}
const cleanedIndexArray = cleanIndexArray(dstIndicesArray, dstVertexCount)
return [cleanedIndexArray, dstArray]
}
simplify(m : THREE.Mesh){
let uint32Array = new Uint32Array(m.geometry.index?.count as number)
m.geometry.index?.array.map((value, index) => uint32Array[index] = value)
const divisor = 2
let target_index_count = 3
if (m.geometry.index){
target_index_count = (m.geometry.index.count / divisor % 3) == 0 ? m.geometry.index.count / divisor : m.geometry.index.count % 3 + m.geometry.index.count
}
// printing arrays before simplification
console.log(uint32Array, "source Index Array", m.geometry.attributes.position.array as Float32Array, "source Vertex postions Array")
const meshIndices = MeshoptSimplifier.simplify(uint32Array, m.geometry.attributes.position.array as Float32Array, 3, target_index_count, 1)
const [remap, dstVertexCount] = MeshoptSimplifier.compactMesh(meshIndices[0])
const [dstIndicesArray, dstVertexArray] = remapGeometries(m.geometry, remap, dstVertexCount)
// printing arrays after simplification
console.log(remap, "new vertex order", dstIndicesArray, "Destination Index array", dstVertexArray, "new Vertex Array")
if(m.geometry.index){
m.geometry.index.array = dstIndicesArray
m.geometry.attributes.position.array.set(dstVertexArray)
}
return m
}
simplify(mesh)
The destination index array contains some reduntant values like 65535 which is which is not referenced in the destination vertex attributes. Also post rendering I don’t see any differnece in the vram usage as it is same as the original unsimplified mesh
I am trying rosolve these inconsistency, can someone please let me know if I am doing anyting wrong with the implementation.
Thanks for helping me in advance