0

I am making a very basic 3d engine. When I render 2 or more objects, it draws lines between them. I do not know why this happens, as I coded the pen to go up after drawing every triangle. A strange thing is that when I draw a background line, each object also draws lines to the background line. I am confused. There is only 1 reason I could think of; it uses the last point of the other object as the first point of the first triangle of the main object. However, it does not seem like this is the case, as it is even happening with a simple line in the background as well.

from turtle import*
from time import*
from math import*
wn=Screen()
speed(0)
ht()
pu()
wn.tracer(0,0)
fov=200
camx=0
camy=0
camz=-5
xoff=0
yoff=0
zoff=0
xrot=pi*2
yrot=pi
zrot=pi
def goto3d(x,y,z):
  rotxx=x
  rotxy=y*cos(yrot)-z*sin(yrot)
  rotxz=y*sin(yrot)+z*cos(yrot)
  rotyx=rotxx*cos(xrot)+rotxz*sin(xrot)
  rotyy=rotxy
  rotyz=rotxz*cos(xrot)-rotxx*sin(xrot)
  rotzx=rotyx*cos(zrot)-rotyy*sin(zrot)
  rotzy=rotyx*sin(zrot)+rotyy*cos(zrot)
  rotzz=rotyz
  transx=rotzx-xoff
  transy=rotzy-yoff
  transz=rotzz-zoff
  newx=fov*transx/transz
  newy=fov*transy/transz
  if transz<0.1 or newx<=-200 or newy<=-200 or newx>=200 or newy>=200:
    return
  goto(newx,newy)
def triangle(p1x,p1y,p1z,p2x,p2y,p2z,p3x,p3y,p3z):
  goto3d(p1x,p1y,p1z)
  pd()
  goto3d(p2x,p2y,p2z)
  goto3d(p3x,p3y,p3z)
  goto3d(p1x,p1y,p1z)
  pu()
def face(p1x,p1y,p1z,p2x,p2y,p2z,p3x,p3y,p3z,p4x,p4y,p4z,r,g,b,a):
  fillcolor(r,g,b,a)
  begin_fill()
  triangle(p1x,p1y,p1z,p2x,p2y,p2z,p3x,p3y,p3z)
  end_fill()
  begin_fill()
  triangle(p2x,p2y,p2z,p3x,p3y,p3z,p4x,p4y,p4z)
  end_fill()
def bbox(x,y,z,w,h,l,r,g,b,a):
  x+=camx
  y+=camy
  z+=camz
  face(x+-w,y+h,z+l,x+w,y+h,z+l,x+-w,y+-h,z+l,x+w,y+-h,z+l,r,g,b,a)
  face(x+-w,y+h,z+-l,x+w,y+h,z+-l,x+-w,y+-h,z+-l,x+w,y+-h,z+-l,r,g,b,a)
  face(x+-w,y+h,z+l,x+-w,y+h,z+-l,x+-w,y+-h,z+l,x+-w,y+-h,z+-l,r,g,b,a)
  face(x+w,y+h,z+l,x+w,y+h,z+-l,x+w,y+-h,z+l,x+w,y+-h,z+-l,r,g,b,a)
  face(x+-w,y+-h,z+l,x+-w,y+-h,z+-l,x+w,y+-h,z+l,x+w,y+-h,z+-l,r,g,b,a)
  face(x+-w,y+h,z+l,x+-w,y+h,z+-l,x+w,y+h,z+l,x+w,y+h,z+-l,r,g,b,a)
def box(x,y,z,w,h,l,r,g,b):
  if w>=2 or h>=2 or l>=2:
    bbox(x-(w/4),y-(h/4),z-(l/4),w/4,h/4,l/4,r,g,b,.2)
    bbox(x+(w/4),y-(h/4),z-(l/4),w/4,h/4,l/4,r,g,b,.2)
    bbox(x+(w/4),y+(h/4),z-(l/4),w/4,h/4,l/4,r,g,b,.2)
    bbox(x-(w/4),y+(h/4),z-(l/4),w/4,h/4,l/4,r,g,b,.2)
    bbox(x-(w/4),y-(h/4),z+(l/4),w/4,h/4,l/4,r,g,b,.2)
    bbox(x+(w/4),y-(h/4),z+(l/4),w/4,h/4,l/4,r,g,b,.2)
    bbox(x+(w/4),y+(h/4),z+(l/4),w/4,h/4,l/4,r,g,b,.2)
    bbox(x-(w/4),y+(h/4),z+(l/4),w/4,h/4,l/4,r,g,b,.2)
  else:
    bbox(x,y,z,w,h,l,r,g,b,.5)
def render():
  goto(-200,-5)
  pd()
  goto(200,-5)
  pu()
  ### ||| objects go here ||| ###
  ### ||| format is box(x,y,z,width,height,length,r,g,b) ||| ###
  box(2,0,-5,2,2,2,0,255,255)
  box(0,0,0,1,1,1,255,0,0)
def tl():
  global xrot
  xrot-=pi/40
def tr():
  global xrot
  xrot+=pi/40
def f():
  global camx
  global camz
  camz+=.3*cos(-xrot)
  camx+=-(.3*sin(-xrot))
def b():
  global camx
  global camz
  camz+=-(.3*cos(-xrot))
  camx+=.3*sin(-xrot)
wn.onkey(tl,'Left')
wn.onkey(tr,'Right')
wn.onkey(f,'Up')
wn.onkey(b,'Down')
wn.listen()
while True:
  clear()
  render()
  update()

1 Answers1

0

