From c58c9f7cc00a11c5bf946bfa6ae83bb10bc76a38 Mon Sep 17 00:00:00 2001 From: James Smith Date: Sun, 2 Sep 2018 16:14:24 +0100 Subject: [PATCH] add ported 3d spinning object app --- 3dspin/coriolis.obj | 50 ++++++ 3dspin/cube.obj | 29 ++++ 3dspin/dodecahedron.obj | 59 +++++++ 3dspin/icosahedron.obj | 51 ++++++ 3dspin/main.py | 359 ++++++++++++++++++++++++++++++++++++++++ 3dspin/octohedron.obj | 27 +++ 3dspin/octotoad.obj | 81 +++++++++ 3dspin/tetrahedron.obj | 19 +++ 8 files changed, 675 insertions(+) create mode 100644 3dspin/coriolis.obj create mode 100644 3dspin/cube.obj create mode 100644 3dspin/dodecahedron.obj create mode 100755 3dspin/icosahedron.obj create mode 100644 3dspin/main.py create mode 100644 3dspin/octohedron.obj create mode 100644 3dspin/octotoad.obj create mode 100644 3dspin/tetrahedron.obj diff --git a/3dspin/coriolis.obj b/3dspin/coriolis.obj new file mode 100644 index 0000000..e9114cd --- /dev/null +++ b/3dspin/coriolis.obj @@ -0,0 +1,50 @@ +# Exported from Wings 3D 1.5.4 +mtllib coriolis.mtl +o Cube1 +#12 vertices, 14 faces +v -1.00000000 -1.00000000 0.0000000e+0 +v -1.00000000 0.0000000e+0 -1.00000000 +v 0.0000000e+0 -1.00000000 -1.00000000 +v -1.00000000 0.0000000e+0 1.00000000 +v 0.0000000e+0 -1.00000000 1.00000000 +v 0.0000000e+0 1.00000000 -1.00000000 +v -1.00000000 1.00000000 0.0000000e+0 +v 0.0000000e+0 1.00000000 1.00000000 +v 1.00000000 -1.00000000 0.0000000e+0 +v 1.00000000 0.0000000e+0 -1.00000000 +v 1.00000000 0.0000000e+0 1.00000000 +v 1.00000000 1.00000000 0.0000000e+0 +v 0.2 0.1 1.01 +v 0.2 -0.1 1.01 +v -0.2 -0.1 1.01 +v -0.2 0.1 1.01 +vn -0.70710678 -0.70710678 0.0000000e+0 +vn -0.70710678 0.0000000e+0 -0.70710678 +vn 0.0000000e+0 -0.70710678 -0.70710678 +vn -0.70710678 0.0000000e+0 0.70710678 +vn 0.0000000e+0 -0.70710678 0.70710678 +vn 0.0000000e+0 0.70710678 -0.70710678 +vn -0.70710678 0.70710678 0.0000000e+0 +vn 0.0000000e+0 0.70710678 0.70710678 +vn 0.70710678 -0.70710678 0.0000000e+0 +vn 0.70710678 0.0000000e+0 -0.70710678 +vn 0.70710678 0.0000000e+0 0.70710678 +vn 0.70710678 0.70710678 0.0000000e+0 +g Cube1_default +usemtl default +s 1 +f 1//1 2//2 3//3 +f 1//1 4//4 7//7 2//2 +f 1//1 5//5 4//4 +f 2//2 6//6 10//10 3//3 +f 2//2 7//7 6//6 +f 3//3 9//9 5//5 1//1 +f 3//3 10//10 9//9 +f 4//4 8//8 7//7 +f 5//5 9//9 11//11 +f 5//5 11//11 8//8 4//4 +f 6//6 12//12 10//10 +f 7//7 8//8 12//12 6//6 +f 8//8 11//11 12//12 +f 10//10 12//12 11//11 9//9 +f 16 15 14 13 \ No newline at end of file diff --git a/3dspin/cube.obj b/3dspin/cube.obj new file mode 100644 index 0000000..ab948e9 --- /dev/null +++ b/3dspin/cube.obj @@ -0,0 +1,29 @@ +# Exported from Wings 3D 1.5.4 +mtllib cube.mtl +o Cube1 +#8 vertices, 6 faces +v -1.00000000 -1.00000000 -1.00000000 +v -1.00000000 -1.00000000 1.00000000 +v -1.00000000 1.00000000 -1.00000000 +v -1.00000000 1.00000000 1.00000000 +v 1.00000000 -1.00000000 -1.00000000 +v 1.00000000 -1.00000000 1.00000000 +v 1.00000000 1.00000000 -1.00000000 +v 1.00000000 1.00000000 1.00000000 +vn -0.57735027 -0.57735027 -0.57735027 +vn -0.57735027 -0.57735027 0.57735027 +vn -0.57735027 0.57735027 -0.57735027 +vn -0.57735027 0.57735027 0.57735027 +vn 0.57735027 -0.57735027 -0.57735027 +vn 0.57735027 -0.57735027 0.57735027 +vn 0.57735027 0.57735027 -0.57735027 +vn 0.57735027 0.57735027 0.57735027 +g Cube1_default +usemtl default +s 1 +f 1//1 5//5 6//6 2//2 +f 2//2 4//4 3//3 1//1 +f 2//2 6//6 8//8 4//4 +f 3//3 7//7 5//5 1//1 +f 4//4 8//8 7//7 3//3 +f 5//5 7//7 8//8 6//6 diff --git a/3dspin/dodecahedron.obj b/3dspin/dodecahedron.obj new file mode 100644 index 0000000..c8ccdc6 --- /dev/null +++ b/3dspin/dodecahedron.obj @@ -0,0 +1,59 @@ +# Exported from Wings 3D 1.5.4 +mtllib dodecahedron.mtl +o dodecahedron1 +#20 vertices, 12 faces +v -0.50000000 0.0000000e+0 1.30901699 +v 0.50000000 0.0000000e+0 1.30901699 +v -0.80901699 -0.80901699 -0.80901699 +v -0.80901699 -0.80901699 0.80901699 +v -0.80901699 0.80901699 -0.80901699 +v -0.80901699 0.80901699 0.80901699 +v 0.80901699 -0.80901699 -0.80901699 +v 0.80901699 -0.80901699 0.80901699 +v 0.80901699 0.80901699 -0.80901699 +v 0.80901699 0.80901699 0.80901699 +v 1.30901699 0.50000000 0.0000000e+0 +v 1.30901699 -0.50000000 0.0000000e+0 +v -1.30901699 0.50000000 0.0000000e+0 +v -1.30901699 -0.50000000 0.0000000e+0 +v -0.50000000 0.0000000e+0 -1.30901699 +v 0.50000000 0.0000000e+0 -1.30901699 +v 0.0000000e+0 1.30901699 0.50000000 +v 0.0000000e+0 1.30901699 -0.50000000 +v 0.0000000e+0 -1.30901699 0.50000000 +v 0.0000000e+0 -1.30901699 -0.50000000 +vn -0.35682209 0.0000000e+0 0.93417236 +vn 0.35682209 0.0000000e+0 0.93417236 +vn -0.57735027 -0.57735027 -0.57735027 +vn -0.57735027 -0.57735027 0.57735027 +vn -0.57735027 0.57735027 -0.57735027 +vn -0.57735027 0.57735027 0.57735027 +vn 0.57735027 -0.57735027 -0.57735027 +vn 0.57735027 -0.57735027 0.57735027 +vn 0.57735027 0.57735027 -0.57735027 +vn 0.57735027 0.57735027 0.57735027 +vn 0.93417236 0.35682209 0.0000000e+0 +vn 0.93417236 -0.35682209 0.0000000e+0 +vn -0.93417236 0.35682209 0.0000000e+0 +vn -0.93417236 -0.35682209 0.0000000e+0 +vn -0.35682209 0.0000000e+0 -0.93417236 +vn 0.35682209 0.0000000e+0 -0.93417236 +vn 0.0000000e+0 0.93417236 0.35682209 +vn 0.0000000e+0 0.93417236 -0.35682209 +vn 0.0000000e+0 -0.93417236 0.35682209 +vn 0.0000000e+0 -0.93417236 -0.35682209 +g dodecahedron1_default +usemtl default +s 1 +f 1//1 4//4 19//19 8//8 2//2 +f 1//1 6//6 13//13 14//14 4//4 +f 2//2 10//10 17//17 6//6 1//1 +f 3//3 20//20 19//19 4//4 14//14 +f 5//5 18//18 9//9 16//16 15//15 +f 7//7 16//16 9//9 11//11 12//12 +f 8//8 12//12 11//11 10//10 2//2 +f 9//9 18//18 17//17 10//10 11//11 +f 12//12 8//8 19//19 20//20 7//7 +f 13//13 6//6 17//17 18//18 5//5 +f 14//14 13//13 5//5 15//15 3//3 +f 15//15 16//16 7//7 20//20 3//3 diff --git a/3dspin/icosahedron.obj b/3dspin/icosahedron.obj new file mode 100755 index 0000000..e5baa11 --- /dev/null +++ b/3dspin/icosahedron.obj @@ -0,0 +1,51 @@ +# Exported from Wings 3D 1.5.4 +mtllib icosahedron.mtl +o icosahedron1 +#12 vertices, 20 faces +v 0.0000000e+0 1.90211303 0.0000000e+0 +v 1.70130162 0.85065081 0.0000000e+0 +v 0.52573111 0.85065081 1.61803399 +v -1.37638192 0.85065081 1.00000000 +v -1.37638192 0.85065081 -1.00000000 +v 0.52573111 0.85065081 -1.61803399 +v -1.70130162 -0.85065081 0.0000000e+0 +v -0.52573111 -0.85065081 -1.61803399 +v 1.37638192 -0.85065081 -1.00000000 +v 1.37638192 -0.85065081 1.00000000 +v -0.52573111 -0.85065081 1.61803399 +v 0.0000000e+0 -1.90211303 0.0000000e+0 +vn 2.7942283e-17 1.00000000 -1.3971142e-17 +vn 0.89442719 0.44721360 0.0000000e+0 +vn 0.27639320 0.44721360 0.85065081 +vn -0.72360680 0.44721360 0.52573111 +vn -0.72360680 0.44721360 -0.52573111 +vn 0.27639320 0.44721360 -0.85065081 +vn -0.89442719 -0.44721360 0.0000000e+0 +vn -0.27639320 -0.44721360 -0.85065081 +vn 0.72360680 -0.44721360 -0.52573111 +vn 0.72360680 -0.44721360 0.52573111 +vn -0.27639320 -0.44721360 0.85065081 +vn -4.1913425e-17 -1.00000000 0.0000000e+0 +g icosahedron1_default +usemtl default +s 1 +f 1//1 3//3 2//2 +f 1//1 4//4 3//3 +f 1//1 5//5 4//4 +f 1//1 6//6 5//5 +f 2//2 6//6 1//1 +f 2//2 9//9 6//6 +f 2//2 10//10 9//9 +f 3//3 10//10 2//2 +f 3//3 11//11 10//10 +f 4//4 11//11 3//3 +f 5//5 7//7 4//4 +f 5//5 8//8 7//7 +f 6//6 8//8 5//5 +f 6//6 9//9 8//8 +f 7//7 11//11 4//4 +f 7//7 12//12 11//11 +f 8//8 12//12 7//7 +f 9//9 12//12 8//8 +f 10//10 12//12 9//9 +f 11//11 12//12 10//10 diff --git a/3dspin/main.py b/3dspin/main.py new file mode 100644 index 0000000..62ffc33 --- /dev/null +++ b/3dspin/main.py @@ -0,0 +1,359 @@ +"""3d rotating polyhedra. 2016 badge competition winner, ported for 2018!""" + +___name___ = "3D Spin" +___license___ = "MIT" +___categories___ = ["Demo"] +___dependencies___ = ["app", "ugfx_helper", "random", "sleep", "buttons"] + +import ugfx +from tilda import Buttons +import math +from uos import listdir +import time +# from imu import IMU +import gc +# import pyb + +app_path = './3dspin' + +from math import sqrt + +class Vector3D: + def __init__(self, x=0.0, y=0.0, z=0.0): + self.x = x + self.y = y + self.z = z + + def magnitude(self): + return sqrt(self.x*self.x+self.y*self.y+self.z*self.z) + + def __sub__(self, v): + return Vector3D(self.x-v.x, self.y-v.y, self.z-v.z) + + def normalize(self): + mag = self.magnitude() + if (mag > 0.0): + self.x /= mag + self.y /= mag + self.z /= mag + else: + raise Exception('*** Vector: error, normalizing zero vector! ***') + + def cross(self, v): #cross product + return Vector3D(self.y*v.z-self.z*v.y, self.z*v.x-self.x*v.z, self.x*v.y-self.y*v.x) + + +#The layout of the matrix (row- or column-major) matters only when the user reads from or writes to the matrix (indexing). For example in the multiplication function we know that the first components of the Matrix-vectors need to be multiplied by the vector. The memory-layout is not important +class Matrix: + ''' Column-major order ''' + + def __init__(self, createidentity=True):# (2,2) creates a 2*2 Matrix + # if rows < 2 or cols < 2: + # raise Exception('*** Matrix: error, getitem((row, col)), row, col problem! ***') + self.rows = 4 + self.cols = 4 + self.m = [[0.0]*self.rows for x in range(self.cols)] + + #If quadratic matrix then create identity one + if createidentity: + for i in range(self.rows): + self.m[i][i] = 1.0 + + def mul(self, right): + if isinstance(right, Matrix): + r = Matrix(False) + for i in range(self.rows): + for j in range(right.cols): + for k in range(self.cols): + r.m[i][j] += self.m[i][k]*right.m[k][j] + return r + elif isinstance(right, Vector3D): #Translation: the last column of the matrix. Remains unchanged due to the the fourth coord of the vector (1). +# if self.cols == 4: + r = Vector3D() + addx = addy = addz = 0.0 + if self.rows == self.cols == 4: + addx = self.m[0][3] + addy = self.m[1][3] + addz = self.m[2][3] + r.x = self.m[0][0]*right.x+self.m[0][1]*right.y+self.m[0][2]*right.z+addx + r.y = self.m[1][0]*right.x+self.m[1][1]*right.y+self.m[1][2]*right.z+addy + r.z = self.m[2][0]*right.x+self.m[2][1]*right.y+self.m[2][2]*right.z+addz + + #In 3D game programming we use homogenous coordinates instead of cartesian ones in case of Vectors in order to be able to use them with a 4*4 Matrix. The 4th coord (w) is not included in the Vector-class but gets computed on the fly + w = self.m[3][0]*right.x+self.m[3][1]*right.y+self.m[3][2]*right.z+self.m[3][3] + if (w != 1 and w != 0): + r.x = r.x/w; + r.y = r.y/w; + r.z = r.z/w; + return r + else: + raise Exception('*** Matrix: error, matrix multiply with not matrix, vector or int or float! ***') + +def loadObject(filename): + print(filename) + if (".obj" in filename): + loadObj(filename) + if (".dat" in filename): + loadDat(filename) + +def loadDat(filename): + global obj_vertices + global obj_faces + obj_vertices = [] + obj_faces = [] + f = open(app_path + "/" + filename) + for line in f: + if line[:2] == "v ": + parts = line.split(" ") + obj_vertices.append( + Vector3D( + float(parts[1]), + float(parts[2]), + float(parts[3]) + ) + ) + gc.collect() + elif line[:2] == "f ": + parts = line.split(" ") + face = [] + for part in parts[1:]: + face.append(int(part.split("/",1)[0])-1) + obj_faces.append(face) + gc.collect() + f.close() + +def loadObj(filename): + global obj_vertices + global obj_faces + obj_vertices = [] + obj_faces = [] + f = open(app_path + "/" + filename) + for line in f: + if line[:2] == "v ": + parts = line.split(" ") + obj_vertices.append( + Vector3D( + float(parts[1]), + float(parts[2]), + float(parts[3]) + ) + ) + gc.collect() + elif line[:2] == "f ": + parts = line.split(" ") + face = [] + for part in parts[1:]: + face.append(int(part.split("/",1)[0])-1) + obj_faces.append(face) + gc.collect() + f.close() + +def toScreenCoords(pv): + px = int((pv.x+1)*0.5*240) + py = int((1-(pv.y+1)*0.5)*320) + return [px, py] + +def createCameraMatrix(x,y,z): + camera_transform = Matrix() + camera_transform.m[0][3] = x + camera_transform.m[1][3] = y + camera_transform.m[2][3] = z + return camera_transform + +def createProjectionMatrix(horizontal_fov, zfar, znear): + s = 1/(math.tan(math.radians(horizontal_fov/2))) + proj = Matrix() + proj.m[0][0] = s * (320/240) # inverse aspect ratio + proj.m[1][1] = s + proj.m[2][2] = -zfar/(zfar-znear) + proj.m[3][2] = -1.0 + proj.m[2][3] = -(zfar*znear)/(zfar-znear) + return proj + +def createRotationMatrix(x_rotation, y_rotation, z_rotation): + rot_x = Matrix() + rot_x.m[1][1] = rot_x.m[2][2] = math.cos(x_rotation) + rot_x.m[2][1] = math.sin(x_rotation) + rot_x.m[1][2] = -rot_x.m[2][1] + + rot_y = Matrix() + rot_y.m[0][0] = rot_y.m[2][2] = math.cos(y_rotation) + rot_y.m[0][2] = math.sin(y_rotation) + rot_y.m[2][0] = -rot_y.m[0][2] + + rot_z = Matrix() + rot_z.m[0][0] = rot_z.m[1][1] = math.cos(z_rotation) + rot_z.m[1][0] = math.sin(z_rotation) + rot_z.m[0][1] = -rot_z.m[1][0] + + return rot_z.mul(rot_x).mul(rot_y) + +def normal(face, vertices, normalize = True): + # Work out the face normal for lighting + normal = (vertices[face[1]]-vertices[face[0]]).cross(vertices[face[2]]-vertices[face[0]]) + if normalize == True: + normal.normalize() + return normal + +def clear_screen(): + # Selectively clear the screen by re-rendering the previous frame in black + global last_polygons + global last_mode + for poly in last_polygons: + if last_mode == FLAT: + ugfx.fill_polygon(0,0, poly, ugfx.BLACK) + ugfx.polygon(0,0, poly, ugfx.BLACK) + +def render(mode, rotation): + # Rotate all the vertices in one go + vertices = [rotation.mul(vertex) for vertex in obj_vertices] + # Calculate normal for each face (for lighting) + if mode == FLAT: + face_normal_zs = [normal(face, vertices).z for face in obj_faces] + # Project (with camera) all the vertices in one go as well + vertices = [camera_projection.mul(vertex) for vertex in vertices] + # Calculate projected normals for each face + if mode != WIREFRAME: + proj_normal_zs = [normal(face, vertices, False).z for face in obj_faces] + # Convert to screen coordinates all at once + # We could do this faster by only converting vertices that are + # in faces that will be need rendered, but it's likely that test + # would take longer. + vertices = [toScreenCoords(v) for v in vertices] + # Render the faces to the screen + vsync() + clear_screen() + + global last_polygons + global last_mode + last_polygons = [] + last_mode = mode + + for index in range(len(obj_faces)): + # Only render things facing towards us (unless we're in wireframe mode) + if (mode == WIREFRAME) or (proj_normal_zs[index] > 0): + # Convert polygon + poly = [vertices[v] for v in obj_faces[index]] + # Calculate colour and render + ugcol = ugfx.WHITE + if mode == FLAT: + # Simple lighting calculation + colour5 = int(face_normal_zs[index] * 31) + colour6 = int(face_normal_zs[index] * 63) + # Create a 5-6-5 grey + ugcol = (colour5 << 11) | (colour6 << 5) | colour5 + # Render polygon + ugfx.fill_polygon(0,0, poly, ugcol) + # Always draw the wireframe in the same colour to fill gaps left by the + # fill_polygon method + ugfx.polygon(0,0, poly, ugcol) + last_polygons.append(poly) + +def vsync(): + None + # while(tear.value() == 0): + # pass + # while(tear.value()): + # pass + +def calculateRotation(smoothing, accelerometer): + # Keep a list of recent rotations to smooth things out + global x_rotation + global z_rotation + # First, pop off the oldest rotation + # if len(x_rotations) >= smoothing: + # x_rotations = x_rotations[1:] + # if len(z_rotations) >= smoothing: + # z_rotations = z_rotations[1:] + # Now append a new rotation + pi_2 = math.pi / 2 + #x_rotations.append(-accelerometer['z'] * pi_2) + #z_rotations.append(accelerometer['x'] * pi_2) + # Calculate rotation matrix + return createRotationMatrix( + # this averaging isn't correct in the first frames, but who cares + math.radians(x_rotation), + math.radians(y_rotation), + math.radians(z_rotation) + ) +print("Hello 3DSpin") + +# Initialise hardware +ugfx.init() +ugfx.clear(ugfx.BLACK) +# imu=IMU() +# buttons.init() + +# Enable tear detection for vsync +# ugfx.enable_tear() +# tear = pyb.Pin("TEAR", pyb.Pin.IN) +#ugfx.set_tear_line(1) + +print("Graphics initalised") + +# Set up static rendering matrices +camera_transform = createCameraMatrix(0, 0, -5.0) +proj = createProjectionMatrix(45.0, 100.0, 0.1) +camera_projection = proj.mul(camera_transform) + +print("Camera initalised") + +# Get the list of available objects, and load the first one +obj_vertices = [] +obj_faces = [] +print("available objects: {}", listdir(app_path)) +objects = [x for x in listdir(app_path) if (((".obj" in x) | (".dat" in x)) & (x[0] != "."))] +selected = 0 +loadObject(objects[selected]) + +print("loaded object {}", objects[selected]) + +# Set up rotation tracking arrays +x_rotation = 0 +z_rotation = 0 +y_rotation = 0 +# Smooth rotations over 5 frames +smoothing = 5 + +# Rendering modes +BACKFACECULL = 1 +FLAT = 2 +WIREFRAME = 3 +# Start with backface culling mode +mode = BACKFACECULL + +last_polygons = [] +last_mode = WIREFRAME + +# Main loop +run = True +while run: + gc.collect() + # Render the scene + render( + mode, + calculateRotation(smoothing, None) + ) + # Button presses + y_rotation += 5 + x_rotation += 3 + z_rotation += 1 + if Buttons.is_pressed(Buttons.JOY_Left): + y_rotation -= 5 + if Buttons.is_pressed(Buttons.JOY_Right): + y_rotation += 5 + if Buttons.is_pressed(Buttons.JOY_Center): + y_rotation = 0 + if Buttons.is_pressed(Buttons.BTN_B): + selected += 1 + if selected >= len(objects): + selected = 0 + loadObject(objects[selected]) + time.sleep_ms(500) # Wait a while to avoid skipping ahead if the user still has the button down + if Buttons.is_pressed(Buttons.BTN_A): + mode += 1 + if mode > 3: + mode = 1 + time.sleep_ms(500) # Wait a while to avoid skipping ahead if the user still has the button down + if Buttons.is_pressed(Buttons.BTN_Menu): + run = False diff --git a/3dspin/octohedron.obj b/3dspin/octohedron.obj new file mode 100644 index 0000000..e988ff4 --- /dev/null +++ b/3dspin/octohedron.obj @@ -0,0 +1,27 @@ +# Exported from Wings 3D 2.0.5 +mtllib octohedron.mtl +o octahedron1 +#6 vertices, 8 faces +v 2.00000000 0.0000000e+0 0.0000000e+0 +v -2.00000000 0.0000000e+0 0.0000000e+0 +v 0.0000000e+0 2.00000000 0.0000000e+0 +v 0.0000000e+0 -2.00000000 0.0000000e+0 +v 0.0000000e+0 0.0000000e+0 2.00000000 +v 0.0000000e+0 0.0000000e+0 -2.00000000 +vn 1.00000000 0.0000000e+0 0.0000000e+0 +vn -1.00000000 0.0000000e+0 0.0000000e+0 +vn 0.0000000e+0 1.00000000 0.0000000e+0 +vn 0.0000000e+0 -1.00000000 0.0000000e+0 +vn 0.0000000e+0 0.0000000e+0 1.00000000 +vn 0.0000000e+0 0.0000000e+0 -1.00000000 +g octahedron1_default +usemtl default +s 1 +f 1//1 5//5 4//4 +f 1//1 6//6 3//3 +f 2//2 5//5 3//3 +f 2//2 6//6 4//4 +f 3//3 5//5 1//1 +f 3//3 6//6 2//2 +f 4//4 5//5 2//2 +f 4//4 6//6 1//1 diff --git a/3dspin/octotoad.obj b/3dspin/octotoad.obj new file mode 100644 index 0000000..1b2fc16 --- /dev/null +++ b/3dspin/octotoad.obj @@ -0,0 +1,81 @@ +# Exported from Wings 3D 2.0.5 +mtllib octoad.mtl +o octotoad1 +#24 vertices, 26 faces +v 1.66800000 0.55600000 0.55600000 +v 1.66800000 0.55600000 -0.55600000 +v 1.66800000 -0.55600000 0.55600000 +v 1.66800000 -0.55600000 -0.55600000 +v -1.66800000 0.55600000 0.55600000 +v -1.66800000 0.55600000 -0.55600000 +v -1.66800000 -0.55600000 0.55600000 +v -1.66800000 -0.55600000 -0.55600000 +v 0.55600000 1.66800000 0.55600000 +v 0.55600000 1.66800000 -0.55600000 +v 0.55600000 -1.66800000 0.55600000 +v 0.55600000 -1.66800000 -0.55600000 +v 0.55600000 0.55600000 1.66800000 +v 0.55600000 0.55600000 -1.66800000 +v 0.55600000 -0.55600000 1.66800000 +v 0.55600000 -0.55600000 -1.66800000 +v -0.55600000 1.66800000 0.55600000 +v -0.55600000 1.66800000 -0.55600000 +v -0.55600000 -1.66800000 0.55600000 +v -0.55600000 -1.66800000 -0.55600000 +v -0.55600000 0.55600000 1.66800000 +v -0.55600000 0.55600000 -1.66800000 +v -0.55600000 -0.55600000 1.66800000 +v -0.55600000 -0.55600000 -1.66800000 +vn 0.85476344 0.36700100 0.36700100 +vn 0.85476344 0.36700100 -0.36700100 +vn 0.85476344 -0.36700100 0.36700100 +vn 0.85476344 -0.36700100 -0.36700100 +vn -0.85476344 0.36700100 0.36700100 +vn -0.85476344 0.36700100 -0.36700100 +vn -0.85476344 -0.36700100 0.36700100 +vn -0.85476344 -0.36700100 -0.36700100 +vn 0.36700100 0.85476344 0.36700100 +vn 0.36700100 0.85476344 -0.36700100 +vn 0.36700100 -0.85476344 0.36700100 +vn 0.36700100 -0.85476344 -0.36700100 +vn 0.36700100 0.36700100 0.85476344 +vn 0.36700100 0.36700100 -0.85476344 +vn 0.36700100 -0.36700100 0.85476344 +vn 0.36700100 -0.36700100 -0.85476344 +vn -0.36700100 0.85476344 0.36700100 +vn -0.36700100 0.85476344 -0.36700100 +vn -0.36700100 -0.85476344 0.36700100 +vn -0.36700100 -0.85476344 -0.36700100 +vn -0.36700100 0.36700100 0.85476344 +vn -0.36700100 0.36700100 -0.85476344 +vn -0.36700100 -0.36700100 0.85476344 +vn -0.36700100 -0.36700100 -0.85476344 +g octotoad1_default +usemtl default +s 1 +f 1//1 3//3 4//4 2//2 +f 1//1 13//13 15//15 3//3 +f 2//2 10//10 9//9 1//1 +f 2//2 14//14 10//10 +f 3//3 11//11 12//12 4//4 +f 3//3 15//15 11//11 +f 4//4 16//16 14//14 2//2 +f 5//5 17//17 18//18 6//6 +f 5//5 21//21 17//17 +f 6//6 8//8 7//7 5//5 +f 6//6 22//22 24//24 8//8 +f 7//7 23//23 21//21 5//5 +f 8//8 20//20 19//19 7//7 +f 8//8 24//24 20//20 +f 9//9 13//13 1//1 +f 9//9 17//17 21//21 13//13 +f 10//10 18//18 17//17 9//9 +f 11//11 19//19 20//20 12//12 +f 12//12 16//16 4//4 +f 12//12 20//20 24//24 16//16 +f 13//13 21//21 23//23 15//15 +f 14//14 22//22 18//18 10//10 +f 15//15 23//23 19//19 11//11 +f 16//16 24//24 22//22 14//14 +f 18//18 22//22 6//6 +f 19//19 23//23 7//7 diff --git a/3dspin/tetrahedron.obj b/3dspin/tetrahedron.obj new file mode 100644 index 0000000..0a88934 --- /dev/null +++ b/3dspin/tetrahedron.obj @@ -0,0 +1,19 @@ +# Exported from Wings 3D 1.5.4 +mtllib tetrahedron.mtl +o tetrahedron1 +#4 vertices, 4 faces +v 0.0000000e+0 1.08866211 0.0000000e+0 +v 0.0000000e+0 -0.54433105 1.15470054 +v -1.00000000 -0.54433105 -0.57735027 +v 1.00000000 -0.54433105 -0.57735027 +vn 0.0000000e+0 1.00000000 -1.1102230e-16 +vn 0.0000000e+0 -0.33333333 0.94280904 +vn -0.81649658 -0.33333333 -0.47140452 +vn 0.81649658 -0.33333333 -0.47140452 +g tetrahedron1_default +usemtl default +s 1 +f 1//1 3//3 2//2 +f 1//1 4//4 3//3 +f 2//2 4//4 1//1 +f 3//3 4//4 2//2