Add support for custom box brush geometry in scene documents

This commit is contained in:
2026-04-05 02:35:11 +02:00
parent cf65b02e8d
commit 82664df74d
5 changed files with 49 additions and 12 deletions

View File

@@ -2,10 +2,11 @@ import { getModelInstances } from "../assets/model-instances";
import { cloneWorldSettings } from "../document/world-settings";
import { getEntityInstances, getPrimaryPlayerStartEntity } from "../entities/entity-instances";
import { getBoxBrushBounds } from "../geometry/box-brush";
import { buildBoxBrushDerivedMeshData } from "../geometry/box-brush-mesh";
import { buildGeneratedModelCollider } from "../geometry/model-instance-collider-generation";
import { cloneInteractionLink, getInteractionLinks } from "../interactions/interaction-links";
import { cloneMaterialDef } from "../materials/starter-material-library";
import { cloneFaceUvState } from "../document/brushes";
import { cloneBoxBrushGeometry, cloneFaceUvState } from "../document/brushes";
import { assertRuntimeSceneBuildable } from "./runtime-scene-validation";
import { FIRST_PERSON_PLAYER_SHAPE } from "./player-collision";
function cloneVec3(vector) {
@@ -32,6 +33,7 @@ function buildRuntimeBrush(brush, document) {
center: cloneVec3(brush.center),
rotationDegrees: cloneVec3(brush.rotationDegrees),
size: cloneVec3(brush.size),
geometry: cloneBoxBrushGeometry(brush.geometry),
faces: {
posX: {
materialId: brush.faces.posX.materialId,
@@ -68,13 +70,15 @@ function buildRuntimeBrush(brush, document) {
}
function buildRuntimeCollider(brush) {
const bounds = getBoxBrushBounds(brush);
const derivedMesh = buildBoxBrushDerivedMeshData(brush);
return {
kind: "box",
kind: "trimesh",
source: "brush",
brushId: brush.id,
center: cloneVec3(brush.center),
rotationDegrees: cloneVec3(brush.rotationDegrees),
size: cloneVec3(brush.size),
vertices: derivedMesh.colliderVertices,
indices: derivedMesh.colliderIndices,
worldBounds: {
min: cloneVec3(bounds.min),
max: cloneVec3(bounds.max)

View File

@@ -1,12 +1,21 @@
import { getModelInstances } from "../assets/model-instances";
import { assertSceneDocumentIsValid, createDiagnostic, formatSceneDiagnosticSummary } from "../document/scene-document-validation";
import { getPrimaryPlayerStartEntity } from "../entities/entity-instances";
import { validateBoxBrushGeometry } from "../geometry/box-brush-mesh";
import { buildGeneratedModelCollider, ModelColliderGenerationError } from "../geometry/model-instance-collider-generation";
function validateBrushGeometry(brush, path, diagnostics) {
for (const diagnostic of validateBoxBrushGeometry(brush)) {
diagnostics.push(createDiagnostic("error", diagnostic.code, diagnostic.message, `${path}.geometry`, "build"));
}
}
export function validateRuntimeSceneBuild(document, options) {
const diagnostics = [];
if (options.navigationMode === "firstPerson" && getPrimaryPlayerStartEntity(document.entities) === null) {
diagnostics.push(createDiagnostic("error", "missing-player-start", "First-person run requires an authored Player Start. Place one or switch to Orbit Visitor.", "entities", "build"));
}
for (const brush of Object.values(document.brushes)) {
validateBrushGeometry(brush, `brushes.${brush.id}`, diagnostics);
}
for (const modelInstance of getModelInstances(document.modelInstances)) {
const path = `modelInstances.${modelInstance.id}.collision.mode`;
const asset = document.assets[modelInstance.assetId];