pointSize property in SceneKit being Ignored - swift

I'm trying to render a point cloud using SceneKit (ultimately for ARKit). However, I'm finding the pointSize (and minimumPointScreenSpaceRadius) properties are ignored when trying to modify the SCNGeometryElement. There was this solution to call on the underlying OpenGL property, but this seems to work only in simulation.
No matter what pointSize I put in, the points are the same size. This is roughly how my code is laid out. I'm wondering if I'm doing something wrong with my GeometryElement setup?
var index: Int = 0
for x_pos in stride(from: start , to: end, by: increment) {
for y_pos in stride(from: start , to: end, by: increment) {
for z_pos in stride(from: start , to: end, by: increment) {
let pos:SCNVector3 = SCNVector3(x: x_pos, y: y_pos, z: z_pos)
positions.append(pos)
normals.append(normal)
indices.append(index)
index = index + 1
}
}
}
let pt_positions : SCNGeometrySource = SCNGeometrySource.init(vertices: positions)
let n_positions: SCNGeometrySource = SCNGeometrySource.init(normals: normals)
let pointer = UnsafeRawPointer(indices)
let indexData = NSData(bytes: pointer, length: MemoryLayout<Int32>.size * indices.count)
let elements = SCNGeometryElement(data: indexData as Data, primitiveType: .point, primitiveCount: positions.count, bytesPerIndex: MemoryLayout<Int>.size)
elements.pointSize = 10.0 //being ignored
elements.minimumPointScreenSpaceRadius = 10 //also being ignored
let pointCloud = SCNGeometry (sources: [pt_positions, n_positions], elements: [elements])
pointCloud.firstMaterial?.lightingModel = SCNMaterial.LightingModel.constant
let ptNode = SCNNode(geometry: pointCloud)
scene.rootNode.addChildNode(ptNode)

you should also specify both element.minimumPointScreenSpaceRadius and element.maximumPointScreenSpaceRadius. if so your point size work! :)

Related

memory issue: realtime eye localization

