Added a very simple light source so the 3D models now have simple shading applied to them.

This commit is contained in:
2020-07-15 04:12:39 -05:00
parent 05d2beb8ac
commit 34f5917359
4 changed files with 98 additions and 32 deletions
+2 -3
View File
@@ -1,5 +1,6 @@
from vectors import Vector2d, Vector3d, Vector4d from vectors import Vector2d, Vector3d, Vector4d
from matrix import Matrix3x3 from matrix import Matrix3x3
from triangle import Triangle
class Engine: class Engine:
def __init__(self, width, height): def __init__(self, width, height):
@@ -41,6 +42,4 @@ class Mesh:
row1 = self.vertices[int(tmp[2]) - 1] row1 = self.vertices[int(tmp[2]) - 1]
row2 = self.vertices[int(tmp[3]) - 1] row2 = self.vertices[int(tmp[3]) - 1]
tri = Matrix3x3(row0, row1, row2) self.triangles.append(Triangle(Matrix3x3(row0, row1, row2)))
self.triangles.append(tri)#Vector3d(x - 1, y - 1, z - 1))
+88 -28
View File
@@ -4,16 +4,31 @@ import copy
from matrix import Matrix4x4, Matrix3x3 from matrix import Matrix4x4, Matrix3x3
from vectors import Vector4d, Vector3d, Vector2d from vectors import Vector4d, Vector3d, Vector2d
from engine import Mesh from engine import Mesh
from triangle import Triangle
ui = window.Window(600, 600) ui = window.Window(600, 600)
near_plane = 0.1 near_plane = 0.1
far_plane = 1000.0 far_plane = 1000.0
fov = 90.0 fov = 90.0
tris = Mesh() 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(): def main():
tris.load_obj_file('shuttle.obj') #tris.load_obj_file('shuttle.obj')
ui.thetax = 1 ui.thetax = 1
ui.window.bind('<Left>', left) ui.window.bind('<Left>', left)
@@ -31,8 +46,7 @@ def right(event):
ui.theta += .01 ui.theta += .01
def mouse_start(event): def mouse_start(event):
#x, y = ui.canvas.old_coords = event.x, event.y
ui.canvas.old_coords = event.x, event.y #x, y
def mouse_end(event): def mouse_end(event):
x, y = ui.canvas.old_coords[0] - event.x, ui.canvas.old_coords[1] - event.y x, y = ui.canvas.old_coords[0] - event.x, ui.canvas.old_coords[1] - event.y
@@ -47,6 +61,8 @@ def mouse_end(event):
ui.thetax += .01 ui.thetax += .01
else: else:
ui.thetax -= .01 ui.thetax -= .01
draw_scene()
#ui.theta += x / ui.width #ui.theta += x / ui.width
def draw_scene(): def draw_scene():
@@ -76,7 +92,9 @@ def draw_scene():
rotation_matrix_x = Matrix4x4(row0, row1, row2, row3) rotation_matrix_x = Matrix4x4(row0, row1, row2, row3)
for tri in tris.triangles: triangles = []
for tri in tris:
# Rotate on the z-axis # Rotate on the z-axis
row0 = rotation_matrix_z.multiply_3d(tri.row0) row0 = rotation_matrix_z.multiply_3d(tri.row0)
row1 = rotation_matrix_z.multiply_3d(tri.row1) row1 = rotation_matrix_z.multiply_3d(tri.row1)
@@ -91,34 +109,76 @@ def draw_scene():
rotated_x = Matrix3x3(row0, row1, row2) rotated_x = Matrix3x3(row0, row1, row2)
# The offset into the screen # The offset into the screen
translated = copy.copy(rotated_x) translated = copy.copy(rotated_x)
translated.row0.z += 8.0 translated.row0.z += 3.0
translated.row1.z += 8.0 translated.row1.z += 3.0
translated.row2.z += 8.0 translated.row2.z += 3.0
# Scale into view
row0 = projection_matrix.multiply_3d(translated.row0)
row1 = projection_matrix.multiply_3d(translated.row1)
row2 = projection_matrix.multiply_3d(translated.row2)
projected = Matrix3x3(row0, row1, row2) # Use cross-product to get the surface normal (a Vector3d)
x = translated.row1.x - translated.row0.x
y = translated.row1.y - translated.row0.y
z = translated.row1.z - translated.row0.z
line1 = Vector3d(x, y, z)
projected.row0.x += 1 x = translated.row2.x - translated.row0.x
projected.row0.y += 1 y = translated.row2.y - translated.row0.y
projected.row1.x += 1 z = translated.row2.z - translated.row0.z
projected.row1.y += 1 line2 = Vector3d(x, y, z)
projected.row2.x += 1
projected.row2.y += 1
projected.row0.x *= .5 * ui.width
projected.row0.y *= .5 * ui.height
projected.row1.x *= .5 * ui.width
projected.row1.y *= .5 * ui.height
projected.row2.x *= .5 * ui.width
projected.row2.y *= .5 * ui.height
coords = [projected.row0.x, projected.row0.y, projected.row1.x, projected.row1.y, projected.row2.x, projected.row2.y] normal = line1.cross_product(line2)
ui.canvas.create_polygon(coords, fill="", outline="black")
# Now we normalize the normal
w = math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z)
normal.x /= w
normal.y /= w
normal.z /= w
# Do we display this triangle?
if normal.dot_product(translated.row0) < 0.0:
# Lighting
light = Vector3d(0, 0, -1) # Shining at the player.
w = math.sqrt(light.x * light.x + light.y * light.y + light.z * light.z)
light.x /= w
light.y /= w
light.z /= w
dot_product = normal.dot_product(light)
r = abs(int(255 * dot_product))
# Scale into view
row0 = projection_matrix.multiply_3d(translated.row0)
row1 = projection_matrix.multiply_3d(translated.row1)
row2 = projection_matrix.multiply_3d(translated.row2)
projected = Matrix3x3(row0, row1, row2)
projected.row0.x += 1
projected.row0.y += 1
projected.row1.x += 1
projected.row1.y += 1
projected.row2.x += 1
projected.row2.y += 1
projected.row0.x *= .5 * ui.width
projected.row0.y *= .5 * ui.height
projected.row1.x *= .5 * ui.width
projected.row1.y *= .5 * ui.height
projected.row2.x *= .5 * ui.width
projected.row2.y *= .5 * ui.height
t = Triangle(projected)
t.color = r
triangles.append(t)
for projected in triangles:
r = projected.color
coords = [projected.coords.row0.x, projected.coords.row0.y, projected.coords.row1.x, projected.coords.row1.y, projected.coords.row2.x, projected.coords.row2.y]
ui.canvas.create_polygon(coords, fill=from_rgb(r, r, r), outline="black")
ui.canvas.update() ui.canvas.update()
ui.canvas.after(100, draw_scene) #ui.canvas.after(100, draw_scene)
def from_rgb(r, b, g):
return "#%02x%02x%02x" %(r, g, b)
main() main()
+7
View File
@@ -0,0 +1,7 @@
import vectors
class Triangle:
def __init__(self, coords):
self.coords = coords # Matrix3x3
self.object_id = None
self.color = None
+1 -1
View File
@@ -17,7 +17,7 @@ class Vector3d:
# Returns the 'normal'. # Returns the 'normal'.
x = self.y * vector3d.z - self.z * vector3d.y x = self.y * vector3d.z - self.z * vector3d.y
y = self.z * vector3d.x - self.x * vector3d.z y = self.z * vector3d.x - self.x * vector3d.z
z = self.x * vectored.y - self.y * vector3d.x z = self.x * vector3d.y - self.y * vector3d.x
return Vector3d(x, y, z) return Vector3d(x, y, z)