Files
terrain_generator/main.py
T

183 lines
5.3 KiB
Python

import window
import math
import copy
from matrix import Matrix4x4, Matrix3x3
from vectors import Vector4d, Vector3d, Vector2d
from engine import Mesh
from triangle import Triangle
ui = window.Window(600, 600)
near_plane = 0.1
far_plane = 1000.0
fov = 90.0
#'''
tris =[
Matrix3x3(Vector3d(0.0,0.0,0.0),Vector3d(0.0,1.0,0.0),Vector3d(1.0,1.0,0.0)),
Matrix3x3(Vector3d(0.0,0.0,0.0),Vector3d(1.0,1.0,0.0),Vector3d(1.0,0.0,0.0)),
Matrix3x3(Vector3d(1.0,0.0,0.0),Vector3d(1.0,1.0,0.0),Vector3d(1.0,1.0,1.0)),
Matrix3x3(Vector3d(1.0,0.0,0.0),Vector3d(1.0,1.0,1.0),Vector3d(1.0,0.0,1.0)),
Matrix3x3(Vector3d(1.0,0.0,1.0),Vector3d(1.0,1.0,1.0),Vector3d(0.0,1.0,1.0)),
Matrix3x3(Vector3d(1.0,0.0,1.0),Vector3d(0.0,1.0,1.0),Vector3d(0.0,0.0,1.0)),
Matrix3x3(Vector3d(0.0,0.0,1.0),Vector3d(0.0,1.0,1.0),Vector3d(0.0,1.0,0.0)),
Matrix3x3(Vector3d(0.0,0.0,1.0),Vector3d(0.0,1.0,0.0),Vector3d(0.0,0.0,0.0)),
Matrix3x3(Vector3d(0.0,1.0,0.0),Vector3d(0.0,1.0,1.0),Vector3d(1.0,1.0,1.0)),
Matrix3x3(Vector3d(0.0,1.0,0.0),Vector3d(1.0,1.0,1.0),Vector3d(1.0,1.0,0.0)),
Matrix3x3(Vector3d(1.0,0.0,1.0),Vector3d(0.0,0.0,1.0),Vector3d(0.0,0.0,0.0)),
Matrix3x3(Vector3d(1.0,0.0,1.0),Vector3d(0.0,0.0,0.0),Vector3d(1.0,0.0,0.0))
]
#'''
#tris = Mesh()
def main():
#tris.load_obj_file('teddy.obj')
ui.thetax = 1
ui.thetay = 1
ui.window.bind('<Left>', left)
ui.window.bind('<Right>', right)
ui.window.bind('<Up>', up)
ui.window.bind('<Down>', down)
ui.window.bind('<ButtonPress-1>', mouse_start)
ui.canvas.bind('<B1-Motion>', mouse_end)
ui.canvas.old_coords = None
ui.window.after(0, draw_scene)
ui.show()
def left(event):
ui.thetax -= .1
draw_scene()
def right(event):
ui.thetax += .1
draw_scene()
def up(event):
ui.thetay += .1
draw_scene()
def down(event):
ui.thetay -= .1
draw_scene()
def mouse_start(event):
ui.canvas.old_coords = event.x, event.y
def mouse_end(event):
x, y = event.x - ui.width / 2, event.y - ui.height / 2#ui.canvas.old_coords[0] - event.x, ui.canvas.old_coords[1] - event.y
if x < 0:
ui.thetax -= .01
else:
ui.thetax += .01
if y < 0:
ui.thetay -= .01
else:
ui.thetay += .01
draw_scene()
#ui.theta += x / ui.width
def draw_scene():
ui.canvas.delete("all")
#ui.theta += .01 # scaling factor
aspect_ratio = ui.height / ui.width
projection_matrix = Matrix4x4.get_projection_matrix(fov, aspect_ratio, near_plane, far_plane)
rotation_matrix_y = Matrix4x4.get_y_rotation_matrix(ui.thetax)
rotation_matrix_x = Matrix4x4.get_x_rotation_matrix(ui.thetay)
triangles = []
for tri in tris:
# Rotate on the z-axis
row1 = rotation_matrix_y.multiply_3d(tri.row1)
row2 = rotation_matrix_y.multiply_3d(tri.row2)
row3 = rotation_matrix_y.multiply_3d(tri.row3)
rotated_y = Matrix3x3(row1, row2, row3)
# Rotate on the x-axis
row1 = rotation_matrix_x.multiply_3d(rotated_y.row1)
row2 = rotation_matrix_x.multiply_3d(rotated_y.row2)
row3 = rotation_matrix_x.multiply_3d(rotated_y.row3)
rotated_x = Matrix3x3(row1, row2, row3)
# The offset into the screen
translated = copy.copy(rotated_x)
translated.row1.z += 3.0
translated.row2.z += 3.0
translated.row3.z += 3.0
# Use cross-product to get the surface normal (a Vector3d)
x = translated.row2.x - translated.row1.x
y = translated.row2.y - translated.row1.y
z = translated.row2.z - translated.row1.z
line1 = Vector3d(x, y, z)
x = translated.row3.x - translated.row1.x
y = translated.row3.y - translated.row1.y
z = translated.row3.z - translated.row1.z
line2 = Vector3d(x, y, z)
normal = line1.cross_product(line2)
# Now we normalize the normal
length = math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z)
normal.x /= length
normal.y /= length
normal.z /= length
# Do we display this triangle?
if normal.dot_product(translated.row1) < 0.0:
# Lighting
light = Vector3d(0, 0, -1) # Shining at the player.
length = math.sqrt(light.x * light.x + light.y * light.y + light.z * light.z)
light.x /= length
light.y /= length
light.z /= length
dot_product = normal.dot_product(light)
r = abs(int(255 * dot_product))
# Scale into view
row1 = projection_matrix.multiply_3d(translated.row1)
row2 = projection_matrix.multiply_3d(translated.row2)
row3 = projection_matrix.multiply_3d(translated.row3)
projected = Matrix3x3(row1, row2, row3)
projected.row1.x += 1
projected.row1.y += 1
projected.row2.x += 1
projected.row2.y += 1
projected.row3.x += 1
projected.row3.y += 1
projected.row1.x *= .5 * ui.width
projected.row1.y *= .5 * ui.height
projected.row2.x *= .5 * ui.width
projected.row2.y *= .5 * ui.height
projected.row3.x *= .5 * ui.width
projected.row3.y *= .5 * ui.height
t = Triangle(projected)
t.color = r
t.average = (t.coords.row1.z + t.coords.row2.z + t.coords.row3.z) / 3
triangles.append(t)
# Sort the triangles so they are drawn in order.
triangles.sort(key=lambda r: r.average, reverse = True)
for projected in triangles:
r = projected.color
coords = [projected.coords.row1.x, projected.coords.row1.y, projected.coords.row2.x, projected.coords.row2.y, projected.coords.row3.x, projected.coords.row3.y]
ui.canvas.create_polygon(coords, fill=from_rgb(r, r, r), outline="black")
ui.canvas.update()
#ui.canvas.after(100, draw_scene)
def from_rgb(r, b, g):
return "#%02x%02x%02x" %(r, g, b)
main()