GDI+ 3D Object Viewer (Wavefront .obj Format)

  • Vor kurzem hat eukalyptus mit diesem Script eine Möglichkeit gezeigt, um 3D Linien darzustellen.
    Ich wollte mal versuchen, eine Version zu schreiben, die 3D Dateien (in diesem Fall das OBJ Format von Wavefront) auslesen und die Modelle als Gitternetz darstellen kann.
    Das ist dabei herausgekommen. Ich weiß, dass das mit anderen Sprachen schneller geht, und über Direct3D oder OpenGL viel besser funktioniert als mit dem dafür gar nicht ausgelegten GDI+, aber ich wollte das so machen :D.
    Es ist leider alles andere als Performant, aber auf meinem PC läuft alles mit weniger als 300 Polygonen relativ flüssig. Das ist ja schon mal was ^^.
    Als Erstes öffnet sich ein Dialog, in dem man eine .obj Datei auswählen kann. Danach werden die Polygondaten aus der obj Datei in Kanten umgewandelt weil sie sich besser in ein Array speichern lassen. Das kann aber je nach Modell ziemlich lange dauern, weil der Teil noch nicht wirklich optimiert ist.. Sobald das Modell angezeigt wird, kann man es mit per linken Mausklick um die Y und Z Achsen drehen, mit den Pfeiltasten Links und Rechts um die X Achse drehen und mit Numpad +, - skalieren.
    Im Script sind noch einige Globale Veriablen die sich nach Belieben verändern lassen.

    Ich hoffe euch gefällt das Programm, trotz des Mangels an Anwendungsgebieten und würde mich über Rückmeldungen freuen :).
    Im Anhang sind noch ein paar Beispielmodelle.
    Die GDIP.au3 könnt ihr hier runterladen (das ist eine extrem nützliche Erweiterung der GDIPlus.au3 aus den Standard-Includes).

    3D Grid Viewer
    [autoit]

    #include <WindowsConstants.au3>
    #include <GUIConstants.au3>
    #include <GDIP.au3>
    #include <WinAPI.au3>
    #include <Misc.au3>
    #include <Array.au3>

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

    ; - Author: name22 (http://www.autoit.de)

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

    Opt("GUIOnEventMode", 1)
    Opt("MouseCoordMode", 2)

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

    ;###-v-SETTINGS-v-###

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

    $iWidth = 800
    $iHeight = 800
    $iDepth = 800
    $fPersp = 0.5

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

    $nRad_Deg = ACos(-1) / 180

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

    $nX_Angle = 0
    $nY_Angle = 0
    $nZ_Angle = 0
    $iX_RotAxis = $iWidth / 2
    $iY_RotAxis = $iHeight / 2
    $iZ_RotAxis = 250
    $nRot_Speed = 0.15

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

    $iARGB_BG = 0xFF000000
    $nFPS = 80

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

    $nScale = 10

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

    ;###-^-SETTINGS-^-###

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

    _GDIPlus_Startup()

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

    $sObjFile = FileOpenDialog("Open 3D Datafile", "", "Wavefront OBJ (*.obj)")
    $sData = FileRead($sObjFile)

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

    $aVertexRaw = StringRegExp($sData, "(?m)^v ([^ ]+) ([^ ]+) ([^ ]+)$", 3)
    $aFaceRaw = StringRegExp($sData, "(?m)^f((?: \S+)+)", 3)

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

    Global $aVertex[UBound($aVertexRaw) / 3 + 1][3] = [[UBound($aVertexRaw) / 3]]
    For $i = 1 To $aVertex[0][0]
    $aVertex[$i][0] = $aVertexRaw[($i - 1) * 3] * $nScale + $iX_RotAxis
    $aVertex[$i][1] = $aVertexRaw[($i - 1) * 3 + 1] * - $nScale + $iY_RotAxis
    $aVertex[$i][2] = $aVertexRaw[($i - 1) * 3 + 2] * - $nScale + $iZ_RotAxis
    Next

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

    ProgressOn("Processing Data", "Optimizing Structure...", "0%", Default, Default, 18)
    Global $aEdge[1][2] = [[0]]
    For $i = 0 To UBound($aFaceRaw) - 1
    $aPoints = StringRegExp($aFaceRaw[$i], " (\d+)", 3)
    For $iSub = 1 To UBound($aPoints) - 1
    $bCheck = False
    For $iCheck = 1 To $aEdge[0][0]
    If ($aEdge[$iCheck][0] = $aPoints[$iSub - 1] And $aEdge[$iCheck][1] = $aPoints[$iSub]) Or ($aEdge[$iCheck][0] = $aPoints[$iSub] And $aEdge[$iCheck][1] = $aPoints[$iSub - 1]) Then
    $bCheck = True
    ExitLoop
    EndIf
    Next
    If $bCheck Then ContinueLoop

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

    $aEdge[0][0] += 1
    ReDim $aEdge[$aEdge[0][0] + 1][2]

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

    $aEdge[$aEdge[0][0]][0] = $aPoints[$iSub - 1]
    $aEdge[$aEdge[0][0]][1] = $aPoints[$iSub]
    Next
    $bCheck = False
    For $iCheck = 1 To $aEdge[0][0]
    If ($aEdge[$iCheck][0] = $aPoints[0] And $aEdge[$iCheck][1] = $aPoints[UBound($aPoints) - 1]) Or ($aEdge[$iCheck][0] = $aPoints[UBound($aPoints) - 1] And $aEdge[$iCheck][1] = $aPoints[0]) Then
    $bCheck = True
    ExitLoop
    EndIf
    Next
    If $bCheck Then ContinueLoop

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

    $aEdge[0][0] += 1
    ReDim $aEdge[$aEdge[0][0] + 1][2]

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

    $aEdge[$aEdge[0][0]][0] = $aPoints[0]
    $aEdge[$aEdge[0][0]][1] = $aPoints[UBound($aPoints) - 1]
    $iProgress = Int($i / (UBound($aFaceRaw) - 1) * 100)
    ProgressSet($iProgress, $iProgress & "% - Polygon " & $i & "/" & UBound($aFaceRaw) - 1)
    Next
    ProgressOff()

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

    $tPoints_V = DllStructCreate("float[" & $aVertex[0][0] * 2 & "]")
    $pPoints_V = DllStructGetPtr($tPoints_V)
    $tPoints_H = DllStructCreate("float[" & $aVertex[0][0] * 2 & "]")
    $pPoints_H = DllStructGetPtr($tPoints_H)
    $tTypes = DllStructCreate("ubyte[" & $aVertex[0][0] & "]")
    $pTypes = DllStructGetPtr($tTypes)
    For $i = 1 To $aVertex[0][0]
    DllStructSetData($tPoints_V, 1, 0, (($i - 1) * 2) + 1)
    DllStructSetData($tPoints_H, 1, 0, (($i - 1) * 2) + 2)
    DllStructSetData($tTypes, 1, 1, $i)
    Next

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

    Global $aWarp_V[5][2] = [[4],[0, 0],[$iWidth / 2 * $fPersp, $iHeight / 2 * $fPersp],[0, $iHeight],[$iWidth / 2 * $fPersp, $iHeight - $iHeight / 2 * $fPersp]]
    Global $aWarp_H[5][2] = [[4],[0, $iHeight],[$iWidth, $iHeight],[$iWidth / 2 * $fPersp, $iHeight - $iHeight / 2 * $fPersp],[$iWidth - $iWidth / 2 * $fPersp, $iHeight - $iHeight / 2 * $fPersp]]

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

    $nSleepTime = 1000 / $nFPS

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

    $nFPS_Display = 0
    $nFPS_Average = $nFPS

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

    $vNTdll = DllOpen("ntdll.dll")
    $vU32Dll = DllOpen("user32.dll")

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

    $tPrecSleep = DllStructCreate("int64 time;")
    $pPrecSleep = DllStructGetPtr($tPrecSleep)

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

    $hMain = GUICreate("3D OBJ Viewer by name22", $iWidth, $iHeight)
    GUISetCursor(16, 1)
    GUISetState()

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

    $hDC_Main = _WinAPI_GetDC($hMain)
    $hDC_Buffer = _WinAPI_CreateCompatibleDC($hDC_Main)
    $hBitmap_Buffer = _WinAPI_CreateCompatibleBitmap($hDC_Main, $iWidth, $iHeight)
    _WinAPI_SelectObject($hDC_Buffer, $hBitmap_Buffer)

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

    $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC_Buffer)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)

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

    $hPen_Figure = _GDIPlus_PenCreate(0xFF00FF00)
    $hPen_Cursor = _GDIPlus_PenCreate(0xFFFF0000)
    $hBrush_FPS = _GDIPlus_BrushCreateSolid(0xFF808080)
    $hBrush_Walls = _GDIPlus_BrushCreateSolid(0xFF00FF00)

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

    $hBitmap_Cursor = _GDIPlus_BitmapCreateFromGraphics(11, 11, $hGraphics)
    $hGraphics_Tmp = _GDIPlus_ImageGetGraphicsContext($hBitmap_Cursor)
    _GDIPlus_GraphicsDrawLine($hGraphics_Tmp, 0, 5, 11, 5, $hPen_Cursor)
    _GDIPlus_GraphicsDrawLine($hGraphics_Tmp, 5, 0, 5, 11, $hPen_Cursor)
    _GDIPlus_GraphicsDispose($hGraphics_Tmp)
    _GDIPlus_PenDispose($hPen_Cursor)

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

    $hStringFormat = _GDIPlus_StringFormatCreate()
    _GDIPlus_StringFormatSetAlign($hStringFormat, 2)
    $hFamily_FPS = _GDIPlus_FontFamilyCreate("Sony Sketch EF")
    $hFont_FPS = _GDIPlus_FontCreate($hFamily_FPS, 8)

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

    $aMeasure = _GDIPlus_GraphicsMeasureString($hGraphics, "FPS: 0", $hFont_FPS, _GDIPlus_RectFCreate(), $hStringFormat)
    $tLayout_FPS = _GDIPlus_RectFCreate(0, $iHeight - DllStructGetData($aMeasure[0], "Height"), $iWidth, 0)

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

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Close", $hMain)
    OnAutoItExitRegister("_Shutdown")

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

    $aMousePosOld = MouseGetPos()
    $nT_Time = TimerInit()
    $nT_UpdateFPS = TimerInit()
    $nT_Sleep = TimerInit() + $nSleepTime

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

    While True
    DllStructSetData($tPrecSleep, "time", -10000 * ($nSleepTime - TimerDiff($nT_Sleep)))
    DllCall($vNTdll, "dword", "ZwDelayExecution", "int", 0, "ptr", $pPrecSleep)
    $nFrameTime = TimerDiff($nT_Sleep)
    $nT_Sleep = TimerInit()
    $nFPS_Cur = 1000 / $nFrameTime
    If TimerDiff($nT_UpdateFPS) >= 1000 Then
    $nFPS_Display = $nFPS_Cur
    $nT_UpdateFPS = TimerInit()
    EndIf

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

    $aMousePosNew = MouseGetPos()
    GUIGetCursorInfo()

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

    If WinActive($hMain) And ($aMousePosNew[0] >= 0 And $aMousePosNew[0] <= $iWidth And $aMousePosNew[1] >= 0 And $aMousePosNew[1] <= $iHeight) And ($aMousePosOld[0] <> $aMousePosNew[0] Or $aMousePosOld[1] <> $aMousePosNew[1]) Then
    If _IsPressed("01", $vU32Dll) Then
    $nY_Angle = -($aMousePosNew[0] - $aMousePosOld[0]) * $nRad_Deg * $nRot_Speed
    $nX_Angle = ($aMousePosNew[1] - $aMousePosOld[1]) * $nRad_Deg * $nRot_Speed
    EndIf
    EndIf
    $aMousePosOld = $aMousePosNew
    If _IsPressed("25", $vU32Dll) Then $nZ_Angle = -$nRad_Deg * $nRot_Speed * 300 / $nFPS_Cur
    If _IsPressed("27", $vU32Dll) Then $nZ_Angle = $nRad_Deg * $nRot_Speed * 300 / $nFPS_Cur
    If _IsPressed("6D", $vU32Dll) Then _Scale(0.9)
    If _IsPressed("6B", $vU32Dll) Then _Scale(1.1)

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

    _GDIPlus_GraphicsClear($hGraphics, $iARGB_BG)

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

    $nSinX = Sin($nX_Angle)
    $nCosX = Cos($nX_Angle)
    $nSinY = Sin($nY_Angle)
    $nCosY = Cos($nY_Angle)
    $nSinZ = Sin($nZ_Angle)
    $nCosZ = Cos($nZ_Angle)

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

    For $iVTX = 1 To $aVertex[0][0]
    If $nX_Angle <> 0 Then
    $iY = $aVertex[$iVTX][1] - $iY_RotAxis
    $iZ = $aVertex[$iVTX][2] - $iZ_RotAxis
    $iY_T = $nCosX * $iY - $nSinX * $iZ
    $iZ_T = $nSinX * $iY + $nCosX * $iZ
    $aVertex[$iVTX][1] = $iY_T + $iY_RotAxis
    $aVertex[$iVTX][2] = $iZ_T + $iZ_RotAxis
    EndIf
    If $nY_Angle <> 0 Then
    $iX = $aVertex[$iVTX][0] - $iX_RotAxis
    $iZ = $aVertex[$iVTX][2] - $iZ_RotAxis
    $iX_T = $nCosY * $iX + $nSinY * $iZ
    $iZ_T = -$nSinY * $iX + $nCosY * $iZ
    $aVertex[$iVTX][0] = $iX_T + $iX_RotAxis
    $aVertex[$iVTX][2] = $iZ_T + $iZ_RotAxis
    EndIf
    If $nZ_Angle <> 0 Then
    $iX = $aVertex[$iVTX][0] - $iX_RotAxis
    $iY = $aVertex[$iVTX][1] - $iY_RotAxis
    $iX_T = $nCosZ * $iX - $nSinZ * $iY
    $iY_T = $nSinZ * $iX + $nCosZ * $iY
    $aVertex[$iVTX][0] = $iX_T + $iX_RotAxis
    $aVertex[$iVTX][1] = $iY_T + $iY_RotAxis
    EndIf
    DllStructSetData($tPoints_V, 1, $aVertex[$iVTX][2], (($iVTX - 1) * 2) + 1)
    DllStructSetData($tPoints_V, 1, $aVertex[$iVTX][1], (($iVTX - 1) * 2) + 2)
    DllStructSetData($tPoints_H, 1, $aVertex[$iVTX][0], (($iVTX - 1) * 2) + 1)
    DllStructSetData($tPoints_H, 1, $aVertex[$iVTX][2], (($iVTX - 1) * 2) + 2)
    Next
    $aTemp = DllCall($ghGDIPDll, "uint", "GdipCreatePath2", "ptr", $pPoints_V, "ptr", $pTypes, "int", $aVertex[0][0], "int", 0, "int*", 0)
    $hPath_V = $aTemp[5]
    $aTemp = DllCall($ghGDIPDll, "uint", "GdipCreatePath2", "ptr", $pPoints_H, "ptr", $pTypes, "int", $aVertex[0][0], "int", 0, "int*", 0)
    $hPath_H = $aTemp[5]
    $nX_Angle = 0
    $nY_Angle = 0
    $nZ_Angle = 0

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

    _GDIPlus_PathWarp($hPath_V, 0, $aWarp_V, 0, 0, $iDepth, $iHeight)
    _GDIPlus_PathWarp($hPath_H, 0, $aWarp_H, 0, 0, $iWidth, $iDepth)
    $aPoints_V = _GDIPlus_PathGetPoints($hPath_V)
    $aPoints_H = _GDIPlus_PathGetPoints($hPath_H)
    _GDIPlus_PathDispose($hPath_V)
    _GDIPlus_PathDispose($hPath_H)

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

    For $iEDG = 1 To $aEdge[0][0]
    _GDIPlus_GraphicsDrawLine($hGraphics, $aPoints_H[$aEdge[$iEDG][0]][0], $aPoints_V[$aEdge[$iEDG][0]][1], $aPoints_H[$aEdge[$iEDG][1]][0], $aPoints_V[$aEdge[$iEDG][1]][1], $hPen_Figure)
    Next

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

    _GDIPlus_GraphicsDrawImageRect($hGraphics, $hBitmap_Cursor, $aMousePosNew[0] - 5, $aMousePosNew[1] - 5, 11, 11)
    _GDIPlus_GraphicsDrawStringEx($hGraphics, "FPS: " & Int($nFPS_Display), $hFont_FPS, $tLayout_FPS, $hStringFormat, $hBrush_FPS)
    _WinAPI_BitBlt($hDC_Main, 0, 0, $iWidth, $iHeight, $hDC_Buffer, 0, 0, $SRCCOPY)
    WEnd

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

    Func _Scale($nScaleRel)
    For $i = 1 To $aVertex[0][0]
    $aVertex[$i][0] = ($aVertex[$i][0] - $iX_RotAxis) * $nScaleRel + $iX_RotAxis
    $aVertex[$i][1] = ($aVertex[$i][1] - $iY_RotAxis) * $nScaleRel + $iY_RotAxis
    $aVertex[$i][2] = ($aVertex[$i][2] - $iZ_RotAxis) * $nScaleRel + $iZ_RotAxis
    Next
    EndFunc ;==>_Scale

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

    Func _Close()
    Exit
    EndFunc ;==>_Close

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

    Func _Shutdown()
    _WinAPI_ReleaseDC($hMain, $hDC_Main)
    _WinAPI_DeleteDC($hDC_Buffer)
    _WinAPI_DeleteObject($hBitmap_Buffer)

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

    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BitmapDispose($hBitmap_Cursor)
    _GDIPlus_PenDispose($hPen_Figure)
    _GDIPlus_BrushDispose($hBrush_FPS)
    _GDIPlus_BrushDispose($hBrush_Walls)
    _GDIPlus_StringFormatDispose($hStringFormat)
    _GDIPlus_FontFamilyDispose($hFamily_FPS)
    _GDIPlus_FontDispose($hFont_FPS)
    _GDIPlus_Shutdown()

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

    DllClose($vNTdll)
    DllClose($vU32Dll)
    EndFunc ;==>_Shutdown

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

    ; #FUNCTION#;===============================================================================
    ;
    ; Name...........: _HighPrecisionSleep()
    ; Description ...: Sleeps down to 0.1 microseconds
    ; Syntax.........: _HighPrecisionSleep( $iMicroSeconds, $hDll=False)
    ; Parameters ....: $iMicroSeconds - Amount of microseconds to sleep
    ; $hDll - Can be supplied so the UDF doesn't have to re-open the dll all the time.
    ; Return values .: None
    ; Author ........: Andreas Karlsson (monoceres)
    ; Modified.......:
    ; Remarks .......: Even though this has high precision you need to take into consideration that it will take some time for autoit to call the function.
    ; Related .......:
    ; Link ..........;
    ; Example .......; No
    ;
    ;;==========================================================================================
    Func _HighPrecisionSleep($iMicroSeconds, $hDll = False)
    Local $hStruct, $bLoaded
    If Not $hDll Then
    $hDll = DllOpen("ntdll.dll")
    $bLoaded = True
    EndIf
    $hStruct = DllStructCreate("int64 time;")
    DllStructSetData($hStruct, "time", -1 * ($iMicroSeconds * 10))
    DllCall($hDll, "dword", "ZwDelayExecution", "int", 0, "ptr", DllStructGetPtr($hStruct))
    If $bLoaded Then DllClose($hDll)
    EndFunc ;==>_HighPrecisionSleep

    [/autoit]
    3D Grid Viewer - v2.0
    [autoit]

    #include <WindowsConstants.au3>
    #include <GUIConstants.au3>
    #include <GDIPlus.au3>
    #include <WinAPI.au3>
    #include <Misc.au3>

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

    ; - Author: name22 (http://www.autoit.de)

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

    Opt("GUIOnEventMode", 1)
    Opt("MouseCoordMode", 2)

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

    #region Global variables
    Global $hDll_User32 = DllOpen("user32.dll")
    Global $hDll_NTDll = DllOpen("ntdll.dll")

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

    Global Const $nPi = ACos(-1), $nTau = $nPi * 2, $nPiDiv180 = $nPi / 180, $nGimbalLockAngle = $nPi / 2 - 0.0001
    Global $hWnd_GUI, $iWidth_GUI, $iHeight_GUI, $iARGB_BG, $nFPS
    Global $hDC_Window, $hDC_Buffer, $hBMP_Buffer, $hGraphics, $hBrush_Black, $hBrush_Green, $hPen_Green, $hStringFormat, $hFamily_FPS, $hFont_FPS, $aMeasure, $tLayout_FPS
    Global $aV_Pos[3], $aV_Target[3], $aV_Up[3], $aV_X[3], $aV_Y[3], $aV_Z[3], $aEye[3], $aCamSpeedMov[3], $aCamSpeedRot[3], $aCamMov[3], $aCamAngle[3], $nFOV
    Global $nJumpVel, $nJumpSpeed, $nGravity, $nY_Zero
    Global $nSleepTime, $nFPS_Display, $nFPS_Cur, $tPrecSleep, $pPrecSleep
    Global $sObjFile, $sData, $aEdges[1][2] = [[0]]

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

    Global $nAngle = 0
    #endregion Global variables

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

    ;###-v-SETTINGS-v-###
    #region General Settings
    ;GUI-size X,Y
    $iWidth_GUI = 600
    $iHeight_GUI = 400

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

    ;Background-color ARGB
    $iARGB_BG = 0xFF000000

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

    ;Desired framerate
    $nFPS = 100

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

    ;Jumping speed / Gravity
    $nJumpSpeed = 2000
    $nGravity = 5000

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

    ;3D Model scale
    $nScale = 10
    #endregion General Settings

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

    #region Camera Settings
    ;Horizontal field of view in degrees
    $nFOV = 70

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

    ;Movement speed X,Y,Z
    $aCamSpeedMov[0] = 1500
    $aCamSpeedMov[1] = 0
    $aCamSpeedMov[2] = 3000

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

    ;Rotation speed X,Y
    $aCamSpeedRot[0] = 1 / ($iWidth_GUI / 2) * $nPi
    $aCamSpeedRot[1] = 1 / ($iHeight_GUI / 2) * $nPi / 2

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

    ;Camera position X,Y,Z
    $aV_Pos[0] = 0
    $aV_Pos[1] = 30
    $aV_Pos[2] = 800

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

    ;Camera target X,Y,Z
    $aV_Target[0] = 0
    $aV_Target[1] = 0
    $aV_Target[2] = -1

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

    ;Camera up-direction X,Y,Z
    $aV_Up[0] = 0
    $aV_Up[1] = 1
    $aV_Up[2] = 0
    #endregion Camera Settings
    ;###-^-SETTINGS-^-###

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

    #region 3D Model
    $sObjFile = FileOpenDialog("Open 3D Datafile", "", "Wavefront OBJ (*.obj)")
    $sData = FileRead($sObjFile)

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

    $aVertexRaw = StringRegExp($sData, "(?m)^v ([^ ]+) ([^ ]+) ([^ ]+)$", 3)
    $aFaceRaw = StringRegExp($sData, "(?m)^f((?: \S+)+)", 3)

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

    Global $aPoints_3D[UBound($aVertexRaw) / 3 + 1][3] = [[UBound($aVertexRaw) / 3]]
    Global $aPoints_2D[$aPoints_3D[0][0] + 1][3] = [[$aPoints_3D[0][0]]]
    For $i = 1 To $aPoints_3D[0][0]
    $aPoints_3D[$i][0] = $aVertexRaw[($i - 1) * 3] * $nScale
    $aPoints_3D[$i][1] = -$aVertexRaw[($i - 1) * 3 + 1] * $nScale
    $aPoints_3D[$i][2] = $aVertexRaw[($i - 1) * 3 + 2] * $nScale
    Next

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

    ProgressOn("Processing Data", "Optimizing Structure...", "0%", Default, Default, 18)
    For $i = 0 To UBound($aFaceRaw) - 1
    $aPoints = StringRegExp($aFaceRaw[$i], " (\d+)", 3)
    For $iSub = 1 To UBound($aPoints) - 1
    $bCheck = False
    For $iCheck = 1 To $aEdges[0][0]
    If ($aEdges[$iCheck][0] = $aPoints[$iSub - 1] And $aEdges[$iCheck][1] = $aPoints[$iSub]) Or ($aEdges[$iCheck][0] = $aPoints[$iSub] And $aEdges[$iCheck][1] = $aPoints[$iSub - 1]) Then
    $bCheck = True
    ExitLoop
    EndIf
    Next
    If $bCheck Then ContinueLoop

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

    $aEdges[0][0] += 1
    ReDim $aEdges[$aEdges[0][0] + 1][2]

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

    $aEdges[$aEdges[0][0]][0] = $aPoints[$iSub - 1]
    $aEdges[$aEdges[0][0]][1] = $aPoints[$iSub]
    Next
    $bCheck = False
    For $iCheck = 1 To $aEdges[0][0]
    If ($aEdges[$iCheck][0] = $aPoints[0] And $aEdges[$iCheck][1] = $aPoints[UBound($aPoints) - 1]) Or ($aEdges[$iCheck][0] = $aPoints[UBound($aPoints) - 1] And $aEdges[$iCheck][1] = $aPoints[0]) Then
    $bCheck = True
    ExitLoop
    EndIf
    Next
    If $bCheck Then ContinueLoop

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

    $aEdges[0][0] += 1
    ReDim $aEdges[$aEdges[0][0] + 1][2]

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

    $aEdges[$aEdges[0][0]][0] = $aPoints[0]
    $aEdges[$aEdges[0][0]][1] = $aPoints[UBound($aPoints) - 1]
    $iProgress = Int($i / (UBound($aFaceRaw) - 1) * 100)
    ProgressSet($iProgress, $iProgress & "% - Polygon " & $i & "/" & UBound($aFaceRaw) - 1)
    Next
    ProgressOff()
    #endregion

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

    #region Initialization
    ;Zero/Ground-level
    $nY_Zero = $aV_Pos[1]

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

    ;Eye position of hypothetical viewer X,Y,Z
    $aEye[0] = $iWidth_GUI / 2
    $aEye[1] = $iHeight_GUI / 2
    $aEye[2] = $iWidth_GUI / (2 * Tan(($nFOV * $nPiDiv180) / 2))

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

    ;Calculate third axis for cameras coordinate-system
    _Vector_Normal($aV_Target)
    _Vector_Normal($aV_Up)
    $aV_Z = $aV_Target
    $aV_Y = $aV_Up
    _Vector_Cross($aV_Z, $aV_Y, $aV_X)
    #endregion Initialization

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

    #region FPS Management
    $nSleepTime = 1000 / $nFPS

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

    $nFPS_Display = 0
    $nFPS_Average = $nFPS

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

    $tPrecSleep = DllStructCreate("int64 time;")
    $pPrecSleep = DllStructGetPtr($tPrecSleep)
    #endregion FPS Management

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

    $hWnd_GUI = GUICreate("3D Engine Test by name22", $iWidth_GUI, $iHeight_GUI)
    GUISetCursor(16, 1, $hWnd_GUI)
    GUISetState()

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

    MouseMove($aEye[0], $aEye[1], 0)

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

    $hDC_Window = _WinAPI_GetDC($hWnd_GUI)
    $hDC_Buffer = _WinAPI_CreateCompatibleDC($hDC_Window)
    $hBMP_Buffer = _WinAPI_CreateCompatibleBitmap($hDC_Window, $iWidth_GUI, $iHeight_GUI)
    _WinAPI_SelectObject($hDC_Buffer, $hBMP_Buffer)

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

    $hPen = _WinAPI_CreatePen($PS_SOLID, 1, 0x00FF00)
    _WinAPI_SelectObject($hDC_Buffer, $hPen)

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

    _GDIPlus_Startup()

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

    $hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC_Buffer)
    _GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)

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

    $hBrush_Black = _GDIPlus_BrushCreateSolid(0xFFF0F0F0)
    $hBrush_Green = _GDIPlus_BrushCreateSolid(0xFF00FF00)
    $hPen_Green = _GDIPlus_PenCreate(0xFF00FF00)

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

    $hStringFormat = _GDIPlus_StringFormatCreate()
    $hFamily_FPS = _GDIPlus_FontFamilyCreate("Consolas")
    $hFont_FPS = _GDIPlus_FontCreate($hFamily_FPS, 6.5, 1)

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

    #region FPS Counter
    $aMeasure = _GDIPlus_GraphicsMeasureString($hGraphics, "FPS: 0000", $hFont_FPS, _GDIPlus_RectFCreate(), $hStringFormat)
    $tLayout_FPS = $aMeasure[0]
    $aMeasure = 0
    DllStructSetData($tLayout_FPS, "X", $iWidth_GUI - DllStructGetData($tLayout_FPS, "Width") - 3)
    DllStructSetData($tLayout_FPS, "Y", $iHeight_GUI - DllStructGetData($tLayout_FPS, "Height"))
    DllStructSetData($tLayout_FPS, "Width", DllStructGetData($tLayout_FPS, "Width") + 3)
    #endregion FPS Counter

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

    GUISetOnEvent($GUI_EVENT_CLOSE, "_Close", $hWnd_GUI)
    GUIRegisterMsg($WM_MOUSEMOVE, "_MouseMove")
    OnAutoItExitRegister("_Shutdown")

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

    $nT_UpdateFPS = TimerInit()
    $nT_Sleep = TimerInit()

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

    While True
    #region FPS Stuff
    DllStructSetData($tPrecSleep, "time", -10000 * ($nSleepTime - TimerDiff($nT_Sleep)))
    DllCall($hDll_NTDll, "dword", "ZwDelayExecution", "int", 0, "ptr", $pPrecSleep)
    $nFrameTime = TimerDiff($nT_Sleep)
    $nT_Sleep = TimerInit()

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

    $nFPS_Cur = 1000 / $nFrameTime
    If TimerDiff($nT_UpdateFPS) >= 1000 Then
    $nFPS_Display = $nFPS_Cur
    $nT_UpdateFPS = TimerInit()
    EndIf
    #endregion FPS Stuff

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

    #region Camera Movement
    If $nJumpVel Then
    $aV_Pos[1] += $nJumpVel / $nFPS_Cur
    $nJumpVel += $nGravity / $nFPS_Cur
    If $aV_Pos[1] > $nY_Zero Then
    $aV_Pos[1] = $nY_Zero
    $nJumpVel = 0
    EndIf
    EndIf
    $aCamMov[0] = 0
    $aCamMov[1] = 0
    $aCamMov[2] = 0
    Switch True
    Case _IsPressed("25", $hDll_User32) Or _IsPressed("41", $hDll_User32)
    $aCamMov[0] = -1
    Case _IsPressed("27", $hDll_User32) Or _IsPressed("44", $hDll_User32)
    $aCamMov[0] = 1
    EndSwitch
    Switch True
    Case _IsPressed("26", $hDll_User32) Or _IsPressed("57", $hDll_User32)
    $aCamMov[2] = 1
    Case _IsPressed("28", $hDll_User32) Or _IsPressed("53", $hDll_User32)
    $aCamMov[2] = -1
    EndSwitch
    If $aCamMov[0] Or $aCamMov[1] Or $aCamMov[2] Then
    _Vector_Normal($aCamMov)
    $aCamMov[0] *= $aCamSpeedMov[0] / $nFPS_Cur
    $aCamMov[2] *= $aCamSpeedMov[2] / $nFPS_Cur
    _Camera_MoveInCameraSpaceXZ($aCamMov)
    EndIf
    If _IsPressed("20", $hDll_User32) And $aV_Pos[1] = $nY_Zero Then $nJumpVel = -$nJumpSpeed
    #endregion Camera Movement

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

    $nAngle += $nPi * 0.5 / $nFPS_Cur

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

    #region 3D Projection
    For $i = 1 To $aPoints_3D[0][0]
    ;Translation to camera-center
    $nX_T = ($aPoints_3D[$i][0] * Cos($nAngle) - $aPoints_3D[$i][1] * Sin($nAngle)) - $aV_Pos[0]
    $nY_T = ($aPoints_3D[$i][0] * Sin($nAngle) + $aPoints_3D[$i][1] * Cos($nAngle)) - $aV_Pos[1]
    $nZ_T = $aPoints_3D[$i][2] - $aV_Pos[2]

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

    ;Rotation to cameras viewing-angle
    $nX = $nX_T * $aV_X[0] + $nY_T * $aV_X[1] + $nZ_T * $aV_X[2]
    $nY = $nX_T * $aV_Y[0] + $nY_T * $aV_Y[1] + $nZ_T * $aV_Y[2]
    $nZ = $nX_T * $aV_Z[0] + $nY_T * $aV_Z[1] + $nZ_T * $aV_Z[2]

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

    ;Perspective projection of 3D coords onto 2D screen
    If $nZ <= -50 Then
    $aPoints_2D[$i][2] = False
    Else
    $nDepth = $aEye[2] + $nX_T * $aV_Z[0] + $nY_T * $aV_Z[1] + $nZ_T * $aV_Z[2]
    $aPoints_2D[$i][0] = (($nX_T * $aV_X[0] + $nY_T * $aV_X[1] + $nZ_T * $aV_X[2]) * $aEye[2]) / $nDepth
    $aPoints_2D[$i][1] = (($nX_T * $aV_Y[0] + $nY_T * $aV_Y[1] + $nZ_T * $aV_Y[2]) * $aEye[2]) / $nDepth
    If Abs($aPoints_2D[$i][0]) > $aEye[0] + 100 Or Abs($aPoints_2D[$i][1]) > $aEye[1] + 100 Then
    $aPoints_2D[$i][2] = False
    Else
    $aPoints_2D[$i][2] = True
    $aPoints_2D[$i][0] += $aEye[0]
    $aPoints_2D[$i][1] += $aEye[1]
    EndIf
    EndIf
    Next
    #endregion 3D Projection

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

    #region Drawing
    _GDIPlus_GraphicsClear($hGraphics, $iARGB_BG)
    For $i = 1 To $aEdges[0][0]
    ;~ _GDIPlus_GraphicsDrawLine($hGraphics, $aPoints_2D[$aEdges[$i][0]][0], $aPoints_2D[$aEdges[$i][0]][1], $aPoints_2D[$aEdges[$i][1]][0], $aPoints_2D[$aEdges[$i][1]][1], $hPen_Green)
    If $aPoints_2D[$aEdges[$i][0]][2] And $aPoints_2D[$aEdges[$i][1]][2] Then _WinAPI_DrawLine($hDC_Buffer, $aPoints_2D[$aEdges[$i][0]][0], $aPoints_2D[$aEdges[$i][0]][1], $aPoints_2D[$aEdges[$i][1]][0], $aPoints_2D[$aEdges[$i][1]][1])
    Next

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

    _GDIPlus_GraphicsDrawEllipse($hGraphics, $aEye[0] - 4, $aEye[1] - 4, 8, 8, $hPen_Green)
    _GDIPlus_GraphicsDrawStringEx($hGraphics, "FPS: " & Round($nFPS_Display, 1), $hFont_FPS, $tLayout_FPS, $hStringFormat, $hBrush_Black)
    _WinAPI_BitBlt($hDC_Window, 0, 0, $iWidth_GUI, $iHeight_GUI, $hDC_Buffer, 0, 0, $SRCCOPY)
    #endregion Drawing
    WEnd

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

    Func _MouseMove($hWnd, $iMsg, $wParam, $lParam)
    #forceref $hWnd, $iMsg, $wParam, $lParam
    Local $iX_MouseMove = BitAND($lParam, 0xFFFF) - $aEye[0]
    Local $iY_MouseMove = BitShift($lParam, 16) - $aEye[1]
    If $iX_MouseMove Then
    $aCamAngle[1] -= $iX_MouseMove * $aCamSpeedRot[1]
    If Abs($aCamAngle[1]) > $nTau Then $aCamAngle[1] = 0
    EndIf
    If $iY_MouseMove Then
    $aCamAngle[0] += $iY_MouseMove * $aCamSpeedRot[0]
    If Abs($aCamAngle[0]) > $nGimbalLockAngle Then $aCamAngle[0] = $nGimbalLockAngle * ($aCamAngle[0] / Abs($aCamAngle[0]))
    EndIf
    MouseMove($aEye[0], $aEye[1], 0)

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

    _Camera_RotateXY($aCamAngle[0], $aCamAngle[1])
    Return 0
    EndFunc ;==>_MouseMove

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

    Func _Camera_MoveInCameraSpaceXZ(ByRef $aMov)
    $aV_Pos[0] += $aMov[0] * $aV_X[0] + $aMov[1] * $aV_X[1] + $aMov[2] * $aV_X[2]
    $aV_Pos[2] += $aMov[0] * $aV_Z[0] + $aMov[1] * $aV_Z[1] + $aMov[2] * $aV_Z[2]
    EndFunc ;==>_Camera_MoveInCameraSpaceXZ

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

    Func _Camera_RotateXY($nX_Angle, $nY_Angle)
    Local $nSinTmpX = Sin($nX_Angle), $nSinTmpY = Sin($nY_Angle)
    Local $nCosTmpX = Cos($nX_Angle), $nCosTmpY = Cos($nY_Angle)
    $aV_Z[0] = $aV_Target[0] * $nCosTmpY + $aV_Target[1] * $nSinTmpX * $nSinTmpY + $aV_Target[2] * $nCosTmpX * $nSinTmpY
    $aV_Z[1] = $aV_Target[1] * $nCosTmpX - $aV_Target[2] * $nSinTmpX
    $aV_Z[2] = $aV_Target[1] * $nSinTmpX * $nCosTmpY - $aV_Target[0] * $nSinTmpY + $aV_Target[2] * $nCosTmpX * $nCosTmpY
    $aV_Y[0] = $aV_Up[0] * $nCosTmpY + $aV_Up[1] * $nSinTmpX * $nSinTmpY + $aV_Up[2] * $nCosTmpX * $nSinTmpY
    $aV_Y[1] = $aV_Up[1] * $nCosTmpX - $aV_Up[2] * $nSinTmpX
    $aV_Y[2] = $aV_Up[1] * $nSinTmpX * $nCosTmpY - $aV_Up[0] * $nSinTmpY + $aV_Up[2] * $nCosTmpX * $nCosTmpY
    _Vector_Cross($aV_Z, $aV_Y, $aV_X)
    EndFunc ;==>_Camera_RotateXY

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

    Func _Vector_Normal(ByRef $aV)
    Local $nL = Sqrt($aV[0] ^ 2 + $aV[1] ^ 2 + $aV[2] ^ 2)
    $aV[0] = $aV[0] / $nL
    $aV[1] = $aV[1] / $nL
    $aV[2] = $aV[2] / $nL
    EndFunc ;==>_Vector_Normal

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

    Func _Vector_Dot(ByRef $aV_A, ByRef $aV_B)
    Return $aV_A[0] * $aV_B[0] + $aV_A[1] * $aV_B[1] + $aV_A[2] * $aV_B[2]
    EndFunc ;==>_Vector_Dot

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

    Func _Vector_Cross(ByRef $aV_A, ByRef $aV_B, ByRef $aV_C)
    $aV_C[0] = $aV_A[1] * $aV_B[2] - $aV_A[2] * $aV_B[1]
    $aV_C[1] = $aV_A[2] * $aV_B[0] - $aV_A[0] * $aV_B[2]
    $aV_C[2] = $aV_A[0] * $aV_B[1] - $aV_A[1] * $aV_B[0]
    EndFunc ;==>_Vector_Cross

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

    Func _Close()
    Exit
    EndFunc ;==>_Close

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

    Func _Shutdown()
    GUIRegisterMsg($WM_MOUSEMOVE, "")

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

    _WinAPI_ReleaseDC($hWnd_GUI, $hDC_Window)
    _WinAPI_DeleteDC($hDC_Buffer)
    _WinAPI_DeleteObject($hBMP_Buffer)
    _WinAPI_DeleteObject($hPen)

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

    _GDIPlus_GraphicsDispose($hGraphics)
    _GDIPlus_BrushDispose($hBrush_Black)
    _GDIPlus_BrushDispose($hBrush_Green)
    _GDIPlus_PenDispose($hPen_Green)
    _GDIPlus_StringFormatDispose($hStringFormat)
    _GDIPlus_FontFamilyDispose($hFamily_FPS)
    _GDIPlus_FontDispose($hFont_FPS)
    _GDIPlus_Shutdown()

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

    DllClose($hDll_NTDll)
    DllClose($hDll_User32)
    EndFunc ;==>_Shutdown

    [/autoit]

    Edit: Ich habe eine neue Version hinzugefügt, die zwar keine markanten neuen Features mit sich bringt, aber von Grund auf neu (besser) geschrieben wurde. Die neue Version verwendet eine andere Steuerung die man sonst eher in einem Ego-shooter findet.

  • Warum legt eigentlich keiner mit den größern GDI+ Beispielen die GDIP.au3 bei :cursing:. Natürlich trotzdem tolles Skript.

    Es läuft schön flüssig. Ein numpad habe ich nicht, habs aber umgeschrieben. Das Skalieren laggt dann schon (MacBook Air i5). Ist natürlich kein Ersatz für Irrlicht, aber du hast einen guten OBJ Interpreter für GDI+ geschrieben. Soweit ich das überblicke könnte man das eigentlich auch auf OGl umschreiben, sozusagen ein Mini-Irrlicht :D.

    Grüße

    Einmal editiert, zuletzt von minx (28. April 2012 um 23:30)

  • Zitat

    Beeindurckend! Wie bist du an den Aufbau der .obj Daten gekommen? Selber herausgefunden?


    Danke. Wavefront obj ist ein offenes Dateiformat, und über Google finden sich einige Erklärungen wie es aufgebaut ist. ;)
    Unter anderem bin ich auf das hier gestoßen: http://en.wikipedia.org/wiki/Wavefront_.obj_file
    Alle anderen Formate die ich kannte waren mit zu kompliziert :D.

  • nice nice^^
    mach ma das man zoomen kann ;D

    Sind TV-Quizfragen zu einfach? A) Ja B) Harry Potter

    Spoiler anzeigen

    Ich gebe zu dieser Post hat wahrscheinlich nicht viel geholfen,
    aber ich versuche wenigstens zu helfen :rolleyes:

  • Zitat

    mach ma das man zoomen kann ;D


    Die Steuerung will ich noch verbessern, so dass man sich besser orientieren kann. Zoomen kann man zwar noch nicht direkt, aber du kannst das ganze Modell mit den + und - Tasten auf dem Numpad vergrößern/verkleinern.

  • Moin,

    sehr schöne Demonstration von dem, was man so alles mit GDI+ machen kann.

    Performancetechnisch sind mir eine Hand voll Sachen aufgefallen. (in wie weit die einen großen Schub bringen weiß ich nicht)
    1. WinActive braucht seine Zeit. In Zeile 170 sollte WinActive ganz zum Schluss abgefragt werden. Das IsPressed eine Zeile Weiter kann noch mit in die If Abfrage reingezogen werden (Vor das WinActive).
    2. Du Rotierst jeden Frame, ob tatsächlich gedreht wurde oder nicht. Evtl macht es sinn ein 2tes Array für die Endkoords einzubauen und dieses ausschließlich im Falle einer Rotation zu aktualisieren.
    3. Die Schleife bei 237 läuft für jede Linie ein Mal durch. Es macht Sinn Den Funktionsaufruf durch den Direkten DllCall zu ersetzen (ohne @error und den ganzen Kram).

  • Moin Marsi.
    Mit deinen Tipps kann man sicherlich noch einige FPS rausholen. Ich werd mal sehen was ich da noch weglassen/verbessern kann. Die Rotation nimmt interessanterweise nur relativ wenig Berechnungszeit in Anspruch. Am längsten dauert (abgesehen von dem PathWarp Zeug) in den meisten Fällen das Zeichnen wie mir scheint.
    Das mit dem zweiten Array ist ne gute Idee, nicht nur aus performance Gründen. Eine Unterteilung zwischen Objekt- und Weltkoordinaten macht das ganze vermutlich übersichtlicher.

  • Großartiges Script! :thumbup:

    Hier hab ich ein Testscript, das ich vor kurzem erstellt hab.
    Damit kann man schnell zoomen, verschieben und drehen ohne das Objekt selbst neu zu berechnen.
    Es wird einfach der Ziel-GraphicsContext transformiert...

    Vielleicht kannst du das ja gebrauchen.
    (linke Maustaste = verschieben, Scrollrad = zoomen, linke Maustaste + Scrollrad = drehen, rechte Maustaste = reset)

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <WinAPI.au3>
    #include <WindowsConstants.au3>

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

    Opt("MustDeclareVars", 1)
    Opt("GUIOnEventMode", 1)

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

    Global $iWidth = 1000;@DesktopWidth
    Global $iHeight = 580;@DesktopHeight

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

    _GDIPlus_Startup()
    Global $hGui = GUICreate("Test", $iWidth, $iHeight)
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
    GUISetOnEvent($GUI_EVENT_SECONDARYDOWN, "_ResetGraphicsTransform")
    Global $hDC = _WinAPI_GetDC($hGui)
    Global $hBMP = _WinAPI_CreateCompatibleBitmap($hDC, $iWidth, $iHeight)
    Global $hBmpTmp = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
    _WinAPI_DeleteObject($hBMP)
    $hBMP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmpTmp)
    _GDIPlus_BitmapDispose($hBmpTmp)
    Global $hCDC = _WinAPI_CreateCompatibleDC($hDC)
    Global $hOBJ = _WinAPI_SelectObject($hCDC, $hBMP)
    Global $hGfxBuffer = _GDIPlus_GraphicsCreateFromHDC($hCDC)
    _GDIPlus_GraphicsSetSmoothingMode($hGfxBuffer, 2)
    _GDIPlus_GraphicsClear($hGfxBuffer, 0xFFFFFFFF)

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

    Global $hPenR = _GDIPlus_PenCreate(0xFFAA0000, 1)
    Global $hBrushR = _GDIPlus_BrushCreateSolid(0x88AA0000)
    Global $hPenG = _GDIPlus_PenCreate(0xFF00AA00, 1)
    Global $hBrushG = _GDIPlus_BrushCreateSolid(0x8800AA00)
    Global $hPenB = _GDIPlus_PenCreate(0xFF0000FF, 1)
    Global $hBrushB = _GDIPlus_BrushCreateSolid(0x880000FF)

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

    GUIRegisterMsg($WM_PAINT, "WM_PAINT")
    GUIRegisterMsg($WM_ERASEBKGND, "WM_PAINT")

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

    Global $iMouseX, $iMouseY
    GUIRegisterMsg($WM_LBUTTONDOWN, "WM_LBUTTONDOWN")
    GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL")
    GUIRegisterMsg($WM_MOUSEMOVE, "WM_MOUSEMOVE")
    GUISetState()

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

    Global $tCurve1 = _CreateCurve(Random(10, 30, 1))
    Global $tCurve2 = _CreateCurve(Random(10, 30, 1))
    Global $tCurve3 = _CreateCurve(Random(10, 30, 1))

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

    _Draw()

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

    While Sleep(10)
    WEnd

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

    Func _Draw()
    _GDIPlus_GraphicsClear($hGfxBuffer, 0xFFFFFFFF)

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

    DllCall($ghGDIPDll, "uint", "GdipFillClosedCurve2", "hwnd", $hGfxBuffer, "hwnd", $hBrushR, "ptr", DllStructGetPtr($tCurve1, "Pnt"), "int", DllStructGetData($tCurve1, "Cnt"), "float", 0, "int", 0)
    DllCall($ghGDIPDll, "uint", "GdipDrawClosedCurve2", "hwnd", $hGfxBuffer, "hwnd", $hPenR, "ptr", DllStructGetPtr($tCurve1, "Pnt"), "int", DllStructGetData($tCurve1, "Cnt"), "float", 0)

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

    DllCall($ghGDIPDll, "uint", "GdipFillClosedCurve2", "hwnd", $hGfxBuffer, "hwnd", $hBrushG, "ptr", DllStructGetPtr($tCurve2, "Pnt"), "int", DllStructGetData($tCurve2, "Cnt"), "float", 0, "int", 0)
    DllCall($ghGDIPDll, "uint", "GdipDrawClosedCurve2", "hwnd", $hGfxBuffer, "hwnd", $hPenG, "ptr", DllStructGetPtr($tCurve2, "Pnt"), "int", DllStructGetData($tCurve2, "Cnt"), "float", 0)

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

    DllCall($ghGDIPDll, "uint", "GdipFillClosedCurve2", "hwnd", $hGfxBuffer, "hwnd", $hBrushB, "ptr", DllStructGetPtr($tCurve3, "Pnt"), "int", DllStructGetData($tCurve3, "Cnt"), "float", 0, "int", 0)
    DllCall($ghGDIPDll, "uint", "GdipDrawClosedCurve2", "hwnd", $hGfxBuffer, "hwnd", $hPenB, "ptr", DllStructGetPtr($tCurve3, "Pnt"), "int", DllStructGetData($tCurve3, "Cnt"), "float", 0)

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

    _WinAPI_BitBlt($hDC, 0, 0, $iWidth, $iHeight, $hCDC, 0, 0, 0x00CC0020)
    EndFunc ;==>_Draw

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

    Func _ResetGraphicsTransform()
    DllCall($ghGDIPDll, "uint", "GdipResetWorldTransform", "hwnd", $hGfxBuffer)
    _Draw()
    EndFunc ;==>_ResetGraphicsTransform

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

    Func WM_LBUTTONDOWN($hWnd, $Msg, $wParam, $lParam)
    $iMouseX = BitAND($lParam, 0x0000FFFF)
    $iMouseY = BitShift($lParam, 16)
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_LBUTTONDOWN

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

    Func WM_MOUSEMOVE($hWnd, $Msg, $wParam, $lParam)

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

    Switch BitAND($wParam, 0x0000FFFF)
    Case 1
    Local $iX = BitAND($lParam, 0x0000FFFF)
    Local $iY = BitShift($lParam, 16)

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

    DllCall($ghGDIPDll, "uint", "GdipTranslateWorldTransform", "hwnd", $hGfxBuffer, "float", $iX - $iMouseX, "float", $iY - $iMouseY, "int", True)

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

    $iMouseX = $iX
    $iMouseY = $iY

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

    _Draw()

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

    EndSwitch

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

    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_MOUSEMOVE

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

    Func WM_MOUSEWHEEL($hWnd, $Msg, $wParam, $lParam)

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

    Switch BitAND($wParam, 0x0000FFFF)
    Case 1
    Local $fAngle = -3
    If BitShift($wParam, 16) < 0 Then $fAngle = 3

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

    Local $tPnt = DllStructCreate("float X; float Y;")
    DllStructSetData($tPnt, "X", $iMouseX)
    DllStructSetData($tPnt, "Y", $iMouseY)

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

    DllCall($ghGDIPDll, "uint", "GdipTransformPoints", "hwnd", $hGfxBuffer, "int", 0, "int", 1, "ptr", DllStructGetPtr($tPnt), "int", 1)

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

    Local $fX = DllStructGetData($tPnt, "X")
    Local $fY = DllStructGetData($tPnt, "Y")

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

    DllCall($ghGDIPDll, "uint", "GdipTranslateWorldTransform", "hwnd", $hGfxBuffer, "float", $fX, "float", $fY, "int", False)
    DllCall($ghGDIPDll, "uint", "GdipRotateWorldTransform", "hwnd", $hGfxBuffer, "float", $fAngle, "int", False)
    DllCall($ghGDIPDll, "uint", "GdipTranslateWorldTransform", "hwnd", $hGfxBuffer, "float", -$fX, "float", -$fY, "int", False)

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

    Case Else
    Local $aInfo = GUIGetCursorInfo($hGui)
    Local $fScale = 1.1
    If BitShift($wParam, 16) < 0 Then $fScale = 0.9

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

    DllCall($ghGDIPDll, "uint", "GdipTranslateWorldTransform", "hwnd", $hGfxBuffer, "float", -$aInfo[0], "float", -$aInfo[1], "int", True)
    DllCall($ghGDIPDll, "uint", "GdipScaleWorldTransform", "hwnd", $hGfxBuffer, "float", $fScale, "float", $fScale, "int", True)
    DllCall($ghGDIPDll, "uint", "GdipTranslateWorldTransform", "hwnd", $hGfxBuffer, "float", $aInfo[0], "float", $aInfo[1], "int", True)

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

    EndSwitch

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

    _Draw()

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

    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_MOUSEWHEEL

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

    Func _CreateCurve($iCnt)
    Local $tCurve = DllStructCreate("uint Cnt; float Pnt[" & $iCnt * 2 & "];")
    DllStructSetData($tCurve, "Cnt", $iCnt)
    For $i = 0 To $iCnt - 1
    DllStructSetData($tCurve, "Pnt", Random(0, $iWidth), $i * 2 + 1)
    DllStructSetData($tCurve, "Pnt", Random(0, $iHeight), $i * 2 + 2)
    Next
    Return $tCurve
    EndFunc ;==>_CreateCurve

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

    Func WM_PAINT($hWnd, $uMsgm, $wParam, $lParam)
    _WinAPI_BitBlt($hDC, 0, 0, $iWidth, $iHeight, $hCDC, 0, 0, 0x00CC0020)
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_PAINT

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

    Func _Exit()
    _GDIPlus_PenDispose($hPenR)
    _GDIPlus_BrushDispose($hBrushR)
    _GDIPlus_PenDispose($hPenG)
    _GDIPlus_BrushDispose($hBrushG)
    _GDIPlus_PenDispose($hPenB)
    _GDIPlus_BrushDispose($hBrushB)
    _GDIPlus_GraphicsDispose($hGfxBuffer)
    _WinAPI_SelectObject($hCDC, $hOBJ)
    _WinAPI_DeleteObject($hBMP)
    _WinAPI_DeleteDC($hCDC)
    _WinAPI_ReleaseDC($hGui, $hDC)
    _GDIPlus_Shutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit]

    E

    EDIT: Hab ich ja total vergessen!
    Ich hab auch mit einer 3D-Matrix experimentiert:

    Spoiler anzeigen
    [autoit]

    #include <GDIPlus.au3>
    #include <GUIConstantsEx.au3>
    #include <WindowsConstants.au3>

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

    Global Const $bMatrixInit = "0x000000000000F03F0000000000000000000000000000000000000000000000000000000000000000000000000000F03F0000000000000000000000000000000000000000000000000000000000000000000000000000F03F0000000000000000000000000000000000000000000000000000000000000000000000000000F03F"
    Global Const $PI = ATan(1) * 4
    Global Const $LENS = 2560

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

    Opt("MustDeclareVars", 1)
    Opt("GUIOnEventMode", 1)

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

    Global $iWidth = 800
    Global $iHeight = 600
    Global $fCenterX = $iWidth / 2
    Global $fCenterY = $iHeight / 2

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

    _GDIPlus_Startup()
    Global $hGui = GUICreate("Matrix Test", $iWidth, $iHeight, 20, 20)
    GUISetOnEvent($GUI_EVENT_CLOSE, "_Exit")
    Global $hDC = _WinAPI_GetDC($hGui)
    Global $hBMP = _WinAPI_CreateCompatibleBitmap($hDC, $iWidth, $iHeight)
    Global $hBmpTmp = _GDIPlus_BitmapCreateFromHBITMAP($hBMP)
    _WinAPI_DeleteObject($hBMP)
    $hBMP = _GDIPlus_BitmapCreateHBITMAPFromBitmap($hBmpTmp)
    _GDIPlus_BitmapDispose($hBmpTmp)
    Global $hCDC = _WinAPI_CreateCompatibleDC($hDC)
    Global $hOBJ = _WinAPI_SelectObject($hCDC, $hBMP)
    Global $hGfxBuffer = _GDIPlus_GraphicsCreateFromHDC($hCDC)
    _GDIPlus_GraphicsSetSmoothingMode($hGfxBuffer, 2)
    _GDIPlus_GraphicsClear($hGfxBuffer, 0xFFFFFFFF)

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

    Global $hPen = _GDIPlus_PenCreate(0xFF00FF00)

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

    GUIRegisterMsg($WM_PAINT, "WM_PAINT")
    GUIRegisterMsg($WM_ERASEBKGND, "WM_PAINT")

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

    GUISetState()

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

    Global $tObj = _Create3DObject(60, 20, 18)

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

    While 1
    Sleep(10)
    _Draw()
    WEnd

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

    Func _Draw()
    Local $tMX = _MX3D_Create()

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

    Local Static $fRX = 0, $fRY = 0, $fRZ = 0, $fS = 1, $fSPlus = 0.01
    $fS += $fSPlus
    If ($fS >= 2.5) Or ($fS < 0.2) Then $fSPlus *= -1
    $fRX += 1
    $fRY += 0.42
    $fRZ += 0.17

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

    Local $iTimer = TimerInit()
    _MX3D_RotateX($tMX, $fRX)
    _MX3D_RotateY($tMX, $fRY)
    _MX3D_RotateZ($tMX, $fRZ)
    _MX3D_Scale($tMX, $fS, $fS, $fS)
    ConsoleWrite("+ Matrix: " & TimerDiff($iTimer) & @CRLF)

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

    $iTimer = TimerInit()
    TransFormPoints($tObj, $tMX)
    ConsoleWrite("> Transform: " & TimerDiff($iTimer) & @CRLF)

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

    Local $iCnt = DllStructGetData($tObj, "Cnt")
    Local $fX, $fY, $fR

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

    _GDIPlus_GraphicsClear($hGfxBuffer, 0xFF000000)
    $iTimer = TimerInit()
    For $i = 0 To $iCnt - 1
    If DllStructGetData($tObj, "Vis", $i + 1) = True Then
    $fX = DllStructGetData($tObj, "Pnt", $i * 2 + 1)
    $fY = DllStructGetData($tObj, "Pnt", $i * 2 + 2)
    DllCall($ghGDIPDll, "int", "GdipDrawEllipse", "handle", $hGfxBuffer, "handle", $hPen, "float", $fX, "float", $fY, "float", 1, "float", 1)
    EndIf
    Next
    ConsoleWrite("! Draw: " & TimerDiff($iTimer) & @CRLF)

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

    _WinAPI_BitBlt($hDC, 0, 0, $iWidth, $iHeight, $hCDC, 0, 0, 0x00CC0020)
    EndFunc ;==>_Draw

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

    Func _MX3D_RotateX(ByRef $tMX, $fD)
    ;[ 1 0 0 0 ]
    ;[ 0 C -S 0 ]
    ;[ 0 S C 0 ]
    ;[ 0 0 0 1 ]

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

    If $fD = 0 Then Return
    Local $fR = $fD * 0.0174532925199433

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

    Local $fC = Cos($fR)
    Local $fS = Sin($fR)

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

    Local $tMX1 = _MX3D_Create()
    DllStructSetData($tMX1, 1, $fC, 6)
    DllStructSetData($tMX1, 1, -$fS, 7)
    DllStructSetData($tMX1, 1, $fS, 10)
    DllStructSetData($tMX1, 1, $fC, 11)

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

    $tMX = _MX3D_MulMatrix($tMX1, $tMX)

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

    EndFunc ;==>_MX3D_RotateX

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

    Func _MX3D_RotateY(ByRef $tMX, $fD)
    ;[ C 0 S 0 ]
    ;[ 0 1 0 0 ]
    ;[-S 0 C 0 ]
    ;[ 0 0 0 1 ]

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

    If $fD = 0 Then Return
    Local $fR = $fD * 0.0174532925199433

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

    Local $fC = Cos($fR)
    Local $fS = Sin($fR)

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

    Local $tMX1 = _MX3D_Create()
    DllStructSetData($tMX1, 1, $fC, 1)
    DllStructSetData($tMX1, 1, $fS, 3)
    DllStructSetData($tMX1, 1, -$fS, 9)
    DllStructSetData($tMX1, 1, $fC, 11)

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

    $tMX = _MX3D_MulMatrix($tMX1, $tMX)

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

    EndFunc ;==>_MX3D_RotateY

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

    Func _MX3D_RotateZ(ByRef $tMX, $fD)
    ;[ C -S 0 0 ]
    ;[ S C 0 0 ]
    ;[ 0 0 1 0 ]
    ;[ 0 0 0 1 ]

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

    If $fD = 0 Then Return
    Local $fR = $fD * 0.0174532925199433

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

    Local $fC = Cos($fR)
    Local $fS = Sin($fR)

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

    Local $tMX1 = _MX3D_Create()
    DllStructSetData($tMX1, 1, $fC, 1)
    DllStructSetData($tMX1, 1, -$fS, 2)
    DllStructSetData($tMX1, 1, $fS, 5)
    DllStructSetData($tMX1, 1, $fC, 6)

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

    $tMX = _MX3D_MulMatrix($tMX1, $tMX)

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

    EndFunc ;==>_MX3D_RotateZ

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

    Func _MX3D_Scale(ByRef $tMX, $fX, $fY, $fZ)
    ;[ X 0 0 0 ]
    ;[ 0 Y 0 0 ]
    ;[ 0 0 Z 0 ]
    ;[ 0 0 0 1 ]

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

    Local $tMX1 = _MX3D_Create()
    DllStructSetData($tMX1, 1, $fX, 1)
    DllStructSetData($tMX1, 1, $fY, 6)
    DllStructSetData($tMX1, 1, $fZ, 11)

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

    $tMX = _MX3D_MulMatrix($tMX1, $tMX)

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

    EndFunc ;==>_MX3D_Scale

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

    Func _MX3D_Translate(ByRef $tMX, $fX, $fY, $fZ)
    ;[ 1 0 0 X ]
    ;[ 0 1 0 Y ]
    ;[ 0 0 1 Z ]
    ;[ 0 0 0 1 ]
    Local $tMX1 = _MX3D_Create()
    DllStructSetData($tMX1, 1, $fX, 4)
    DllStructSetData($tMX1, 1, $fY, 8)
    DllStructSetData($tMX1, 1, $fZ, 12)

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

    $tMX = _MX3D_MulMatrix($tMX1, $tMX)
    EndFunc ;==>_MX3D_Translate

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

    Func _MX3D_MulMatrix($tMX1, $tMX2)
    Local $tMX = DllStructCreate("double[16];")

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

    Local $fS
    For $x = 0 To 2
    For $y = 0 To 3
    $fS = 0
    For $z = 0 To 3
    $fS += DllStructGetData($tMX2, 1, $x * 4 + $z + 1) * DllStructGetData($tMX1, 1, $z * 4 + $y + 1)
    Next
    DllStructSetData($tMX, 1, $fS, $x * 4 + $y + 1)
    Next
    Next

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

    DllStructSetData($tMX, 1, 1, 16)

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

    Return $tMX
    EndFunc ;==>_MX3D_MulMatrix

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

    Func _MX3D_MulVector($tMX, $fX, $fY, $fZ, ByRef $fRX, ByRef $fRY, ByRef $fRZ)
    $fRX = ($fX * DllStructGetData($tMX, 1, 1)) + ($fY * DllStructGetData($tMX, 1, 2)) + ($fZ * DllStructGetData($tMX, 1, 3)) + DllStructGetData($tMX, 1, 4)
    $fRY = ($fX * DllStructGetData($tMX, 1, 5)) + ($fY * DllStructGetData($tMX, 1, 6)) + ($fZ * DllStructGetData($tMX, 1, 7)) + DllStructGetData($tMX, 1, 8)
    $fRZ = ($fX * DllStructGetData($tMX, 1, 9)) + ($fY * DllStructGetData($tMX, 1, 10)) + ($fZ * DllStructGetData($tMX, 1, 11)) + DllStructGetData($tMX, 1, 12)
    Return True
    EndFunc ;==>_MX3D_MulVector

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

    Func _MX3D_Clear(ByRef $tMX)
    $tMX = 0
    $tMX = DllStructCreate("double[16];")
    EndFunc ;==>_MX3D_Clear

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

    Func _MX3D_Reset(ByRef $tMX)
    ;[ 1 0 0 0 ]
    ;[ 0 1 0 0 ]
    ;[ 0 0 1 0 ]
    ;[ 0 0 0 1 ]
    Local $tSet = DllStructCreate("byte[128];", DllStructGetPtr($tMX))
    DllStructSetData($tSet, 1, $bMatrixInit)
    EndFunc ;==>_MX3D_Reset

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

    Func _MX3D_Create()
    ;[ 1 0 0 0 ]
    ;[ 0 1 0 0 ]
    ;[ 0 0 1 0 ]
    ;[ 0 0 0 1 ]
    Local $tMX = DllStructCreate("double[16];")

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

    DllStructSetData($tMX, 1, 1, 1)
    DllStructSetData($tMX, 1, 1, 6)
    DllStructSetData($tMX, 1, 1, 11)
    DllStructSetData($tMX, 1, 1, 16)

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

    Return $tMX
    EndFunc ;==>_MX3D_Create

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

    Func TransFormPoints($tPnt, $tMX)
    Local $iCnt = DllStructGetData($tPnt, "Cnt")
    Local $fX, $fY, $fZ, $fRX, $fRY, $fRZ, $fD
    Local $iIdx

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

    For $i = 0 To $iCnt - 1
    $iIdx = $i * 3
    $fX = DllStructGetData($tPnt, "3D", $iIdx + 1)
    $fY = DllStructGetData($tPnt, "3D", $iIdx + 2)
    $fZ = DllStructGetData($tPnt, "3D", $iIdx + 3)

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

    _MX3D_MulVector($tMX, $fX, $fY, $fZ, $fRX, $fRY, $fRZ)

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

    $fD = ($LENS - $fRZ)
    If $fD > 0 Then
    $iIdx = $i * 2
    DllStructSetData($tPnt, "Pnt", $fCenterX + ($LENS * $fRX / $fD), $iIdx + 1)
    DllStructSetData($tPnt, "Pnt", $fCenterY - ($LENS * $fRY / $fD), $iIdx + 2)
    DllStructSetData($tPnt, "Vis", True, $i + 1)
    Else
    DllStructSetData($tPnt, "Vis", False, $i + 1)
    EndIf
    Next

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

    EndFunc ;==>TransFormPoints

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

    Func _Create3DObject($fRadius, $iSlices, $iBands)
    Local $iCnt = $iSlices * $iBands
    Local $tPnt = DllStructCreate("uint Cnt; float Pnt[" & $iCnt * 2 & "]; byte Vis[" & $iCnt & "]; float 3D[" & $iCnt * 3 & "];")
    DllStructSetData($tPnt, "Cnt", $iCnt - 1)

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

    Local $iPnt = 0, $iIdx, $fPhi, $fTheta
    For $i = 0 To $iSlices - 1
    $fPhi = $PI / ($iSlices - 1) * $i
    For $j = 0 To $iBands - 1
    $fTheta = 2 * (-$PI / ($iBands - 1) * $j)
    $iIdx = $iPnt * 3
    DllStructSetData($tPnt, "3D", -Int($fRadius * Sin($fPhi) * Cos($fTheta)), $iIdx + 1)
    DllStructSetData($tPnt, "3D", -Int($fRadius * Sin($fPhi) * Sin($fTheta)), $iIdx + 2)
    DllStructSetData($tPnt, "3D", -Int($fRadius * Cos($fPhi)), $iIdx + 3)

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

    $iPnt += 1
    Next
    Next

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

    Return $tPnt
    EndFunc ;==>_Create3DObject

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

    Func WM_PAINT($hWnd, $uMsgm, $wParam, $lParam)
    _WinAPI_BitBlt($hDC, 0, 0, $iWidth, $iHeight, $hCDC, 0, 0, 0x00CC0020)
    Return $GUI_RUNDEFMSG
    EndFunc ;==>WM_PAINT

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

    Func _Exit()
    _GDIPlus_PenDispose($hPen)
    _GDIPlus_GraphicsDispose($hGfxBuffer)
    _WinAPI_SelectObject($hCDC, $hOBJ)
    _WinAPI_DeleteObject($hBMP)
    _WinAPI_DeleteDC($hCDC)
    _WinAPI_ReleaseDC($hGui, $hDC)
    _GDIPlus_Shutdown()
    Exit
    EndFunc ;==>_Exit

    [/autoit]
  • Hi,
    Klasse Script!

    Zitat

    Am längsten dauert (abgesehen von dem PathWarp Zeug) in den meisten Fällen das Zeichnen wie mir scheint.

    Habs bei mir mal durchgestoppt, am definitiv längsten dauert die FOR/TO-Schleife mit _GDIPlus_GraphicsDrawLine(), nämlich bei mir beim Torus-Beispiel mit 900 Linien (gezoomt ca. 20.000 Pixel) ca. 230ms => 4 FPS....

    Ohne Worte, denn "LinienZeichnen" ist seit Anbeginn aller Zeiten die wohl ausoptimierteste Funktion auf dem PC überhaupt.
    Da unabhängig von der Menge der gezeichneten Pixel/Linie die FPS gleich bleiben, kann das nur heissen, dass es (wieder mal) einen irren Funktionsoverhead bei _GDIPlus_GraphicsDrawLine() gibt...
    Typisch MS-API-Funktionen: 99% wildes durch den Kernel/Treiber gehüpfe, 1% Funktionsabarbeitung :thumbdown:

  • Zitat

    Ohne Worte, denn "LinienZeichnen" ist seit Anbeginn aller Zeiten die wohl ausoptimierteste Funktion auf dem PC überhaupt.
    Da unabhängig von der Menge der gezeichneten Pixel/Linie die FPS gleich bleiben, kann das nur heissen, dass es (wieder mal) einen irren Funktionsoverhead bei _GDIPlus_GraphicsDrawLine() gibt...
    Typisch MS-API-Funktionen: 99% wildes durch den Kernel/Treiber gehüpfe, 1% Funktionsabarbeitung :thumbdown:


    :D. Jetzt weiß ich wieso mir das alles so langsam vorkommt ^^. Dieser Geschwindigkeitsverlust lässt sich ja leider nicht wirklich umgehen, aber immerhin funktioniert das Prinzip.

    Zitat

    Hier hab ich ein Testscript, das ich vor kurzem erstellt hab.
    Damit kann man schnell zoomen, verschieben und drehen ohne das Objekt selbst neu zu berechnen.
    Es wird einfach der Ziel-GraphicsContext transformiert...


    Super! :thumbup:
    Genau so wollte ich es auch zuerst machen, aber nachdem eine Zeit lang nur Müll bei meinen Versuchen rausgekommen ist, hab ich einfach die Koordinaten per Rotationsmatrix umgerechnet. ^^
    Ich würde gerne mal versuchen das in meinem Script einzubauen um Geschwindigkeitsunterschiede festzustellen.

    Dein Beispiel mit der 3D Matrix ist ja mal der Hammer. 8| Ich hab mir vor einiger Zeit mal angeschaut wie so eine Perspektivische Verzerrung als Matrix möglich ist, aber das war mir noch zu kompliziert. Vielleicht verstehe ich es ja wenn ich dein Beispiel mal unter die Lupe nehme...

  • Dein Viewer ist echt klasse :thumbup:
    Aber leider kann man damit nur Low-poligon-moddels anschauen, denn wenn man welche mit "etwas mehr" Polygonen nimmt braucht es ewig um nur die Informationen zu laden.
    Ich habe es mit einem 80 000 Poly Objekt getestet und nach 5min. hab ich es gestoppt weil es einfach zu lange dauert.

    Aber für kleinere Objekte ist es echt gut


    mfg Yellow

    §1 Ich kann nicht für meine scripts inhaftiert werden, auch wenn bereits 3 Menschen erblindeten an den Folgen der Korrekturlesung.  8o

  • Zitat

    Ich habe es mit einem 80 000 Poly Objekt getestet und nach 5min. hab ich es gestoppt weil es einfach zu lange dauert.


    Ich dachte das wäre ersichtlich ^^.
    Selbst wenn du geduldig genug bist, es würde nachher vermutlich mit ca. 0.00001 FPS laufen... Dafür ist das ganze aber überhaupt nicht gedacht. Wie bereits erwähnt, wirkliche Anwendungsgebiete gibt es nicht, reine Spielerei ;).

  • Ich hoffe ich trete hier niemandem auf die Füße wenn ich diesen Thread noch mal ausgrabe. :whistling:

    Ich habe vor einiger Zeit an einer neuen Version gearbeitet (fast komplett neu geschrieben). Dieses mal allerdings mit Ego-Perspektive und entsprechender Steuerung (WASD zum umherlaufen und die Maus bewegt den Sichtwinkel).
    Es wird keine PathWarp Funktion verwendet um die perspektivische Krümmung zu erreichen, stattdessen werden die Berechnungen dafür in nativem AutoIt erledigt. Das hat die Performance auf keinen Fall verschlechtert, interessanterweise.
    Außerdem arbeite ich mit einer Kameratransformation, das heißt man kann sowohl Objekte als auch Kamera im Raum unabhängig voneinander positionieren.

    Mit diesem Script als Grundlage könnte man sogar ein kleines 3D Spiel in Ego Perspektive umsetzen, fast ausschließlich mit nativem AutoIt. Und wenn GDI+ nicht so lahm beim Linienzeichnen wäre, gäbe es wirklich keine Performance-Probleme :rolleyes: .

    Edit: Vielleicht sollte ich auch verraten, dass ich das Script im ersten Beitrag eingefügt habe... :pinch:

  • Hi,
    wie gehabt, sehr schick!

    Wenn ich am Wochenende mal bissl Zeit habe, schreibe ich mal die Linien-Zeichenfunktion in Asm, bzw. das hab ich schon, ist nur irgendwo vergraben^^
    Wenn die Eck-Koordinaten in einer Struct liegen, kann man die auch gleich mit dem Asm-Prog auslesen. Das sollte dann einiges beim Zeichnen beschleunigen...