I copied a code of YouTube, about displaying 3d cubes on a screen in Python, without the use of external modules (like PyOpenGL). It works fine, but the moment you go between tw
The application does not correctly draw the geometry, when apart of a faces (primitive, side of a cube) is behind and the other part in front of the eye position. That happens if the transformed z coordinate (vert_list += [(x,y,z)]
) is positive for the some vertices and negative for negative for some other vertices that form primitive (face).
You can test that behavior with ease, if you skip all the faces, where at least one z coordinate is negative (behind the eye):
while True:
# [...]
for obj in objects:
# [...]
for f in range(len(obj.faces)):
face = obj.faces[f]
#on_screen = False
#for i in face:
# x,y = screen_coords[i]
# if vert_list[i][2]>0 and x>0 and x<w and y>0 and y<h: on_screen = True; break
# draw a face if any projected coordinate (x, y) is in the viewing volume
on_screen = False
for i in face:
x,y = screen_coords[i]
if x>0 and x<w and y>0 and y<h: on_screen = True; break
# skip a face if NOT ALL z coordinates are positive
if on_screen:
on_screen = all([vert_list[i][2]>0 for i in face])
if on_screen:
# [...]
The issue can be solved by clipping the geometry at hypothetical near plane. See Viewing frustum:
while True:
# [...]
for obj in objects:
# [...]
for f in range(len(obj.faces)):
face = obj.faces[f]
on_screen = False
for i in face:
x,y = screen_coords[i]
if vert_list[i][2]>0 and x>0 and x<w and y>0 and y<h: on_screen = True; break
# clip geometry at near plane
if on_screen:
near = 0.01
for i in face:
if vert_list[i][2]<0:
x, y, z = vert_list[i]
nearscale = 200/near
x,y = x*nearscale,y*nearscale
screen_coords[i] = (cx+int(x),cy+int(y))
if on_screen:
coords = [screen_coords[i] for i in face]
face_list += [coords]
face_color += [obj.colors[f]]
depth += [sum(sum(vert_list[j][i]**2 for i in range(3)) for j in face) / len(face)]