3d Anwendung ruckelt stark

Previous topic - Next topic

ProNerd

Und zwar versuche ich derweil eine kleine 3d Welt, in der ich mich bewegen kann, zu programmieren. Bisher habe ich bewusste auf die x3d befehle verzichtet weil es mir mehr um die mathematischen Grundlagen geht. Mittlerweile habe ich zwar jetzt eine kleine Welt und das Movement hinbekommen, aber das ganze ruckelt extrem stark.
vereinfacht ist das programm folgendermaßen (in Pseudecode)
Init:
•   Initialisiere circa 1000 Objekte im Modellkoordinatensystem (jedes Objekt ist gekennzeichnet durch 4 Eckpunkte, und der Einheitsgröße Größe 100 * 100 ohne dicke)
•   verschiebe die Objekte(Punkte) an ihre entsprechende Position im Weltkoordinatensystem mithilfe der Initialisierungsvektoren (x,y,z sowie eine drehung, mehr ist momentan nicht erforderlich)
Update:
•   Transformiere alle Punkte von allen Objekten falls verschoben wird (vorwärts- rückwärts gehen, drehen etc..).
•   Transformiere nun die Koordinaten aller Punkte (dafür wird nur eine Transformationsmatrix verwendet) um sie in die entsprechende Perspektive zu bringen.
•   Liegt ein Punkt x,y im definierten sichtbaren Volumen (Pyramidenfrustum) dann initialisiere diesen Punkt in Points[] mit dem dazugehörigen normierten Z-Wert und der Farbe des Objekts
Render:
•   Initialisiere die Variablen Z-Werte[][] und Farb-Were[][] mit den Dimensionen des sichtbaren Bereichts, und zwar mit z = -1(Objekt ist unsichtbar) und Farbe = schwarz
•   Für jeden Punkt in Points[]: Wenn der z-Wert der in Z-Werte[][] steht kleiner ist als der z-wert von Points, übernehme den neuen Z und C Wert
•   Lösche alle Punkte in Points[]
•   Falls ein Z-Wert in Z-Werte
  • [y] größer -1 ist setpixel mit der C-Werte
  • [y] an die Position x,y


    Soweit so gut, aber das ruckelt so krass. Es werden einfach so viele Punkte in Points[] erzeugt und jeder muss einzeln geprüft werden. Da alle Objekte im sichtbaren Volumen liegen ergeben sich an die 1000* 4 = 4000Points. Ich hatte ursprünglich noch Verbindungslinien zwischen den EckPunkten errechnet (von Polygonen soll erst mal gar nicht die Rede sein) aber dann sind es so krass viele Punkte die erzeigt werden, dass das Programm unsteuerbar wird. Egal welche fps oder Auflösung ich einstelle. Sobald vielleicht noch 400 Punkte zu sehen ist wird die Performance besser.
    Meine Vermutung ist, dass ich eigentlich den richtigen z Buffer auf der Grafikkarte ansprechen müsste, weil der viel schneller ist usw.. aber ich mein es gab ja auch schon einfach 3d Applikationen für uralte Konsolen und PC's (Wolfenstein) etc.., in sofern müsste ich was rudimentäres doch auch so zum laufen bringen. Selbst bei einem einfachen Testprogramm wo ich nur ne schleife mit 640 * 480 nehme und sage setpixel(x,y,) ruckelt es. Insofern denke ich, dass es nicht an den paar Transformationsberechnunge liegen kann, sondern eher an der falschen benutzung des Befehl SetPixels bzw. der Rasterungsmethode. Oder wo liegt der Fehler?

ProNerd

#1
ja das stimmt schon, das Program ist nur leider etwas zu lang geraten. Es geht eigentlich auch nur um die Implementierung des Z Buffering Algorythmus. Die z und Farb Werte von jedem Punkte werden in einem Type gespeichert:
Code (glbasic) Select

//setze die Variablen zurück
self.DataZ[] = self.DataZInit[]
self.DataC[] = self.DataCInit[]

//Z-Buffer Algorythmus
LOCAL p AS TPoint
FOREACH p IN Points[]
IF self.DataZ[p.x][p.y] > p.z
self.DataZ[p.x][p.y] = p.z
self.DataC[p.x][p.y] = p.color
ENDIF
DELETE p
NEXT