I'm currently working on a iOS-application, which should be able to detect the localization. I've created an tflite which comprises some CNN layers. In order to use the tflite in XCode/Swift I've created a helper class in which the tflite calculates the output. Whenever I run the predict-function once, it works. But apparently the predict function doesn't work in real-time camera-thread.
After about 7 seconds, XCode is throwing the following error:
Thread 1: EXC_BAD_ACCESS (code=1, address=0x123424001). This error must be evoken by looping through the image. Since I need each pixel value I'm using the solution suggested by Firebase.But apparently this solution is not waterproofed. Can anybody help to resolve this memory issue?
func creatInputForCNN(resizedImage: UIImage?) -> Data{
// In this section of the code I loop through the image (150,200,3)
// in order to fetch each pixel value (RGB).
let image: CGImage = resizedImage.cgImage!
guard let context = CGContext(
data: nil,
width: image.width, height: image.height,
bitsPerComponent: 8, bytesPerRow: image.width * 4,
space: CGColorSpaceCreateDeviceRGB(),
bitmapInfo: CGImageAlphaInfo.noneSkipFirst.rawValue
) else {return nil}
context.draw(image, in: CGRect(x: 0, y: 0, width: image.width, height: image.height))
guard let imageData = context.data else {return nil}
let size_w = 150
let size_H = 200
var inputData:Data?
inputData = Data()
for row in 0 ..< size_H{
for col in 0 ..< size_w {
let offset = 4 * (row * context.width + col)
// (Ignore offset 0, the unused alpha channel)
let red = imageData.load(fromByteOffset: offset+1, as: UInt8.self)
let green = imageData.load(fromByteOffset: offset+2, as: UInt8.self)
let blue = imageData.load(fromByteOffset: offset+3, as: UInt8.self)
// Normalize channel values to [0.0, 1.0]. This requirement varies
// by model. For example, some models might require values to be
// normalized to the range [-1.0, 1.0] instead, and others might
// require fixed-point values or the original bytes.
var normalizedRed:Float32 = Float32(red) / 255
var normalizedGreen:Float32 = (Float32(green) / 255
var normalizedBlue:Float32 = Float32(blue) / 255
// Append normalized values to Data object in RGB order.
let elementSize = MemoryLayout.size(ofValue: normalizedRed)
var bytes = [UInt8](repeating: 0, count: elementSize)
memcpy(&bytes, &normalizedRed, elementSize)
inputData!.append(&bytes, count: elementSize)
memcpy(&bytes, &normalizedGreen, elementSize)
inputData!.append(&bytes, count: elementSize)
memcpy(&bytes, &normalizedBlue, elementSize)
inputData!.append(&bytes, count: elementSize)
return inputData
}
This is the code

Generate random values based on a seed Swift 3

lets say you were making a game and this game has procedurally generated terrain from a seed that the user inputted in his world-creation menu
and this seed generates a set of values that only change if the seed changes
for instance lets say you want to get a random set of integers to generate in a for-loop and pull randomly from an array the set of integers stay the same every time and pull the same items from the array in the exact same order every time you run the for-loop until you change the seed
how would one achieve this in swift
in my code here i can get the terrain to spawn in but it does not generate the same every time which is what i am trying to get it to do
override func didMove(to view: SKView) {
let tile1 = SKTileDefinition(texture: SKTexture(imageNamed: "stone") ,size: CGSize(width: 64, height: 64))
let tile2 = SKTileDefinition(texture: SKTexture(imageNamed: "water") ,size: CGSize(width: 64, height: 64))
let tile3 = SKTileDefinition(texture: SKTexture(imageNamed: "sand") ,size: CGSize(width: 64, height: 64))
let tile4 = SKTileDefinition(texture: SKTexture(imageNamed: "grass") ,size: CGSize(width: 64, height: 64))
let tileGroup1 = SKTileGroup(tileDefinition: tile1)
let tileGroup2 = SKTileGroup(tileDefinition: tile2)
let tileGroup3 = SKTileGroup(tileDefinition: tile3)
let tileGroup4 = SKTileGroup(tileDefinition: tile4)
let tileGroup5 = SKTileGroup(tileDefinition: tile4)
let tileGroup6 = SKTileGroup(tileDefinition: tile4)
let tileSet = SKTileSet(tileGroups: [tileGroup1,tileGroup2,tileGroup3,tileGroup4,tileGroup5,tileGroup6])
let columns = 5
let rows = 5
let tileSize = CGSize(width: 64, height: 64)
//this is another GKNoise class called Noise
let noise = Noise()
let noiseMap = GKNoiseMap(noise, size: vector_double2(10.0,10.0), origin: vector_double2(0.0,0.0), sampleCount: vector_int2(100), seamless: true)
//this is another SKTileMapNode Class called TileMap and a class func called tileMapNodes
let tileMap = TileMap.tileMapNodes(tileSet: tileSet, columns: columns, rows: rows, tileSize: tileSize, from: noiseMap, tileTypeNoiseMapThresholds: [(-1.0 as NSNumber),(+1.0 as NSNumber)])
tileMapNode = tileMap.first!
let seed = Int
for column in 0 ..< tileMapNode.numberOfColumns {
for row in 0 ..< tileMapNode.numberOfRows {
let rand = Int(arc4random_uniform(UInt32(tileSet.tileGroups.count)))
print(rand)
let tile = tileMapNode.tileSet.tileGroups[rand]
tileMapNode.setTileGroup(tile, forColumn: column, row: row)
}
}
If you want to generate a random value based on a specific seed use: srand48 and drand48:
srand allow you to specify the seed:
srand48(230)
Then drand48 will give you a double between 0 and 1:
let doubleValue = drand48()
So in your case, if you want an Int between 0 and 9, you can do something like:
srand48(230)
print("Random number: \(1 + Int((drand48() * 8) + 0.5))")
print("Random number: \(1 + Int((drand48() * 8) + 0.5))")
print("Random number: \(1 + Int((drand48() * 8) + 0.5))")
It will give you the 3 pseudo random numbers until you change the seed
Here is the drand48 applied to your new question:
let seed = srand48(230)
for column in 0 ..< tileMapNode.numberOfColumns {
for row in 0 ..< tileMapNode.numberOfRows {
let rand = Int(Double(tileSet.tileGroups.count) * drand48() - 0.5)
print(rand)
let tile = tileMapNode.tileSet.tileGroups[rand]
tileMapNode.setTileGroup(tile, forColumn: column, row: row)
}
}

Detect overlaping if enumerating nodes

I would like to know how should I detect overlapping nodes while enumerating them? Or how should I make that every random generated position in Y axis is at least some points higher or lower.
This is what I do:
1 - Generate random number between -400 and 400
2 - Add those into array
3 - Enumerate and add nodes to scene with generated positions like this:
var leftPositions = [CGPoint]()
for _ in 0..<randRange(lower: 1, upper: 5){
leftPositions.append(CGPoint(x: -295, y: Helper().randomBetweenTwoNumbers(firstNumber: leftSparkMinimumY, secondNumber: leftSparkMaximumY)))
}
leftPositions.enumerated().forEach { (index, point) in
let leftSparkNode = SKNode()
leftSparkNode.position = point
leftSparkNode.name = "LeftSparks"
let leftSparkTexture = SKTexture(imageNamed: "LeftSpark")
LeftSpark = SKSpriteNode(texture: leftSparkTexture)
LeftSpark.name = "LeftSparks"
LeftSpark.physicsBody = SKPhysicsBody(texture: leftSparkTexture, size: LeftSpark.size)
LeftSpark.physicsBody?.categoryBitMask = PhysicsCatagory.LeftSpark
LeftSpark.physicsBody?.collisionBitMask = PhysicsCatagory.Bird
LeftSpark.physicsBody?.contactTestBitMask = PhysicsCatagory.Bird
LeftSpark.physicsBody?.isDynamic = false
LeftSpark.physicsBody?.affectedByGravity = false
leftSparkNode.addChild(LeftSpark)
addChild(leftSparkNode)
}
But like this sometimes they overlap each other because the generated CGPoint is too close to the previous one.
I am trying to add some amount of triangles to the wall and those triangles are rotated by 90°
To describe in image what I want to achieve:
And I want to avoid thing like this:
Your approach to this is not the best, i would suggest only storing the Y values in your position array and check against those values to make sure your nodes will not overlap. The following will insure no two sparks are within 100 points of each other. You may want to change that value depending on your node's actual height or use case.
Now, obviously if you end up adding too many sparks within an 800 point range, this just will not work and cause an endless loop.
var leftPositions = [Int]()
var yWouldOverlap = false
for _ in 0..<randRange(lower: 1, upper: 5){
//Moved the random number generator to a function
var newY = Int(randY())
//Start a loop based on the yWouldOverlap Bool
repeat{
yWouldOverlap = false
//Nested loop to range from +- 100 from the randomly generated Y
for p in newY - 100...newY + 100{
//If array already contains one of those values
if leftPosition.contains(p){
//Set the loop Bool to true, get a new random value, and break the nested for.
yWouldOverlap = true
newY = Int(randY())
break
}
}
}while(yWouldOverlap)
//If we're here, the array does not contain the new value +- 100, so add it and move on.
leftPositions.append(newY)
}
func randY() -> CGFloat{
return Helper().randomBetweenTwoNumbers(firstNumber: leftSparkMinimumY, secondNumber: leftSparkMaximumY)
}
And here is a different version of your following code.
for (index,y) in leftPositions.enumerated() {
let leftSparkNode = SKNode()
leftSparkNode.position = CGPoint(x:-295,y:CGFloat(y))
leftSparkNode.name = "LeftSparks\(index)" //All node names should be unique
let leftSparkTexture = SKTexture(imageNamed: "LeftSpark")
LeftSpark = SKSpriteNode(texture: leftSparkTexture)
LeftSpark.name = "LeftSparks"
LeftSpark.physicsBody = SKPhysicsBody(texture: leftSparkTexture, size: LeftSpark.size)
LeftSpark.physicsBody?.categoryBitMask = PhysicsCatagory.LeftSpark
LeftSpark.physicsBody?.collisionBitMask = PhysicsCatagory.Bird
LeftSpark.physicsBody?.contactTestBitMask = PhysicsCatagory.Bird
LeftSpark.physicsBody?.isDynamic = false
LeftSpark.physicsBody?.affectedByGravity = false
leftSparkNode.addChild(LeftSpark)
addChild(leftSparkNode)
}

SceneKit SCNPhysicsVehicle wheels point toward centre of vehicle

I'm trying to get the SceneKit Physics Vehicle demonstration from WWDC working using Swift 2 and also the Scene Editor and .scnassets. I'm adapting this port of the demo to Swift 1.
I've also been experimenting with some of the Model I/O functions, such as SkyBox and normal map generation.
Everything works fine, except that the wheels are rotated 180 degrees around their steering axes, so that the hubcaps point in towards the centre of the car:
Hubcaps pointing inwards
The wheels spin in the right direction, and the car can be driven and steered fine, but it just looks very weird (and the left-right wheelbase is narrower than it should be).
If I comment out the SCNPhysicsVehicle and SCNPhysicsVehicleWheel code, so that it's just geometry with a physics body for the chassis, the geometry displays correctly, with the wheel hubs pointing outward:
Hubcaps pointing outwards
I've tried rotating the wheelnodes using wheelnode0.rotation before defining the SCNPhysicsVehicleWheel, but it has no effect.
I tried reversing the wheel axles with wheel0.axle = SCNVector3(x: 1,y: 0,z: 0) and that makes the wheels face the right way, hubcap outwards, (and they still spin the right way), but the car moves backwards (ie the opposite direction to how the wheels are spinning).
It feels like something weird is going on with how axes are being translated, but I can't figure what it is. I've tried it with the original .dae model from the Apple demo, as well as converted to an .scn file. I've tried it inside and outside an .scnassets folder (in case it was something to do with scnassets auto correction of up axis). I tried inverting the wheel steering axes, but that just resulted in the wheels pointing up in the air.
Here's my vehicle creation function, with all the stuff I've tried commented out. Full repo is here: https://github.com/Utsira/SCNPhysicsVehicle-test. Can anyone see what's going wrong here? Thanks in advance.
func setupCar() -> SCNNode {
let carScene = SCNScene(named: "art.scnassets/rc_car.scn") //rc_car.dae
let chassisNode = carScene!.rootNode.childNodeWithName("rccarBody", recursively: true)!
chassisNode.position = SCNVector3Make(0, 10, 30)
//chassisNode.rotation = SCNVector4(0, 1, 0, CGFloat(M_PI))
let body = SCNPhysicsBody.dynamicBody()
body.allowsResting = false
body.mass = 80
body.restitution = 0.1
body.friction = 0.5
body.rollingFriction = 0
chassisNode.physicsBody = body
scnScene.rootNode.addChildNode(chassisNode)
//getNode("rccarBody", fromDaePath: "rc_car.dae")
let wheelnode0 = chassisNode
.childNodeWithName("wheelLocator_FL", recursively: true)!
let wheelnode1 = chassisNode
.childNodeWithName("wheelLocator_FR", recursively: true)!
let wheelnode2 = chassisNode
.childNodeWithName("wheelLocator_RL", recursively: true)!
let wheelnode3 = chassisNode
.childNodeWithName("wheelLocator_RR", recursively: true)!
//wheelnode0.geometry!.firstMaterial!.emission.contents = UIColor.blueColor()
// SCNTransaction.begin()
// wheelnode0.rotation = SCNVector4(x: 0, y: 1, z: 0, w: Float(M_PI)) //CGFloat(M_PI)
// wheelnode1.rotation = SCNVector4(x: 0, y: 1, z: 0, w: Float(M_PI))
// wheelnode2.rotation = SCNVector4(x: 0, y: 1, z: 0, w: Float(M_PI))
// wheelnode3.rotation = SCNVector4(x: 0, y: 1, z: 0, w: Float(M_PI))
// SCNTransaction.commit()
// wheelnode0.eulerAngles = SCNVector3Make(0, Float(M_PI), 0 )
let wheel0 = SCNPhysicsVehicleWheel(node: wheelnode0)
let wheel1 = SCNPhysicsVehicleWheel(node: wheelnode1)
let wheel2 = SCNPhysicsVehicleWheel(node: wheelnode2)
let wheel3 = SCNPhysicsVehicleWheel(node: wheelnode3)
// wheel0.steeringAxis = SCNVector3Make(0, -1, 1) //wheels point up in the air with 0,1,0
// wheel1.steeringAxis = SCNVector3Make(0, -1, 1)
// wheel2.steeringAxis = SCNVector3Make(0, -1, 1)
// wheel3.steeringAxis = SCNVector3Make(0, -1, 1)
//
// wheel0.axle = SCNVector3(x: 1,y: 0,z: 0) //wheels face and spin the right way, but car moves in opposite direction with 1,0,0
// wheel1.axle = SCNVector3(x: 1,y: 0,z: 0)
// wheel2.axle = SCNVector3(x: 1,y: 0,z: 0)
// wheel3.axle = SCNVector3(x: 1,y: 0,z: 0)
// wheel0.steeringAxis = SCNVector3()
// var min = SCNVector3(x: 0, y: 0, z: 0)
// var max = SCNVector3(x: 0, y: 0, z: 0)
// wheelnode0.getBoundingBoxMin(&min, max: &max)
// let wheelHalfWidth = Float(0.5 * (max.x - min.x))
// var w0 = wheelnode0.convertPosition(SCNVector3Zero, toNode: chassisNode)
// w0 = w0 + SCNVector3Make(wheelHalfWidth, 0, 0)
// wheel0.connectionPosition = w0
// var w1 = wheelnode1.convertPosition(SCNVector3Zero, toNode: chassisNode)
// w1 = w1 - SCNVector3Make(wheelHalfWidth, 0, 0)
// wheel1.connectionPosition = w1
// var w2 = wheelnode2.convertPosition(SCNVector3Zero, toNode: chassisNode)
// w2 = w2 + SCNVector3Make(wheelHalfWidth, 0, 0)
// wheel2.connectionPosition = w2
// var w3 = wheelnode3.convertPosition(SCNVector3Zero, toNode: chassisNode)
// w3 = w3 - SCNVector3Make(wheelHalfWidth, 0, 0)
// wheel3.connectionPosition = w3
vehicle = SCNPhysicsVehicle(chassisBody: chassisNode.physicsBody!,
wheels: [wheel0, wheel1, wheel2, wheel3])
scnScene.physicsWorld.addBehavior(vehicle)
return chassisNode
}
I Found A Solution:
(but not the solution I hoped for)
My fix was to adjust the connectionPosition of "FrontLeftWheel", so much to the right, that it took the role of "FrontRightWheel".
And "FrontRightWheel", so much to the left, that it took the role of "FrontLeftWheel".
I also did this for the back.
Basically, where you have:
SCNVector3Make(wheelHalfWidth, 0, 0)
I replaced it with:
SCNVector3Make(wheelHalfWidth * 5.2, 0, 0)
However, you may have to fool around with the number "5.2" to match up with your COLLADA (.dae).
A Note:
Do Not forget to replace:
vehicle = SCNPhysicsVehicle(chassisBody: chassisNode.physicsBody!,
wheels: [wheel0, wheel1, wheel2, wheel3])
With:
vehicle = SCNPhysicsVehicle(chassisBody: chassisNode.physicsBody!,
wheels: [wheel1, wheel0, wheel3, wheel2])
This way, when you use car.wheels[0].You get the wheel you are expecting
I think your problem is that you are not setting the connection positions for each wheel. Apple's default ObjectiveC code is tricky to translate to swift.
wheel0.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel0Node convertPosition:SCNVector3Zero toNode:chassisNode]) + (vector_float3){wheelHalfWidth, 0.0, 0.0});
wheel1.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel1Node convertPosition:SCNVector3Zero toNode:chassisNode]) - (vector_float3){wheelHalfWidth, 0.0, 0.0});
wheel2.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel2Node convertPosition:SCNVector3Zero toNode:chassisNode]) + (vector_float3){wheelHalfWidth, 0.0, 0.0});
wheel3.connectionPosition = SCNVector3FromFloat3(SCNVector3ToFloat3([wheel3Node convertPosition:SCNVector3Zero toNode:chassisNode]) - (vector_float3){wheelHalfWidth, 0.0, 0.0});
These four lines translate (ignoring the repetition)
let wheel0Position = wheel0Node.convertPosition(SCNVector3Zero, to: chassisNode)
let vector0Float3 = vector_float3(wheel0Position.x, wheel0Position.y, wheel0Position.z) + vector_float3(wheelHalfWidth, 0,0)
wheel0.connectionPosition = SCNVector3(vector0Float3.x, vector0Float3.y, vector0Float3.z)
let wheel1Position = wheel1Node.convertPosition(SCNVector3Zero, to: chassisNode)
let vector1Float3 = vector_float3(wheel1Position.x, wheel1Position.y, wheel1Position.z) - vector_float3(wheelHalfWidth, 0,0)
wheel1.connectionPosition = SCNVector3(vector1Float3.x, vector1Float3.y, vector1Float3.z)
let wheel2Position = wheel2Node.convertPosition(SCNVector3Zero, to: chassisNode)
let vector2Float3 = vector_float3(wheel2Position.x, wheel2Position.y, wheel2Position.z) + vector_float3(wheelHalfWidth, 0,0)
wheel2.connectionPosition = SCNVector3(vector2Float3.x, vector2Float3.y, vector2Float3.z)
let wheel3Position = wheel3Node.convertPosition(SCNVector3Zero, to: chassisNode)
let vector3Float3 = vector_float3(wheel3Position.x, wheel3Position.y, wheel3Position.z) - vector_float3(wheelHalfWidth, 0,0)
wheel3.connectionPosition = SCNVector3(vector3Float3.x, vector3Float3.y, vector3Float3.z)
By adding or substracting vector_float3, the wheels are positioned in the right place.
Also, bear in mind that you can't scale the node in the scene or weird things may happen.
Encountered the same issue, my solution was to rotate all wheel nodes so the Y axis pointed down. I figured gravity is a downward force.