When I render 2 or more objects, it draws lines between them. I do not know why this happens

The problem happens even when you only have one object -- comment out your first (small blue) box and just move the second (large red) one:

enter image description here

The problem is in goto3d() and triangle() as goto3d() has a failure situation (which it tests for) that it doesn't signal back to triangle() so it goes ahead and continues drawing.

Below is my rework of your code to patch this issue (and translate the code into Python ;-)

from turtle import Screen, Turtle
from math import pi, sin, cos

fov = 200

camx = 0
camy = 0
camz = -5

xoff = 0
yoff = 0
zoff = 0

xrot = pi * 2
yrot = pi
zrot = pi

def goto3d(x, y, z):
    rotxx = x
    rotxy = y * cos(yrot) - z * sin(yrot)
    rotxz = y * sin(yrot) + z * cos(yrot)
    rotyx = rotxx * cos(xrot) + rotxz * sin(xrot)
    rotyy = rotxy
    rotyz = rotxz * cos(xrot) - rotxx * sin(xrot)
    rotzx = rotyx * cos(zrot) - rotyy * sin(zrot)
    rotzy = rotyx * sin(zrot) + rotyy * cos(zrot)
    rotzz = rotyz

    transx = rotzx - xoff
    transy = rotzy - yoff
    transz = rotzz - zoff

    if transz < 0.1:
        return False

    newx = fov * transx/transz
    newy = fov * transy/transz

    if not -200 < newx < 200 or not -200 < newy < 200:
        return False

    turtle.goto(newx, newy)

    return True

def triangle(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z):
    if goto3d(p1x, p1y, p1z):

        turtle.pendown()
        turtle.begin_fill()
        goto3d(p2x, p2y, p2z)
        goto3d(p3x, p3y, p3z)
        goto3d(p1x, p1y, p1z)
        turtle.end_fill()
        turtle.penup()

def face(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z, p4x, p4y, p4z, color):
    turtle.fillcolor(color)

    triangle(p1x, p1y, p1z, p2x, p2y, p2z, p3x, p3y, p3z)
    triangle(p2x, p2y, p2z, p3x, p3y, p3z, p4x, p4y, p4z)

def bbox(x, y, z, w, h, l, color):
    x += camx
    y += camy
    z += camz

    face(x - w, y + h, z + l, x + w, y + h, z + l, x - w, y - h, z + l, x + w, y - h, z + l, color)
    face(x - w, y + h, z - l, x + w, y + h, z - l, x - w, y - h, z - l, x + w, y - h, z - l, color)
    face(x - w, y + h, z + l, x - w, y + h, z - l, x - w, y - h, z + l, x - w, y - h, z - l, color)
    face(x + w, y + h, z + l, x + w, y + h, z - l, x + w, y - h, z + l, x + w, y - h, z - l, color)
    face(x - w, y - h, z + l, x - w, y - h, z - l, x + w, y - h, z + l, x + w, y - h, z - l, color)
    face(x - w, y + h, z + l, x - w, y + h, z - l, x + w, y + h, z + l, x + w, y + h, z - l, color)

def box(x, y, z, w, h, l, color):
    if w >= 2 or h >= 2 or l >= 2:
        # transparent_color = (*color, 0.2)
        transparent_color = color

        bbox(x - w/4, y - h/4, z - l/4, w/4, h/4, l/4, transparent_color)
        bbox(x + w/4, y - h/4, z - l/4, w/4, h/4, l/4, transparent_color)
        bbox(x + w/4, y + h/4, z - l/4, w/4, h/4, l/4, transparent_color)
        bbox(x - w/4, y + h/4, z - l/4, w/4, h/4, l/4, transparent_color)
        bbox(x - w/4, y - h/4, z + l/4, w/4, h/4, l/4, transparent_color)
        bbox(x + w/4, y - h/4, z + l/4, w/4, h/4, l/4, transparent_color)
        bbox(x + w/4, y + h/4, z + l/4, w/4, h/4, l/4, transparent_color)
        bbox(x - w/4, y + h/4, z + l/4, w/4, h/4, l/4, transparent_color)
    else:
        # transparent_color = (*color, 0.5)
        transparent_color = color

        bbox(x, y, z, w, h, l, transparent_color)

def render():
    turtle.clear()
    turtle.goto(-200, -5)
    turtle.pendown()
    turtle.goto(200, -5)
    turtle.penup()

    ### ||| objects go here ||| ###
    ### ||| format is box(x, y, z, width, height, length, (r, g, b)) ||| ###
    box(2, 0, -5, 2, 2, 2, (0, 255, 255))
    box(0, 0, 0, 1, 1, 1, (255, 0, 0))

    screen.update()
    screen.ontimer(render)

def tl():
    global xrot
    xrot -= pi/40

def tr():
    global xrot
    xrot += pi/40

def f():
    global camx, camz

    camz += 0.3 * cos(-xrot)
    camx += -(0.3 * sin(-xrot))

def b():
    global camx, camz

    camz += -(0.3 * cos(-xrot))
    camx += 0.3 * sin(-xrot)

screen = Screen()
screen.tracer(0)
screen.colormode(255)

turtle = Turtle()
turtle.hideturtle()
turtle.penup()

screen.onkey(tl, 'Left')
screen.onkey(tr, 'Right')
screen.onkey(f, 'Up')
screen.onkey(b, 'Down')
screen.listen()

render()

screen.mainloop()

I disabled transparency as my system doesn't support it, but you can uncomment the appropriate lines to put it back.

cdlane
  • 40,441
  • 5
  • 32
  • 81