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).
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:
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?
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)
}