ios 如何为RealityKit / ARView指定双面材质?

ep6jt1vc  于 2023-02-17  发布在  iOS
关注(0)|答案(5)|浏览(193)

我试图在RealityKit中加载一个模型和纹理(在ARView示例中设置),但我似乎不知道如何指定材质应该是双面的。
我将模型加载为ModelEntity,将纹理加载为TextureResource。模型和纹理正在加载,但渲染的是单面。由于模型是打开的(即背面可见),因此在如何渲染上存在差距。
到目前为止,我已经,

let entity: ModelEntity = try .loadModel(named: "model.obj")

var material = SimpleMaterial()
material.baseColor = try .texture(.load(named: "texture.png"))
entity.model?.materials = [material]

我希望能找到一处房产

material.twoSided = true

但到目前为止,我还没有在RealityKit中找到对等的东西。
有人知道如何在RealityKit中设置双面材质吗?

z4iuyo4d

z4iuyo4d1#

目前似乎没有任何方法可以通过RealityKit API以编程方式完成此操作。
你能改变你的模型定义,使它不做背面剔除吗?例如,在一个USDZ文件中,我导入它定义网格的一部分为:

def Mesh "Plane_1"
  {
    uniform bool doubleSided = 1

可以先使用usdzconvert(https://developer.apple.com/download/more/?=USDPython)将obj文件转化为used文件,然后手动编辑该文件,再将其导入到场景中。
这也可能取决于模型的设置方式,您可以将多个材质传递到应用于模型不同部分的材质数组,您可以查看模型需要的材质数量:

entity.model?.mesh.expectedMaterialCount
bvuwiixz

bvuwiixz2#

正如其他人已经回答的,你不能通过编程来完成。但是你可以通过检查面板手动为每个模型完成。见下图。在底部附近,你有“双面”复选框。

uurv41yg

uurv41yg3#

我不认为有办法做到这一点。RealityKit仍处于早期阶段。RealityKit中的材料支持目前非常有限。我认为有计划在iOS 14或更高版本中改变这一点。文档中有一些注解描述了尚不存在的功能,例如材料协议中说“描述一种材料(颜色、着色器、纹理等),它们定义了网格部件的外观。”目前还没有办法定义自定义着色器。如果你看看RealityKit框架包,有着色器图形定义和新的材质特性还没有在公共API中公开。2我怀疑会有一个着色器图形编辑器,对自定义着色器的支持,双面材料也来了。

yhqotfr8

yhqotfr84#

这是可以做到的,但需要换个Angular :你创建了一个双面的网格,而不是创建一个双面的材料。2这是通过在每个模型中提取每个部分,并创建一个法线反转的双曲面(和三角形反转)来完成的。3使用下面的代码,上述问题的解决方案变为:

do {
   let entity: ModelEntity = try .loadModel(named: "model.obj")
   if let model = entity.model {
       try model.mesh.addInvertedNormals()
       // or alternatively, since this model isn't onscreen yet:
       // model.mesh = try model.mesh.addingInvertedNormals()
       var material = SimpleMaterial()
       material.baseColor = try .texture(.load(named: "texture.png"))
       model.materials = [material]
       entity.model = model
   }
} catch {}

现在实体将在两面显示材料。下面是代码:

import Foundation
import RealityKit

public extension MeshResource {
    // call this to create a 2-sided mesh that will then be displayed 
    func addingInvertedNormals() throws -> MeshResource {
        return try MeshResource.generate(from: contents.addingInvertedNormals())
    }
    
    // call this on a mesh that is already displayed to make it 2 sided
    func addInvertedNormals() throws {
        try replace(with: contents.addingInvertedNormals())
    }

    static func generateTwoSidedPlane(width: Float, depth: Float, cornerRadius: Float = 0) -> MeshResource {
        let plane = generatePlane(width: width, depth: depth, cornerRadius: cornerRadius)
        let twoSided = try? plane.addingInvertedNormals()
        return twoSided ?? plane
    }
}

public extension MeshResource.Contents {
    func addingInvertedNormals() -> MeshResource.Contents {
        var newContents = self

        newContents.models = .init(models.map { $0.addingInvertedNormals() })

        return newContents
    }
}

public extension MeshResource.Model {
    func partsWithNormalsInverted() -> [MeshResource.Part] {
        return parts.map { $0.normalsInverted() }.compactMap { $0 }
    }
    
    func addingParts(additionalParts: [MeshResource.Part]) -> MeshResource.Model {
        let newParts = parts.map { $0 } + additionalParts
        
        var newModel = self
        newModel.parts = .init(newParts)
        
        return newModel
    }
    
    func addingInvertedNormals() -> MeshResource.Model {
        return addingParts(additionalParts: partsWithNormalsInverted())
    }
}

public extension MeshResource.Part {
    func normalsInverted() -> MeshResource.Part? {
        if let normals, let triangleIndices {
            let newNormals = normals.map { $0 * -1.0 }
            var newPart = self
            newPart.normals = .init(newNormals)
            // ordering of points in the triangles must be reversed,
            // or the inversion of the normal has no effect
            newPart.triangleIndices = .init(triangleIndices.reversed())
            // id must be unique, or others with that id will be discarded
            newPart.id = id + " with inverted normals"
            return newPart
        } else {
            print("No normals to invert, returning nil")
            return nil
        }
    }
}

所以,调用addingInvertedNormals()创建一个网格,它将在两边显示相同的材质。我已经用它创建了一个双面网格平面。
通过一些额外的工作(作为练习!),您可以为创建的零件指定不同的材质索引,并在每一侧显示不同的材质。

btxsgosb

btxsgosb5#

你所描述的叫做剔除。例如检查MTLCullMode。从那里你可以跳转到不同的点,在那里你可以设置剔除模式(你对没有剔除感兴趣)。

相关问题