Gouraud Shaded Polygons from Scratch

  • Objekte in einer 3D Darstellung werden aus Polygonen erzeugt. Damit man die Kanten der Polygone nicht so sehr sieht und damit Lichteffekte (Shading) sichtbar wird, wird eine Technik namens Gouraud Shading (<> Flat Shading) eingesetzt.

    Ich hab das Ganze aus Spaß mal gan von vorn angefangen. Und so wird nur aus einer Funktion die einen einzigen Pixel färbt ein Polygon mit Smooth-Shading erzeugt. Dabei ist eine DllStruct das Canvas und muss nur bearbeitet werden. Nach dem Bearbeiten wird sie einfach auf die GUI beblittet ohne dabei auf Zeichenfunktionen aus GDI o.ä. zuzugreifen ^^.

    Spoiler anzeigen
    [autoit]

    #include <WindowsConstants.au3>
    #include <WinAPI.au3>
    #include <StaticConstants.au3>

    [/autoit] [autoit][/autoit] [autoit]

    Local $w = 500, $h = 500
    Local $xOrigin = $w/2;
    Local $yOrigin = $h-30;

    [/autoit] [autoit][/autoit] [autoit]

    $hgui = GUICreate("Gouraud Shaded Polys", $w, $h + 20)
    $hTime = GUICtrlCreateLabel("", 0, $h, $w, 20, $SS_CENTER)
    $DC_gui = _WinAPI_GetDC($hgui)
    GUISetState()

    [/autoit] [autoit][/autoit] [autoit]

    Global $ptr, $hbmp
    $DC_bitmap = _CreateNewBmp32($w, $h, $ptr, $hbmp)
    Global $struct = DllStructCreate("dword["& $w * $h& "]", $ptr)

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    $Timer = TimerInit()

    [/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]

    Do
    gpoly(Random(0,$w/2,1),Random(0,$h/2,1),Random($w/2,$w,1),Random(0,$h/2,1),Random(0,$w,1),Random($h/2,$h,1),Random(0,255,1),Random(0,255,1),Random(0,255,1))
    GUICtrlSetData($hTime, timerdiff($Timer))
    _WinAPI_BitBlt($DC_gui, 0, 0, $w, $h, $DC_bitmap, 0, 0, $srccopy)
    $Timer = TimerInit()
    Until GUIGetMsg() = -3

    [/autoit] [autoit][/autoit] [autoit]

    _DeleteBitmap32($DC_bitmap, $ptr, $hbmp)

    Func gpoly ($x1, $y1, $x2, $y2, $x3, $y3, $c1, $c2, $c3)
    DIM $poly[$h][2]
    DIM $colr[$h][2]
    Local $m = 0, $x = 0, $c = 0, $cm = 0
    IF $x1 + $x2 <> 0 AND $y1 + $y2 <> 0 THEN $m = ($x1 - $x2) / ($y1 - $y2)
    IF $c1 + $c2 <> 0 AND $y1 + $y2 <> 0 THEN $cm = ($c1 - $c2) / ($y1 - $y2)
    FOR $y = $y1 TO $y2
    $poly[$y][0] = $x + $x1
    $colr[$y][0] = $c + $c1
    $x = $x + $m
    $c = $c + $cm
    NEXT
    Local $m = 0, $x = 0, $c = 0, $cm = 0
    IF $x2 + $x3 <> 0 AND $y2 + $y3 <> 0 THEN $m = ($x2 - $x3) / ($y2 - $y3)
    IF $c2 + $c3 <> 0 AND $y2 + $y3 <> 0 THEN $cm = ($c2 - $c3) / ($y2 - $y3)
    FOR $y = $y2 TO $y3
    $poly[$y][0] = $x + $x2
    $colr[$y][0] = $c + $c2
    $x = $x + $m
    $c = $c + $cm
    NEXT
    Local $m = 0, $x = 0, $c = 0, $cm = 0
    IF $x1 + $x3 <> 0 AND $y1 + $y3 <> 0 THEN $m = ($x1 - $x3) / ($y1 - $y3)
    IF $c1 + $c3 <> 0 AND $y1 + $y3 <> 0 THEN $cm = ($c1 - $c3) / ($y1 - $y3)
    FOR $y = $y1 TO $y3
    $poly[$y][1] = $x + $x1
    $colr[$y][1] = $c + $c1
    $x = $x + $m
    $c = $c + $cm
    NEXT
    FOR $y = $y1 TO $y3
    gLINE($poly[$y][0], $poly[$y][1], $y, $colr[$y][0], $colr[$y][1])
    NEXT
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func gLINE($x1, $x2, $y, $c1, $c2)
    If $x1 > $x2 Then
    SWAP ($x1, $x2)
    SWAP ($c1, $c2)
    EndIf
    Local $cm = 0, $c = 0
    IF $c2 - $c1 <> 0 AND $x2 - $x1 <> 0 THEN $cm = ($c2 - $c1) / ($x2 - $x1)
    FOR $x = $x1 TO $x2
    DllStructSetData($struct, 1, ($c+$c1), $y*$w + $x + 1)
    $c += $cm
    NEXT
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func Swap(ByRef $a, ByRef $b)
    $t = $b
    $b = $a
    $a = $t
    EndFunc

    [/autoit] [autoit][/autoit] [autoit]

    Func _CreateNewBmp32($iwidth, $iheight, ByRef $ptr, ByRef $hbmp) ;erstellt leere 32-bit-Bitmap; Rückgabe $HDC und $ptr und handle auf die Bitmapdaten
    $hcdc = _WinAPI_CreateCompatibleDC(0) ;Desktop-Kompatiblen DeviceContext erstellen lassen
    $tBMI = DllStructCreate($tagBITMAPINFO) ;Struktur der Bitmapinfo erstellen und Daten eintragen
    DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4);Structgröße abzüglich der Daten für die Palette
    DllStructSetData($tBMI, "Width", $iwidth)
    DllStructSetData($tBMI, "Height", -$iheight) ;minus =standard = bottomup
    DllStructSetData($tBMI, "Planes", 1)
    DllStructSetData($tBMI, "BitCount", 32) ;32 Bit = 4 Bytes => AABBGGRR
    $adib = DllCall('gdi32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
    $hbmp = $adib[0] ;hbitmap handle auf die Bitmap, auch per GDI+ zu verwenden
    $ptr = $adib[4] ;pointer auf den Anfang der Bitmapdaten, vom Assembler verwendet
    _WinAPI_SelectObject($hcdc, $hbmp) ;objekt hbitmap in DC
    Return $hcdc ;DC der Bitmap zurückgeben
    EndFunc ;==>_CreateNewBmp32

    [/autoit] [autoit][/autoit] [autoit]

    Func _DeleteBitmap32($DC, $ptr, $hbmp)
    _WinAPI_DeleteDC($DC)
    _WinAPI_DeleteObject($hbmp)
    $ptr = 0
    EndFunc ;==>_DeleteBitmap32

    [/autoit]