swift SceneKit object is empty - swift

im trying to show a earth model on screen, loaded model from here (tried and other same models), but id didn't show on screen
[let scene = SCNScene(named: "tierra-1.obj")
if scene == nil {
print("nuuuul")
return
}
// 2: Add camera node
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
// 3: Place camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 0)
// 4: Set camera on scene
scene?.rootNode.addChildNode(cameraNode)
// 5: Adding light to scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light?.type = .omni
lightNode.position = SCNVector3(x: 0, y: 0, z: 0)
scene?.rootNode.addChildNode(lightNode)
// 6: Creating and adding ambien light to scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light?.type = .ambient
ambientLightNode.light?.color = UIColor.darkGray
scene?.rootNode.addChildNode(ambientLightNode)
// If you don't want to fix manually the lights
sceneView.autoenablesDefaultLighting = true
// Allow user to manipulate camera
sceneView.allowsCameraControl = true
// Show FPS logs and timming
sceneView.showsStatistics = true
// Set background color
sceneView.backgroundColor = UIColor.white
// Allow user translate image
sceneView.cameraControlConfiguration.allowsTranslation = false
// Set scene settings
sceneView.scene = scene][2]
but after loading I have empty screen (example), how to fix that?

I copied and ran your code using a custom obj, I got it loaded and in the viewport.
I loaded in an obj, using a node, and not trying to load the obj as the scene itself.
I noticed that your camera is at world space 0,0,0. that would most likely be inside the mesh, which would appear see through as materials are defaulted with backface culling on.
I assign the material to be blue, just to make it easier to spot incase the asset is very small. I would suggest selecting the asset in XCode, and you can see the bounding box size. This will help get a better idea for how far away you need to move the camera to get it to see the mesh.
import ModelIO
import SceneKit
import SceneKit.ModelIO
import PlaygroundSupport
let scene = SCNScene()
let sceneView = SCNView(frame: CGRect(x:0, y:0, width:800, height:800))
// Set scene settings
sceneView.scene = scene
// 2: Add camera node
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
// 3: Place camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 10)
// 4: Set camera on scene
scene.rootNode.addChildNode(cameraNode)
// Material
let blueMaterial = SCNMaterial()
blueMaterial.diffuse.contents = UIColor.blue
// Accessing the Playground resource folder
let path = Bundle.main.path(forResource:"randomAsset", ofType: "obj")
let asset = MDLAsset(url: URL(string: path!)!)
let object = asset.object(at: 0)
let objNode = SCNNode(mdlObject: object)
objNode.geometry?.materials = [blueMaterial]
scene.rootNode.addChildNode(objNode)
// Allow user to manipulate camera
sceneView.allowsCameraControl = true
// Show FPS logs and timming
//sceneView.showsStatistics = true
// Set background color
sceneView.backgroundColor = UIColor.gray
// Allow user translate image
sceneView.cameraControlConfiguration.allowsTranslation = true
PlaygroundPage.current.setLiveView(sceneView)

I dont think SceneKit supporst loading an Obj as a scene. They currently only allow types that have the ability to export scene data eg.camera,lights. https://developer.apple.com/documentation/scenekit/scnscenesource
If you want to load the obj file you will have to import it into your scene.
This post should help https://forums.developer.apple.com/thread/3979

Related

Adding SCNLight inside SK3DNode

I am creating an SK3DNode inside an SKScene:
let ball: SK3DNode = {
let scnScene = SCNScene()
let ballGeometry = SCNSphere(radius: 200)
let ballNode = SCNNode(geometry: ballGeometry)
ballNode.position = SCNVector3(0, 0, 0)
let material = SCNMaterial()
material.diffuse.contents = UIImage(named: "wall")
ballGeometry.materials = [material]
let light = SCNLight()
light.type = .omni
light.color = UIColor.white
let lightNode = SCNNode()
lightNode.light = light
scnScene.rootNode.addChildNode(ballNode)
scnScene.rootNode.addChildNode(lightNode)
let node = SK3DNode(viewportSize: CGSize(width: 1000, height: 1000))
node.scnScene = scnScene
node.autoenablesDefaultLighting = false
return node
}()
However, the sphere renders black. Tried it with or without the material. Is there something I am missing?
The sphere is manually placed at (0, 0, 0) and so is the light (default value). This means that the light is placed inside the sphere. This means that the surface of the sphere is facing away from the light source and thus isn't lit.

Scene Kit View with moving Object

