auto-git:

[change] src/viewport-three/viewport-host.ts
This commit is contained in:
2026-03-31 20:05:58 +02:00
parent b423115186
commit 45899ecc6a

View File

@@ -327,6 +327,49 @@ export class ViewportHost {
this.camera.lookAt(this.cameraTarget);
}
private applyWorld() {
if (this.currentWorld === null) {
return;
}
const world = this.currentWorld;
this.ambientLight.color.set(world.ambientLight.colorHex);
this.ambientLight.intensity = world.ambientLight.intensity;
this.sunLight.color.set(world.sunLight.colorHex);
this.sunLight.intensity = world.sunLight.intensity;
this.sunLight.position.set(world.sunLight.direction.x, world.sunLight.direction.y, world.sunLight.direction.z).normalize().multiplyScalar(18);
if (world.background.mode === "image") {
this.scene.background = this.loadedImageAssets[world.background.assetId]?.texture ?? null;
return;
}
this.scene.background = null;
}
private rebuildLocalLights(document: SceneDocument) {
this.clearLocalLights();
for (const entity of getEntityInstances(document.entities)) {
const selected = this.currentSelection.kind === "entities" && this.currentSelection.ids.includes(entity.id);
switch (entity.kind) {
case "pointLight": {
const renderObjects = this.createPointLightRenderObjects(entity, selected);
this.localLightGroup.add(renderObjects.group);
this.localLightRenderObjects.set(entity.id, renderObjects);
break;
}
case "spotLight": {
const renderObjects = this.createSpotLightRenderObjects(entity, selected);
this.localLightGroup.add(renderObjects.group);
this.localLightRenderObjects.set(entity.id, renderObjects);
break;
}
}
}
}
private rebuildBrushMeshes(document: SceneDocument, selection: EditorSelection) {
this.clearBrushMeshes();
@@ -395,6 +438,18 @@ export class ViewportHost {
private createEntityRenderObjects(entity: EntityInstance, selected: boolean): EntityRenderObjects {
switch (entity.kind) {
case "pointLight":
return this.createPointLightGizmoRenderObjects(entity.id, entity.position, entity.distance, entity.colorHex, selected);
case "spotLight":
return this.createSpotLightGizmoRenderObjects(
entity.id,
entity.position,
entity.direction,
entity.distance,
entity.angleDegrees,
entity.colorHex,
selected
);
case "playerStart":
return this.createPlayerStartRenderObjects(entity.id, entity.position, entity.yawDegrees, selected);
case "soundEmitter":
@@ -414,6 +469,147 @@ export class ViewportHost {
group.add(mesh);
}
private createPointLightRenderObjects(
entityId: string,
position: Vec3,
distance: number,
colorHex: string,
selected: boolean
): EntityRenderObjects {
const markerColor = colorHex;
const displayRadius = Math.max(0.5, distance);
const group = new Group();
group.position.set(position.x, position.y, position.z);
const core = new Mesh(
new SphereGeometry(0.16, 16, 12),
new MeshStandardMaterial({
color: markerColor,
emissive: markerColor,
emissiveIntensity: selected ? 0.22 : 0.1,
roughness: 0.28,
metalness: 0.05
})
);
const range = new Mesh(
new SphereGeometry(displayRadius, 16, 12),
new MeshStandardMaterial({
color: markerColor,
emissive: markerColor,
emissiveIntensity: selected ? 0.08 : 0.03,
roughness: 0.85,
metalness: 0,
transparent: true,
opacity: selected ? 0.16 : 0.08,
wireframe: true
})
);
for (const mesh of [core, range]) {
this.tagEntityMesh(mesh, entityId, "pointLight", group);
}
return {
group,
meshes: [core, range]
};
}
private createSpotLightRenderObjects(
entityId: string,
position: Vec3,
direction: Vec3,
distance: number,
angleDegrees: number,
colorHex: string,
selected: boolean
): EntityRenderObjects {
const markerColor = colorHex;
const group = new Group();
group.position.set(position.x, position.y, position.z);
const forward = new Vector3(direction.x, direction.y, direction.z).normalize();
const coneLength = Math.max(0.85, distance);
const coneRadius = Math.max(0.16, Math.tan((angleDegrees * Math.PI) / 360) * coneLength);
const orientation = new Quaternion().setFromUnitVectors(new Vector3(0, 1, 0), forward);
group.quaternion.copy(orientation);
const core = new Mesh(
new SphereGeometry(0.16, 14, 10),
new MeshStandardMaterial({
color: markerColor,
emissive: markerColor,
emissiveIntensity: selected ? 0.24 : 0.1,
roughness: 0.28,
metalness: 0.05
})
);
const cone = new Mesh(
new CylinderGeometry(coneRadius, 0, coneLength, 20, 1, true),
new MeshStandardMaterial({
color: markerColor,
emissive: markerColor,
emissiveIntensity: selected ? 0.08 : 0.03,
roughness: 0.85,
metalness: 0,
transparent: true,
opacity: selected ? 0.16 : 0.08,
wireframe: true
})
);
cone.position.y = coneLength * 0.5;
for (const mesh of [core, cone]) {
this.tagEntityMesh(mesh, entityId, "spotLight", group);
}
return {
group,
meshes: [core, cone]
};
}
private createSpotLightObjects(entity: SpotLightEntity): Group {
const group = new Group();
const light = new SpotLight(entity.colorHex, entity.intensity, entity.distance, (entity.angleDegrees * Math.PI) / 180, 0.18, 1);
const direction = new Vector3(entity.direction.x, entity.direction.y, entity.direction.z).normalize();
const orientation = new Quaternion().setFromUnitVectors(new Vector3(0, 1, 0), direction);
group.position.set(entity.position.x, entity.position.y, entity.position.z);
group.quaternion.copy(orientation);
light.position.set(0, 0, 0);
light.target.position.set(0, 1, 0);
group.add(light);
group.add(light.target);
return group;
}
private createPointLightObjects(entity: PointLightEntity): Group {
const group = new Group();
const light = new PointLight(entity.colorHex, entity.intensity, entity.distance);
group.position.set(entity.position.x, entity.position.y, entity.position.z);
light.position.set(0, 0, 0);
group.add(light);
return group;
}
private createPointLightRenderObjectsWrapper(entity: PointLightEntity): LocalLightRenderObjects {
return {
group: this.createPointLightObjects(entity)
};
}
private createSpotLightRenderObjectsWrapper(entity: SpotLightEntity): LocalLightRenderObjects {
return {
group: this.createSpotLightObjects(entity)
};
}
private createPlayerStartRenderObjects(entityId: string, position: Vec3, yawDegrees: number, selected: boolean): EntityRenderObjects {
const markerColor = selected ? PLAYER_START_SELECTED_COLOR : PLAYER_START_COLOR;
const group = new Group();