feat(avlivebody): lights, material and visibility
This commit is contained in:
@@ -13,7 +13,7 @@ final class MeshEntity {
|
||||
private static let vertexCount = 10475
|
||||
private let faces: [UInt32]
|
||||
private var pools: [Int: ModelEntity] = [:]
|
||||
private let material = SimpleMaterial(
|
||||
private var material = SimpleMaterial(
|
||||
color: NSColor(white: 0.8, alpha: 1.0),
|
||||
roughness: 0.5, isMetallic: false)
|
||||
|
||||
@@ -41,6 +41,17 @@ final class MeshEntity {
|
||||
}
|
||||
}
|
||||
|
||||
func setVisible(_ visible: Bool) { root.isEnabled = visible }
|
||||
|
||||
func setMaterial(metallic: Bool, roughness: Double) {
|
||||
material = SimpleMaterial(
|
||||
color: NSColor(white: 0.8, alpha: 1.0),
|
||||
roughness: .float(Float(roughness)), isMetallic: metallic)
|
||||
for entity in pools.values {
|
||||
entity.model?.materials = [material]
|
||||
}
|
||||
}
|
||||
|
||||
private func buildMesh(_ verts: [SIMD3<Float>])
|
||||
-> MeshResource? {
|
||||
guard verts.count == Self.vertexCount, !faces.isEmpty else {
|
||||
|
||||
@@ -16,6 +16,10 @@ final class SceneController {
|
||||
private let camera = PerspectiveCamera()
|
||||
private let worldAnchor = AnchorEntity(world: .zero)
|
||||
|
||||
private let keyLight = DirectionalLight()
|
||||
private let fillLight = DirectionalLight()
|
||||
private let rimLight = DirectionalLight()
|
||||
|
||||
private(set) var videoQuad: VideoQuad?
|
||||
private(set) var skeleton: SkeletonEntity?
|
||||
private(set) var mesh: MeshEntity?
|
||||
@@ -33,6 +37,25 @@ final class SceneController {
|
||||
arView.environment.background = .color(.black)
|
||||
arView.scene.addAnchor(worldAnchor)
|
||||
|
||||
keyLight.light.intensity = 4000
|
||||
keyLight.orientation = simd_quatf(angle: .pi / 6,
|
||||
axis: SIMD3(1, 0, 0))
|
||||
let keyA = AnchorEntity(world: SIMD3<Float>(1, 2, -1))
|
||||
keyA.addChild(keyLight)
|
||||
arView.scene.addAnchor(keyA)
|
||||
|
||||
fillLight.light.intensity = 1500
|
||||
fillLight.light.color = NSColor(red: 0.7, green: 0.8,
|
||||
blue: 1.0, alpha: 1.0)
|
||||
let fillA = AnchorEntity(world: SIMD3<Float>(-2, 1, -2))
|
||||
fillA.addChild(fillLight)
|
||||
arView.scene.addAnchor(fillA)
|
||||
|
||||
rimLight.light.intensity = 2000
|
||||
let rimA = AnchorEntity(world: SIMD3<Float>(0, 1, -5))
|
||||
rimA.addChild(rimLight)
|
||||
arView.scene.addAnchor(rimA)
|
||||
|
||||
camera.camera.fieldOfViewInDegrees = 55
|
||||
cameraAnchor.addChild(camera)
|
||||
arView.scene.addAnchor(cameraAnchor)
|
||||
@@ -65,6 +88,25 @@ final class SceneController {
|
||||
mesh?.update(persons)
|
||||
}
|
||||
|
||||
func setSkeletonVisible(_ v: Bool) { skeleton?.setVisible(v) }
|
||||
func setMeshVisible(_ v: Bool) { mesh?.setVisible(v) }
|
||||
func setVideoVisible(_ v: Bool) { videoQuad?.setVisible(v) }
|
||||
func setVideoOpacity(_ v: Double) { videoQuad?.setOpacity(v) }
|
||||
|
||||
func updateMeshMaterial(metallic: Bool, roughness: Double) {
|
||||
mesh?.setMaterial(metallic: metallic, roughness: roughness)
|
||||
}
|
||||
|
||||
func setLightIntensities(key: Double, fill: Double, rim: Double) {
|
||||
keyLight.light.intensity = Float(key)
|
||||
fillLight.light.intensity = Float(fill)
|
||||
rimLight.light.intensity = Float(rim)
|
||||
}
|
||||
|
||||
func setFieldOfView(_ deg: Double) {
|
||||
camera.camera.fieldOfViewInDegrees = Float(deg)
|
||||
}
|
||||
|
||||
// MARK: - Orbital camera
|
||||
|
||||
private func applyCamera() {
|
||||
|
||||
@@ -18,6 +18,8 @@ final class SkeletonEntity {
|
||||
private let material = SimpleMaterial(
|
||||
color: NSColor.systemYellow, roughness: 0.6, isMetallic: false)
|
||||
|
||||
func setVisible(_ visible: Bool) { root.isEnabled = visible }
|
||||
|
||||
func update(_ skeletons: [Int: SkeletonPayload]) {
|
||||
// Drop pools for pids no longer present.
|
||||
for pid in pools.keys where skeletons[pid] == nil {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import AppKit
|
||||
import CoreImage
|
||||
import CoreVideo
|
||||
import Foundation
|
||||
@@ -10,6 +11,7 @@ final class VideoQuad {
|
||||
let entity = ModelEntity()
|
||||
|
||||
private let ciContext = CIContext()
|
||||
private var opacity: Double = 1.0
|
||||
/// Plane is 1.6 m wide, 16:9; positioned 2 m behind the body.
|
||||
private static let width: Float = 1.6
|
||||
private static let height: Float = 0.9
|
||||
@@ -26,6 +28,17 @@ final class VideoQuad {
|
||||
SIMD3<Float>(0, 0, Self.zBack)
|
||||
}
|
||||
|
||||
func setVisible(_ visible: Bool) { entity.isEnabled = visible }
|
||||
|
||||
func setOpacity(_ value: Double) {
|
||||
opacity = value
|
||||
// Re-tint current material; `update(_:)` will also use `opacity`.
|
||||
if var mat = entity.model?.materials.first as? UnlitMaterial {
|
||||
mat.color = .init(tint: NSColor(white: 1, alpha: CGFloat(value)))
|
||||
entity.model?.materials = [mat]
|
||||
}
|
||||
}
|
||||
|
||||
/// Replace the plane's texture from a decoded camera frame.
|
||||
func update(_ pixelBuffer: CVPixelBuffer) {
|
||||
let ci = CIImage(cvPixelBuffer: pixelBuffer)
|
||||
@@ -39,8 +52,9 @@ final class VideoQuad {
|
||||
return
|
||||
}
|
||||
var material = UnlitMaterial()
|
||||
material.color = .init(tint: .white,
|
||||
texture: .init(texture))
|
||||
material.color = .init(
|
||||
tint: NSColor(white: 1, alpha: CGFloat(opacity)),
|
||||
texture: .init(texture))
|
||||
entity.model?.materials = [material]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user