64 lines
2.4 KiB
Swift
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)
|
|
}
|
|
}
|
|
}
|