【问题标题】:Repeating a texture over a plane in SceneKit在 SceneKit 中的平面上重复纹理
【发布时间】:2017-07-05 08:11:54
【问题描述】:

我有一个 32x32 .png 图像,我想在 SCNPlane 上重复该图像。我得到的代码(见下文)导致图像被拉伸以适应平面的大小,而不是重复。

代码:

let planeGeo = SCNPlane(width: 15, height: 15)

let imageMaterial = SCNMaterial()
imageMaterial.diffuse.contents = UIImage(named: "art.scnassets/grid.png")

planeGeo.firstMaterial = imageMaterial

let plane = SCNNode(geometry: planeGeo)

plane.geometry?.firstMaterial?.diffuse.wrapS = SCNWrapMode.repeat
plane.geometry?.firstMaterial?.diffuse.wrapT = SCNWrapMode.repeat

【问题讨论】:

    标签: swift xcode textures repeat


    【解决方案1】:

    我修好了。图片好像被放大了。如果我这样做imageMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(32, 32, 0),图片会重复。

    【讨论】:

    • 找到一种在 GUI 中执行此操作的方法?
    • @jfisk 不幸的是没有。我最好的猜测是以某种方式使用精灵,但我没有足够的研究来给出一个好的答案。
    • 我发布了关于如何在 GUI 中执行此操作的答案,而不是作为评论,因为我知道有时很难在 SceneKit 编辑器中导航。
    【解决方案2】:

    在 ARKit 中实现平面可视化时,我遇到了同样的问题。我想将检测到的平面可视化为棋盘图案。我通过使用正确配置的SCNMaterial 创建一个名为“PlaneNode”的自定义SCNNode 来修复它。材质使用 wrapS, wrapT = .repeat 并根据平面本身的大小正确计算比例。

    看起来像这样:

    看看下面的代码,内联的 cmets 包含解释。

    class PlaneNode : SCNNode {
    
        init(planeAnchor: ARPlaneAnchor) {
            super.init()
            // Create the 3D plane geometry with the dimensions reported
            // by ARKit in the ARPlaneAnchor instance
            let planeGeometry = SCNPlane(width:CGFloat(planeAnchor.extent.x), height:CGFloat(planeAnchor.extent.z))
            // Instead of just visualizing the grid as a gray plane, we will render
            // it in some Tron style colours.
            let material = SCNMaterial()
            material.diffuse.contents = PaintCode.imageOfViewARPlane
            //the scale gives the number of times the image is repeated
            //ARKit givest the width and height in meters, in this case we want to repeat
            //the pattern each 2cm = 0.02m so we divide the width/height to find the number of patterns
            //we then round this so that we always have a clean repeat and not a truncated one
            let scaleX = (Float(planeGeometry.width)  / 0.02).rounded()
            let scaleY = (Float(planeGeometry.height) / 0.02).rounded()
            //we then apply the scaling
            material.diffuse.contentsTransform = SCNMatrix4MakeScale(scaleX, scaleY, 0)
            //set repeat mode in both direction otherwise the patern is stretched!
            material.diffuse.wrapS = .repeat
            material.diffuse.wrapT = .repeat
            //apply material
            planeGeometry.materials = [material];
            //make a node for it
            self.geometry = planeGeometry
            // Move the plane to the position reported by ARKit
            position.x = planeAnchor.center.x
            position.y = 0
            position.z = planeAnchor.center.z
            // Planes in SceneKit are vertical by default so we need to rotate
            // 90 degrees to match planes in ARKit
            transform =  SCNMatrix4MakeRotation(-Float.pi / 2.0, 1.0, 0.0, 0.0);
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        func update(planeAnchor: ARPlaneAnchor) {
            guard let planeGeometry = geometry as? SCNPlane else {
                fatalError("update(planeAnchor: ARPlaneAnchor) called on node that has no SCNPlane geometry")
            }
            //update the size
            planeGeometry.width = CGFloat(planeAnchor.extent.x)
            planeGeometry.height = CGFloat(planeAnchor.extent.z)
            //and material properties
            let scaleX = (Float(planeGeometry.width)  / 0.02).rounded()
            let scaleY = (Float(planeGeometry.height) / 0.02).rounded()
            planeGeometry.firstMaterial?.diffuse.contentsTransform = SCNMatrix4MakeScale(scaleX, scaleY, 0)
            // Move the plane to the position reported by ARKit
            position.x = planeAnchor.center.x
            position.y = 0
            position.z = planeAnchor.center.z
    
        }
    }
    

    【讨论】:

    • 插图精美
    【解决方案3】:

    要在 SceneKit 编辑器中执行此操作,请在场景中选择您的平面(如果需要,添加一个),然后选择右上角的“材质检查器”选项卡。然后,在“属性”和“漫反射”下,选择你的纹理。现在,通过单击“漫反射”左侧的克拉展开漫反射部分,然后向下到显示“比例”的位置。在这里,您可以增加缩放比例,使纹理看起来可以重复而不是拉伸。对于这个问题,OP 必须将缩放设置为 32x32。

    【讨论】:

      【解决方案4】:

      你可以从场景工具包查看器中学习它假设你的场景工具包中有 SCNplane

      创建场景文件拖动平面

      12 英寸的尺寸是 0.3048

      并在漫反射中选择图像

      现在您有 4 个网格的图像,如图所示

      我们希望每个盒子都以每英寸显示,所以对于 12 英寸,我们需要 12 个盒子 * 12 个盒子,因为我们有 12 英寸的盒子

      计算它。首先我们需要将 0.3048 米转换为英寸

      这是米/0.0254答案是12。

      但我们需要每个网格以每英寸显示,所以我们还需要除以 12 / 4 = 3

      现在转到显示材料检查器并将比例值更改为 3

      你可以看到 12 英寸的飞机有 12 个盒子。

      希望对你有帮助

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-08-20
        • 2022-01-08
        • 1970-01-01
        • 2016-09-05
        • 2014-11-25
        • 2017-12-30
        • 2014-11-15
        • 2012-09-08
        相关资源
        最近更新 更多