Moin,
Habe mir überlegt mal einen kleinen Test für den Schattenwurf abzuhalten was Rechtecke betrifft. (Soll später in ASM ablaufen und teiltransparente Grafiken unterstützen, sodass man 2D Grafiken benutzen kann die je nach Lichtquelle einen Schatten haben. Die Sache mit dem GdipFillPolygon ist erstmal provisorisch).
Leider habe ich gemerkt, dass das von mir verwendete Verfahren relativ Fehlerbehaftet und Langsam ist.
Man kann mit ASM natürlich viel rausholen, aber der bessere Algorithmus schlägt den schnelleren Computer.
Verfahren
- Ermittlung der 3 von der Lichtquelle am weitesten entfernten Eckpunkte
- Berechnung der 3 Gradengleichungen mit z = 0 = P + a * Vz (für z = 0 trifft die Gerade den Boden. Damit ist der Multiplikator a bekannt)
- Berechnung der 3 Punkte am Boden
- Zusammenstellung von aPoints mit den 3 Eckpunkten und 3 Bodenpunkten
- Umsortierung (dieser Schritt dürfte garnicht vorkommen, aber ich weiß nicht wie man aPoints klüger zusammenstellt, sodass es direkt passt)
- GdipFillPolygon (dient erstmal nur als Platzhalter)
Daher bitte ich darum mir mitzuteilen, falls jemand schonmal etwas ähnliches gebaut hat, was mehr Performance bietet. (Leicht herauszufinden indem man die anzahl Rechtecke erhöht und schaut wann es ruckelt).
Skript
#include <GDIPlus.au3>
#include <Array.au3>
Opt('GuiOnEventMode', 1)
Opt('MustDeclareVars', 1)
Global Const $BLACKNESS = 66, $WHITENESS = 16711778
Global Const $iW = @DesktopWidth/4, $iH = @DesktopWidth/4, $iD = ($iW^2+$iH^2)^0.5
Global Const $iAnzahl = 8
Global Const $_ID_Rect = 1
_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]Global $aLight[3] = [$iW/2, $iH/2, $iD]
Global $aArea[1]
; 2D Obj
; [0] - Objekttyp
; [1] - x
; [2] - y
; [3] - w
; [4] - h
; [5] - vX
; [6] - vY
; [7] - Gravitationsmultiplikator ( 0 - 1 )
; [8] - Höhe über dem Boden
Global $hGUI = GUICreate('Schatten Test', $iW, $iH)
Global $hDC = _WinAPI_GetDC($hGUI)
Global $hIMG_Front = _Image_Create($iW, $iH)
Global $hDC_Buf_Front = DllStructGetData($hIMG_Front, 1, 1)
Global $hGFX_Buf_Front = _GDIPlus_GraphicsCreateFromHDC($hDC_Buf_Front)
Global $hIMG_Back = _Image_Create($iW, $iH)
Global $hDC_Buf_Back = DllStructGetData($hIMG_Back, 1, 1)
Global $hGFX_Buf_Back = _GDIPlus_GraphicsCreateFromHDC($hDC_Buf_Back)
Global $hBRU_Obj = _GDIPlus_BrushCreateSolid(0xFFA0A0A0)
Global $hBRU_Sch = _GDIPlus_BrushCreateSolid(0x30000000)
Global $hDLL_MSIMG32 = DllOpen('MSIMG32.DLL')
Global $vBlendFunc = __Image_GetBlendFunction()
_GDIPlus_GraphicsSetSmoothingMode($hGFX_Buf_Back, 4)
_GDIPlus_GraphicsSetSmoothingMode($hGFX_Buf_Front, 4)
GUISetOnEvent(-3, 'EVENT', $hGUI)
GUIRegisterMsg(0xF, 'WM_PAINT')
OnAutoItExitRegister('_X')
GUISetState(@SW_SHOW, $hGUI)
_Main()
[/autoit] [autoit][/autoit] [autoit]Func _Main()
[/autoit] [autoit][/autoit] [autoit]For $i = 1 To $iAnzahl Step 1
_Area_AddRect($aArea, _Rect_Create(($i = 1) * 999))
Next
While Sleep(50)
_WinAPI_BitBlt($hDC_Buf_Front, 0, 0, $iW, $iH, 0, 0, 0, $BLACKNESS)
_WinAPI_BitBlt($hDC_Buf_Back, 0, 0, $iW, $iH, 0, 0, 0, $WHITENESS)
_Area_Render($hGFX_Buf_Front, $hGFX_Buf_Back, $aArea)
WM_PAINT()
WEnd
EndFunc
[/autoit] [autoit][/autoit] [autoit]Func _Area_Render($hGFX_Front, $hGFX_Back, ByRef $aArea)
[/autoit] [autoit][/autoit] [autoit]Local $aObj, $aPoints, $tPoints
[/autoit] [autoit][/autoit] [autoit]For $i = 0 To UBound($aArea) - 1 Step 1
$aObj = $aArea[$i]
DllCall($ghGDIPDll, "int", "GdipFillRectangle", "handle", $hGFX_Front, "handle", $hBRU_Obj, "float", $aObj[1], "float", $aObj[2], "float", $aObj[3], "float", $aObj[4])
$aPoints = _CalcShadowRect($aLight, $aObj)
$tPoints = DllStructCreate("float[" & $aPoints[0][0] * 2 & "]")
For $iI = 1 To $aPoints[0][0]
DllStructSetData($tPoints, 1, $aPoints[$iI][0], (($iI - 1) * 2) + 1)
DllStructSetData($tPoints, 1, $aPoints[$iI][1], (($iI - 1) * 2) + 2)
Next
DllCall($ghGDIPDll, "int", "GdipFillPolygon", "handle", $hGFX_Buf_Back, "handle", $hBRU_Sch, "struct*", $tPoints, "int", $aPoints[0][0], "int", "FillModeAlternate")
[/autoit] [autoit][/autoit] [autoit]$aObj[1] += $aObj[5]
$aObj[2] += $aObj[6]
If $aObj[1] < 0 Then
$aObj[1] = -$aObj[1]
$aObj[5] = -$aObj[5]
ElseIf ($aObj[1] + $aObj[3]) > $iW Then
$aObj[1] -= ($aObj[1] + $aObj[3]) - $iW
$aObj[5] = -$aObj[5]
EndIf
If $aObj[2] < 0 Then
$aObj[2] = -$aObj[2]
$aObj[6] = -$aObj[6]
ElseIf ($aObj[2] + $aObj[4]) > $iH Then
$aObj[2] -= ($aObj[2] + $aObj[4]) - $iH
$aObj[6] = -$aObj[6]
EndIf
$aArea[$i] = $aObj
Next
EndFunc
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit]Func _CalcShadowRect($aLight, $aRect)
Local $aDist[4], $aVect[4][3], $xTmp
$aVect[0][0] = $aRect[1] - $aLight[0]
$aVect[0][1] = $aRect[2] - $aLight[1]
$aVect[1][0] = $aRect[1] + $aRect[3] - $aLight[0]
$aVect[1][1] = $aRect[2] - $aLight[1]
$aVect[2][0] = $aRect[1] - $aLight[0]
$aVect[2][1] = $aRect[2] + $aRect[4] - $aLight[1]
$aVect[3][0] = $aRect[1] + $aRect[3] - $aLight[0]
$aVect[3][1] = $aRect[2] + $aRect[4] - $aLight[1]
$aVect[0][2] = $aRect[8] - $aLight[2]
$aVect[1][2] = $aVect[0][2]
$aVect[2][2] = $aVect[0][2]
$aVect[3][2] = $aVect[0][2]
For $i = 0 To 3 Step 1
$aDist[$i] = ($aVect[$i][0]^2 + $aVect[$i][1]^2)^0.5
Next
While ($aDist[0] > $aDist[1]) Or ($aDist[1] > $aDist[2]) Or ($aDist[2] > $aDist[3])
For $i = 0 To 2 Step 1
If $aDist[$i] > $aDist[$i + 1] Then
$xTmp = $aDist[$i]
$aDist[$i] = $aDist[$i + 1]
$aDist[$i + 1] = $xTmp
$xTmp = $aVect[$i][0]
$aVect[$i][0] = $aVect[$i+1][0]
$aVect[$i+1][0] = $xTmp
$xTmp = $aVect[$i][1]
$aVect[$i][1] = $aVect[$i+1][1]
$aVect[$i+1][1] = $xTmp
EndIf
Next
WEnd
;~ [0][0] - Number of vertices
;~ [1][0] - Vertice 1 X position
;~ [1][1] - Vertice 1 Y position
;~ [2][0] - Vertice 2 X position
;~ [2][1] - Vertice 2 Y position
;~ [n][0] - Vertice n X position
;~ [n][1] - Vertice n Y position
Local $aRet[7][2]
$aRet[0][0] = 6
For $i = 1 To 3 Step 1
$aRet[$i][0] = $aLight[0] + $aVect[$i][0]
$aRet[$i][1] = $aLight[1] + $aVect[$i][1]
Next
;~ For $i = 4 To 6 Step 1
;~ $aRet[$i][0] = $aLight[0] + $aVect[$i-3][0] + 10
;~ $aRet[$i][1] = $aLight[1] + $aVect[$i-3][1] + 10
;~ Next
;~ X = lightX + a * VectX
;~ Y = lightY + a * VectY
;~ 0 = lightZ + a * VectZ
;~ a = lightZ/VectZ
[/autoit] [autoit][/autoit] [autoit]For $i = 4 To 6 Step 1
$aRet[$i][0] = $aLight[0] - $aVect[$i-3][0] * $aLight[2] / $aVect[$i-3][2]
$aRet[$i][1] = $aLight[1] - $aVect[$i-3][1] * $aLight[2] / $aVect[$i-3][2]
Next
;~ _ArrayDisplay($aRet)
;~ _ArrayDisplay($aRet)
For $x = 1 To 5 Step 1
;~ _ArrayDisplay($aRet)
For $i = $x+1 To 6 Step 1
If ($aRet[$x][0] = $aRet[$i][0]) Or ($aRet[$x][1] = $aRet[$i][1]) Then
;~ ConsoleWrite($i & @CRLF)
$xTmp = $aRet[$i][0]
$aRet[$i][0] = $aRet[$x][0]
$aRet[$x][0] = $xTmp
$xTmp = $aRet[$i][1]
$aRet[$i][1] = $aRet[$x][1]
$aRet[$x][1] = $xTmp
ExitLoop
EndIf
Next
Next
Local $iRichtung = 0
[/autoit] [autoit][/autoit] [autoit]If ($aRet[4][0] - $aRet[1][0]) < 0 Then $iRichtung += 1
If ($aRet[4][1] - $aRet[1][1]) < 0 Then $iRichtung += 2
;~ Switch $iRichtung
;~ Case 0
;~ Case 1
;~ Case 2
;~ Case 3
_Swap($aRet[3][0], $aRet[5][0])
_Swap($aRet[3][1], $aRet[5][1])
_Swap($aRet[5][0], $aRet[6][0])
_Swap($aRet[5][1], $aRet[6][1])
;~ EndSwitch
;~ _GDIPlus_GraphicsDrawString($hGFX_Buf_Front, 'richtung: ' & $iRichtung, $aRet[1][0]+10, $aRet[1][1]+10)
[/autoit] [autoit][/autoit] [autoit];~ _ArrayDisplay($aRet)
[/autoit] [autoit][/autoit] [autoit][/autoit] [autoit];~ For $i = 1 To 6 Step 1
;~ _GDIPlus_GraphicsFillEllipse($hGFX_Buf_Back, $aRet[$i][0] - 3, $aRet[$i][1] - 3, 6, 6, $hBRU_Obj)
;~ _GDIPlus_GraphicsDrawString($hGFX_Buf_Back, $i, $aRet[$i][0] - 3, $aRet[$i][1] - 3)
;~ Next
;~ _ArrayDisplay($aRet)
[/autoit] [autoit][/autoit] [autoit]Return $aRet
[/autoit] [autoit][/autoit] [autoit]EndFunc
[/autoit] [autoit][/autoit] [autoit]Func _Swap(ByRef $a, ByRef $b)
Local $c = $a
$a = $b
$b = $c
EndFunc
Func EVENT()
Switch @GUI_CtrlId
Case -3
Exit
EndSwitch
EndFunc
Func WM_PAINT()
DllCall($hDLL_MSIMG32, 'int', 'AlphaBlend', 'ptr', $hDC_Buf_Back, 'int', 0, 'int', 0, 'int', $iW, 'int', $iH, 'ptr', $hDC_Buf_Front, 'int', 0, 'int', 0, 'int', $iW, 'int', $iH, 'dword', $vBlendFunc)
_WinAPI_BitBlt($hDC, 0, 0, $iW, $iH, $hDC_Buf_Back, 0, 0, 0xCC0020)
EndFunc
Func _X()
_GDIPlus_GraphicsDispose($hGFX_Buf_Back)
_GDIPlus_GraphicsDispose($hGFX_Buf_Front)
_Image_Delete($hIMG_Back)
_Image_Delete($hIMG_Front)
_WinAPI_ReleaseDC($hGUI, $hDC)
_GDIPlus_BrushDispose($hBRU_Obj)
_GDIPlus_BrushDispose($hBRU_Sch)
_GDIPlus_Shutdown()
DllClose($hDLL_MSIMG32)
EndFunc
Func _Rect_Create($x = 0, $y = 0, $w = 0, $h = 0, $vX = 0, $vY = 0, $fGrav = 1, $nHoehe = 0)
If $x + $y + $w + $h + $vX + $vY + $fGrav = 1 Then
$w = Random($iW/16/4, $iW/16)
$h = Random($iH/16/4, $iH/16)
$x = Random($w/2, $iW - $w/2)
$y = Random($h/2, $iH - $h/2)
;~ $x = Random($w/2, $iW - $w/2)
;~ $y = Random($h/2, $iH - $h/2)
$vX = _AbsRandom(0.5, 1) * 5
$vY = (5 - Abs($vX)) * _RandomSign()
$fGrav = Random(0, 1)
$nHoehe = Random($iD/18, $iD/14)
EndIf
If $x = 999 Then
$w = $iD/32
$h = $iD/32
$x = $iW/2 - $w*2 + 0.00000031
$y = $iH/2 - $h*2 + 0.000000314
$vX = 5 + 0.000000001
$vY = 0 + 0.000000001
$fGrav = Random(0, 1)
$nHoehe = $iD*0.9
EndIf
Local $a[9] = [$_ID_Rect, $x, $y, $w, $h, $vX, $vY, $fGrav, $nHoehe]
Return $a
EndFunc
Func _AbsRandom($nMin, $nMax)
Return _RandomSign() * Random($nMin, $nMax)
EndFunc
Func _RandomSign()
Switch Random(0, 1, 1)
Case 0
Return 1
Case 1
Return -1
EndSwitch
EndFunc
Func _Area_AddRect(ByRef $aArea, $aRect)
Local $u = UBound($aArea)
If ($u = 1) And Not IsArray($aArea[0]) Then
$aArea[0] = $aRect
Else
ReDim $aArea[$u + 1]
$aArea[$u] = $aRect
EndIf
EndFunc
Func _Image_Create($iW, $iH)
Local $Ptr, $hDC, $hBmp, $tBMI, $qDIB, $vStruct
$hDC = _WinAPI_CreateCompatibleDC(0)
$tBMI = DllStructCreate($tagBITMAPINFO)
DllStructSetData($tBMI, "Size", DllStructGetSize($tBMI) - 4)
DllStructSetData($tBMI, "Width", $iW)
DllStructSetData($tBMI, "Height", -$iH)
DllStructSetData($tBMI, "Planes", 1)
DllStructSetData($tBMI, "BitCount", 32)
$qDIB = DllCall('GDI32.dll', 'ptr', 'CreateDIBSection', 'hwnd', 0, 'ptr', DllStructGetPtr($tBMI), 'uint', 0, 'ptr*', 0, 'ptr', 0, 'uint', 0)
$hBmp = $qDIB[0]
$Ptr = $qDIB[4]
_WinAPI_SelectObject($hDC, $hBmp)
$vStruct = DllStructCreate('int[5]')
DllStructSetData($vStruct, 1, $hDC, 1)
DllStructSetData($vStruct, 1, $iW, 2)
DllStructSetData($vStruct, 1, $iH, 3)
DllStructSetData($vStruct, 1, $Ptr, 4)
DllStructSetData($vStruct, 1, $hBmp, 5)
Return $vStruct
EndFunc ;==>_Image_Create
Func _Image_Delete(ByRef $vStruct)
_WinAPI_DeleteObject(DllStructGetData($vStruct, 1, 5))
_WinAPI_DeleteDC(DllStructGetData($vStruct, 1, 1))
$vStruct = 0
EndFunc ;==>_Image_Delete
Func __Image_GetBlendFunction($iAlpha = 255)
Local $vStruct = DllStructCreate($tagBLENDFUNCTION)
DllStructSetData($vStruct, 1, 0) ; 0 = AC_SRC_OVER
DllStructSetData($vStruct, 2, 0) ; 0 "Must be Zero"
DllStructSetData($vStruct, 3, $iAlpha) ; Alpha fürs ganze Bild
DllStructSetData($vStruct, 4, 1) ; 1 = Bild enthält einen Alphakanal
Local $vData = DllStructCreate('dword', DllStructGetPtr($vStruct))
Local $iData = DllStructGetData($vData, 1)
Return $iData
EndFunc ;==>__Image_GetBlendFunction
PS: Die "Lichtquelle" ist in der Mitte.
Edit: Boah, nach dem durchlesen merke ich, dass Deutsch am Morgen nicht meine Stärke ist
lg
Mars