Zeichenfunktionen - Gouraud Shading für Polygone
Übersicht

![]() |
DivineDominionBetreff: Zeichenfunktionen - Gouraud Shading für Polygone |
![]() Antworten mit Zitat ![]() |
---|---|---|
Habe versucht Gouraudshading einzubauen - geht auch. Der Weg dahin fing aber mit Grundlagen an, die ich hier mal Stück für Stück hinstellen will.
Als erstes das eigentliche Programm von wo aus ich dann alles getestet habe: Code: [AUSKLAPPEN] Strict Framework brl.basic Import brl.glmax2d Import brl.pixmap Graphics 640, 480, 0 'Pixel werden in Pixmap gesetzt - malen ist dann leider lahm... Global hBack:TPixmap = CreatePixmap( 640, 480, PF_RGBA8888 ) Global hBArr:Byte Ptr[640, 480] For Local x:Int = 0 Until hBack.width For Local y:Int = 0 Until hBack.height hBArr[ x, y ] = PixmapPixelPtr( hBack, x, y ) Next Next '################### 'Hier kommen Anweisungen hin zum malen später While Not KeyHit( KEY_ESCAPE ) Cls DrawPixmap hBack, 0, 0 Flip FlushMem Wend Als erstes - und als Basis für alles andere später - werden Pixel gebraucht. Habe eine Funktion zum malen von außerhalb, die aber erst später eingefügt. Daher ist bei manchen Funktionen wohl einiges an unnötigem Speicherverbrauch zu verzeichnen, wenn ich extra einen Punkt erstelle für den Parameter. Code: [AUSKLAPPEN] Type TPoint Field x:Int, y:Int, z:Int 'Z war für später wichtig Field r:Byte, g:Byte, b:Byte 'Einen Punkt kopieren Function clone:TPoint( p:TPoint ) Local temp:TPoint = New TPoint temp.x = p.x temp.y = p.y temp.r = p.r temp.g = p.g temp.b = p.b Return temp EndFunction Function create:TPoint( x:Int, y:Int ) Local temp:TPoint = New TPoint temp.x = x temp.y = y Return temp EndFunction Method color( r:Byte, g:Byte, b:Byte ) Self.r = r Self.g = g Self.b = b EndMethod Method set( ) drawPixel( Self.x, Self.y, Self.r, Self.g, Self.b, 255 ) Rem hBArr[ Self.x, Self.y ][0] = Self.r hBArr[ Self.x, Self.y ][1] = Self.g hBArr[ Self.x, Self.y ][2] = Self.b hBArr[ Self.x, Self.y ][3] = 255 EndRem EndMethod EndType 'Pixel in Buffer setzen (später erst dazugekommen) Function drawPixel( x:Int, y:Int, r:Byte, g:Byte, b:Byte, a:Byte ) hBArr[ x, y ][0] = r hBArr[ x, y ][1] = g hBArr[ x, y ][2] = b hBArr[ x, y ][3] = a EndFunction 'Grundlegende Funktionen: 'Set/Unset ebdeutet immer weiß oder schwarz, waren die ersten Versuche 'für spätere Funktionen Function getPointFromPixel:TPoint( x:Int, y:Int ) Local temp:TPoint = TPoint.create( x, y ) Local r:Byte, b:Byte, g:Byte r = hBArr[ x, y ][0] g = hBArr[ x, y ][1] b = hBArr[ x, y ][2] temp.color( r, g, b ) Return temp EndFunction Function set_pixel( p:TPoint ) p.color( 255, 255, 255 ) p.set EndFunction Function del_pixel( p:TPoint ) p.color( 0, 0, 0 ) p.set EndFunction Function isPixelSet( x:Int, y:Int ) If hBArr[x, y][0] = 255 And hBArr[x, y][1] = 255 And hBArr[x, y][2] = 255 Then Return True EndFunction 'Linie "plotten", mit Abständen Function plot_line( p:TPoint, q:TPoint ) Rem Funktionsgleichung: y = m * x + b EndRem Local m:Double, b:Double 'Punkt kopieren p = TPoint.clone( p ) m = Double( q.y - p.y ) / Double( q.x - p.x ) b = Double( p.y * q.x - q.y * p.x ) / Double( q.x - p.x ) While p.x <= q.x p.y = Int( m * p.x + b + 0.5 ) set_pixel p p.x :+ 1 Wend p = Null EndFunction Function bresenham_line( p:TPoint, q:TPoint ) 'Punkt kopieren p = TPoint.clone( p ) 'Abstand Local DiffX:Int, DiffY:Int DiffX = q.x - p.x DiffY = q.y - p.y '"Richtung" oder sowas Local inc_x:Int, inc_y:Int If DiffX > 0 Then inc_x = 1 Else inc_x = -1 If DiffY > 0 Then inc_y = 1 Else inc_y = -1 Local error:Int, delta:Int, schwelle:Int If Abs( DiffY ) < Abs( DiffX ) error = -Abs( DiffX ) delta = 2 * Abs( DiffY ) schwelle = 2 * error While p.x <> q.x set_pixel p p.x :+ inc_x error :+ delta If error > 0 p.y :+ inc_y error :+ schwelle EndIf Wend Else error = -Abs( DiffY ) delta = 2 * Abs( DiffX ) schwelle = 2 * error While p.y <> q.y set_pixel p p.y :+ inc_y error :+ delta If error > 0 p.x :+ inc_x error :+ schwelle EndIf Wend EndIf set_pixel q EndFunction 'Linie interpolieren, also Farbverlauf erstellen Function bresenham_line_interpolated( p:TPoint, q:TPoint ) 'Punkt kopieren p = TPoint.clone( p ) 'Abstand Local DiffX:Int, DiffY:Int, Diff:Int DiffX = q.x - p.x DiffY = q.y - p.y Diff = Sqr( DiffX * DiffX + DiffY * DiffY ) 'Farbdifferenz Local dr:Int = q.r - p.r Local dg:Int = q.g - p.g Local db:Int = q.b - p.b Local dx:Int, dy:Int, d:Int Local r:Int, g:Int, b:Int 'Farbe pro pixel Local r_pp:Int = dr / Diff Local g_pp:Int = dg / Diff Local b_pp:Int = db / Diff '???????? Local inc_x:Int, inc_y:Int If DiffX > 0 Then inc_x = 1 Else inc_x = -1 If DiffY > 0 Then inc_y = 1 Else inc_y = -1 Local error:Int, delta:Int, schwelle:Int If Abs( DiffY ) < Abs( DiffX ) '0 - 45° (spitz) error = -Abs( DiffX ) delta = 2 * Abs( DiffY ) schwelle = 2 * error While p.x <> q.x dx = - Abs( q.x - p.x ) dy = - Abs( q.y - p.y ) d = - Sqr( dx * dx + dy * dy ) r = r_pp * d g = g_pp * d b = b_pp * d p.color( r, g, b ) p.set( ) p.x :+ inc_x error :+ delta If error > 0 p.y :+ inc_y error :+ schwelle EndIf Wend Else error = -Abs( DiffY ) delta = 2 * Abs( DiffX ) schwelle = 2 * error While p.y <> q.y dx = - Abs( q.x - p.x ) dy = - Abs( q.y - p.y ) d = - Sqr( dx * dx + dy * dy ) r = r_pp * d g = g_pp * d b = b_pp * d p.color( r, g, b ) p.set( ) p.y :+ inc_y error :+ delta If error > 0 p.x :+ inc_x error :+ schwelle EndIf Wend EndIf q.set EndFunction Function bresenham_circle( p:TPoint, r:Int ) Local x:Int, y:Int x = 0 y = r Local d:Int, dx:Int, dxy:Int d = 1 - r dx = 3 dxy = -2 * r + 5 While y >= x 'Das hier kann man mittlerweile umschreiben set_pixel( TPoint.create( p.x + x, p.y + y ) ) set_pixel( TPoint.create( p.x + y, p.y + x ) ) set_pixel( TPoint.create( p.x + y, p.y - x ) ) set_pixel( TPoint.create( p.x + x, p.y - y ) ) set_pixel( TPoint.create( p.x - x, p.y - y ) ) set_pixel( TPoint.create( p.x - y, p.y - x ) ) set_pixel( TPoint.create( p.x - y, p.y + x ) ) set_pixel( TPoint.create( p.x - x, p.y + y ) ) If d < 0 d :+ dx dx :+ 2 dxy :+ 2 x :+ 1 Else d :+ dxy dx :+ 2 dxy :+ 4 x :+ 1 y:- 1 EndIf Wend EndFunction 'Füllroutine Function fillRowByRow( x:Int, y:Int ) Local lg:Int, rg:Int Local hilf:TPoint Local px = x While Not isPixelSet( x, y ) hilf = TPoint.create( x, y ) set_pixel( hilf ) x :- 1 Wend lg = x + 1 x = px + 1 While Not isPixelSet( x, y ) hilf = TPoint.create( x, y ) set_pixel( hilf ) x :+ 1 Wend rg = x - 1 For Local pos:Int = rg To lg Step -1 If Not isPixelSet( pos, y - 1 ) Then fillRowByRow( pos, y - 1 ) If Not isPixelSet( pos, y + 1 ) Then fillRowByRow( pos, y + 1 ) Next EndFunction '"Normale" lineare Interpolation mit Farbe Function line_interpolated( p:TPoint, q:TPoint ) 'Positionsdifferenz Local diffX:Int = q.x - p.x Local diffY:Int = q.y - p.y Local arr:TPoint[Abs(diffY)] 'Gesamte Differenz und Erhöhung für Mu Local diff:Int = Sqr( diffX * diffX + diffY * diffY ) Local fac:Float = 1.0 / diff 'Farbdifferenz Local dr:Int, dg:Int, db:Int dr = q.r - p.r dg = q.g - p.g db = q.b - p.b 'Farben und Koordinaten der Punkte Local r:Byte, g:Byte, b:Byte Local x:Int, y:Int Local mu:Float = 0.0 While mu <= 1.0 x = diffX * mu + p.x y = p.y + diffY * mu 'Farbdifferenz * Schritt r = p.r + dr * mu g = p.g + dg * mu b = p.b + db * mu r = 255 'Pixel malen drawPixel( x, y, r, g, b, 255 ) 'Pixelabstand mu :+ fac Wend EndFunction 'Linie für Testzwecke zeichnen Function ll( p:TPoint, q:TPoint ) Local diffX:Int = q.x - p.x Local diffY:Int = q.y - p.y Local x:Int, y:Float = p.y Local delta:Float = 1.0 * diffY / diffX For x = p.x To q.x drawPixel( x, y, 255, 255, 0, 255 ) y :+ delta Next EndFunction Ja, und dann noch fein was zum anschauen (muss an die markeirte Stelle) Code: [AUSKLAPPEN] Local p:TPoint = TPoint.create( 10, 10 ) p.color( 255, 128, 0 ) local q:TPoint = TPoint.create( 190, 239 ) q.color( 30, 130, 180 ) line_interpolated( p, q ) local m:TPoint = TPoint.create( 400, 200 ) bresenham_circle( m, 20 ) fillRowByRow( m.x, m.y ) |
||
christian.tietze@gmail.com - https://christiantietze.de
macOS |
- Zuletzt bearbeitet von DivineDominion am So, Mai 15, 2005 20:02, insgesamt einmal bearbeitet
Dreamora |
![]() Antworten mit Zitat ![]() |
|
---|---|---|
*nicht versteht, was das mit Gouraud Shading zu tun hat* | ||
Ihr findet die aktuellen Projekte unter Gayasoft und könnt mich unter @gayasoft auf Twitter erreichen. |
![]() |
DivineDominion |
![]() Antworten mit Zitat ![]() |
---|---|---|
Nicht so schnell, war beim Schulsport ![]() Also, weiter gehts. Jetzt kommen Kanten, die ich bei einem Polygon später für eine Edgelist brauche. Die Koordinaten der einzelnen Punkte werden in einem Array (_raster) gespeichert. Das ist dann wie bei plot_line, wo für jede X-Koordinate immer nur eine Y-Koordinate existierte, nur eben nun andersrum: Jede Zeile (Y) bekommt ein X zugeordnet. Nicht ganz der mathematische Fubnktionsbegriff aber dafür füllen wir die Abstände von links nach rechts, nicht oben nach unten. Ginge aber wohl auch. Also das hier irgendwie in eine include-Datei auslagern oder unten an den Code dranhängen. Code: [AUSKLAPPEN] Type TEdge Field hStart:TPoint, hEnd:TPoint Field _height:Int Field _xmin:Int, _xmax:Int Field _ymin:Int, _ymax:Int 'Bedeutung der Dimensionen: '[0, 2] : [y, x(0) & rgb(1)] Field _raster:Int[0,2] Function create:TEdge( p:TPoint, q:TPoint ) Local temp:TEdge = New TEdge 'Startpunkt soll der Obere sein If q.y < p.y temp.hStart = q temp.hEnd = p Else temp.hStart = p temp.hEnd = q EndIf temp._ymin = temp.hStart.y temp._ymax = temp.hEnd.y Rem Breite NICHT +1. damit der unterste Pixel ignoriert wird. Dieser untere Punkt wird von angrenzenden Polygonen verwendet (für nix anderes ist diese Variable sonst zu gebrauchen) und so ersetzt. EndRem temp._height = temp._ymax - temp._ymin If p.x < q.x temp._xmin = p.x temp._xmax = q.x Else temp._xmin = q.x temp._xmax = p.x EndIf 'y -> x, rgb - Liste erstellen temp.interpolate( ) Return temp EndFunction Method draw( ) For Local i:Int = 0 Until Self._height 'Farbe am Punkt der Zeile Local rgb:Int = Self._raster[i, 1] 'Farbanteile Local r:Int, g:Int, b:Int hex_rgb( rgb, r, g, b ) 'Position des Punktes der Zeile Local x:Int = Self._raster[i, 0] Local y:Int = Self.hStart.y + i 'Malen drawpixel( Self._xmin + x, y, r, g, b, 255 ) Next EndMethod Method interpolate( ) 'Kürzere Namen Local p:TPoint = Self.hStart Local q:TPoint = Self.hEnd 'Vertikale Differenz Local diffY:Int = q.y - p.y 'Raster entsprechend vergrößern Self._raster = New Int[diffY+1, 2] 'Attribute der Geradengleichung 'Steigung Local m:Float = Float( q.y - p.y ) / Float( q.x - p.x ) 'Achsenabschnitt Local y0:Float = Float( p.y * q.x - q.y * p.x ) / Float( q.x - p.x ) 'Steigung = 0 -> Horizontale If m = 0 'Buffer-Punkt Local arr_p:TPoint 'Je nachdem, welcher Punkt der Linke ist... If p.x < q.x arr_p = p Else arr_p = q EndIf '... wird die Koordinate genommen um einen Wert zu speichern Self._raster[0, 0] = arr_p.x - Self._xmin Self._raster[0, 1] = rgb_hex( arr_p.r, arr_p.g, arr_p.b ) 'Funktion verlassen Return EndIf 'Prozentualer Anteil eines Pixels gemessen an der Höhe Local verhaeltnis:Float = 1.0 / diffY 'Farbdifferenz vom Start- zum Ednpunkt Local dr:Int, dg:Int, db:Int dr = q.r - p.r dg = q.g - p.g db = q.b - p.b 'Die Höhe entlang iterieren For Local i:Int = 0 To diffY 'Umformen der Gleichung: ' y = mx + y0 '<=> x = ( y - y0 ) / m 'x-Position an y Self._raster[i, 0] = Int( ( ( p.y + i ) - y0 ) / m ) - Self._xmin 'Fortschritt "in %", relativ zur Höhe Local schritt:Float = i * verhaeltnis 'Farbanteile Local r:Int = 0, g:Int = 0, b:Int = 0 'Grundfarbe + ( Differenz * Fortschritt ) r = p.r + dr * schritt g = p.g + dg * schritt b = p.b + db * schritt 'Farbwert in Hex Local rgb:Int = rgb_hex( r, g, b ) 'Farbe speichern Self._raster[i, 1] = rgb Next EndMethod EndType 'Farbumwandlung (Hex wird im Array gespeichert, da nur eine einzige Zahl) Function rgb_hex( r:Byte, g:Byte, b:Byte ) Return ( r Shl 16 ) | ( g Shl 8 ) | b EndFunction Function hex_rgb( rgb:Int, r:Int Var, g:Int Var, b:Int Var ) r = (rgb Shr 16) & $ff g = (rgb Shr 8) & $ff b = rgb & $ff EndFunction Neues Beispiel für besagte Stelle im Hauptcode: Code: [AUSKLAPPEN] local p:TPoint = TPoint.create( 10, 10 ) p.color( 255, 255, 0 ) local q:TPoint = TPoint.create( 213, 423 ) q.color( 0, 0, 255 ) local e:TEdge = TEdge.create( p, q ) e.interpolate '_raster erstellen e.draw |
||
christian.tietze@gmail.com - https://christiantietze.de
macOS |
![]() |
DivineDominion |
![]() Antworten mit Zitat ![]() |
---|---|---|
Und dann kommen eben die Polygone. Habe ehrlichgesagt nur konvexe Polygone getestet, und zwar Dreiecke ![]() Das Raster sit nun zweidimensional. soll heißen, dass wir nicht nur für jede Zeile (Y) ein X speichern. Diesmal haben wir nämlich xStart und xEnd für jede Zeile, zwischen denen ausgefüllt wird. Die erste Dimension ist, wie im Code gleich kurz angedeutet, die Zeile (0 bis höhe - 1). Die zweite steht entweder xStart (links, 0) oder xEnd (rechts, 1). Wir interpoleiren horizontal von links nach rechts, deswegen. Die dritte Dimension hat dann für den jeweiligen X-Punkt die Koordinate (0) als auch die Farbe für den Punkt (1). Hmm, ja, anhängen und Beispiel unten testen. Code: [AUSKLAPPEN] Type TPoly Field _xmin:Int, _xmax:Int Field _ymin:Int, _ymax:Int Field _height:Int '[0, 2, 2] : [y, links (0) | rechts (1), x (0) | rgb (1)] Field _raster:Int[0,2,2] Field hEdgeList:TList Method New( ) Self.hEdgeList = CreateList( ) EndMethod Method draw( ) Local h:Int = Self._ymax - Self._ymin For Local i:Int = 0 To h - 1 'Relativer y-Wert + absolute Position Local y:Int = i + Self._ymin 'Linker Punkt Local x1:Int = Self._raster[i, 0, 0] + Self._xmin Local rgb1:Int = Self._raster[i, 0, 1] Local r1:Int, g1:Int, b1:Int hex_rgb( rgb1, r1, g1, b1 ) Local x2:Int = Self._raster[i, 1, 0] + Self._xmin Local rgb2:Int = Self._raster[i, 1, 1] Local r2:Int, g2:Int, b2:Int hex_rgb( rgb2, r2, g2, b2 ) 'Abstand zwischen Punkten Local dx:Int = x2 - x1 'Farbdifferenz Local dr:Int, dg:Int, db:Int dr = r2 - r1 dg = g2 - g1 db = b2 - b1 'Abstand "in %" Local verhaeltnis:Float = 1.0 / dx For Local j:Int = 0 To dx 'Relative Distanzüberbrückung + Startposition Local x:Int = j + x1 'Fortschritt "in %" = Distanzüberbrückung * % Local schritt:Float = j * verhaeltnis 'Farbe = Farbbasis + Fortschritt zur Zielfarbe Local r:Int = r1 + dr * schritt Local g:Int = g1 + dg * schritt Local b:Int = b1 + db * schritt drawPixel( x, y, r, g, b, 255 ) Next drawPixel( x1, y, r1, g1, b1, 255 ) ''drawPixel( x2, y, r2, g2, b2, 255 ) Next EndMethod Method addEdge( edge:TEdge ) Self.hEdgeList.addLast( edge ) EndMethod Method mergeEdges( ) Self._xmin = GraphicsWidth( ) Self._xmax = 0 Self._ymin = GraphicsHeight( ) Self._ymax = 0 For Local edge:TEdge = EachIn Self.hEdgeList If edge._xmin < Self._xmin Then Self._xmin = edge._xmin If edge._xmax > Self._xmax Then Self._xmax = edge._xmax If edge._ymin < Self._ymin Then Self._ymin = edge._ymin If edge._ymax > Self._ymax Then Self._ymax = edge._ymax Next Self._height = Self._ymax - Self._ymin + 1 'Jedes Y hat 2 X - links und rechts Local arr:Int[Self._height, 2, 2] For Local h:Int = 0 Until Self._height arr[h, 0, 0] = -1 arr[h, 1, 0] = -1 Next For Local edge:TEdge = EachIn Self.hEdgeList 'Local i:Int 'Kante - Start = Relative Anfangsposition Local dy:Int = edge._ymin - Self._ymin Local dx:Int = edge._xmin - Self._xmin For Local i:Int = 0 Until edge._height 'Y = Anfangsposition + Schritt Local y:Int = dy + i Local x = edge._raster[i, 0] + dx Local rgb = edge._raster[i, 1] If arr[y, 0, 0] > -1 'Schon gesetzt If arr[y, 0, 0] > x 'Größer als aktueller Wert 'Wert verswhcieben und neuen speichern arr[y, 1, 0] = arr[y, 0, 0] 'x arr[y, 1, 1] = arr[y, 0, 1] 'rgb arr[y, 0, 0] = x arr[y, 0, 1] = rgb Else 'Wert ist größer als gespeicherter arr[y, 1, 0] = x arr[y, 1, 1] = rgb EndIf Else 'Nicht vorhanden => links (0) speichern arr[y, 0, 0] = x arr[y, 0, 1] = rgb EndIf Next Next Self._raster = arr EndMethod EndType Hier das Beispiel: Code: [AUSKLAPPEN] 'Eckpunkte
local p_a:TPoint = TPoint.create( 10, 300 ) p_a.color 255, 0, 0 local p_b:TPoint = TPoint.create( 312, 140 ) p_b.color 0, 255, 0 local p_c:TPoint = Tpoint.create( 200, 10 ) p_c.color 0, 0, 255 'Seitenkanten local e_a:TEdge = TEdge.create( p_b, p_c ) local e_b:TEdge = TEdge.create( p_a, p_c ) local e_c:TEdge = TEdge.create( p_a, p_b ) 'Kanten interpolieren (sonst ist array leer) e_a.interpolate e_b.interpolate e_c.interpolate 'Dreieck local poly:TPoly = new TPoly poly.addEdge e_a poly.addEdge e_b poly.addEdge e_c poly.mergeEdges poly.draw |
||
christian.tietze@gmail.com - https://christiantietze.de
macOS |
![]() |
Vertex |
![]() Antworten mit Zitat ![]() |
---|---|---|
Ahh, wunderbar! Hast du schonmal ein paar Speed-Tests gemacht, ob man das event. für Softwarerendering benutzen kann? So 2000 Triangles bei flüssiger FPS Rate wären schon ganz gut.
Gut gefällt mir, das alles aufeinander aufbaut. Kenne noch die anderen Gouraudshading Funktionen hier im Forum, wo man nichtmehr durchgesehen hat. Benutzt du direkt den Gouraudalgorithmus? Wenn ja, wäre vllt. ganz gut, wenn du ihn nochmal mit eigenen Worten erklährst. mfg olli |
||
vertex.dreamfall.at | GitHub |
![]() |
DivineDominion |
![]() Antworten mit Zitat ![]() |
---|---|---|
Wer Theorie will:
http://www-lehre.informatik.un...0000000000 Habe damit angefangen früher mal, und diesmal hab ich auch versucht es zu verstehen ![]() Rastern von Dreiecken sit eben das man von oben nach unten (Scanline) die Start- und Endpunkte (xMin und xMax bzw. xStart und xEnd) speichert und dann dazwischen ansich bloß interpoliert. Naja zumindest wird oft das Wort "interpolieren" erwähnt etc und die Formel konnte ich auch entsprechend "umdingsen" ![]() ![]() Das mache ich im Prinzip beim Rastern der Kanten (Tedge.interpolate) und das Füllen dann auch anders: ![]() Ich weiß nicht ob es so anders aussehen würde, aber ich kann Farben schlecht addieren und dachte mir, dass es so schneller wäre als für jeden Pixel x2-xi zu rechnen etc... Naja das Zeug ist saulahm, übrigens ![]() |
||
christian.tietze@gmail.com - https://christiantietze.de
macOS |
Übersicht


Powered by phpBB © 2001 - 2006, phpBB Group