"Kleines 3D"

Hier könnt Ihr gute, von Euch geschriebene Codes posten. Sie müssen auf jeden Fall funktionieren und sollten möglichst effizient, elegant und beispielhaft oder einfach nur cool sein.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

"Kleines 3D"

Beitrag von Kekskiller »

Mich hatte am Wochendende die Wut gepackt und ich musste spontan das Basiswissen über Vektoren lernen. Nach dem ich enttäuscht feststellen musste, dass das Hautpproblem ja ohnehin das Rendern ist, habe ich mich dem Rendern zugewandt.

Ein zufällig generiertes Bild aus Wire-Frame-Polygonen:
Bild

Der Code ist noch nicht vollständig und das 3D-Objekt kann bisher nur auf der Y-Achse rotiert werden. Ich werde den Code eigenmächtig erweitern und versuchen, irgendwie eine Art Renderer hinzubekommen...

Ich bin offen für Vorschläge jeder Art :allright: . Aber ich möchte keinen hier erwischen, der hier ganze 3D-Berechnungen reinstellt :doh: . Höchstens ein paar Denkanstöße :)

Das Ergebnis (unvollständig) sieht bisher so aus:

Code: Alles auswählen

;{-iso3d
Structure gVector
  X.f
  Y.f
  Z.f
  color.l
  xPlot.l;letztes x auf screen
  yPlot.l;letztes y auf screen
EndStructure

Structure gPolygon
  Alpha.gVector
  Betha.gVector
  Gamma.gVector
EndStructure

Structure gQuad
  Alpha.gVector
  Betha.gVector
  Gamma.gVector
  Delta.gVector
EndStructure

Structure gCam
  X.f ;x-verschiebung des mittelpunktes
  Y.f ;y-verschiebung des mittelpunktes
  Rotation.l ;die rotation der kamera um den mittelpunkt.
EndStructure

Structure gScreen
  aspectX.f;aspekt von briete und höhe (kleinste seite = 1.0
  aspectY.f;
  UnitVectorSize.f;größe eines einheitsvektor auf dem bildschirm (abhängig von der bildschirmgröße)
  sizeX.l;größte des bildschirms
  sizeY.l;
  UVsizeX.f;vorberechnete UnitVectorGrößen fürs Rendern
  UVsizeY.f;
EndStructure

Structure gScene
  gMaxUnitSize.l ;größte größe eines vektorgebildes
  p_gSceneVectors.l ;zeiger auf szenen-speicher (wird nur bei alloziieren verändert)
  p_gLastChangedVector.l ;pointer auf letzten veränderten vektor (schneller beim speichern)
  gSceneSize.l ;größe des Szenenspeichers
  gVectorsInScene.l ;anzahl vektoren im Szenenspeicher
  gMaxPossibleVectors.l ;maximale anzahl von vektoren, die in eine szene passen
EndStructure

;{-konstanten
#gType_Vec = 0 
#gType_Poly = 1
#gType_PolyEnd = 2
#gType_Quad = 3 

#gType_Line_Part = 3 ;teil oder anfang einer linie
#gType_Line_End = 4 ;endstück einer linie (MUSS immer letztes element sein

#gPoke_X = 1
#gPoke_Y = #gPoke_X + SizeOf(Float)
#gPoke_Z = #gPoke_Y + SizeOf(Float)
#gPoke_Col = #gPoke_Z + SizeOf(Float)

#gFlags_Non = 0
#gFlags_DrawAxis = 1
#gFlags_SetUpScreen_StretchUV = 2

#gDegree_45 = 0.785398
#gDegree_90 = 1.570796

#gCOLOR_AXIS_TEXT = $FFFFFF
#gCOLOR_X_AXIS = $FF0000
#gCOLOR_Y_AXIS = $0000FF
#gCOLOR_Z_AXIS = $00FF00

#gAXIS_X_VECTOR_X = 1
#gAXIS_X_VECTOR_Y = 0
#gAXIS_X_VECTOR_Z = 0

#gAXIS_Y_VECTOR_X = 0
#gAXIS_Y_VECTOR_Y = 1
#gAXIS_Y_VECTOR_Z = 0

#gAXIS_Z_VECTOR_X = 0
#gAXIS_Z_VECTOR_Y = 0
#gAXIS_Z_VECTOR_Z = 1
;}-
Procedure.f AngleToSin(angle.w)
  s.f = (#PI / 180) * angle
  ProcedureReturn s
EndProcedure

Procedure gSetUpScreen(*screen.gScreen, sizeX.l,sizeY.l, uvs.f, flags)
  *screen\sizeX = sizeX
  *screen\sizeY = sizeY
  
  If *screen\sizeX > *screen\sizeY
    *screen\aspectX = *screen\sizeX / *screen\sizeY
    *screen\aspectY = 1.0
  ElseIf *screen\sizeY > *screen\sizeX
    *screen\aspectX = 1.0
    *screen\aspectY = *screen\sizeY / *screen\sizeX
  EndIf
  
  *screen\UnitVectorSize = uvs
  
  If flags & #gFlags_SetUpScreen_StretchUV
    ;vorberechnete UV-Größen (Einheitsvektorgröße auf dem Bildschirm)
    *screen\UVsizeX = *screen\UnitVectorSize * *screen\aspectX
    *screen\UVsizeY = *screen\UnitVectorSize * *screen\aspectY
  Else
    *screen\UVsizeX = *screen\UnitVectorSize
    *screen\UVsizeY = *screen\UnitVectorSize
  EndIf
EndProcedure

Procedure gNewScene(*scene.gScene, vectors.l, gMaxUnitSize=1+SizeOf(gQuad))
  *scene\gMaxUnitSize = gMaxUnitSize
  *scene\p_gSceneVectors = AllocateMemory(vectors * gMaxUnitSize)
  *scene\p_gLastChangedVector = *scene\p_gSceneVectors
  *scene\gMaxPossibleVectors = vectors
  *scene\gVectorsInScene = 0
  *scene\gSceneSize = vectors * *scene\gMaxUnitSize
EndProcedure

Procedure gAddVectorDirect(*scene.gScene, vectortype.b, X.f, Y.f, Z.f, c.l)
  ;pointer auf letzten vektor um eine unitgröße erhöhen (wenn überhaupt gesetzt)
  If *scene\gVectorsInScene > 0
    *scene\p_gLastChangedVector + *scene\gMaxUnitSize
  EndIf
  ;type poken
  PokeB(*scene\p_gLastChangedVector, vectortype)
  ;daten sichern
  PokeF(*scene\p_gLastChangedVector + #gPoke_X, X)
  PokeF(*scene\p_gLastChangedVector + #gPoke_Y, Y)
  PokeF(*scene\p_gLastChangedVector + #gPoke_Z, Z)
  PokeL(*scene\p_gLastChangedVector + #gPoke_Col, c)
  *scene\gVectorsInScene + 1
EndProcedure

Procedure.s gGetTypeString(vectortype.b)
  Select vectortype
    Case #gType_Poly: ProcedureReturn "Poly"
    Case #gType_Quad: ProcedureReturn "Quad"
    Case #gType_Vec: ProcedureReturn "Vec"
  EndSelect
EndProcedure

Procedure.s gGetSceneContentAsString(*scene.gScene)
  Protected back.s, *p
  *p = *scene\p_gSceneVectors
  back.s + "*gSceneVector: " + Str(*p) + Chr(10) + Chr(13)
  back.s + "*gLastChangedVector: " + Str(*scene\p_gLastChangedVector) + Chr(10) + Chr(13)
  back.s + "vectors in scene: " + Str(*scene\gVectorsInScene) + " from max. " + Str(*scene\gMaxPossibleVectors) + Chr(10) + Chr(13)
  back.s + Chr(10) + Chr(13)
  For Z = 0 To *scene\gVectorsInScene-1
    back.s + "#" + Str(Z+1) + Chr(10) + Chr(13)
    back.s + "type: " + gGetTypeString(PeekB(*p)) + Chr(10) + Chr(13)
    back.s + "x: " + Str(PeekF(*p+#gPoke_X)) + Chr(10) + Chr(13)
    back.s + "y: " + Str(PeekF(*p+#gPoke_Y)) + Chr(10) + Chr(13)
    back.s + "z: " + Str(PeekF(*p+#gPoke_Z)) + Chr(10) + Chr(13)
    back.s + Chr(10) + Chr(13)
    *p + *scene\gMaxUnitSize
  Next
  ProcedureReturn back
EndProcedure

Procedure gRenderSzene(*scene.gScene, *screen.gScreen, xRender.l,yRender.l, yRot.f, xRot.f, zRot.f, flags.b=#gFlags_Non)
  Protected *p
  Protected *gPoly.gPolygon, *gQuad.gQuad, *gVec.gVector, *gLastVec.gVector, *gLastVec2.gVector, *gLastVec3.gVector
  Protected type.l, lasttype.l, lasttype2.l, lasttype3.l
  
  ;x und y sind der mittelpunkt auf dem bildschirm... 
  ;resolution ist die auflösung der szene, d.h. wie viele einheitsvektoren auf einem bild platz finden...
  
  ;arbeitspointer zuweisen
  *p = *scene\p_gSceneVectors
  
  If flags & #gFlags_DrawAxis
    
    ;x-achse 
    uvXx = xRender + Cos(yRot) * *screen\UVsizeX
    uvXy = yRender + Sin(yRot) * *screen\UVsizeY
    
    ;y-achse
    uvYx = xRender
    uvYy = yRender - *screen\UnitVectorSize
    
    ;z-achse
    uvZx = xRender + Cos(yRot + #gDegree_90) * *screen\UVsizeX
    uvZy = yRender + Sin(yRot + #gDegree_90) * *screen\UVsizeY
    
    ;Von 0-Punkt aus Rendern
    ;~~~~~~~~~~~~~~~~~~~~~~~
    LineXY(xRender,yRender, uvXx,uvXy, #gCOLOR_X_AXIS);(blau)
    LineXY(xRender,yRender, uvYx,uvYy, #gCOLOR_Y_AXIS);(rot)
    LineXY(xRender,yRender, uvZx,uvZy, #gCOLOR_Z_AXIS);(grün)
    
    DrawText(uvXx,uvXy, "X", #gCOLOR_AXIS_TEXT, #gCOLOR_X_AXIS)
    DrawText(uvYx,uvYy, "Y", #gCOLOR_AXIS_TEXT, #gCOLOR_Y_AXIS)
    DrawText(uvZx,uvZy, "Z", #gCOLOR_AXIS_TEXT, #gCOLOR_Z_AXIS)
    
  EndIf
  
  ;wenn vektoren vorhanden, alle durchgehen und rendern
  If *scene\gVectorsInScene > 0
    For Z=0 To *scene\gVectorsInScene-1
      
      ;{comment
      ;Render-Theorie:
      ;~~~~~~~~~~~~~~~~~~~~~~~~~~~
      ;Zuallererst berechnen wir die X-Position. X ist im Prinzip auch nur ein Punkt, der sich
      ;auf einem Kreis bewegt -> die Größe des Kreises ist dabei abhängig von der X-Koordinate
      ;des Vektors. Somit benutzen wir ganz normale Kreis-Punkt-Positionen. Die Rotation bezieht
      ;sich dabei auf die Rotation des Y-Achse (da diese die Position auf dem Kreis MITBESTIMMT!)
      ;
      ;  M = Mittelpunkt
      ;
      ;  Mx + cos Y-Rotation * X-Koordinate * Pixellänge eines Einheitsvektors
      ;  My + sin Y-Rotation * X-Koordinate * Pixellänge eines Einheitsvektors
      ;
      ;Es ist wichtig, nur die X-Koordinaten im ersten Schritt zu nehmen, da die Kreisgröße sich
      ;in dieser orthogonalen Berechnung auf einen statischen Radius beschränkt, d.h. der Radius
      ;ist auf dem Bildschirm IMMER gleich.
      ;
      ;Danach folgt die Zurechnung der Y-Koordinaten! Da bei dieser einfachen Darstellung auf eine
      ;Z/X-Rotation verzichtet wird, kann ruhig nur die Y-Position des Vektors verändert (die auf
      ;dem Bildschirm!). Dabei müssen wir ganz einfach die Y-Koordinate im Raum von Y abziehen
      ;
      ;  My - Y-Koordinate * Pixellänge eines Einheitsvektors
      ;
      ;Letzten Endes wird von dem nun besthenden Punkt (der im Moment nur eine 2dimensionale
      ;auf einer X/Y-Achse im Raum ist) eine Schlenker um 90 in Richtung der Innen-Raumes machen.
      ;Klingt seltsam, ist aber einfach. Da wir uns schon auf dem Kreis der X-Koordinate befinden,
      ;müssen wir vom Kreispunkt 90° abzweigen (da Z senkrecht zu X steht). Noch die X-Berechnung
      ;in Erinnerung? Ist ähnlich, da wir ja sozusagen einen zweiten Kreis erstellen müssen (dessen
      ;Punkt - wie schonmal zwei mal erwähnt - um 90 Grad versetzt ist als der Original-Punkt).
      ;
      ;  Mx + cos (Y-Rotation + 90) * Z-Koordinate * Pixellänge eines Einheitsvektors
      ;  My + sin (Y-Rotation + 90) * Z-Koordinate * Pixellänge eines Einheitsvektors
      ;
      ;}
      
      ;typ ziehen und arbeitsvektor setzen (*gVec)
      type = PeekB(*p)
      *gVec = *p + 1
      
      ;position auf x-achse setzen
      *gVec\xPlot = xRender + Cos(yRot) * *gVec\X * *screen\UVsizeX
      *gVec\yPlot = yRender + Sin(yRot) * *gVec\X * *screen\UVsizeY
      
      ;position auf y-achse erweitern
      *gVec\yPlot - *gVec\Y * *screen\UnitVectorSize
      
      ;position auf z-achse erweitern
      *gVec\xPlot + Cos(yRot + #gDegree_90) * *gVec\Z * *screen\UVsizeX
      *gVec\yPlot + Sin(yRot + #gDegree_90) * *gVec\Z * *screen\UVsizeY
      
      ;einzeichnen (+ flächen rechnen)
      Select type
        Case #gType_Vec
          Circle(*gVec\xPlot, *gVec\yPlot, 4, *gVec\color)
          
        Case #gType_Poly
          ;wenn letzter vector auch vom polygon, dann
          If lasttype = #gType_Poly
            LineXY(*gLastVec\xPlot, *gLastVec\yPlot, *gVec\xPlot,*gVec\yPlot, *gLastVec\color) ;vom jetzigen zum letzten nachziehen
          EndIf
          ;diesen vektor für den nächsten vektor speichern
          *gLastVec3 = *gLastVec2
          *gLastVec2 = *gLastVec
          *gLastVec = *gVec
          
        Case #gType_PolyEnd
          ;wenn letzter überhaupt ein polygon
          If lasttype = #gType_Poly
            LineXY(*gLastVec\xPlot, *gLastVec\yPlot, *gVec\xPlot,*gVec\yPlot, *gLastVec\color);vom jetzigen zum letzten nachziehen
            LineXY(*gLastVec2\xPlot, *gLastVec2\yPlot, *gVec\xPlot,*gVec\yPlot, *gVec\color);vom jetzigen zum ersten
          EndIf
          ;diesen vektor für den nächsten vektor speichern
          *gLastVec3 = *gLastVec2
          *gLastVec2 = *gLastVec
          *gLastVec = *gVec
          
      EndSelect
      
      ;pointer auf nächsten vektor erhöhen
      *p + *scene\gMaxUnitSize
      ;letze typen speichern (wir benötigen insgesamt 4 variablen wegen poly(3vec) und quad(4vec)
      lasttype3 = lasttype2
      lasttype2 = lasttype
      lasttype = type
      
    Next
  EndIf

EndProcedure

Procedure.l GetVector(*scene.gScene, vektorindex.l)
  ProcedureReturn *scene\p_gSceneVectors + vektorindex * *scene\gMaxUnitSize
EndProcedure
;}-

;-deklarieren
Declare CreateScene()

;-initialisieren
InitSprite()
InitKeyboard()
Global myScreen.gScreen
Global myScene.gScene
Global mySceneRotation.l

;-fenster + szene erstellen
CreateScene()
mySceneRotation = 45

;-hauptschleife
Repeat
  ;event-handling
  Select WindowEvent()
    Case #PB_Event_CloseWindow: End
  EndSelect
  
  ;rendern
  ClearScreen(0)
    StartDrawing(ScreenOutput())
      gRenderSzene(@myScene, @myScreen, myScreen\sizeX/2,myScreen\sizeY/1.3, AngleToSin(mySceneRotation),AngleToSin(0),AngleToSin(0), #gFlags_DrawAxis)
    StopDrawing()
  FlipBuffers()
  
  ;delay
  Delay(1)
  mySceneRotation + 1
  If mySceneRotation >= 359
    mySceneRotation = 0
  EndIf
ForEver

; Procedure MoveThem()
  ; 

;-prozeduren
Procedure CreateScene()
  gSetUpScreen(@myScreen, 640,480, 40, #gFlags_Non)
  
  ;RGB(255,255,255)
  
  gNewScene(@myScene, 3)
  For Z = 0 To 6
    gAddVectorDirect(@myScene, #gType_Poly,    Random(4),Random(4),Random(3), RGB(255,255,255))
    gAddVectorDirect(@myScene, #gType_Poly,    Random(4),Random(4),Random(3), RGB(255,255,255))
    gAddVectorDirect(@myScene, #gType_PolyEnd, Random(4),Random(4),Random(3), RGB(255,255,255))
  Next
  
  OpenWindow(0, 0,0, myScreen\sizeX,myScreen\sizeY, "iso3d", #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_TitleBar)
  OpenWindowedScreen(WindowID(0), 0,0, myScreen\sizeX,myScreen\sizeY, 0,0,0)
EndProcedure
Benutzeravatar
#NULL
Beiträge: 2238
Registriert: 20.04.2006 09:50

Beitrag von #NULL »

cool :) (mehr kann ich dazu nicht sagen, hab kein plan davon <) )
my pb stuff..
Bild..jedenfalls war das mal so.
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

#NULL hat geschrieben:cool :) (mehr kann ich dazu nicht sagen, hab kein plan davon <) )
lol, dass nenn ich doch mal positive Einstellung XD
Benutzeravatar
AndyX
Beiträge: 1272
Registriert: 17.12.2004 20:10
Wohnort: Niederösterreich
Kontaktdaten:

Beitrag von AndyX »

O_O fett! :shock:

ich hatte auch mal versucht (hab nach dutzenden jämmerlichen Versuchen aufgegeben), einen Software Renderer zu schreiben. Mein Teil konnte schon Dreiecke füllen (sogar mit Shading), aber rotieren konnte man gar nichts XD
Benutzeravatar
Green Snake
Beiträge: 1394
Registriert: 22.02.2005 19:08

Beitrag von Green Snake »

Jo, sieht cool aus :allright:

thx fürs Teilen :D
-.-"
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

Ich habe jetzt noch die X-Rotation hinzugefügt, nur bin ich gerade dabei, das Speichersystem zu verändern/zu optimieren. Man wird einen Vektorspeicher haben und seperat dazu (wird nur vom Renderer verwendet) einen Formenspeicher für Polygone und Quads/Planes. Heute sind mir auch tolle Gedanken gekommen, wie ich Perspektive, Kameraflächen und das "Absägen" von Vektoren (wenn der Vektor z.b. durch eine Fläche durchgeht, aber nicht gerendert werden kann) machen kann. Aber das erfordert nochmal einiges an Umstrukturierungen, darum werde ich mich erstmal an den Speicher machen. Ich denke, ich werde heute noch fertig, ich schiebe das ganze dann heute noch nach :allright: !
Kekskiller
Beiträge: 752
Registriert: 14.09.2004 21:39
Kontaktdaten:

Beitrag von Kekskiller »

Hm... Ich habe jetzt auch die X-Rotation integriert und Umstrukturiert. Aber da ist nur ein Test, Polygone funktionieren diesmal nicht... Ich will diese dähmliche Z-Rotation richtig einbauen. Den ursprünglichen Winkel auf dem Bildschirm zu ermitteln klappt schon, aber irgendwie muss ich beim Addieren der zusätzlichen Winkelwerte einen Wert-Überfluss abfangen, hm...

Code: Alles auswählen

;{-iso3d
Structure gVector
  X.f
  Y.f
  Z.f
  xPlot.l;letztes x auf screen
  yPlot.l;letztes y auf screen
EndStructure

Structure gPolygon
  Alpha.l;pointer zu vektoren, die die polygon-basis bilden
  Betha.l;
  Gamma.l;
EndStructure

Structure gQuad
  Alpha.l;pointer zu vektoren, die die quad-basis bilden
  Betha.l;
  Gamma.l;
  Delta.l;
EndStructure

Structure gCam
  X.f ;x-verschiebung des mittelpunktes
  Y.f ;y-verschiebung des mittelpunktes
  Rotation.l ;die rotation der kamera um den mittelpunkt.
EndStructure

Structure gScreen
  aspectX.f;aspekt von briete und höhe (kleinste seite = 1.0
  aspectY.f;
  sizeX.l;größte des bildschirms
  sizeY.l;
  UVsizeX.f;vorberechnete UnitVectorGrößen fürs Rendern
  UVsizeY.f;
  uvs_on_screenX.f
  uvs_on_screenY.f
EndStructure

Structure gScene
  gMaxUnitSize.l ;größte größe eines vektorgebildes
  p_gSceneVectors.l ;zeiger auf szenen-speicher (wird nur bei alloziieren verändert, enthält die vektordaten)
  p_gLastChangedVector.l ;pointer auf letzten veränderten vektor (schneller beim speichern)
  gSceneSize.l ;größe des Szenenspeichers
  gVectorsInScene.l ;anzahl vektoren im Szenenspeicher
  gMaxPossibleVectors.l ;maximale anzahl von vektoren, die in eine szene passen
  p_gSceneShapes.l;pointer auf formenspeicher (enthält "visuelles" wie polygone, quads, sprites, etc...)
EndStructure

;{-konstanten
#gPoke_X = 0
#gPoke_Y = #gPoke_X + SizeOf(Float)
#gPoke_Z = #gPoke_Y + SizeOf(Float)

#gFlags_Non = 0
#gFlags_DrawAxis = 1
#gFlags_SetUpScreen_GetUVfromXUV = 2
#gFlags_SetUpScreen_GetUVfromYUV = 2

#gDegree_45 = 0.785398
#gDegree_90 = 1.570796
#gDegree_180 = 3.141593
#gDegree_270 = 4.712389

#gCOLOR_AXIS_TEXT = $FFFFFF
#gCOLOR_X_AXIS = $FF0000
#gCOLOR_Y_AXIS = $0000FF
#gCOLOR_Z_AXIS = $00FF00

#gAXIS_X_VECTOR_X = 1
#gAXIS_X_VECTOR_Y = 0
#gAXIS_X_VECTOR_Z = 0

#gAXIS_Y_VECTOR_X = 0
#gAXIS_Y_VECTOR_Y = 1
#gAXIS_Y_VECTOR_Z = 0

#gAXIS_Z_VECTOR_X = 0
#gAXIS_Z_VECTOR_Y = 0
#gAXIS_Z_VECTOR_Z = 1
;}-


Global globFirstRot.b


Procedure.f AngleToSin(angle.w)
  s.f = (#PI / 180) * angle
  ProcedureReturn s
EndProcedure

Procedure gSetUpScreen(*screen.gScreen, sizeX.l,sizeY.l, uvs_on_screenX.f, uvs_on_screenY.f)
  *screen\sizeX = sizeX
  *screen\sizeY = sizeY
  
  If *screen\sizeX > *screen\sizeY
    *screen\aspectX = *screen\sizeX / *screen\sizeY
    *screen\aspectY = 1.0
  ElseIf *screen\sizeY > *screen\sizeX
    *screen\aspectX = 1.0
    *screen\aspectY = *screen\sizeY / *screen\sizeX
  EndIf
  
  *screen\uvs_on_screenX = uvs_on_screenX
  *screen\uvs_on_screenY = uvs_on_screenY
  
  *screen\UVsizeX = *screen\sizeX / *screen\uvs_on_screenX
  *screen\UVsizeY = *screen\sizeY / *screen\uvs_on_screenY
EndProcedure

Procedure gNewScene(*scene.gScene, vectors.l)
  If *scene
    
    *scene\gMaxUnitSize = SizeOf(gVector)
    *scene\p_gSceneVectors = AllocateMemory(vectors * *scene\gMaxUnitSize)
    *scene\p_gLastChangedVector = *scene\p_gSceneVectors
    *scene\gMaxPossibleVectors = vectors
    *scene\gVectorsInScene = 0
    *scene\gSceneSize = vectors * *scene\gMaxUnitSize
    
  EndIf
EndProcedure

Procedure gAddVectorDirect(*scene.gScene, X.f, Y.f, Z.f)
  If *scene
    
    ;pointer auf letzten vektor um eine unitgröße erhöhen (wenn überhaupt gesetzt)
    If *scene\gVectorsInScene > 0
      *scene\p_gLastChangedVector + *scene\gMaxUnitSize
    EndIf
    ;daten sichern
    PokeF(*scene\p_gLastChangedVector + #gPoke_X, X)
    PokeF(*scene\p_gLastChangedVector + #gPoke_Y, Y)
    PokeF(*scene\p_gLastChangedVector + #gPoke_Z, Z)
    *scene\gVectorsInScene + 1
    
  EndIf
EndProcedure

Procedure.s gGetSceneContentAsString(*scene.gScene)
  Protected back.s, *p
  If *scene
    
    *p = *scene\p_gSceneVectors
    back.s + "*gSceneVector: " + Str(*p) + Chr(10) + Chr(13)
    back.s + "*gLastChangedVector: " + Str(*scene\p_gLastChangedVector) + Chr(10) + Chr(13)
    back.s + "vectors in scene: " + Str(*scene\gVectorsInScene) + " from max. " + Str(*scene\gMaxPossibleVectors) + Chr(10) + Chr(13)
    back.s + Chr(10) + Chr(13)
    For Z = 0 To *scene\gVectorsInScene-1
      back.s + "#" + Str(Z+1) + Chr(10) + Chr(13)
      back.s + "x: " + Str(PeekF(*p+#gPoke_X)) + Chr(10) + Chr(13)
      back.s + "y: " + Str(PeekF(*p+#gPoke_Y)) + Chr(10) + Chr(13)
      back.s + "z: " + Str(PeekF(*p+#gPoke_Z)) + Chr(10) + Chr(13)
      back.s + Chr(10) + Chr(13)
      *p + *scene\gMaxUnitSize
    Next
    ProcedureReturn back
    
  Else
    ProcedureReturn ""
  EndIf
EndProcedure

Procedure.l gAbsLong(var.l)
  ProcedureReturn 2147483648 - var & 2147483647
EndProcedure

Procedure.b gAbsByte(var.b)
  ProcedureReturn 256 - var & 255
EndProcedure

Procedure gRenderSzene(*scene.gScene, *screen.gScreen, xRender.l,yRender.l, yRot.f, xRot.f, zRot.f, flags.b=#gFlags_Non)
  Protected *p
  Protected *gPoly.gPolygon, *gQuad.gQuad, *gVec.gVector
  Protected gA.l, gB.l, gC.l, gCos.f, gSin.f
  If *scene
    
    ;arbeitspointer zuweisen
    *p = *scene\p_gSceneVectors
    
    If flags & #gFlags_DrawAxis
      
      ;x-achse 
      uvXx = xRender + Cos(yRot) * *screen\UVsizeX
      uvXy = yRender + Sin(yRot) * *screen\UVsizeY * Sin(xRot)
      
      ;y-achse
      uvYx = xRender
      uvYy = yRender + *screen\UVsizeY * Sin(xRot + #gDegree_270)
      
      ;z-achse
      uvZx = xRender + Cos(yRot + #gDegree_90) * *screen\UVsizeX
      uvZy = yRender + Sin(yRot + #gDegree_90) * *screen\UVsizeY * Sin(xRot)
      
      ;Von 0-Punkt aus Rendern
      ;~~~~~~~~~~~~~~~~~~~~~~~
      LineXY(xRender,yRender, uvXx,uvXy, #gCOLOR_X_AXIS);(blau)
      LineXY(xRender,yRender, uvYx,uvYy, #gCOLOR_Y_AXIS);(rot)
      LineXY(xRender,yRender, uvZx,uvZy, #gCOLOR_Z_AXIS);(grün)
      
      DrawText(uvXx,uvXy, "X", #gCOLOR_AXIS_TEXT, #gCOLOR_X_AXIS)
      DrawText(uvYx,uvYy, "Y", #gCOLOR_AXIS_TEXT, #gCOLOR_Y_AXIS)
      DrawText(uvZx,uvZy, "Z", #gCOLOR_AXIS_TEXT, #gCOLOR_Z_AXIS)
      
    EndIf
    
    ;wenn vektoren vorhanden, alle durchgehen und rendern
    If *scene\gVectorsInScene > 0
      For Z=0 To *scene\gVectorsInScene-1
        
        ;{comment
        ;Render-Theorie:
        ;~~~~~~~~~~~~~~~~~~~~~~~~~~~
        ;Zuallererst berechnen wir die X-Position. X ist im Prinzip auch nur ein Punkt, der sich
        ;auf einem Kreis bewegt -> die Größe des Kreises ist dabei abhängig von der X-Koordinate
        ;des Vektors. Somit benutzen wir ganz normale Kreis-Punkt-Positionen. Die Rotation bezieht
        ;sich dabei auf die Rotation des Y-Achse (da diese die Position auf dem Kreis MITBESTIMMT!)
        ;
        ;  M = Mittelpunkt
        ;
        ;Edit: Erweiterung auf X-Rotation erfolgt durch Sinus-Multiplikation bei My mit der X-Rotation.
        ;
        ;  Mx + cos Y-Rotation * X-Koordinate * Pixellänge eines Einheitsvektors
        ;  My + sin Y-Rotation * X-Koordinate * Pixellänge eines Einheitsvektors * sin X-Rotation
        ;
        ;Es ist wichtig, nur die X-Koordinaten im ersten Schritt zu nehmen, da die Kreisgröße sich
        ;in dieser orthogonalen Berechnung auf einen statischen Radius beschränkt, d.h. der Radius
        ;ist auf dem Bildschirm IMMER gleich.
        ;
        ;Danach folgt die Zurechnung der Y-Koordinaten! Da bei dieser einfachen Darstellung auf eine
        ;Z/X-Rotation verzichtet wird, kann ruhig nur die Y-Position des Vektors verändert (die auf
        ;dem Bildschirm!). Dabei müssen wir ganz einfach die Y-Koordinate im Raum von Y abziehen
        ;
        ;Edit: Hierbei auch mit X-Rotation erweitern, allerdings mit X-Rotation + 270° (da sich Y um 270°
        ;von den anderen Achsen unterscheidet! Vom Umsetzen also sehr angenehm...
        ;
        ;  My - Y-Koordinate * Pixellänge eines Einheitsvektors * sin (X-Rotation + 270°)
        ;
        ;Letzten Endes wird von dem nun besthenden Punkt (der im Moment nur eine 2dimensionale
        ;auf einer X/Y-Achse im Raum ist) eine Schlenker um 90 in Richtung der Innen-Raumes machen.
        ;Klingt seltsam, ist aber einfach. Da wir uns schon auf dem Kreis der X-Koordinate befinden,
        ;müssen wir vom Kreispunkt 270° abzweigen (da Z senkrecht zu X steht). Noch die X-Berechnung
        ;in Erinnerung? Ist ähnlich, da wir ja sozusagen einen zweiten Kreis erstellen müssen (dessen
        ;Punkt - wie schonmal zwei mal erwähnt - um 270 Grad versetzt ist als der Original-Punkt).
        ;
        ; Edit: Erweiterung auf X-Rotation wie bei X-Koordinaten-Einbindung
        ;
        ;  Mx + cos (Y-Rotation + 90°) * Z-Koordinate * Pixellänge eines Einheitsvektors
        ;  My + sin (Y-Rotation + 90°) * Z-Koordinate * Pixellänge eines Einheitsvektors * sin X-Rotation
        ;
        ;Anmerkung: Da wo ich überall 270° schrieb, kann man auch theoretisch auch 90° einsetzen,
        ;dann würde sich aber auch das Verhalten von Winkel zu Darstellung ändern! Ich muss zugeben,
        ;dass ich das bei einigen Rechnungen getan habe und sie nicht ganz mit den Beispielen übereinstimmen...
        ;}
        
        ;typ ziehen und arbeitsvektor setzen (*gVec)
        *gVec = *p
        
        ;x-koordinaten einberechnen (+ y/x-rotation)
        *gVec\xPlot = xRender + Cos(yRot) * *gVec\X * *screen\UVsizeX
        *gVec\yPlot = yRender + Sin(yRot) * *gVec\X * *screen\UVsizeY * Sin(xRot)
        
        ;y-koordinaten einberechnen (+ x-rotation, y wird nicht benötigt, "da es y selbst ist")
        *gVec\yPlot + *screen\UVsizeY * *gVec\Y * Sin(xRot + #gDegree_270)
        
        ;z-koordinaten einberechnen (+ y/x-rotation)
        *gVec\xPlot + Cos(yRot + #gDegree_90) * *gVec\Z * *screen\UVsizeX
        *gVec\yPlot + Sin(yRot + #gDegree_90) * *gVec\Z * *screen\UVsizeY * Sin(xRot)
        
        ;{comment
        ;Z-Rotation-Therorie
        ;~~~~~~~~~~~~~~~~~~~
        ;Die Z-Rotation beim Rendern hat nicht mehr viel mit der eigentlichen Z-Achse zu tun. Es ist
        ;eher eine Drehung des Bildschirms anhand der sichtbaren Punkten. Da die Polygone erst nach
        ;dieser Berechnung gerendert werden, kann man immer noch prima weiterrendern.
        ;
        ;Die Berechnung der Z-Rotation erfolgt über den Satz des Pytagoras, als Drehpunkt gilt die
        ;Bildschirmmitte.
        ;
        ; gA = Seite a
        ; gB = Seite b
        ; gC = Seite c (unsere entfernung)
        ; gCos = Cosinus des bereits vorhandenen Winkels zum Mittelpunkt
        ; gSin = Sinus des bereits vorhandenen Winkels zum Mittelpunkt
        ;
        ;}
        
        ;z-Rotation mit einbeziehen
        
        DisableDebugger
        
        If globFirstRot = 0
          
          Debug "yRender: " + Str(yRender)
          Debug "yRender: " + Str(yRender)
          Debug ""
          Debug "*gVec\xPlot: " + Str(*gVec\xPlot)
          Debug "*gVec\yPlot: " + Str(*gVec\yPlot)
          Debug ""
        
          gA = yRender - *gVec\yPlot
          gB = xRender - *gVec\xPlot
          ; If gA < 0: gA * -1: EndIf
          ; If gB < 0: gB * -1: EndIf
          Debug "gA: " + Str(gA)
          Debug "gB: " + Str(gB)
          Debug ""
          
          gC = Sqr(gA * gA + gB * gB)
          Debug "gC: " + Str(gC)
          Debug ""
          
          gCos = gB / gC
          gSin = gA / gC
          Debug "gCos: " + StrF(gCos)
          Debug "gSin: " + StrF(gSin)
          Debug ""
          
          *gVec\xPlot = xRender - gCos * gC
          *gVec\yPlot = yRender - gSin * gC
          Debug "*gVec\xPlot: " + Str(*gVec\xPlot)
          Debug "*gVec\yPlot: " + Str(*gVec\yPlot)
          Debug ""
          
          globFirstRot = 0
        
        EndIf
        
        EnableDebugger
        
        ;einzeichnen
        If *gVec\xPlot > 0 And *gVec\xPlot < *screen\sizeX
          If *gVec\yPlot > 0 And *gVec\yPlot < *screen\sizeY
            Circle(*gVec\xPlot, *gVec\yPlot, 1, #gCOLOR_AXIS_TEXT)
          EndIf
        EndIf
        
        ;pointer auf nächsten vektor erhöhen
        *p + *scene\gMaxUnitSize
        
      Next
    EndIf
    
  EndIf
EndProcedure

Procedure.l gGetVector(*scene.gScene, vektorindex.l)
  If *scene
    ProcedureReturn *scene\p_gSceneVectors + vektorindex * *scene\gMaxUnitSize
  Else
    ProcedureReturn 0
  EndIf
EndProcedure
;}-

;-deklarieren
Declare CreateScene()

;-initialisieren
InitSprite()
InitKeyboard()
InitMouse()
Global myScreen.gScreen
Global myScene.gScene
Global myYRotation.l
Global myXRotation.l
Global myZRotation.l
Global polycount.l, polycol.l

;-fenster + szene erstellen
CreateScene()

MessageRequester("iso3d", gGetSceneContentAsString(@myScene))

;-hauptschleife
Repeat
  ;event-handling
  event = WindowEvent()
  
  ;maus
  ExamineMouse()
  ExamineKeyboard()
  
  ;drehung durch maus updaten
  myYRotation - MouseDeltaX()
  myXRotation + MouseDeltaY()
  myZRotation + MouseWheel()
  
  ;rendern
  ClearScreen(0)
    StartDrawing(ScreenOutput())
      gRenderSzene(@myScene, @myScreen, myScreen\sizeX/2,myScreen\sizeY/2, AngleToSin(myYRotation),AngleToSin(myXRotation),AngleToSin(myZRotation), #gFlags_DrawAxis)
    StopDrawing()
  FlipBuffers()
  
  ;delay
  Delay(1)
Until KeyboardPushed(#PB_Key_Escape) Or event = #PB_Event_CloseWindow



;-prozeduren
Procedure CreateScene()
  gSetUpScreen(@myScreen, 640,480, 20*(640/380),20)
  
  gNewScene(@myScene, 15)
  For polycount = 0 To 6
    gAddVectorDirect(@myScene, Random(10),Random(10),Random(10))
    gAddVectorDirect(@myScene, Random(10),Random(10),Random(10))
    gAddVectorDirect(@myScene, Random(10),Random(10),Random(10))
  Next
  gAddVectorDirect(@myScene, 0,0,0)
  gAddVectorDirect(@myScene, 2,0,0)
  gAddVectorDirect(@myScene, 0,2,0)
  gAddVectorDirect(@myScene, 0,0,2)
  
  OpenWindow(0, 0,0, myScreen\sizeX,myScreen\sizeY, "iso3d", #PB_Window_ScreenCentered|#PB_Window_SystemMenu|#PB_Window_TitleBar)
  OpenWindowedScreen(WindowID(0), 0,0, myScreen\sizeX,myScreen\sizeY, 0,0,0)
EndProcedure
Antworten