Skip to content

Instantly share code, notes, and snippets.

@SamyBencherif
Created May 7, 2015 15:35
Show Gist options
  • Save SamyBencherif/beb112dbfea667656989 to your computer and use it in GitHub Desktop.
Save SamyBencherif/beb112dbfea667656989 to your computer and use it in GitHub Desktop.
Classable Cube.py
from scene import *
from math import *
CUBE = [ [(-1, 1, -1), (1, 1, -1), (1, -1, -1), (-1, -1, -1)], #front face
[(1, 1, -1), (1, 1, 1), (1, -1, 1), (1, -1, -1)], #right face
[(-1, 1, -1), (1, 1, -1), (1, 1, 1), (-1, 1, 1)], #top face
[(-1, -1, -1), (1, -1, -1), (1, -1, 1), (-1, -1, 1)], #bottom face
[(-1, 1, -1), (-1, 1, 1), (-1, -1, 1), (-1, -1, -1)], #left face
[(-1, 1, 1), (1, 1, 1), (1, -1, 1), (-1, -1, 1)], #back face
]
def transform(point, transformationVector):
k = [0]*max(len(point), len(transformationVector))
for i in range(max(len(point), len(transformationVector))):
try:
k[i] += point[i]
except:
pass
try:
k[i] += transformationVector[i]
except:
pass
return tuple(k)
def rotate(point3D, axis, angle):
if axis == 'x':
r = sqrt(point3D[1]**2+point3D[2]**2)
theta = atan2(point3D[1], point3D[2])
return (point3D[0], r*cos(radians(angle)+theta), r*sin(radians(angle)+theta))
elif axis == 'y':
r = sqrt(point3D[0]**2+point3D[2]**2)
theta = atan2(point3D[2],point3D[0])
return (r*cos(radians(angle)+theta), point3D[1], r*sin(radians(angle)+theta))
else:
r = sqrt(point3D[0]**2+point3D[1]**2)
theta = atan2(point3D[1], point3D[0])
return (r*cos(radians(angle)+theta), r*sin(radians(angle)+theta), point3D[2])
def midpoint(face): #just for 4,2 sides
if len(face)==4:
return midpoint((midpoint((face[0],face[1])),midpoint((face[2],face[3]))))
else:
return (face[1][2]+(face[0][2]-face[1][2])/2, face[1][1]+(face[0][1]-face[1][1])/2, face[1][0]+(face[0][0]-face[1][0])/2)
def distance(point1, point2):
return ((point1[2]-point2[2])**2+(point1[1]-point2[1])**2+(point1[0]-point2[0])**2)**.5
def triangle(a, b, c):
d = (((b[0]+c[0])/2-a[0])**2+((b[1]+c[1])/2-a[1])**2)**.5
s = (cos(atan2((b[1]+c[1])/2-a[1],(b[0]+c[0])/2-a[0])), sin(atan2((b[1]+c[1])/2-a[1],(b[0]+c[0])/2-a[0])))
su = (cos(atan2(b[1]-c[1],b[0]-c[0])), sin(atan2(b[1]-c[1],b[0]-c[0])))
for i in range(int(d+1)):
l = ((b[0]-c[0])**2+(b[1]-c[1])**2)**.5
line(a[0]+(i)*s[0]+((i*l)/(2*d))*su[0],a[1]+(i)*s[1]+((i*l)/(2*d))*su[1],a[0]+(i)*s[0]-((i*l)/(2*d))*su[0],a[1]+(i)*s[1]-((i*l)/(2*d))*su[1])
#Thanks to Grayson York for suggesting this function
def dualsort(list1, list2): #sort list1 apply to list2, return list2
#list1 = list(list1)
#list2 = list(list2)
assert len(list1)==len(list2)
for i in range(len(list1)):
for j in range(i):
if list1[j]>list1[i]:
a = list1[i]
b = list2[i]
del list1[i]
del list2[i]
list1 = list1[:j]+[a]+list1[j:]
list2 = list2[:j]+[b]+list2[j:]
break
return list2
class World:
lamps = []
objects = []
skybox = Color(0,0,0)
plane = -5
focus = (0,0,-7)
scale = 150
def addLamp(self, lamp):
self.lamps.append(lamp)
return self.lamps[-1]
def addObject(self, object):
self.objects.append(object)
return self.objects[-1]
def render(self, bounds=rect(0,0,0,0)):
background(self.skybox[0], self.skybox[1], self.skybox[2])
stroke(0,0,0)
stroke_weight(1)
ObjectR = []
for object in self.objects:
#object.MeshData = map(lambda x: Poly(map(lambda y: transform(object.position, y),x.PointData), x.color), object.MeshData)
for face in object.MeshData:
faceR = []
for point in face.PointData:
faceR.append(rotate(rotate(rotate(point, 'x', object.rotation[0]), 'y', object.rotation[1]), 'z', object.rotation[2]))
ObjectR.append(Poly(map(lambda x: transform(x, object.position), faceR),face.color))
#self.cube = cubeR
ObjectRS = dualsort(map(lambda x: distance(midpoint(x.PointData), self.focus), ObjectR), ObjectR)[::-1]
if True:
for i in range(len(ObjectRS)): #New: cubeRS is the rotated cube sorted for render sequence
face = ObjectRS[i]
shade = (0,0,0)
face2D = []
for point in face.PointData:
pc = (self.plane-self.focus[2])/float(point[2]-self.focus[2])
nv = (self.focus[0]+(point[0]-self.focus[0])*pc, self.focus[1]+(point[1]-self.focus[1])*pc)
um = self.scale
nv = (nv[0]*um, nv[1]*um)
face2D.append(transform(nv, (bounds.w/2, bounds.h/2))) #adjust these values
for lamp in self.lamps:
if distance(midpoint(face.PointData), lamp.position):
t = lamp.brightness/distance(midpoint(face.PointData), lamp.position)
else:
t = lamp.brightness
g = face
shade = transform(((lamp.color.r+g.color.r)*t/2,(lamp.color.g+g.color.g)*t/2,(lamp.color.b+g.color.b)*t/2), shade)
#color system works
for i in range(0, len(face2D), 1):
stroke(shade[0], shade[1], shade[2])
triangle(face2D[i],face2D[(i+1)%len(face2D)],face2D[(i+2)%len(face2D)])
class Lamp:
position = (0,0,0)
brightness = 0
color = Color(1,1,1)
def __init__(self, position=(0,0,0), brightness=0, color=Color(1,1,1)):
self.position = position
self.brightness = brightness
self.color = color
class Object:
MeshData = []
position = (0,0,0)
rotation = (0,0,0)
def __init__(self, PolyList, initialRotation=(0,0,0)):
self.MeshData = PolyList
#self.setRotation(initialRotation)
self.rotation = initialRotation
class Poly:
PointData = []
color = (0,0,0)
def __init__(self, PointData, color=(0,0,0)):
self.PointData = PointData
self.color = color
class MyScene (Scene):
def setup(self):
self.myWorld = World()
self.myWorld.skybox = (1,1,1)
self.cube1 = self.myWorld.addObject(Object(map(lambda x: Poly(x,Color(1,1,1)), CUBE)))
self.cube2 = self.myWorld.addObject(Object(map(lambda x: Poly(x,Color(0,0,1)), CUBE)))
self.cube1.position = (0,-2,0)
self.cube2.position = (0,-1,5)
self.cube2.rotation = (0,45,0)
self.lamp = self.myWorld.addLamp(Lamp((5,5,0),5, Color(1,1,1)))
def draw(self):
self.cube1.rotation = (0,self.cube1.rotation[1]+1,0)
self.cube2.rotation = (0,self.cube2.rotation[1]+1,0)
self.myWorld.render(self.bounds)
self.cube2.position = (0,-1,max(-1,self.cube2.position[2]-0.1))
def touch_began(self, touch):
pass
def touch_moved(self, touch):
pass
def touch_ended(self, touch):
pass
run(MyScene())
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment