Forum Archive

How to add 3D objects with scnbox

ELECTRO8888

Does anybody know how to use scnbox or any easy way to add moving cameras and 3D objects? Pls send explain your answer, I am very new to Pythonista

cvp

@ELECTRO8888 If I correctly understand, see here

ELECTRO8888

Thx, but sadly I already saw that, I barely understood any of it... thx for responding so fast though!

ELECTRO8888

@cvp I also had tried to copy, paste, and run your code bit by bit to understand it but couldn’t, sorry, I am kinda new to Pythonista and python, and btw I am using Pythonist with python 3

ELECTRO8888

@cvp I just reviewed the code you gave the other person, but I get errors I don’t know how to fix :(

cvp

@ELECTRO8888 The code at the end of here works

ELECTRO8888

@cvp Thx!! I will try it now :)

ELECTRO8888

@cvp hey, it works!! Thx so much!!! Although i can’t figure out what part of it makes the shapes, I am trying to make a game with Pythonista (3D) but, Idk how to make 3D shapes with this app

(Edit: what I meant was, if you don’t mind, could you please give me a line of code to make a 3D cube along with an explanation as of how it works?)

ELECTRO8888

@cvp NVM I figured it out, thx so much for the help!!!!!

(Edit: Sorry if that sounded rude.. I got a little excited that I found out how to make a cube and did caps)

cvp

@ELECTRO8888 sorry to answer so late but I wasn't at home, you'll get it tomorrow

ELECTRO8888

@cvp That is fine

ELECTRO8888

@cvp I do have one more question though... sorry.. I found some code while researching, and I can’t understand most of it XD are you okay with maybe putting some comments in it explaining it? Also could you please make it to where I can place a 2 in the level list for the finish as well as making it to where I can give it a different texture? I am so sorry for all of this, I don’t know much with Pythonista or this website, anyways, here is the code: ```

RayCast

Simple raycasting based renderer

Touch the left part to rotate, and touch the right part to move forward

Coded in a few hours during my holidays, July 2014, straight from my iPhone - thanks Pythonista !!!

Feel free to upgrade !

Enjoy !

Emmanuel ICART

eicart@momorprods.com

from scene import *
from math import *

rendering step - 1=best(slower)

RENDERING_STEP=1

level data

1 = wall, 0 = empty

level = [[1,1,1,1,1,1,1,1],
[1,1,1,1,0,0,1,1],
[1,1,1,1,1,0,0,1],
[1,1,1,0,0,1,0,1],
[1,1,1,0,0,1,0,1],
[1,1,1,0,1,1,0,1],
[1,1,1,0,0,0,0,1],
[1,1,1,1,1,1,1,1]]
LX=len(level[0])
LZ=len(level)
LN=len(level[2])

CellSize=107
scan=10

player

xo=CellSizeLX/2
zo=CellSize
LZ/2
no=CellSize*LN/2
angle=45.0
fov=80

class RayCastScene (Scene):
def setup(self):
# preload the texture
self.texture='plf:Ground_StoneMid'
self.texture1='plf:Tile_DoorOpen_mid'
self.screenWidth=int(self.size.w)
self.screenHeight=int(self.size.h)
self.xTouchStart=0
self.yTouchStart=0
load_image(self.texture)
load_image(self.texture1)
pass

def draw(self):
    global angle
    global xo
    global zo
    global no
    # This will be called for every frame (typically 60 times per second).

    # clear background 
    background(0, 0, 0)

    focale=0.5*self.screenWidth/tan(radians(fov/2))

    # compute each screen column
    for column in range(0,self.screenWidth,RENDERING_STEP):
        scan_angle=angle+((float(column)-self.screenWidth/2)*fov)/self.screenWidth
        c=cos(radians(scan_angle))
        s=sin(radians(scan_angle))
        if abs(c)<0.001:
            if c>0:
                c=0.001
            else:
                c=-0.001

        if abs(s)<0.001:
            if s>0:
                s=0.001
            else:
                s=-0.001

        t2=s/c
        t1=c/s
        ok1=True
        ok2=True

        #Initialization of ray casting
        pz1=t2*CellSize
        if c>0:
            px1=CellSize
            ini=0
        else:
            px1=-CellSize
            pz1=-pz1
            ini=CellSize-1

        xp1=ini+(((int)(xo/CellSize))*CellSize)
        zp1=zo+((xp1-xo)*pz1)/px1
        np1=ini+(((int)(xo/CellSize))*CellSize)

        px2=t1*CellSize
        if s>0:
            pz2=CellSize
            ini=0
        else:
            pz2=-CellSize
            px2=-px2
            ini=CellSize-1

        zp2=ini+(((int)(zo/CellSize))*CellSize)
        xp2=xo+((zp2-zo)*px2)/pz2
        np2=xo+((zp2-zo)*px2)/pz2

        #****** cast a ray for z walls ******
        compteur=0
        while True:
            xp1+=px1
            zp1+=pz1
            np1+=px1
            compteur+=1
            xd=(int)(xp1/CellSize) % LX
            zd=(int)(zp1/CellSize) % LZ
            nd=(int)(np1/CellSize) % LN
            if (xd<0): xd=0
            if (zd<0): zd=0

            if level[xd][zd] !=0 or compteur>=scan:
                break

        if (compteur==scan):ok1=False
        distance1=(xp1-xo)/c
        col1=(zp1 % CellSize)
        if (px1<=0): col1=CellSize-1-col1

        #****** cast a ray for x walls ****** 
        compteur=0
        while True:
            xp2+=px2
            zp2+=pz2
            compteur+=1
            xd=(int)(xp2/CellSize) % LX
            zd=(int)(zp2/CellSize) % LZ
            nd=(int)(np2/CellSize) % LN
            if (xd<0):xd=0
            if (zd<0):zd=0
            if level[xd][zd]!=0 or compteur>=scan: break

        if (compteur==scan): ok2=False
        distance2=(zp2-zo)/s
        col2=(xp2 % CellSize)
        if (pz2>=0):col2=CellSize-1-col2

        #Choose the nearest wall (x or z)
        if (distance1<distance2):
            distance=1+(distance1)
            colonne=col1
        else:
            distance=1+(distance2)
            colonne=col2

        if ok1 or ok2:
            # fix the fishbowl effect
            distance=distance*cos(radians(angle-scan_angle))

            #compute the wall screen height
            hauteur = ((CellSize*focale)/distance)

        # draw the column
        ximage=(colonne*128)/CellSize # 101 x 171 tile
        image(self.texture,column,(self.screenHeight-hauteur)/2,RENDERING_STEP,hauteur,ximage,0,RENDERING_STEP,171)


    # display fingers
    fill(1, 0, 0)
    for touch in list(self.touches.values()):
        ellipse(touch.location.x - 50, touch.location.y - 50, 100, 100)

        # rotation control
        if (touch.location.x<self.screenWidth/2):
            angle += 0.04*(touch.location.x-self.xTouchStart)
        else:
        # displacement control
            speed=(touch.location.y-self.yTouchStart)*0.04
            dx=speed*cos(radians(angle))
            dz=speed*sin(radians(angle))
            if level[int((xo+dx)/CellSize)][int(zo/CellSize)]!=0:dx=0
            if level[int(xo/CellSize)][int((zo+dz)/CellSize)]!=0:dz=0
            xo+=dx
            zo+=dz

def touch_began(self, touch):
    global angle
    self.angleStart=angle
    if touch.location.x<self.screenWidth/2:self.xTouchStart=touch.location.x
    else:
        self.yTouchStart=touch.location.y
    pass

def touch_moved(self, touch):
    pass

def touch_ended(self, touch):
    pass

run(RayCastScene(),LANDSCAPE)
```
* list item

