Mini 3d Engine

Für allgemeine Fragen zur Programmierung mit PureBasic.
TheBauminator
Beiträge: 3
Registriert: 17.08.2015 17:40

Mini 3d Engine

Beitrag von TheBauminator »

hey Leute,
ich hab heut mal versucht eine kleine 3d engine zu schreiben:
http://www.dropbox.com/s/b9r5htqn1fetn2 ... 0.jpg?dl=0

Über eine kleine Karte wird berechnet, was angezeigt werden muss.

Umso weiter entfernt ein objekt ist, umso kleiner ist es.

Code: Alles auswählen

hoehe=600-abstand
Dabei gibt es ein Problem:
Wie auf dem Bild deutlich zu sehen ist, ist das Fischaugenmäßig verzerrt.
Wie kann man das Verhältnis von Abstand und hoehe berechnen, damit es nicht so verzerrt wirkt?
Ich hab schon alles mögliche versucht, aber es klappt irgendwie nie.
Kann mir jemand helfen?
Benutzeravatar
NicTheQuick
Ein Admin
Beiträge: 8820
Registriert: 29.08.2004 20:20
Computerausstattung: Ryzen 7 5800X, 64 GB DDR4-3200
Ubuntu 24.04.2 LTS
GeForce RTX 3080 Ti
Wohnort: Saarbrücken

Re: Mini 3d Engine

Beitrag von NicTheQuick »

Da ich nicht so wirklich weiß, was du da hinten dran noch alles so berechnest, kann ich dir hier schwer helfen. Ein lauffähiges Beispiel wäre besser.
TheBauminator
Beiträge: 3
Registriert: 17.08.2015 17:40

Re: Mini 3d Engine

Beitrag von TheBauminator »

Code: Alles auswählen



If InitSprite() = 0 Or InitKeyboard() = 0 Or ExamineDesktops()=0 Or InitMouse()=0
  MessageRequester("Error", "Sprite system can't be initialized", 0)
  End
 EndIf
 


   

Procedure.f Abstand_Luftlinie(x,y,x2,y2)
  ProcedureReturn Sqr(Abs(x-x2)*Abs(x-x2)+Abs(y-y2)*Abs(y-y2))
EndProcedure

  Structure polygon
  RGB.i
  x1.i
  y1.i
  x2.i
  y2.i
  a1.i ;abstand
  a2.i
  w1.i ;winkel1
  w2.i ;winkel2
  seitwert.i
  EndStructure

Global Dim p.polygon(5000)
Global polyid.i

Procedure Add_polygon(x1,y1,x2,y2,rgb=0,sw=0)
 polyid+1
 p.polygon(polyid)\x1=x1
 p.polygon(polyid)\y1=y1
 p.polygon(polyid)\x2=x2
 p.polygon(polyid)\y2=y2
 p.polygon(polyid)\RGB=rgb
  p.polygon(polyid)\seitwert=sw
EndProcedure

Global Dim Map(15,15)

  For Y = 0 To 14
    For X = 0 To 14
      Read Map(X, Y) 
    Next 
  Next 
  
   For Y = 0*50 To 14*50 Step 50
    For X = 0*50 To 14*50 Step 50
     If Map(X/50, Y/50) =0 Or Map(X/50, Y/50) =2
      If Map(X/50, Y/50) =0:farbe=RGB(255,0,0):Else:farbe=RGB(0,0,255):EndIf
      Add_polygon(X,Y,X+50,Y,farbe,1)       ;1
      Add_polygon(X+50,Y,X+50,Y+50,farbe,2) ;2
      Add_polygon(X+50,Y+50,X,Y+50,farbe,3) ;3
      Add_polygon(X,Y+50,X,Y,farbe,4)       ;4
      
      ;    --1    
      ;           
      ; |4      |2
      ;           
      ;    --3     
      
     EndIf  
    Next 
  Next 
  
 Debug polyid
  
  
  
  
  
  px.f=350
  py.f=450
  pw=0 ;playerwinkel
  field_ofv=70
  backrenderwert=600
  breitenzer=10
  
  
