Add tank catalog with USDZ models and tank selection

Introduce TankDefinition/TankCatalog loaded from Tanks.json, bundle the
Drachengas USDZ tank models, add tank selection and preview views, and
update the AR experience, editor and project views to use the catalog.
Includes tests for catalog loading and model selection.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Dennis Nemec
2026-09-26 19:12:39 +02:00
parent 992bb32025
commit b8536d4182
63 changed files with 2317 additions and 188 deletions

View File

@ -7,6 +7,7 @@
import RealityKit
import Metal
import UIKit
/// Kapselt das Höhen-Fade-CustomMaterial für den unterirdischen Tank:
/// verblasst die Opacity anhand der Welt-Höhe (Kopf opak, vergrabener Teil transparent).
@ -22,7 +23,9 @@ enum TankDepthFadeMaterial {
return CustomMaterial.SurfaceShader(named: "tankDepthFadeSurface", in: library)
}()
/// Ersetzt die Materialien der Entity (rekursiv) durch das Fade-CustomMaterial.
/// Ersetzt die Originalmaterialien rekursiv durch CustomMaterial-Versionen,
/// wobei Texturen und Farben des USDZ erhalten bleiben. Schatten werden für
/// transparente Model-Entities separat deaktiviert.
static func apply(to entity: Entity) {
guard let shader else { return }
forEachModelEntity(entity) { modelEntity in
@ -36,16 +39,26 @@ enum TankDepthFadeMaterial {
return custom
}
modelEntity.model = component
modelEntity.components.set(GroundingShadowComponent(castsShadow: false))
modelEntity.components.set(DynamicLightShadowComponent(castsShadow: false))
}
}
/// Aktualisiert die Boden-Höhe (Welt-Y) in bereits angewandten Fade-Materialien.
static func updateGroundY(_ groundY: Float, on entity: Entity) {
static func updateGroundY(
_ groundY: Float,
belowAlpha: Float = 0.3,
on entity: Entity
) {
forEachModelEntity(entity) { modelEntity in
guard var component = modelEntity.model else { return }
component.materials = component.materials.map { material in
guard var custom = material as? CustomMaterial else { return material }
custom.custom.value = SIMD4<Float>(groundY, band, belowAlpha, 0)
var customValue = custom.custom.value
customValue.x = groundY
customValue.y = band
customValue.z = belowAlpha
custom.custom.value = customValue
return custom
}
modelEntity.model = component