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
#include <WindowsConstants.au3>
#include <GUIConstants.au3>
#include <GDIP.au3>
#include <WinAPI.au3>
#include <Misc.au3>
#include <Array.au3>
; - Author: name22 (http://www.autoit.de)
[/autoit] [autoit][/autoit] [autoit]Opt("GUIOnEventMode", 1)
Opt("MouseCoordMode", 2)
;###-v-SETTINGS-v-###
[/autoit] [autoit][/autoit] [autoit]$iWidth = 800
$iHeight = 800
$iDepth = 800
$fPersp = 0.5
$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
$iARGB_BG = 0xFF000000
$nFPS = 80
$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)
$aVertexRaw = StringRegExp($sData, "(?m)^v ([^ ]+) ([^ ]+) ([^ ]+)$", 3)
$aFaceRaw = StringRegExp($sData, "(?m)^f((?: \S+)+)", 3)
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
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
$aEdge[0][0] += 1
ReDim $aEdge[$aEdge[0][0] + 1][2]
$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
$aEdge[0][0] += 1
ReDim $aEdge[$aEdge[0][0] + 1][2]
$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()
$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
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]]
$nSleepTime = 1000 / $nFPS
[/autoit] [autoit][/autoit] [autoit]$nFPS_Display = 0
$nFPS_Average = $nFPS
$vNTdll = DllOpen("ntdll.dll")
$vU32Dll = DllOpen("user32.dll")
$tPrecSleep = DllStructCreate("int64 time;")
$pPrecSleep = DllStructGetPtr($tPrecSleep)
$hMain = GUICreate("3D OBJ Viewer by name22", $iWidth, $iHeight)
GUISetCursor(16, 1)
GUISetState()
$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)
$hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC_Buffer)
_GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)
$hPen_Figure = _GDIPlus_PenCreate(0xFF00FF00)
$hPen_Cursor = _GDIPlus_PenCreate(0xFFFF0000)
$hBrush_FPS = _GDIPlus_BrushCreateSolid(0xFF808080)
$hBrush_Walls = _GDIPlus_BrushCreateSolid(0xFF00FF00)
$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)
$hStringFormat = _GDIPlus_StringFormatCreate()
_GDIPlus_StringFormatSetAlign($hStringFormat, 2)
$hFamily_FPS = _GDIPlus_FontFamilyCreate("Sony Sketch EF")
$hFont_FPS = _GDIPlus_FontCreate($hFamily_FPS,
$aMeasure = _GDIPlus_GraphicsMeasureString($hGraphics, "FPS: 0", $hFont_FPS, _GDIPlus_RectFCreate(), $hStringFormat)
$tLayout_FPS = _GDIPlus_RectFCreate(0, $iHeight - DllStructGetData($aMeasure[0], "Height"), $iWidth, 0)
GUISetOnEvent($GUI_EVENT_CLOSE, "_Close", $hMain)
OnAutoItExitRegister("_Shutdown")
$aMousePosOld = MouseGetPos()
$nT_Time = TimerInit()
$nT_UpdateFPS = TimerInit()
$nT_Sleep = TimerInit() + $nSleepTime
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
$aMousePosNew = MouseGetPos()
GUIGetCursorInfo()
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)
_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)
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
_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)
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
_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
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
Func _Close()
Exit
EndFunc ;==>_Close
Func _Shutdown()
_WinAPI_ReleaseDC($hMain, $hDC_Main)
_WinAPI_DeleteDC($hDC_Buffer)
_WinAPI_DeleteObject($hBitmap_Buffer)
_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()
DllClose($vNTdll)
DllClose($vU32Dll)
EndFunc ;==>_Shutdown
; #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
3D Grid Viewer - v2.0
#include <WindowsConstants.au3>
#include <GUIConstants.au3>
#include <GDIPlus.au3>
#include <WinAPI.au3>
#include <Misc.au3>
; - Author: name22 (http://www.autoit.de)
[/autoit] [autoit][/autoit] [autoit]Opt("GUIOnEventMode", 1)
Opt("MouseCoordMode", 2)
#region Global variables
Global $hDll_User32 = DllOpen("user32.dll")
Global $hDll_NTDll = DllOpen("ntdll.dll")
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]]
Global $nAngle = 0
#endregion Global variables
;###-v-SETTINGS-v-###
#region General Settings
;GUI-size X,Y
$iWidth_GUI = 600
$iHeight_GUI = 400
;Background-color ARGB
$iARGB_BG = 0xFF000000
;Desired framerate
$nFPS = 100
;Jumping speed / Gravity
$nJumpSpeed = 2000
$nGravity = 5000
;3D Model scale
$nScale = 10
#endregion General Settings
#region Camera Settings
;Horizontal field of view in degrees
$nFOV = 70
;Movement speed X,Y,Z
$aCamSpeedMov[0] = 1500
$aCamSpeedMov[1] = 0
$aCamSpeedMov[2] = 3000
;Rotation speed X,Y
$aCamSpeedRot[0] = 1 / ($iWidth_GUI / 2) * $nPi
$aCamSpeedRot[1] = 1 / ($iHeight_GUI / 2) * $nPi / 2
;Camera position X,Y,Z
$aV_Pos[0] = 0
$aV_Pos[1] = 30
$aV_Pos[2] = 800
;Camera target X,Y,Z
$aV_Target[0] = 0
$aV_Target[1] = 0
$aV_Target[2] = -1
;Camera up-direction X,Y,Z
$aV_Up[0] = 0
$aV_Up[1] = 1
$aV_Up[2] = 0
#endregion Camera Settings
;###-^-SETTINGS-^-###
#region 3D Model
$sObjFile = FileOpenDialog("Open 3D Datafile", "", "Wavefront OBJ (*.obj)")
$sData = FileRead($sObjFile)
$aVertexRaw = StringRegExp($sData, "(?m)^v ([^ ]+) ([^ ]+) ([^ ]+)$", 3)
$aFaceRaw = StringRegExp($sData, "(?m)^f((?: \S+)+)", 3)
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
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
$aEdges[0][0] += 1
ReDim $aEdges[$aEdges[0][0] + 1][2]
$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
$aEdges[0][0] += 1
ReDim $aEdges[$aEdges[0][0] + 1][2]
$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
#region Initialization
;Zero/Ground-level
$nY_Zero = $aV_Pos[1]
;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))
;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
#region FPS Management
$nSleepTime = 1000 / $nFPS
$nFPS_Display = 0
$nFPS_Average = $nFPS
$tPrecSleep = DllStructCreate("int64 time;")
$pPrecSleep = DllStructGetPtr($tPrecSleep)
#endregion FPS Management
$hWnd_GUI = GUICreate("3D Engine Test by name22", $iWidth_GUI, $iHeight_GUI)
GUISetCursor(16, 1, $hWnd_GUI)
GUISetState()
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)
$hPen = _WinAPI_CreatePen($PS_SOLID, 1, 0x00FF00)
_WinAPI_SelectObject($hDC_Buffer, $hPen)
_GDIPlus_Startup()
[/autoit] [autoit][/autoit] [autoit]$hGraphics = _GDIPlus_GraphicsCreateFromHDC($hDC_Buffer)
_GDIPlus_GraphicsSetSmoothingMode($hGraphics, 2)
$hBrush_Black = _GDIPlus_BrushCreateSolid(0xFFF0F0F0)
$hBrush_Green = _GDIPlus_BrushCreateSolid(0xFF00FF00)
$hPen_Green = _GDIPlus_PenCreate(0xFF00FF00)
$hStringFormat = _GDIPlus_StringFormatCreate()
$hFamily_FPS = _GDIPlus_FontFamilyCreate("Consolas")
$hFont_FPS = _GDIPlus_FontCreate($hFamily_FPS, 6.5, 1)
#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
GUISetOnEvent($GUI_EVENT_CLOSE, "_Close", $hWnd_GUI)
GUIRegisterMsg($WM_MOUSEMOVE, "_MouseMove")
OnAutoItExitRegister("_Shutdown")
$nT_UpdateFPS = TimerInit()
$nT_Sleep = TimerInit()
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()
$nFPS_Cur = 1000 / $nFrameTime
If TimerDiff($nT_UpdateFPS) >= 1000 Then
$nFPS_Display = $nFPS_Cur
$nT_UpdateFPS = TimerInit()
EndIf
#endregion FPS Stuff
#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
$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]
;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]
;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
#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
_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
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)
_Camera_RotateXY($aCamAngle[0], $aCamAngle[1])
Return 0
EndFunc ;==>_MouseMove
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
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
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
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
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
Func _Close()
Exit
EndFunc ;==>_Close
Func _Shutdown()
GUIRegisterMsg($WM_MOUSEMOVE, "")
_WinAPI_ReleaseDC($hWnd_GUI, $hDC_Window)
_WinAPI_DeleteDC($hDC_Buffer)
_WinAPI_DeleteObject($hBMP_Buffer)
_WinAPI_DeleteObject($hPen)
_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()
DllClose($hDll_NTDll)
DllClose($hDll_User32)
EndFunc ;==>_Shutdown
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.