How can I show a moving 3D object in my Simple view Application using scene kit view with swift 4.
For example bee.glb file in windows, I am using these four files:
body.bmp
body.jpg
volkeswagon-vw-beetle.mtl
volkeswagon-vw-beetle.obj
import UIKit
import SceneKit
import ARKit
class ViewController: UIViewController {
#IBOutlet weak var sceneView: SCNView!
override func viewDidLoad() {
super.viewDidLoad()
// 1: Load .obj file
let scene = SCNScene(named: "volkeswagon-vw-beetle.obj")
// 2: Add camera node
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
// 3: Place camera
cameraNode.position = SCNVector3(x: 0, y: 10, z: 35)
// 4: Set camera on scene
scene!.rootNode.addChildNode(cameraNode)
// 5: Adding light to scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light?.type = .omni
lightNode.position = SCNVector3(x: 0, y: 10, z: 35)
scene?.rootNode.addChildNode(lightNode)
// 6: Creating and adding ambien light to scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light?.type = .ambient
ambientLightNode.light?.color = UIColor.darkGray
scene?.rootNode.addChildNode(ambientLightNode)
// Allow user to manipulate camera
sceneView.allowsCameraControl = true
// Show FPS logs and timming
sceneView.showsStatistics = true
// Set background color
sceneView.backgroundColor = UIColor.white
// Allow user translate image
sceneView.cameraControlConfiguration.allowsTranslation = false
// Set scene settings
sceneView.scene = scene
}
}
The output is:
"3DVideo[6430:105708] [SceneKit] Error: Physically based lighting model is not supported by the OpenGL renderer, using Phong instead (3)
2019-09-02 03:29:13.297536-0700 3DVideo[6430:105708] [SceneKit] Error: Physically based lighting model is not supported by the OpenGL renderer, using Phong instead (2)
2019-09-02 03:29:13.308381-0700 3DVideo[6430:105708] [SceneKit] Error: Physically based lighting model is not supported by the OpenGL renderer, using Phong instead"
i resolve this issue by Just change my file extension from .obj to .dae.Because obj file has no any animation

SceneKit: sceneView projectPoint with multiple cameras

If a scene contains multiple cameras, which camera does the projectPoint method use to project points from 3D to screen-space? If this is defined by the pointOfView property, then how come when I update the position of the pointOfView a given 3D point is still projected to the same 2D point?
Since SCNCamera belongs to SCNView, just set the PoV via the "pointOfView" instance property of a View to a required camera node.
let cameraNode001 = SCNNode()
cameraNode001.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode001)
cameraNode001.position = SCNVector3(x: 0, y: 0, z: 15)
let cameraNode002 = SCNNode()
cameraNode002.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode002)
cameraNode002.position = SCNVector3(x: 10, y: 10, z: 30)
let sceneView = self.view as! SCNView
sceneView.scene = scene
sceneView.pointOfView = cameraNode001
then you can change PoV:
sceneView.pointOfView = cameraNode002

Using SceneKit for hitTesting not returning a hit with SCNNode

