如何在RealityKit中通过MeshDescriptor实现网格实例化
我正在尝试在RealityKit中实现网格实例化——在一个绘制调用中将同一个网格渲染多次(可能的情况)。
为了简化起见,我在Reality Composer Pro创建了一个立方体。
我尝试使用 MeshInstancesComponent —— 它确实能生成合并后的网格 —— 但因为阴影投射出现了一些奇怪的问题而没有奏效。而 MeshDescriptor,则没有这个阴影问题。
因此,为了访问底层顶点数据,我有以下代码,是改自 这里:
extension MeshResource.Contents {
func forEachVertex(_ callback: (SIMD3<Float>, UInt32?, SIMD2<Float>?, SIMD3<Float>, SIMD3<Float>, Int, SIMD3<Float>) -> Void) {
for instance in self.instances {
guard let model = self.models[instance.model] else { continue }
let instanceToModel = instance.transform
for part in model.parts {
var vertexes: [SIMD4<Float>] = []
var indices: [UInt32] = []
var texCoords: [SIMD2<Float>] = []
var norms: [SIMD4<Float>] = []
var tangents: [SIMD4<Float>] = []
var bitangents: [SIMD4<Float>] = []
var materialIndexes = [Int]()
for position in part.positions {
vertexes.append(instanceToModel * SIMD4<Float>(position, 1.0))
}
materialIndexes.append(part.materialIndex)
if let allIndices = part.triangleIndices {
for index in allIndices {
indices.append(index)
}
}
if let allTex = part.textureCoordinates {
for coord in allTex {
texCoords.append(coord)
}
}
if let n = part.normals {
for norm in n {
norms.append(SIMD4<Float>(norm, 1.0))
}
}
if let t = part.tangents {
for tan in t {
tangents.append(SIMD4<Float>(tan, 1.0))
}
}
if let b = part.bitangents {
for tan in b {
bitangents.append(SIMD4<Float>(tan, 1.0))
}
}
for i in 0..<vertexes.count {
let v = vertexes[i]
callback([v.x, v.y, v.z], indices[i], texCoords[i], [norms[i].x, norms[i].y, norms[i].z], [tangents[i].x, tangents[i].y, tangents[i].z], materialIndexes[0], [bitangents[i].x, bitangents[i].y, bitangents[i].z])
}
}
}
}
}
然后,我为每个网格创建一个单独的 MeshDescriptor:
var descriptors = [MeshDescriptor]()
for i in 0..<createdTrees.count {
var d = MeshDescriptor()
var positions = [SIMD3<Float>]()
var normals = [SIMD3<Float>]()
var indexes = [UInt32]()
var textureCoords = [SIMD2<Float>]()
var tangents = [SIMD3<Float>]()
var biTangents = [SIMD3<Float>]()
var material_Index: Int = 0
createdTrees[i]!.components[ModelComponent.self]!.mesh.contents.forEachVertex { position, index, textureCoordinate, normal, tangent, materialIndex, bitangent in
positions.append(position)
normals.append(normal)
indexes.append(index!)
textureCoords.append(textureCoordinate!)
tangents.append(tangent)
material_Index = materialIndex
biTangents.append(bitangent)
}
d.positions = MeshBuffers.Positions.init(positions)
d.textureCoordinates = MeshBuffers.TextureCoordinates.init(textureCoords)
d.normals = MeshBuffers.Normals.init(normals)
d.tangents = MeshBuffers.Tangents.init(tangents)
d.bitangents = MeshBuffers.Tangents.init(biTangents)
d.primitives = .triangles(indexes)
d.materials = .allFaces(UInt32(material_Index))
descriptors.append(d)
}
最后,我用 MeshResource,并通过 MeshDescriptor 数组来生成:
do {
let combinedMesh = try MeshResource.generate(from: descriptors)
let material = createdTrees[0]!.components[ModelComponent.self]!.materials[0]
let comboEntity = ModelEntity(mesh: combinedMesh, materials: [material])
comboEntity.position = createdTrees[0]!.position
comboEntity.move(to: Transform(pitch: -90.0 * .pi / 180.0), relativeTo: comboEntity)
self.gameScene?.addChild(comboEntity)
} catch {
print(error.localizedDescription)
}
结果:只创建了一个实例——但其他的都不存在。并且有些面可见,有些则不可见。
我已经尝试过:翻转法线(将每个法线分量乘以 -1.0),以及颠倒顶点数据数组。
问题:我可以做哪些修改,以实现对 MeshDescriptor 的网格实例化?
解决方案
好的,我再次尝试了 MeshInstancesComponent,解决了此前在阴影投射方面遇到的问题。原来其实是材质/纹理的问题——从 PhysicallyBasedMaterial 迁移到着色器图材质后,所有实例的阴影都变得良好。
以下是我的代码——改自 这里。
let count: Int = self.positions.count
let instanceData = try? LowLevelInstanceData(instanceCount: count)
let mesh = referenceEntity.components[ModelComponent.self]!.mesh
let modelID = mesh.contents.models.first?.id
instanceData?.withMutableTransforms {
for i in 0..<count {
let transform = Transform(
scale: [1.0, 1.0, 1.0],
translation: [self.positions[i].x, self.positions[i].y, self.positions[i].z])
$0[i] = transform.matrix
}
}
if let data = instanceData {
do {
let component = try MeshInstancesComponent(mesh: mesh, modelID: modelID, instances: data)
referenceEntity.components.set(component)
} catch {
}
}
注:虽然我尚未验证对绘制数量的影响,但我注意到使用这种实例化策略后,CPU使用显著下降。
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。