Reputation: 11
I'm trying to convert facelandmarks to 3d points in scenekit.Even with incorrect depth value face tracks correctly but it is not useful as occluder. because worldpoint is wrong and face mesh always stays front of every sceneobject or back of every sceneobject. I've tried to use faceNode.transform = matrix
(from mediapipe) it works great but it does not track landmarks. Right now I update geometry vertices by using these landmarks and update geometry uv with uv.json data that mediapipe provided.
How can i get correct world position of landmarks in scenekit? Thank you.
if let normalizedLandmarkArray = firstFaceNormalizedLandmarks {
let vertexPositionArray = normalizedLandmarkArray.enumerated().map { index, landmark -> simd_float3 in
let screenX = CGFloat(landmark.x) * imageWidth
let screenY = CGFloat(landmark.y) * imageHeight
let screenPoint = SCNVector3(screenX, screenY, 1)
let worldPoint = sceneView.unprojectPoint(screenPoint)
return simd_float3(Float(worldPoint.x), Float(worldPoint.y), Float(worldPoint.z))
}
struct MyVertex {
var x: Float // Position X
var y: Float // Position Y
var z: Float // Position Z
var nx: Float // Normal X
var ny: Float // Normal Y
var nz: Float // Normal Z
var s: Float // Texture Coordinate S (U)
var t: Float // Texture Coordinate T (V)
}
func updateFaceNodeGeometry(landmarks: [simd_float3], geometry: SCNGeometry) -> SCNGeometry? {
guard !uValues.isEmpty, !vValues.isEmpty else {
print("❌ UV values are not loaded.")
return nil
}
let limitedLandmarks = landmarks.prefix(468)
var vertices: [MyVertex] = []
for (index, landmark) in limitedLandmarks.enumerated() {
let vertex = MyVertex(
x: landmark.x,
y: landmark.y,
z: landmark.z,
nx: 0.0, ny: 0.0, nz: 1.0, // Normaller varsayılan olarak yüzey normaline ayarlandı
s: uValues[index],
t: vValues[index]
)
vertices.append(vertex)
}
let data = NSData(bytes: vertices, length: vertices.count * MemoryLayout<MyVertex>.size)
let vertexSource = SCNGeometrySource(
data: data as Data,
semantic: .vertex,
vectorCount: vertices.count,
usesFloatComponents: true,
componentsPerVector: 3, // x, y, z
bytesPerComponent: MemoryLayout<Float>.size,
dataOffset: 0,
dataStride: MemoryLayout<MyVertex>.size
)
let normalSource = SCNGeometrySource(
data: data as Data,
semantic: .normal,
vectorCount: vertices.count,
usesFloatComponents: true,
componentsPerVector: 3, // nx, ny, nz
bytesPerComponent: MemoryLayout<Float>.size,
dataOffset: MemoryLayout.offset(of: \MyVertex.nx)!,
dataStride: MemoryLayout<MyVertex>.size
)
let texcoordSource = SCNGeometrySource(
data: data as Data,
semantic: .texcoord,
vectorCount: vertices.count,
usesFloatComponents: true,
componentsPerVector: 2, // s, t
bytesPerComponent: MemoryLayout<Float>.size,
dataOffset: MemoryLayout.offset(of: \MyVertex.s)!,
dataStride: MemoryLayout<MyVertex>.size
)
let updatedElement = geometry.elements.first ?? SCNGeometryElement(
data: Data(),
primitiveType: .triangles,
primitiveCount: limitedLandmarks.count / 3,
bytesPerIndex: MemoryLayout<UInt16>.size
)
guard let oldVertexSource = geometry.sources(for: .vertex).first else {
print("❌ Vertex source not found in geometry!")
return nil
}
// ✅ 6. Yeni Geometry Oluştur
let updatedGeometry = SCNGeometry(
sources: [vertexSource, normalSource, texcoordSource],
elements: [updatedElement]
)
if let material = updatedGeometry.firstMaterial {
material.isDoubleSided = true
material.writesToDepthBuffer = true
material.readsFromDepthBuffer = true
material.transparency = 1.0
material.transparencyMode = .dualLayer
material.fillMode = .fill
// material.diffuse.contents = UIColor.green
}
// DispatchQueue.main.async {
// self.faceNode?.geometry = updatedGeometry
// self.sceneView.scene?.isPaused = true
// self.sceneView.scene?.isPaused = false
// self.sceneView.setNeedsDisplay()
// }
//
// print("✅ Geometry updated successfully with C Struct Style!")
return updatedGeometry
}
i tried to convert mediapipe z value to scenekit z value but i couldn't
Upvotes: 1
Views: 27