Seite 1 von 1

Mini 3d Engine

Verfasst: 17.08.2015 17:54
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?

Re: Mini 3d Engine

Verfasst: 17.08.2015 18:11
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.

Re: Mini 3d Engine

Verfasst: 17.08.2015 18:26
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

Re: Mini 3d Engine

Verfasst: 17.08.2015 18:50
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.

Re: Mini 3d Engine

Verfasst: 17.08.2015 19:03
von TheBauminator
Danke!
Irgend sowas mit Tan(Radian(fieldofview))*0.5 hab ich im Internet auch gefunden,
aber nicht mit einer genauen formel