The documentation in XCode clearly states that hitTesting a geometry in SceneKit can be done with SCNRender, SCNView or the SCNNode themselves when one plans to test a 3D line segment. I have a use for SCNScene with its nodes without a renderer or a view, therefore I am planning to use SCNNode hitTesting. I create a SCNScene, put a SCNNode in it and test a simple ray that goes through, but I always get an empty hitList and I don't understand why:
import Swift
import SceneKit
let boxGeometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0)
let boxNode = SCNNode(geometry: boxGeometry)
var scene = SCNScene()
scene.rootNode.addChildNode(boxNode)
let from = SCNVector3(x: 0, y: -2, z: 0)
let to = SCNVector3(x: 0, y: 2 , z: 0)
var hits = scene.rootNode.hitTestWithSegmentFromPoint(from, toPoint: to, options:nil) // this is always empty
if hits != nil {
if hits!.count > 0 {
var hit = (hits!.first as! SCNHitTestResult).node as SCNNode
}
}
I have tried passing various forms of options but nothing changes.
SCNHitTestFirstFoundOnlyKey: yes or no does not change anything
SCNHitTestSortResultsKey: yes or no does not change anything
SCNHitTestClipToZRangeKey: invalid for SCNNode
SCNHitTestBackFaceCullingKey: yes or no does not change anything
SCNHitTestBoundingBoxOnlyKey: yes or no does not change anything
SCNHitTestRootNodeKey: rootNOde of scene or boxNode does not change
anything
SCNHitTestIgnoreHiddenNodesKey: yes or no does not change anything
What am I doing wrong?
I have found the answer, which is either a bug or a feature: using SCNScene and its nodes SCNNode for 3D hitTesting, in particular the method: "hitTestWithSegmentFromPoint(toPoint:options:)" does not return a hit unless the scene is included in an SCNView. It appears it cannot be used offscreen. My guess is yours for why this is the case, although I can imagine it has something to do with performing some of these quite expensive calculations on the graphics card.
I have tested this using the GameView SCNScene starter project. The critical line is self.gameView!.scene = scene
override func awakeFromNib(){
let scene = SCNScene()
let boxGeometry = SCNBox(width: 1.0, height: 1.0, length: 1.0, chamferRadius: 0.0)
let boxNode = SCNNode(geometry: boxGeometry)
boxNode.position=SCNVector3(x: 0, y: 0, z: 0)
scene.rootNode.addChildNode(boxNode)
// create and add a camera to the scene
let cameraNode = SCNNode()
cameraNode.camera = SCNCamera()
scene.rootNode.addChildNode(cameraNode)
// place the camera
cameraNode.position = SCNVector3(x: 0, y: 0, z: 15)
// create and add a light to the scene
let lightNode = SCNNode()
lightNode.light = SCNLight()
lightNode.light!.type = SCNLightTypeOmni
lightNode.position = SCNVector3(x: 0, y: 10, z: 10)
scene.rootNode.addChildNode(lightNode)
// create and add an ambient light to the scene
let ambientLightNode = SCNNode()
ambientLightNode.light = SCNLight()
ambientLightNode.light!.type = SCNLightTypeAmbient
ambientLightNode.light!.color = NSColor.darkGrayColor()
scene.rootNode.addChildNode(ambientLightNode)
// set the scene to the view
// uncomment this to fail
self.gameView!.scene = scene
// allows the user to manipulate the camera
self.gameView!.allowsCameraControl = true
// show statistics such as fps and timing information
self.gameView!.showsStatistics = true
// configure the view
self.gameView!.backgroundColor = NSColor.blackColor()
let hitList = scene.rootNode.hitTestWithSegmentFromPoint(SCNVector3(x:-10,y:0,z:0), toPoint: SCNVector3(x:10,y:0,z:0), options:[SCNHitTestBackFaceCullingKey:false, SCNHitTestSortResultsKey:true, SCNHitTestIgnoreHiddenNodesKey:false])
if hitList?.count > 0 {
println("Hit found: \n\n\( hitList![0] )") // assign self.gameView!.scene = scene to reach this point.
} else {
println("No hit") // uncomment self.gameView!.scene = scene to reach this point.
}
}
I've also had trouble with hitTestWithSegmentFromPoint.
I was calling it in viewDidLoad() and it returned a 0 elements array, though I was sure there was a hit.
Calling it in viewDidAppear() (or later) solved my problem.

Simple SceneKit scene shows black screen instead of SCNPlane

I am getting my feet wet with iOS SceneKit, however the following sample code (which executes inside viewDidLoad) is not behaving as expected. I want it to
place a camera at origin with direction of view towards positive z axis
place a red rectangle parallel to xy-plane at z = 100
Why does the rendering not reveal the red rectangle but only a black screen?
let scene = SCNScene()
// prepare camera
let camera = SCNCamera()
camera.zNear = 90
camera.zFar = 110
let cameraNode = SCNNode()
cameraNode.position = SCNVector3Make(0, 0, 0)
cameraNode.rotation = SCNVector4Make(1, 0, 0, Float(M_PI))
cameraNode.camera = camera
scene.rootNode.addChildNode(cameraNode)
// prepare light
let light = SCNLight()
light.type = SCNLightTypeOmni
light.color = SKColor(white: 0.3, alpha: 1.0)
let lightNode = SCNNode()
lightNode.light = light;
scene.rootNode.addChildNode(lightNode)
// prepare plane
let plane = SCNPlane(width: 400, height: 400)
plane.firstMaterial!.doubleSided = true
plane.firstMaterial!.diffuse.contents = UIColor.redColor().CGColor
let planeNode = SCNNode(geometry: plane)
planeNode.position = SCNVector3Make(0, 0, 100)
scene.rootNode.addChildNode(planeNode)
// prepare view as SCNView
let sceneView = view as SCNView
sceneView.backgroundColor = SKColor.blackColor()
sceneView.scene = scene
sceneView.delegate = self
sceneView.jitteringEnabled = true // i.e. improve visual rendering
sceneView.pointOfView = cameraNode
looks like you rotate around the x axis instead of the y axis (so that the camera looks in the desired direction)