//Render die Punkte
FOR i = Map.viewminx TO Map.viewmaxx
FOR j = Map.viewmaxy TO Map.viewminy
IF self.DataC[i][j] > 0 THEN SETPIXEL i,j,self.DataC[i][j]
NEXT
NEXT



Code (glbasic) Select

TYPE TPoint
x;y;z
color
FUNCTION Init: x,y,z, color
self.x = x
self.y = y
self.z = z
self.color = color
DIMPUSH Points[], self
ENDFUNCTION
ENDTYPE

wieviel Elemente sollte ein Type sinnvollerweise enthalten? Ich sammel in einem Type Punkte (es gibt nur 4 Variablen in diesem Type,x,y,z und farbe). So kommen in jedem Cycle an die zig tausend Type Elemente zusammen. (Alle Elemente in diesem Type werden am Ende des cycles komplett gelöscht)

Ich gleiche jeden einzelnen Punkt mit einer Datenvariable ab, die mit 640*480 dimensioniert ist. Ich schau welchen Wert hat diese Datenvariable an der stelle des zu testenden Punktes und überschreibe ihn falls er größer ist. In dem Fall wird auch eine weitere Datenvariable die ebenso gross dimensioniert ist mit einem Wert aus Punkte[] beschrieben. Beide Datenvariable werden am anfang des cycles geresetet.

Dann durchlaufe ich die erste Datenvariablen und setze bei allen Werten, wo nicht mehr der Ausgangswert drin steht, ein Pixel in der Farbe aus der zweiten Datenvariable

bei 640*480 gibt es schon 307200 Pixel. Mit einigen Objekten im Hintergrund kommen da sicher Millionen Punkte zusammen. Kann man soviele in einem Type speichern und die in jedem Cycle, wieder reseten und testen oder wie haben die das damals zu Wolfenstein Zeiten gemacht?

kanonet

Du kannst so etwas nicht komplett in der CPU berechnen (GPU wäre viel schneller) und erwarten, dass es flüssig läuft. Dann noch lauter Array-einfügen- und -lösch-Befehle (kostet alles massig Zeit) pro Frame und zusätzlich dann noch mit SETPIXEL zeichnen (wohl langsamster aller Grafikbefehle) . Das wirkt ja beinahe als ob du absichtlich langsam sein willst...

Wenn du 3D willst, dann verwende 3D, das ist alles optimiert und läuft wenn möglich auf der GPU.
Willst du dich wirklich mit dem kreieren von pseudo-3D-Objekten beschäftigen, dann schaue dir mal Wampus Arbeit an: www.glbasic.com/forum/index.php?topic=8151
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

ProNerd

#3
Quote from: kanonet on 2013-Sep-20
Du kannst so etwas nicht komplett in der CPU berechnen (GPU wäre viel schneller) und erwarten, dass es flüssig läuft. Dann noch lauter Array-einfügen- und -lösch-Befehle (kostet alles massig Zeit) pro Frame und zusätzlich dann noch mit SETPIXEL zeichnen (wohl langsamster aller Grafikbefehle) . Das wirkt ja beinahe als ob du absichtlich langsam sein willst...

Wenn du 3D willst, dann verwende 3D, das ist alles optimiert und läuft wenn möglich auf der GPU.
Willst du dich wirklich mit dem kreieren von pseudo-3D-Objekten beschäftigen, dann schaue dir mal Wampus Arbeit an: www.glbasic.com/forum/index.php?topic=8151

ich les gerade das wolfenstein mit raycasting und vielen tricks so hinbekommen wurde. Das Beispiel von Wampus ist auch nicht schlecht :)

kanonet

Ich bin mir sicher, dass man auch früher nicht alles auf der CPU gemacht hat, sondern auch die GPU genutzt hat. Außerdem wurden da ganz andere Techniken eingesetzt, viel hardwarenäher programmiert etc. Kannst also nicht mit dem hier vergleichen.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Schranz0r

Dein Flaschenhals ist Setpixel!
Versuchst du eine Voxelengine zu machen?
Nimm mal lieber DRAWRECT, sollte schneller sein...
I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

ProNerd

