SceneKit with, thanks to @jonB , the camera of your iDevice as background
from objc_util import *
import ctypes
import ui
import math
from ImageColor import getrgb
load_framework('SceneKit')
SCNView, SCNScene, SCNBox, SCNNode, SCNMaterial, SCNCamera, SCNLight, SCNAction, SCNLookAtConstraint = map(ObjCClass, ['SCNView', 'SCNScene', 'SCNBox', 'SCNNode', 'SCNMaterial', 'SCNCamera', 'SCNLight', 'SCNAction', 'SCNLookAtConstraint' ])
class SCNVector3(Structure):
_fields_ = [('x', c_float), ('y', c_float), ('z', c_float)]
def camera_in_ui_view(ui_view):
#https://github.com/jsbain/objc_hacks/blob/master/live_camera_view.p
device = 0
# 0 = back camera
# 1 = front camera
ui_view._session=ObjCClass('AVCaptureSession').alloc().init()
ui_view._session.setSessionPreset_('AVCaptureSessionPresetHigh');
inputDevices=ObjCClass('AVCaptureDevice').devices()
#print(inputDevices)
ui_view._inputDevice=inputDevices[device]
deviceInput=ObjCClass('AVCaptureDeviceInput').deviceInputWithDevice_error_(ui_view._inputDevice, None);
if ui_view._session.canAddInput_(deviceInput):
ui_view._session.addInput_(deviceInput)
ui_view._previewLayer=ObjCClass('AVCaptureVideoPreviewLayer').alloc().initWithSession_(ui_view._session)
ui_view._previewLayer.setVideoGravity_('AVLayerVideoGravityResizeAspectFill')
rootLayer=ObjCInstance(ui_view).layer()
rootLayer.setMasksToBounds_(True)
ui_view._previewLayer.setFrame_(CGRect(CGPoint(-70, 0), CGSize(ui_view.height,ui_view.height)))
rootLayer.insertSublayer_atIndex_(ui_view._previewLayer,0)
ui_view._session.startRunning()
@on_main_thread
def demo():
main_view = ui.View()
w, h = ui.get_screen_size()
main_view.frame = (0,0,w,h)
# background = image
#bg = ui.ImageView()
#w, h = ui.get_screen_size()
#bg.frame = (0,0,w,h)
#bg.image = ui.Image.named('test:Peppers')
#bg.content_mode = ui.CONTENT_SCALE_ASPECT_FILL
#main_view.add_subview(bg)
camera_in_ui_view(main_view) # background = camera
main_view_objc = ObjCInstance(main_view)
scene_view = SCNView.alloc().initWithFrame_options_(((0, 0),(w, h)), None).autorelease()
# transparent scene_view background, thus we see main_view background
scene_view.setBackgroundColor_(ObjCClass('UIColor').clearColor())
scene_view.setAutoresizingMask_(18)
scene_view.setAllowsCameraControl_(True)
main_view_objc.addSubview_(scene_view)
main_view.name = 'SceneKit Demo'
scene = SCNScene.scene()
scene_view.setScene_(scene)
root_node = scene.rootNode()
camera = SCNCamera.camera()
camera_node = SCNNode.node()
camera_node.setCamera(camera)
camera_node.setPosition((0,0,5))
root_node.addChildNode_(camera_node)
#https://medium.com/@zxlee618/custom-geometry-in-scenekit-f91464297fd1
verts = [
SCNVector3(0, 1, 0),
SCNVector3(-0.5, 0, 0.5),
SCNVector3(0.5, 0, 0.5),
SCNVector3(0.5, 0, -0.5),
SCNVector3(-0.5, 0, -0.5),
SCNVector3(0, -1, 0)]
SCNVector3Array3 = SCNVector3 * len(verts)
verts_array = SCNVector3Array3(*verts)
SCNGeometrySource = ObjCClass('SCNGeometrySource')
s = SCNGeometrySource.geometrySourceWithVertices_count_(byref(verts_array), len(verts), restype=c_void_p, argtypes=[POINTER(SCNVector3Array3), c_ulong],)
indexes = [3,3,3,3,3,3,3,3,
0, 1, 2,
2, 3, 0,
3, 4, 0,
4, 1, 0,
1, 5, 2,
2, 5, 3,
3, 5, 4,
4, 5, 1]
indexes_array = (c_int*len(indexes))(*indexes)
datIndexes = ObjCClass('NSData').dataWithBytes_length_(indexes_array,sizeof(indexes_array))
# primitiveType = 0 for SCNGeometryPrimitiveTypeTriangles
# 4 for SCNGeometryPrimitiveTypePolygon
# primitiveCount = 1
e = ObjCClass('SCNGeometryElement').geometryElementWithData_primitiveType_primitiveCount_bytesPerIndex_(datIndexes,4,8,sizeof(c_int))
geometry = ObjCClass('SCNGeometry').geometryWithSources_elements_([s],[e])
#print(geometry.geometryElements()[0].data()) # to check
Material = SCNMaterial.material()
Material.contents = ObjCClass('UIColor').colorWithRed_green_blue_alpha_(1,0.9,0.9,1.0)
geometry.setMaterials_([Material])
geometry_node = SCNNode.nodeWithGeometry_(geometry)
root_node.addChildNode_(geometry_node)
e2 = []
Materials = []
colors = ['red','blue','green','yellow','orange','pink','cyan','orchid']
for i in range(0,8):
j = 8 + i*3
indexes2 = [indexes[j],indexes[j+1],indexes[j+2]]
indexes_array2 = (c_int*len(indexes2))(*indexes2)
datIndexes2 = ObjCClass('NSData').dataWithBytes_length_(indexes_array2,sizeof(indexes_array2))
e = ObjCClass('SCNGeometryElement').geometryElementWithData_primitiveType_primitiveCount_bytesPerIndex_(datIndexes2,0,1,sizeof(c_int))
e2.append(e)
rgb = getrgb(colors[i])
r,g,b = tuple(c/255.0 for c in rgb)
Material = SCNMaterial.material()
Material.contents = ObjCClass('UIColor').colorWithRed_green_blue_alpha_(r,g,b,1.0)
Materials.append(Material)
geometry2 = ObjCClass('SCNGeometry').geometryWithSources_elements_([s],e2)
geometry2.setMaterials_(Materials)
geometry2_node = SCNNode.nodeWithGeometry_(geometry2)
tx,ty,tz = (-1.5,0,0)
x = (1,0,0,0, 0,1,0,0, 0,0,1,0, tx,ty,tz,1) # translation
geometry2_node.setPivot_(x)
root_node.addChildNode_(geometry2_node)
# Add a constraint to the camera to keep it pointing to the target geometry
constraint = SCNLookAtConstraint.lookAtConstraintWithTarget_(geometry_node)
constraint.gimbalLockEnabled = True
camera_node.constraints = [constraint]
light_node = SCNNode.node()
light_node.setPosition_((100, 0, -10))
light = SCNLight.light()
light.setType_('directional')
light.setCastsShadow_(True)
light.setColor_(UIColor.whiteColor().CGColor())
light_node.setLight_(light)
root_node.addChildNode_(light_node)
rotate_action = SCNAction.repeatActionForever_(SCNAction.rotateByX_y_z_duration_(0, math.pi*2, 0, 10))
geometry_node.runAction_(rotate_action)
geometry2_node.runAction_(rotate_action)
main_view.present(hide_title_bar=True)
demo()
