Repeating a texture over a plane in SceneKit

前端 未结 4 1130
眼角桃花
眼角桃花 2021-02-05 17:05

I have a 32x32 .png image that I want to repeat over a SCNPlane. The code I\'ve got (See below) results in the image being stretched to fit the size of the plane, rather than re

相关标签:
4条回答
  • 2021-02-05 17:20

    I faced an identical issue when implementing plane visualisation in ARKit. I wanted to visualise the detected plane as a checkerboard pattern. I fixed it by creating a custom SCNNode called a "PlaneNode" with a correctly configured SCNMaterial. The material uses wrapS, wrapT = .repeat and calculates the scale correctly based on the size of the plane itself.

    Looks like this:

    Have a look at the code below, the inline comments contain the explanation.

    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
    
        }
    }
    
    0 讨论(0)
  • 2021-02-05 17:22

    I fixed it. It seems like the image was zoomed in. If I do imageMaterial.diffuse.contentsTransform = SCNMatrix4MakeScale(32, 32, 0), the image repeats.

    0 讨论(0)
  • 2021-02-05 17:28

    You can learn it from Scene kit viewer Suppose You have SCNplane in your scene kit

    Create scene file drag a plane

    Which size is 12 inches in meter it is 0.3048

    and select image in diffuse

    now You have image with 4 Grid as shown in image

    we want each box to be show in each inches so for 12 Inches we need 12 box * 12 box as we have 12 inches box

    to calculate it. First we need convert 0.3048 meter to inches

    which is meters / 0.0254 answer is 12.

    but we need each grid to show in each inch so we also need to divide 12 / 4 = 3

    now goto show material inspector and change scale value to 3

    you can see 12 boxes for 12 inch plane.

    Hope it is helpful

    0 讨论(0)
  • 2021-02-05 17:30

    To do this in the SceneKit editor, select your plane (add one if needed) in the scene and then select the "Material Inspector" tab on the top right. Then, under "Properties" and where it says "Diffuse", select your texture. Now, expand the diffuse section by clicking the carat to the left of "Diffuse" and go down to where it says "Scale". Here, you can increase the scaling so that the texture can look repeated rather than stretched. For this question, the OP would have to set the scaling to 32x32.

    0 讨论(0)
提交回复
热议问题