versuche es jetzt mit ray casting und hänge an ner Stelle fest wo man massig Punkte rendern muss und die Performance lässt es leider nicht zu :(

siehe dieses Tutorial: http://www.permadi.com/tutorial/raycast/rayc11.html

Code (glbasic) Select

GLOBAL boden = GENSPRITE(); LOADANIM "boden.png", boden, 1,1 //32*32 Tile

FOR j = 0 TO 240 - 1
FOR i = 0 TO 640 - 1
DRAWANIM boden, scannedframe[i][j],i, j + 240
NEXT
NEXT



kanonet

Gibt es einen Grund, warum du ein Basic nutzen willst, aber dann doch alles auf die Komplizierte Weise erledigen willst. Brauchst dich dann nicht zu wundern, wenn es langsam ist. Btw. wird Raycasting meist nicht für Liverendering wie Spiele etc. Geeignet (da zu langsam), sondern für rendern von detaillierten Bildern etc. Dass live zu erledigen ist ein Basic wohl kaum geeignet, eventuell könntest du dem etwas näher kommen, wenn du GLSL zusätzlich nutzt.
Ansonsten zählt meine Empfehlung aus meinem ersten Post hier im Thread.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

ProNerd

#8
du meinst raytracing (ne 3 dimensionale Version von raycasting). raycasting ist die übliche 3d technik der 90ziger zum live rendern.

ausserdem wieso komplizierte weise? Ich möchte einfach nur ne kleine raycasting engine wie dukenukem, doom etc.. selbst machen. Zumindest versuchen. Das macht Spass und Basic ist nun mal halt die einzige Sprache die ich kenne.

Ich verstehe nicht wo der unterschied ist ob ich 20*15 bilder mit der Tilesize von 32 render, oder direkt 640*480 Punkte. Es werden in beiden Fällen gleich viele Pixels gerendered. mein computer rendered permanent bilder von 1600*900. Aber warum kackt Basic so krass ab, wenn man punkt für punkt zeichnen will. Genau das ist es aber was ich will. Mit welcher Sprache geht das wenn nicht mit GLBasic?

Was erwartet mich überhaupt wenn ich solche Sachen umsetzen will? Ich hab im Quake Code gesehen, dass kritische Sachen wie Vektoren Umrechnungen etc.. mit Assembler gemacht wurden.


kanonet

Dafür ist GLBasic (und andere vergleichbare) nicht gemacht, meine Antworten diesbezüglich kennst du bereits, (GPU muss auch genutzt werden, etc. siehe mein ersten Post hier), wenn sie dir nicht gefällt ist das schade, aber eben nicht zu ändern. Und ja, eine Raytracing Engine selbst zu schreiben ist nicht banal.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

ProNerd

hier mal 2 screenshots, eine wand ist bereits mit Texturen belegt. Als nächstes wollte ich den Boden machen

kanonet

Aber das muss doch nicht per Pixel sein? Denn selben Effekt kannst du doch auch mit Polyvector erreichen (siehe Link oben), wenn du nicht 3D nutzen willst. Ein ganzes Bild einzeln zusammenzupixel ist wohl langsam.
Lenovo Thinkpad T430u: Intel i5-3317U, 8GB DDR3, NVidia GeForce 620M, Micron RealSSD C400 @Win7 x64

Schranz0r

#12
Polyvector ist da die Wahl!

GLBasic kann das locker, schau mal in die Samples unter Maze, da hat Gernot mal was gamacht!

EDIT:

Achso, ich glaub SETPIXEL ist CPU und die DRAW.... Befehle sind auf der GPU.
Kann das einer so bestätigen?! GERNOT? :)
I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard

ProNerd

#13
du meinst ich rechne nur das grid auf die perspektive um, und hab dann die eckpunkt um das mit polyvektoren zu rastern ? :)

gute idee, aber sag mal, gibt es trotzdem die Möglichkeit an die Rasterfunktion von OpenGL ranzukommen? So dass ich anstatt setpixel einfach sage, rasterpixel?

für licht und wettereffekte brauche ich pixelweises arbeiten früher oder später auf jeden fall, oder nicht?

Schranz0r

Ja so dachte ich :D
In den Samples ist die gl.gbas das ist ein voller openGL wrapper!
I <3 DGArray's :D

PC:
AMD Ryzen 7 3800X 16@4.5GHz, 16GB Corsair Vengeance LPX DDR4-3200 RAM, ASUS Dual GeForce RTX™ 3060 OC Edition 12GB GDDR6, Windows 11 Pro 64Bit, MSi Tomahawk B350 Mainboard