Home > Net >  Why does my 3D extruded UIBezierPath have duplicates?
Why does my 3D extruded UIBezierPath have duplicates?

Time:01-23

I have a series of UIBezierPath's that I've turned into 3D objects in SceneKit. They form a long, jagged line with occasional gaps (a gap separates one object from another).

Here's what that looks like: enter image description here

The problem: As I move the camera around, the material on the side of the objects flickers strangely and changes colors.

I believe what's happening is that my path-drawing code is wrong, and is somehow creating duplicate objects positioned inside the existing object(s). So, I think the flickering color is really the other, duplicate object showing through.

Here's what the flickering color showing through looks like: enter image description here

To see the problem in action, the following code can be pasted directly into a new Game template Xcode project using SceneKit. You may paste it at the end of GameViewController's viewDidLoad.

var previousBezierPathPoint: CGPoint = CGPoint.zero
let numOfPointsPerLine: Int = 8
var hugePath = UIBezierPath()
var wasGap: Bool = false
let gapWidth: CGFloat = 10.0
var currentZdepth: CGFloat = CGFloat.random(in: 5.0...30.0)
for i in 0..<14 {
   let pp = wasGap ? CGPoint(x: CGFloat(previousBezierPathPoint.x)   gapWidth, y: CGFloat(previousBezierPathPoint.y)) : CGPoint(x: CGFloat(previousBezierPathPoint.x), y: CGFloat(previousBezierPathPoint.y))
   let isGap: Bool = i > 1 && Float.random(in: 0...100) > 60.0
            
   if !isGap {
      if wasGap || i == 0 {
         hugePath = UIBezierPath()

         hugePath.move(to: pp)
                    
         currentZdepth = CGFloat.random(in: 5.0...30.0)
      }
                
      for j in 1..<numOfPointsPerLine {
          let point = CGPoint(x: pp.x   (CGFloat(j)*25.0), y: pp.y   CGFloat.random(in: -8.0...8.0))
                    
          hugePath.addLine(to: point)
                    
          previousBezierPathPoint = point
      }
                
      let pathRef = hugePath.cgPath.copy(strokingWithWidth: 10.0, lineCap: CGLineCap.butt, lineJoin: CGLineJoin.miter, miterLimit: 1.0)
      let newPath = UIBezierPath(cgPath: pathRef.normalized())
                
      let hugeShape = SCNShape(path: newPath, extrusionDepth: currentZdepth)

      let colors = [
                    UIColor.green,
                    UIColor.yellow,
                    UIColor.purple,
                    UIColor.gray,
                    UIColor.darkGray
      ]
      let tempMat = SCNMaterial()
      tempMat.diffuse.contents = colors[Int.random(in: 0..<colors.count)]
      let frontMat = SCNMaterial()
      frontMat.diffuse.contents = UIColor.red
      hugeShape.materials = [frontMat, tempMat, tempMat, tempMat, tempMat, tempMat]

      let hugeNode = SCNNode()
      hugeNode.geometry = hugeShape

      hugeNode.position.x = 0.0
      hugeNode.position.z = Float(-50.0   (currentZdepth*0.5))
      hugeNode.position.y = 0.0

      scnView.scene?.rootNode.addChildNode(hugeNode)
      } else {
         if hugePath.isEmpty == false {
            hugePath.close()
         }
      }
            
      wasGap = isGap
}

Please note that this question is related to this one.

Question: How can I change my code so that there are no duplicate objects?

CodePudding user response:

It looks like you are continually building your path each time through the loop...

Not entirely sure if this will give you your desired results, but...

Instead of this:

    if wasGap || i == 0 {
        hugePath = UIBezierPath()
                
        hugePath.move(to: pp)
                
        currentZdepth = CGFloat.random(in: 5.0...30.0)
    } 

try this:

    hugePath = UIBezierPath()
    hugePath.move(to: pp)

    if wasGap || i == 0 {
        currentZdepth = CGFloat.random(in: 5.0...30.0)
    }
  • Related