Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
[SOLVED] First attempt to integrate ARkit and first questions...
-
Sorry, a side note guys. Has anyone written anything either in a gist or in the forum that really explains @on_main_thread as it applies specifically to Pythonista and some simple logic to know wether you need to be using it. Or is it safe to say if you are not using objC or your own threads that you can safley say you dont need to be concerned with it?
-
According to Ole's reply in one issue. @on_main_thread is there for objc_util only. Every other module should handle this internally. If not and main thread is required, it's a bug.
See https://github.com/omz/Pythonista-Issues/issues/461 for more info.
-
-
@zrzka , ok thanks thats very clear! Just good to know
-
Back to the original problem:
per apple docs, you have to add the child view controller first:[self addChildViewController:childVC];
[self.view addSubview:childVC.view];
[childVC didMoveToParentViewController:self];The problem i think is that ui.Views don't have a viewcontroller until they are presented
-
@JonB, allright! So, by changing the
MyARView
__init__
toinitialize
and only calling it afterpresent
:v = MyARView() v.present('full_screen', hide_title_bar=True) v.initialize()
... we can follow the right order, using the "forbidden"
nextResponder
trick:self_objc.nextResponder().addChildViewController_(cvc) self_objc.addSubview_(sceneview) cvc.didMoveToParentViewController_(self_objc)
... after which
CustomViewController_viewWillAppear_
no longer needs to be called manually, i.e. things work as they should.(Here's a gist with this version of the code.)
But still, debug info does not appear, nor does the cube stay anchored to the surroundings.
-
@omz, just checking: for ARKit to really work in Pythonista, would Pythonista need to include the
arkit
key inplist
or somesuch? -
Nope, the key is not required. See https://developer.apple.com/documentation/arkit (Important section at the beginning). You only need device with >= A9 chip. Use isSupported to check if your device is supported.
-
@zrzka, thanks.
Again, just to be sure, I checked the property and got
True
on my 6S+.Would be nice if someone could run the gist from the previous post, maybe on a newer device, just to check that the results are similar.
-
@mikael and @JonB, many thanks. It's better, now, the custom view controller is correctly "mounted".
I'm investigating the ARSession problem and i'm trying to understand why its configuration stays null after a "runWithConfiguration_" call (I'm going to use some delegate methods in order to spy the initialization process...).
I will update my github ASAP.Stay tuned...
-
I'm rewriting the Apple demo (candles, ...) into Python(ista). Will share it when finished.
-
@zrzka, just curious, did you progress with this? And if not, was it due to some problems or just other more important things taking up your bandwidth?
-
@mikael simple answer, pretty busy these days :/
-
If anyone needs a bridge for SceneKit I have https://github.com/scj643/objc_tools/blob/master/objc_tools/scenekit/sk_scene.py
-
@scj643, looks good, thanks. As soon as some real programmer gets ARKit working, I am sure to use your code.
-
omg this works well. The cube scene generation example perfectly matches the local world - just set it up at (0,0,0).
-
@momorprods, thanks for the heads up. Looks like with the 3.3 beta ARKit now works on Pythonista!
-
hehe yep made my day! Struggling now into loading SceneKit SCN file, did anyone had chance with this?
-
Hi all, stay tuned for this topic...
I've made some progress since the 3.3 beta delivery and some new personal investigations watching ARKit headers.
... I'm refactoring my basic code sample...
-
Hi,
Finally, I managed to initialize an ar session
but I remain open to any improvement (
especially the famous ARKit constants and the call to the sleep function ;o)Here the code :
# coding: utf-8 import objc_util from objc_util import * import ui import os import sys #from myDebugToolKit import * import time from enum import IntFlag load_framework('SceneKit') load_framework('ARKit') # Some 'constants' used by ARkit # But i can't transfer them to the ARKit framework, why ????? class ARWorldAlignment(IntFlag): ARWorldAlignmentGravity = 0 ARWorldAlignmentGravityAndHeading = 1 ARWorldAlignmentCamera = 2 class ARPlaneDetection(IntFlag): ARPlaneDetectionNone = 0 ARPlaneDetectionHorizontal = 1 << 0 ARPlaneDetectionVertical = 1 << 1 # Work In Progress here, I'm deciphering the ARKit constants... #class ARSCNDebugOption(IntFlag): # ARSCNDebugOptionNone = 0 # ARSCNDebugOptionShowWorldOrigin = int("ffffffff80000000", 16) # ARSCNDebugOptionShowFeaturePoints = int("ffffffff40000000", 16) class ARSessionRunOptions(IntFlag): ARSessionRunOptionsNone = 0 ARSessionRunOptionResetTracking = 1 << 0 ARSessionRunOptionRemoveExistingAnchors = 1 << 1 NSError = ObjCClass('NSError') SCNScene = ObjCClass('SCNScene') ARSCNView = ObjCClass('ARSCNView') ARWorldTrackingConfiguration = ObjCClass('ARWorldTrackingConfiguration') ARSession = ObjCClass('ARSession') UIViewController = ObjCClass('UIViewController') ARPlaneAnchor = ObjCClass('ARPlaneAnchor') # I should refactor te following line in a class but I need to learn more the create_objcc_class function sceneview = None # Here some set up functions used by the main class def createSampleScene(): # an empty scene scene = SCNScene.scene() return scene def setDebugOptions(arscn): # Work In Progress Here, I'm trying to decipher the arkit constants... #val = ARSCNDebugOption.ARSCNDebugOptionShowWorldOrigin | ARSCNDebugOption.ARSCNDebugOptionShowFeaturePoints val = int("fffffffffc000000", 16) # this value is a combination of ShowWorldOrigin and ShowFeaturePoints flags, but I can't isolate each flags.... print('Before calling setDebugOptions_(%s) : debugOptions=%s' %(hex(val), hex(arscn.debugOptions()))) arscn.setDebugOptions_(val) print('After calling setDebugOptions_(%s) : debugOptions=%s' % (hex(val),hex(arscn.debugOptions()))) def createARSceneView(x, y, w, h, debug=True): v = ARSCNView.alloc().initWithFrame_((CGRect(CGPoint(x, y), CGSize(w, h)))) v.setShowsStatistics_(debug) # I love statistics... return v # Some callback definitions used by create_objc_class def CustomViewController_touchesBegan_withEvent_(_self, _cmd, _touches, event): touches = ObjCInstance(_touches) for t in touches: loc = t.locationInView_(sceneview) sz = ui.get_screen_size() print(loc) @on_main_thread def runARSession(arsession): arconfiguration = ARWorldTrackingConfiguration.alloc().init() arconfiguration.setPlaneDetection_ (ARPlaneDetection.ARPlaneDetectionHorizontal) arconfiguration.setWorldAlignment_(ARWorldAlignment.ARWorldAlignmentGravity) # I do not use ARWorldAlignmentGravityAndHeading anymore because on my device, sometimes it fails to initialize the ar session because of an unitialized sensor (error 102). I think my magnetic phone casing plays tricks on me... arsession.runWithConfiguration_options_(arconfiguration, ARSessionRunOptions.ARSessionRunOptionResetTracking | ARSessionRunOptions.ARSessionRunOptionRemoveExistingAnchors ) time.sleep(0.5) # Let the system breathe ;o) Ok, that's the workarround I found to retrieve the ar session configuration (otherwise I got None).... print('configuration',arsession.configuration()) # Very usefull for the debuging (at least for me !) def CustomViewController_viewWillAppear_(_self, _cmd, animated): return def CustomViewController_viewWillDisappear_(_self, _cmd, animated): session = sceneview.session() session.pause() def MyARSCNViewDelegate_renderer_didAdd_for_(_self, _cmd, scenerenderer, node, anchor): if not isinstance(anchor, (ARPlaneAnchor)): return # to be implemented... def MyARSCNViewDelegate_session_didFailWithError_(_self,_cmd,_session,_error): print('error',_error,_cmd,_session) err_obj=ObjCInstance(_error) print(err_obj) # Again, very usefull for the debuging... # The main class... class MyARView(ui.View): def __init__(self): super().__init__(self) @on_main_thread def initialize(self): global sceneview self.flex = 'WH' screen = ui.get_screen_size() # set up the scene scene = createSampleScene() # set up the ar scene view delegate methods = [MyARSCNViewDelegate_renderer_didAdd_for_,MyARSCNViewDelegate_session_didFailWithError_] protocols = ['ARSCNViewDelegate'] MyARSCNViewDelegate = create_objc_class('MyARSCNViewDelegate', NSObject, methods=methods, protocols=protocols) delegate = MyARSCNViewDelegate.alloc().init() # set up the ar scene view sceneview = createARSceneView(0, 0, screen.width, screen.height) sceneview.scene = scene sceneview.setDelegate_(delegate) # set up the custom view controller methods = [CustomViewController_touchesBegan_withEvent_, CustomViewController_viewWillAppear_, CustomViewController_viewWillDisappear_] protocols = [] CustomViewController = create_objc_class('CustomViewController', UIViewController, methods=methods, protocols=protocols) cvc = CustomViewController.alloc().init() cvc.view = sceneview # internal scheming... self_objc = ObjCInstance(self) self_objc.nextResponder().addChildViewController_(cvc) self_objc.addSubview_(sceneview) cvc.didMoveToParentViewController_(self_objc) # here, we try... runARSession(sceneview.session()) # I call here this function because I'm trying to find the best place to run the ar session... setDebugOptions(sceneview) # I call here this function because I'm trying to find the best place to set the debuging options.... def will_close(self): session = sceneview.session() session.pause() if __name__ == '__main__': v = MyARView() v.present('full_screen', hide_title_bar=True, orientations=['portrait']) v.initialize()
Note: if someone can correct the autorotate, I'm also interested !o)
Edit: I found a solution for my autorotate problem -> I turn it off ;o)