Update collision detection to handle triangle meshes and transformed colliders

This commit is contained in:
2026-04-07 05:44:04 +02:00
parent a9567d3dc8
commit a74a7c02f0
5 changed files with 163 additions and 33 deletions

View File

@@ -592,19 +592,36 @@ export class RuntimeHost {
}
collectRuntimeStaticWaterContactPatches(brush) {
const contactBounds = [];
for (const otherBrush of this.runtimeScene?.brushes ?? []) {
if (otherBrush.id === brush.id || otherBrush.volume.mode !== "none") {
const runtimeBrushesById = new Map((this.runtimeScene?.brushes ?? []).map((runtimeBrush) => [runtimeBrush.id, runtimeBrush]));
for (const collider of this.runtimeScene?.colliders ?? []) {
if (collider.source === "brush") {
const otherBrush = runtimeBrushesById.get(collider.brushId);
if (otherBrush === undefined || otherBrush.id === brush.id || otherBrush.volume.mode !== "none") {
continue;
}
contactBounds.push({
kind: "triangleMesh",
vertices: collider.vertices,
indices: collider.indices,
transform: {
position: collider.center,
rotationDegrees: collider.rotationDegrees,
scale: {
x: 1,
y: 1,
z: 1
}
}
});
continue;
}
contactBounds.push({
kind: "orientedBox",
center: otherBrush.center,
rotationDegrees: otherBrush.rotationDegrees,
size: otherBrush.size
});
}
for (const collider of this.runtimeScene?.colliders ?? []) {
if (collider.source !== "modelInstance") {
if (collider.kind === "trimesh") {
contactBounds.push({
kind: "triangleMesh",
vertices: collider.vertices,
indices: collider.indices,
transform: collider.transform
});
continue;
}
contactBounds.push({

View File

@@ -815,21 +815,40 @@ export class RuntimeHost {
private collectRuntimeStaticWaterContactPatches(brush: RuntimeBoxBrushInstance) {
const contactBounds: Parameters<typeof collectWaterContactPatches>[1] = [];
for (const otherBrush of this.runtimeScene?.brushes ?? []) {
if (otherBrush.id === brush.id || otherBrush.volume.mode !== "none") {
const runtimeBrushesById = new Map((this.runtimeScene?.brushes ?? []).map((runtimeBrush) => [runtimeBrush.id, runtimeBrush]));
for (const collider of this.runtimeScene?.colliders ?? []) {
if (collider.source === "brush") {
const otherBrush = runtimeBrushesById.get(collider.brushId);
if (otherBrush === undefined || otherBrush.id === brush.id || otherBrush.volume.mode !== "none") {
continue;
}
contactBounds.push({
kind: "triangleMesh",
vertices: collider.vertices,
indices: collider.indices,
transform: {
position: collider.center,
rotationDegrees: collider.rotationDegrees,
scale: {
x: 1,
y: 1,
z: 1
}
}
});
continue;
}
contactBounds.push({
kind: "orientedBox",
center: otherBrush.center,
rotationDegrees: otherBrush.rotationDegrees,
size: otherBrush.size
});
}
for (const collider of this.runtimeScene?.colliders ?? []) {
if (collider.source !== "modelInstance") {
if (collider.kind === "trimesh") {
contactBounds.push({
kind: "triangleMesh",
vertices: collider.vertices,
indices: collider.indices,
transform: collider.transform
});
continue;
}

View File

@@ -2204,11 +2204,20 @@ export class ViewportHost {
if (brush.id === excludedBrushId || brush.volume.mode !== "none") {
continue;
}
const derivedMesh = buildBoxBrushDerivedMeshData(brush);
contactBounds.push({
kind: "orientedBox",
center: brush.center,
rotationDegrees: brush.rotationDegrees,
size: brush.size
kind: "triangleMesh",
vertices: derivedMesh.colliderVertices,
indices: derivedMesh.colliderIndices,
transform: {
position: brush.center,
rotationDegrees: brush.rotationDegrees,
scale: {
x: 1,
y: 1,
z: 1
}
}
});
}
for (const modelInstance of getModelInstances(document.modelInstances)) {
@@ -2222,7 +2231,17 @@ export class ViewportHost {
try {
const generatedCollider = buildGeneratedModelCollider(modelInstance, asset, this.loadedModelAssets[modelInstance.assetId]);
if (generatedCollider !== null) {
contactBounds.push(generatedCollider.worldBounds);
if (generatedCollider.kind === "trimesh") {
contactBounds.push({
kind: "triangleMesh",
vertices: generatedCollider.vertices,
indices: generatedCollider.indices,
transform: generatedCollider.transform
});
}
else {
contactBounds.push(generatedCollider.worldBounds);
}
}
}
catch {

View File

@@ -3013,11 +3013,21 @@ export class ViewportHost {
continue;
}
const derivedMesh = buildBoxBrushDerivedMeshData(brush);
contactBounds.push({
kind: "orientedBox",
center: brush.center,
rotationDegrees: brush.rotationDegrees,
size: brush.size
kind: "triangleMesh",
vertices: derivedMesh.colliderVertices,
indices: derivedMesh.colliderIndices,
transform: {
position: brush.center,
rotationDegrees: brush.rotationDegrees,
scale: {
x: 1,
y: 1,
z: 1
}
}
});
}
@@ -3036,7 +3046,16 @@ export class ViewportHost {
const generatedCollider = buildGeneratedModelCollider(modelInstance, asset, this.loadedModelAssets[modelInstance.assetId]);
if (generatedCollider !== null) {
contactBounds.push(generatedCollider.worldBounds);
if (generatedCollider.kind === "trimesh") {
contactBounds.push({
kind: "triangleMesh",
vertices: generatedCollider.vertices,
indices: generatedCollider.indices,
transform: generatedCollider.transform
});
} else {
contactBounds.push(generatedCollider.worldBounds);
}
}
} catch {
// Validation already surfaces unsupported collider modes; the viewport keeps rendering.