Files
Gas-Tank-AR-App/GasTankAR/Views/TankAR/TankDepthFadeMaterial.swift
2026-09-02 20:54:36 +02:00

64 lines
2.4 KiB
Swift

//
// TankDepthFadeMaterial.swift
// GasTankAR
//
// Created by Dennis Nemec on 26.08.26.
//
import RealityKit
import Metal
/// Kapselt das Höhen-Fade-CustomMaterial für den unterirdischen Tank:
/// verblasst die Opacity anhand der Welt-Höhe (Kopf opak, vergrabener Teil transparent).
@MainActor
enum TankDepthFadeMaterial {
/// Fade-Band (Meter) unterhalb der Bodenkante, über das die Transparenz einsetzt.
static let band: Float = 0.15
/// Minimale Opacity des vergrabenen Teils.
static let belowAlpha: Float = 0.3
private static let shader: CustomMaterial.SurfaceShader? = {
guard let library = MTLCreateSystemDefaultDevice()?.makeDefaultLibrary() else { return nil }
return CustomMaterial.SurfaceShader(named: "tankDepthFadeSurface", in: library)
}()
/// Ersetzt die Materialien der Entity (rekursiv) durch das Fade-CustomMaterial.
static func apply(to entity: Entity) {
guard let shader else { return }
forEachModelEntity(entity) { modelEntity in
guard var component = modelEntity.model else { return }
component.materials = component.materials.map { material in
guard var custom = try? CustomMaterial(from: material, surfaceShader: shader) else {
return material
}
custom.blending = .transparent(opacity: 1.0)
custom.custom.value = SIMD4<Float>(0, band, belowAlpha, 0)
return custom
}
modelEntity.model = component
}
}
/// Aktualisiert die Boden-Höhe (Welt-Y) in bereits angewandten Fade-Materialien.
static func updateGroundY(_ groundY: Float, 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)
return custom
}
modelEntity.model = component
}
}
private static func forEachModelEntity(_ entity: Entity, _ body: (ModelEntity) -> Void) {
if let modelEntity = entity as? ModelEntity {
body(modelEntity)
}
for child in entity.children {
forEachModelEntity(child, body)
}
}
}