;If OpenScreen(1920, 1080, 32, "mini3dengine",#PB_Screen_NoSynchronization )
If OpenScreen(1920, 1080, 32, "mini3dengine")

 
 CreateSprite(0,50,50)
StartDrawing(SpriteOutput(0))
Box(0,0,50,50,RGB(255,0,0))
StopDrawing()
TransparentSpriteColor(0,RGB(255,255,255))

 CreateSprite(1,50,50)
StartDrawing(SpriteOutput(1))
Box(0,0,50,50,RGB(0,255,0))
StopDrawing()
TransparentSpriteColor(1,RGB(255,255,255))

 CreateSprite(2,50,50)
StartDrawing(SpriteOutput(2))
Box(0,0,50,50,RGB(0,0,255))
StopDrawing()
TransparentSpriteColor(2,RGB(255,255,255))

CreateSprite(20,30,30)
StartDrawing(SpriteOutput(20))
Box(0,0,30,30,RGB(255,255,255))
StopDrawing()


  ;LoadSprite(20, "sichtfeld.bmp")
   ; TransparentSpriteColor(20,RGB(255,255,255))
 
  
  CopySprite(0,30)
    
  CopySprite(2,32)
  
  Structure pxxl
   id.i
   zbuffer.f
   over.i
  EndStructure
   
NewList render.pxxl()
  

  Repeat
    FlipBuffers()
    ClearScreen(RGB(0,0,0))
    
    If 1=0
   For Y = 0 To 14
    For X = 0 To 14
     If Map(X, Y) =0:DisplaySprite(0,X*50,Y*50):EndIf 
     If Map(X, Y) =1:DisplaySprite(1,X*50,Y*50):EndIf
     If Map(X, Y) =2:DisplaySprite(2,X*50,Y*50):EndIf
    Next 
   Next 
    EndIf
    
    For zae=1 To polyid
    x1= p.polygon(zae)\x1
    y1= p.polygon(zae)\y1
     p.polygon(zae)\a1=Abstand_Luftlinie(px,py,x1,y1)
     p.polygon(zae)\w1=Degree(ATan2(px-x1, py-y1))
     
     
    x2= p.polygon(zae)\x2
    y2= p.polygon(zae)\y2
    p.polygon(zae)\a2=Abstand_Luftlinie(px,py,x2,y2)
    p.polygon(zae)\w2=Degree(ATan2(px-x2, py-y2))
    Next
    
    
    
    ClearList(render.pxxl())
    
    For zae=1 To polyid
     If  (p.polygon(zae)\w1>=pw And  p.polygon(zae)\w1<=pw+field_ofv) Or (p.polygon(zae)\w2>=pw And  p.polygon(zae)\w2<=pw+field_ofv)
      
      
      AddElement(render.pxxl())
      render.pxxl()\id=zae 
      
      render.pxxl()\zbuffer=(p.polygon(zae)\a1+p.polygon(zae)\a2)/2
    ;  Debug zae
    ;  StartDrawing(ScreenOutput())
     ;  LineXY(p.polygon(zae)\x1+1,p.polygon(zae)\y1+1,p.polygon(zae)\x2+1,p.polygon(zae)\y2+1,RGB(0,0,255))
     ;StopDrawing()
     ElseIf  (p.polygon(zae)\w1>=pw-360 And  p.polygon(zae)\w1<=pw+field_ofv-360) Or (p.polygon(zae)\w2>=pw-360 And  p.polygon(zae)\w2<=pw+field_ofv-360)
   
       
       AddElement(render.pxxl())
       render.pxxl()\id=zae 
       render.pxxl()\over=1
       render.pxxl()\zbuffer=(p.polygon(zae)\a1+p.polygon(zae)\a2)/2
       
       
     ElseIf  (p.polygon(zae)\w1>=pw+360 And  p.polygon(zae)\w1<=pw+field_ofv+360) Or (p.polygon(zae)\w2>=pw+360 And  p.polygon(zae)\w2<=pw+field_ofv+360)
      Debug "ja"
             
       AddElement(render.pxxl())
       render.pxxl()\id=zae 
       render.pxxl()\over=2
      render.pxxl()\zbuffer=(p.polygon(zae)\a1+p.polygon(zae)\a2)/2
      
     EndIf
    Next 
   
    
  ;  zae=140
    ; StartDrawing(ScreenOutput())
    ;   LineXY(p.polygon(zae)\x1,p.polygon(zae)\y1,p.polygon(zae)\x2,p.polygon(zae)\y2,RGB(255,0,255))
    ; StopDrawing()

    SortStructuredList(render.pxxl(), #PB_Sort_Descending, OffsetOf(pxxl\zbuffer), TypeOf(pxxl\zbuffer))
    FirstElement(render.pxxl())
    ForEach render.pxxl()
   
     zae=render.pxxl()\id
     wert=backrenderwert-p.polygon(zae)\a1
     wert2=backrenderwert-p.polygon(zae)\a2
     
     wert=Sqr((wert*wert)+1000)
     wert2=Sqr((wert2*wert2)+10)
     
     wert=30000/p.polygon(zae)\a1
     wert2=30000/p.polygon(zae)\a2
     ;https://www.dropbox.com/s/z8oureki679kxrm/screen0.bmp?dl=0
     ;https://www.dropbox.com/s/b9r5htqn1fetn2f/screen0.jpg?dl=0
    ; wert=(p.polygon(zae)\a1/Tan(Radian(field_ofv)*0.5))
    ; wert2=(p.polygon(zae)\a2/Tan(Radian(field_ofv)*0.5))
     
     
     
     
     ;Debug "1: "+wert1
     ;Debug "2: "+wert2
     ;If wert<600:wert=0:EndIf
     ;If wert2<600:wert2=0:EndIf
     
      x1=(p.polygon(zae)\w1-pw)*breitenzer
      x4=(p.polygon(zae)\w1-pw)*breitenzer
      
      x2=(p.polygon(zae)\w2-pw)*breitenzer
      x3=(p.polygon(zae)\w2-pw)*breitenzer
      
      If render.pxxl()\over=1
       x1=(p.polygon(zae)\w1-pw+360)*breitenzer
       x4=(p.polygon(zae)\w1-pw+360)*breitenzer
      
       x2=(p.polygon(zae)\w2-pw+360)*breitenzer
       x3=(p.polygon(zae)\w2-pw+360)*breitenzer
      ElseIf render.pxxl()\over=2
       x1=(p.polygon(zae)\w1-pw-360)*breitenzer
       x4=(p.polygon(zae)\w1-pw-360)*breitenzer
      
       x2=(p.polygon(zae)\w2-pw-360)*breitenzer
       x3=(p.polygon(zae)\w2-pw-360)*breitenzer
      EndIf
       
       
        
     y1=-wert+backrenderwert
     y4=wert+backrenderwert
     
     y2=-wert2+backrenderwert
     y3=wert2+backrenderwert
     
     y1-150
     y2-150
     y3-150
     y4-150
     
     If x2<x1 :Swap x1,x2:Swap y1,y2:EndIf 
     If x3<x4 :Swap x3,x4:Swap y3,y4:EndIf 
     
     If p.polygon(zae)\RGB=RGB(255,0,0)
      TransformSprite(30, x1, y1,  x2, y2,  x3, y3,  x4, y4)
      DisplayTransparentSprite(30,800,0)
     Else 
      TransformSprite(32, x1, y1,  x2, y2,  x3, y3,  x4, y4)
      DisplayTransparentSprite(32,800,0)
     EndIf  
     

 
    Next 
  ;

    
    If 1=1
   For Y = 0 To 14
    For X = 0 To 14
     If Map(X, Y) =0:DisplaySprite(0,X*50,Y*50):EndIf 
     If Map(X, Y) =1:DisplaySprite(1,X*50,Y*50):EndIf
     If Map(X, Y) =2:DisplaySprite(2,X*50,Y*50):EndIf
    Next 
   Next 
   EndIf 
   
   RotateSprite(20,pw+field_ofv/2, #PB_Absolute)
    DisplayTransparentSprite(20,px-15,py-15)
    
    ExamineKeyboard()
    key=0
    If KeyboardPushed(#PB_Key_Up)
     dy.f=-Cos(Radian(pw-field_ofv/2))
     dx.f=Sin(Radian(pw-field_ofv/2))
     key=1
    EndIf
    If KeyboardPushed(#PB_Key_Down)
     dy.f=Cos(Radian(pw-field_ofv/2))
     dx.f=-Sin(Radian(pw-field_ofv/2))
     key=1
    EndIf
    If KeyboardPushed(#PB_Key_Left)
     dx.f=-Cos(Radian(pw-field_ofv/2))
     dy.f=-Sin(Radian(pw-field_ofv/2))
     key=1
    EndIf
    If KeyboardPushed(#PB_Key_Right)
     dx.f=Cos(Radian(pw-field_ofv/2))
     dy.f=Sin(Radian(pw-field_ofv/2))
     key=1
    EndIf
    
    If key=1
     py.f+dy
     px.f+dx
    EndIf
     
    ppx=Round((px-25)/50, #PB_Round_Nearest)
    ppy=Round((py-25)/50, #PB_Round_Nearest)
    If Map(ppx,ppy)=0 Or Map(ppx,ppy)=2

     wand=1
     py.f-dy
     px.f-dx
    EndIf 
    
    
    If KeyboardPushed(#PB_Key_Period):pw+3:EndIf
    If KeyboardPushed(#PB_Key_Comma):pw-3:EndIf
    
    ;pw+1

    pw+MouseDeltaX()/3
    
    If pw>180:pw-360:EndIf
    If pw<-180:pw+360:EndIf
    ax=px
    ay=py
    ExamineMouse()
    bx=MouseX()
    by=MouseY()
    winkl=Degree(ATan2(Ax-Bx, Ay-By))

    ;DisplayTransparentSprite(500,MouseX(),MouseY())
    
    
    If KeyboardReleased(#PB_Key_F1)
     GrabSprite(1000,0,0,1920,1080)
     SaveSprite(1000, "screen"+Str(Date())+".bmp")
     sh+1
    EndIf
  Until KeyboardPushed(#PB_Key_Escape)
  
Else
  MessageRequester("Error", "Can't open screen !", 0)
 EndIf
 
 

 
 DataSection
  Data.i 0,0,0,0,0,0,2,2,2,0,0,0,0,0,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 2,1,1,1,1,0,2,0,0,1,1,1,1,1,2
  Data.i 2,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,2,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,1,1,1,1,1,1,1,1,1,1,1,1,1,0
  Data.i 0,0,2,0,0,0,0,0,0,0,0,0,0,0,0
 EndDataSection
Benutzeravatar
STARGÅTE
Kommando SG1
Beiträge: 7035
Registriert: 01.11.2005 13:34
Wohnort: Glienicke
Kontaktdaten:

Re: Mini 3d Engine

Beitrag von STARGÅTE »

Ohne dein Code komplett verstanden zu haben, kann ich dir sagen, dass die Formel falsch ist:
hoehe=600-abstand

Nach deine Formel, würde es ja irgendwann sogar 0 werden.

Im allgemeinen Errechnen sich die U,V-Bildschirmkoordinaten mit folgenden Formeln aus den relativen X,Y,Z-Koordinaten:
U = X*d / Z
V = Y*d / Z
Wobei d zB durch d = ScreenHeight / Tan(Radian(FieldOfView)*0.5) errechnet werden kann.

Du dividierst also deine 3D-Koordinaten durch den Abstand von der Camera.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Aktuelles Projekt: Lizard - Skriptsprache für symbolische Berechnungen und mehr
TheBauminator
Beiträge: 3
Registriert: 17.08.2015 17:40

Re: Mini 3d Engine

Beitrag von TheBauminator »

Danke!
Irgend sowas mit Tan(Radian(fieldofview))*0.5 hab ich im Internet auch gefunden,
aber nicht mit einer genauen formel
Antworten