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

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



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