cvp

@ELECTRO8888 Sorry, no answer today, time to go to sleep here in Belgium for an old guy 😢, but try this

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' ])

@on_main_thread
def demo():
    main_view = ui.View()
    main_view_objc = ObjCInstance(main_view)
    scene_view = SCNView.alloc().initWithFrame_options_(((0, 0),(main_view.width,main_view.height)), None).autorelease()
    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((-30,30,30))
    root_node.addChildNode_(camera_node) 

    geometry = SCNBox.boxWithWidth_height_length_chamferRadius_(10, 10, 10, 0)

    geometry_node = SCNNode.nodeWithGeometry_(geometry)
    root_node.addChildNode_(geometry_node)

    Materials = []
    colors = ['red','blue','green','yellow','orange','pink']
    for i in range(0,6):
      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)
    geometry.setMaterials_(Materials)

    # 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_((10, 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)

    main_view.present('full_screen')

demo()
cvp

@ELECTRO8888 I never use the Scene module, which is for 2d.
When you post here a script, try to include it between 2 lines of 3 backticks, using just under your topic title.
I've copied your code, corrected some indentations and put some # before comments lines like "level data" alone.
There was also two erroneous lines where the * was missing

xo=CellSize*LX/2
zo=CellSize*LZ/2

Anyway, the script works but the mathematical part has to be studied by your-self.
Good luck and welcome here

ELECTRO8888

@cvp Thx and okay and Thx!

JonB

The way they original Ray cast code worked, it traced a ray for each pixel until it hit a wall:

if level[xd][zd] !=0 or compteur>=scan:
                break

You would need to figure out which type of wall was hit (level[xd][yd]) then choose the texture that happens later based on that.

SmartGoat

@ELECTRO8888 would love to see how your game looks, I kept my project in mind but don’t have actually the energy to start it, and i’m really interested in how you’ll do it

ELECTRO8888

@SmartGoat Thx! That means a lot