EXC_BAD_INSTRUCTION when spawning an object

So I'm trying to spawn a falling object in my game and i'm using an array to set all the possible xSpawn points and then I randomise through the array to get an x value but the problem is when It gets to this line in the code:
let SpawnPoint = UInt32(randomX)
It gives me the EXC_BAD_INSTRUCTION error and I can't seem to see why. I'm still new to swift so an explanation as to why it gives me an error at this point would be greatly cherished.
Full Code:
func spawnFallingOjects() {
let xSpawnOptions = [-50, -100, 0, 100, 150]
let randomX = xSpawnOptions[Int(arc4random_uniform(UInt32(xSpawnOptions.count)))]
let Bomb = SKSpriteNode(imageNamed: "YellowFrog")
Bomb.zPosition = 900
let SpawnPoint = UInt32(randomX)
Bomb.position = CGPoint(x: CGFloat(arc4random_uniform(SpawnPoint)), y: self.size.height)
let action = SKAction.moveToY(-350, duration: 2.0)
Bomb.runAction(SKAction.repeatActionForever(action))
self.addChild(Bomb)
}
Two out of five members of xSpawnOptions are negative numbers, which cannot be represented in an unsigned integer. So when you try to convert them to such with:
let SpawnPoint = UInt32(randomX)
it crashes as you'd expect.
It's not clear what you're trying to do with your random number generation, but one way or another you need to change the logic of it to account for this, perhaps by calculating a random number which is always positive, and then adding or subtracting an offset to it, for example:
let SpawnPoint: UInt32 = 50
Bomb.position = CGPoint(x: CGFloat(Int(arc4random_uniform(SpawnPoint)) + randomX), y: self.size.height)