I record videos using ARKit & ReplayKit.
I realised that the camera/video stream is pretty shaky when using ARKit/ARSCNView.
Is there a way to use a Stabilization Mode that is available for example in AVCaptureConnection to capture a video stream : -> activeVideoStabilizationMode
Is there something similar in ARKit ?
Here is some example code, pretty basic arkit setup:
#IBOutlet var sceneView: ARSCNView!
let scene = SCNScene()
func setupScene() {
sceneView.delegate = self
sceneView.session.delegate = self
sceneView.autoenablesDefaultLighting = true
// Set the scene to the view
sceneView.scene = scene
}
func resetTracking() {
// Create a session configuration
let configuration = ARWorldTrackingConfiguration()
configuration.planeDetection = .horizontal
// Run the view's session
sceneView.session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
}
Related
I've followed the answer in this SO question regarding playing the animation of a USDZ file with the following code:
#IBOutlet var arView: ARView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
arView = ARView(frame: self.view.frame)
self.view.addSubview(arView)
arView.cameraMode = .nonAR
let newAnchor = AnchorEntity(world: .zero)
let newEnt = try! Entity.load(named: "Vintage Toy Robot")
newAnchor.addChild(newEnt)
arView.scene.addAnchor(newAnchor)
print(newEnt.availableAnimations)
for anim in newEnt.availableAnimations {
newEnt.playAnimation(anim.repeat(duration: .infinity),
transitionDuration: 1.25, startsPaused: false)
}
}
However, the animation does not play, the USDZ file is just static.
Download robot model with animation from AR Quick Look page. Your code is working. Do not use not-animated robot from Reality Composer library.
let entity = try! Entity.load(named: "toy_robot_vintage.usdz")
And delete these two lines of code (you've got 2 ARViews, it's blocking the animation):
arView = ARView(frame: self.view.frame)
self.view.addSubview(arView)
I want to show two different 3D objects in two different ARSCNViews.
With this question it's allowed to show the two ARSCNViews, but it is basically cloned one view to another.
I want to display different objects in each view.
Do you have any idea?
Yes, it's possible. You can create two ARSCNViews with different models, or even a RealityKit view and an ARKit view. However, in both cases you have to use the same running ARSession. It is not possible to run two different sessions in parallel.
import ARKit
class ViewController: UIViewController {
#IBOutlet var sceneView: ARSCNView!
#IBOutlet var sceneViewTwo: ARSCNView!
override func viewDidLoad() {
super.viewDidLoad()
sceneViewTwo.session = sceneView.session
let scene = SCNScene(named: "art.scnassets/ship.scn")!
sceneView.scene = scene
let sceneTwo = SCNScene()
sceneViewTwo.scene = sceneTwo
let sphere = SCNNode(geometry: SCNSphere(radius: 0.1))
sphere.position.z = -1.0
sceneViewTwo.scene.rootNode.addChildNode(sphere)
let config = ARWorldTrackingConfiguration()
sceneView.session.run(config)
}
}
I am playing around with the code I downloaded from Apple Developer site on AR Image Detection. I am trying to modify it to show a specific image in the AR Resource folder in Resources/Assets.xcassets once an image is detected. I see a similar question was posted 2 years ago and I tried the one and only answer on it but have no success. Can anyone help? Thank-you!
import ARKit
import SceneKit
import UIKit
class ViewController: UIViewController, ARSCNViewDelegate {
#IBOutlet var sceneView: ARSCNView!
#IBOutlet weak var blurView: UIVisualEffectView!
/// The view controller that displays the status and "restart experience" UI.
lazy var statusViewController: StatusViewController = {
return children.lazy.compactMap({ $0 as? StatusViewController }).first!
}()
/// A serial queue for thread safety when modifying the SceneKit node graph.
let updateQueue = DispatchQueue(label: Bundle.main.bundleIdentifier! +
".serialSceneKitQueue")
/// Convenience accessor for the session owned by ARSCNView.
var session: ARSession {
return sceneView.session
}
// MARK: - View Controller Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
sceneView.delegate = self
sceneView.session.delegate = self
// Hook up status view controller callback(s).
statusViewController.restartExperienceHandler = { [unowned self] in
self.restartExperience()
}
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
// Prevent the screen from being dimmed to avoid interuppting the AR experience.
UIApplication.shared.isIdleTimerDisabled = true
// Start the AR experience
resetTracking()
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
session.pause()
}
// MARK: - Session management (Image detection setup)
/// Prevents restarting the session while a restart is in progress.
var isRestartAvailable = true
/// Creates a new AR configuration to run on the `session`.
/// - Tag: ARReferenceImage-Loading
func resetTracking() {
guard let referenceImages = ARReferenceImage.referenceImages(inGroupNamed: "AR Resources", bundle: nil) else {
fatalError("Missing expected asset catalog resources.")
}
let configuration = ARWorldTrackingConfiguration()
configuration.detectionImages = referenceImages
session.run(configuration, options: [.resetTracking, .removeExistingAnchors])
statusViewController.scheduleMessage("Look around to detect images", inSeconds: 7.5, messageType: .contentPlacement)
}
// MARK: - ARSCNViewDelegate (Image detection results)
/// - Tag: ARImageAnchor-Visualizing
func renderer(_ renderer: SCNSceneRenderer, didAdd node: SCNNode, for anchor: ARAnchor) {
guard let imageAnchor = anchor as? ARImageAnchor else { return }
let referenceImage = imageAnchor.referenceImage
updateQueue.async {
// Create a plane to visualize the initial position of the detected image.
let plane = SCNPlane(width: referenceImage.physicalSize.width,
height: referenceImage.physicalSize.height)
let planeNode = SCNNode(geometry: plane)
planeNode.opacity = 0.25
/*
`SCNPlane` is vertically oriented in its local coordinate space, but
`ARImageAnchor` assumes the image is horizontal in its local space, so
rotate the plane to match.
*/
planeNode.eulerAngles.x = -.pi / 2
/*
Image anchors are not tracked after initial detection, so create an
animation that limits the duration for which the plane visualization appears.
*/
planeNode.runAction(self.imageHighlightAction)
plane.materials = [SCNMaterial()]
plane.materials[0].diffuse.contents = UIImage(named: "Macbook 12-inch")
// Add the plane visualization to the scene.
node.addChildNode(planeNode)
DispatchQueue.main.async {
let imageName = referenceImage.name ?? ""
self.statusViewController.cancelAllScheduledMessages()
self.statusViewController.showMessage("Detected image “\(imageName)”")
}
}
}
var imageHighlightAction: SCNAction {
return .sequence([
.wait(duration: 0.25),
.fadeOpacity(to: 0.85, duration: 0.25),
.fadeOpacity(to: 0.15, duration: 0.25),
.fadeOpacity(to: 0.85, duration: 0.25),
.fadeOut(duration: 0.5),
.removeFromParentNode()
])
}
}
In Xcode's Assets folder, click on + button and create a folder for reference images (use .png or .jpg formats). In Xcode's directories this folder will get .arresourcegroup extention.
// AR and Textures –> AR Resource Group
You can rename this folder. There's no need to put inside this folder Hi-Res images. Appropriate resolution for each image is 400x400. Put there not more than 100 images. That's all.
Your code may look like this:
guard let images = ARReferenceImage.referenceImages(
inGroupNamed: "AR Resources",
bundle: nil)
else { return }
let config = ARWorldTrackingConfiguration()
config.detectionImages = images
config.maximumNumberOfTrackedImages = 3
arView.session.run(config, options: [])
I don't have much experience in scenekit, I'm actually working in project in a using scenekit, I'm creating sceneView and adding configurations for my project, but I don't know what's the 'showsStatistics' propiety meaning
var sceneView: SCNView!
var scena = SCNScene()
var nodeInitial = SCNNode()
var arrayNodes = [SCNNode] ()
override func viewDidLoad() {
super.viewDidLoad()
nodeInitial = SCNScene(named: "art.scnassets/world.dae")!
for node in nodeInitial.rootNode.ChildNodes as [SCNNode] {
arrayNode.append(node)
}
scene.rootNode.addChildNode(arrayNode.last!)
sceneView.scene = scene
sceneView.allowsCameraControl = true
sceneView.showsStatistics = true
}
The results throw at me:
The part of left I understand that it makes reference to model propieties, but the part of right I don't know and every time I add elements it increases values and when I delete all the nodes it also increases
I'm creating a game using Sprite Kit. I have my GameScene and GameOverScenenow I want to create a MenuScene Where do I control the order of the MenuScene so that it shows up after LaunchScene
class GameViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
if let scene = GameScene.unarchiveFromFile("MenuScene") as? GameScene {
// Configure the view.
let skView = self.view as! SKView
skView.ignoresSiblingOrder = true
scene.scaleMode = .AspectFill
skView.presentScene(scene)
}
}
Edit tried putting ("MenuScene") as the scene but when I run the game that scene won't show
Ok so I found out that I was one the right path. I just needed to change this line. Instead of this
if let scene = GameScene.unarchiveFromFile("MenuScene") as? GameScene {
add this
if let scene = MenuScene.unarchiveFromFile("MenuScene") as? MenuScene {