feat: instance node
All checks were successful
Deploy to GitHub Pages / build_site (push) Successful in 2m44s

This commit is contained in:
2024-05-06 01:10:23 +02:00
parent a01a409b97
commit 10a12ad41c
20 changed files with 695 additions and 147 deletions

View File

@@ -1,21 +1,5 @@
import { fastHashArrayBuffer } from "@nodes/utils";
import { BufferAttribute, BufferGeometry, Float32BufferAttribute, Mesh, MeshMatcapMaterial, TextureLoader, type Group } from "three";
function fastArrayHash(arr: ArrayBuffer) {
let ints = new Uint8Array(arr);
const sampleDistance = Math.max(Math.floor(ints.length / 100), 1);
const sampleCount = Math.floor(ints.length / sampleDistance);
let hash = new Uint8Array(sampleCount);
for (let i = 0; i < sampleCount; i++) {
const index = i * sampleDistance;
hash[i] = ints[index];
}
return fastHashArrayBuffer(hash.buffer);
}
import { MeshMatcapMaterial, TextureLoader, type Group } from "three";
import { createGeometryPool, createInstancedGeometryPool } from "./geometryPool";
const loader = new TextureLoader();
const matcap = loader.load('/matcap_green.jpg');
@@ -25,122 +9,19 @@ const material = new MeshMatcapMaterial({
matcap
});
function createGeometryFromEncodedData(
encodedData: Int32Array,
geometry = new BufferGeometry(),
): BufferGeometry {
// Extract data from the encoded array
let index = 1;
// const geometryType = encodedData[index++];
const vertexCount = encodedData[index++];
const faceCount = encodedData[index++];
let hash = fastArrayHash(encodedData);
if (geometry.userData?.hash === hash) {
return geometry;
}
// Indices
const indicesEnd = index + faceCount * 3;
const indices = encodedData.subarray(index, indicesEnd);
index = indicesEnd;
// Vertices
const vertices = new Float32Array(
encodedData.buffer,
index * 4,
vertexCount * 3,
);
index = index + vertexCount * 3;
let posAttribute = geometry.getAttribute(
"position",
) as BufferAttribute | null;
if (posAttribute && posAttribute.count === vertexCount) {
posAttribute.set(vertices, 0);
posAttribute.needsUpdate = true;
} else {
geometry.setAttribute(
"position",
new Float32BufferAttribute(vertices, 3),
);
}
const normals = new Float32Array(
encodedData.buffer,
index * 4,
vertexCount * 3,
);
index = index + vertexCount * 3;
if (
geometry.userData?.faceCount !== faceCount ||
geometry.userData?.vertexCount !== vertexCount
) {
// Add data to geometry
geometry.setIndex([...indices]);
}
const normalsAttribute = geometry.getAttribute(
"normal",
) as BufferAttribute | null;
if (normalsAttribute && normalsAttribute.count === vertexCount) {
normalsAttribute.set(normals, 0);
normalsAttribute.needsUpdate = true;
} else {
geometry.setAttribute("normal", new Float32BufferAttribute(normals, 3));
}
geometry.userData = {
vertexCount,
faceCount,
hash,
};
return geometry;
}
let meshes: Mesh[] = [];
let geometryPool: ReturnType<typeof createGeometryPool>;
let instancePool: ReturnType<typeof createInstancedGeometryPool>;
export function updateGeometries(inputs: Int32Array[], group: Group) {
geometryPool = geometryPool || createGeometryPool(group, material);
instancePool = instancePool || createInstancedGeometryPool(group, material);
let totalVertices = 0;
let totalFaces = 0;
let newGeometries = [];
for (let i = 0; i < Math.max(meshes.length, inputs.length); i++) {
let existingMesh = meshes[i];
let input = inputs[i];
if (input) {
if (input[0] !== 1) {
continue
}
totalVertices += input[1];
totalFaces += input[2];
} else {
if (existingMesh) {
existingMesh.visible = false;
}
continue;
}
if (existingMesh) {
createGeometryFromEncodedData(input, existingMesh.geometry);
} else {
let geo = createGeometryFromEncodedData(input);
const mesh = new Mesh(geo, material);
meshes[i] = mesh;
newGeometries.push(mesh);
}
}
for (let i = 0; i < newGeometries.length; i++) {
group.add(newGeometries[i]);
}
geometryPool.update(inputs.filter(i => i[0] === 1));
instancePool.update(inputs.filter(i => i[0] === 2));
return { totalFaces, totalVertices };
}