1. مهمان گرامی، جهت ارسال پست، دانلود و سایر امکانات ویژه کاربران عضو، ثبت نام کنید.
    بستن اطلاعیه

مباحث پيشرفته Direct3D - بخش سوم

شروع موضوع توسط hector2141 ‏15/10/12 در انجمن برنامه نویسی

  1. کاربر ارشد

    تاریخ عضویت:
    ‏6/9/12
    ارسال ها:
    14,318
    تشکر شده:
    2,702
    امتیاز دستاورد:
    0
    حرفه:
    daneshjo
    [​IMG]
    در درسهای قبلی در مورد load کردن اشیا از یک فایل X صحبت کردم اما در مورد چگونگی گرفتن اطلاعات vertex از یک شی Mesh صحبت نشد . کتابخانه D3DX برای اینکار دو تابع دارد :
    تابع D3DXMeshVertexBuffer8GetData : اطلاعات یک شی D3DXMesh را گرفته و در یک آرایه از D3DVERTEX ذخیره می کند :


    D3DXMeshVertexBuffer8GetData( D3DXMeshobj As Unknown, Offset As Long, Size As Long, Flags As Long, Data As Any) As Long
    D3DXMeshobj As Unknown = A D3DXMESH object that you want to extract the data from .
    Offset As Long = How far into the vertex buffer we want to start reading, 0 is the beginning
    Size As Long = Size of the vertex buffer, this will be Len(D3DVERTEX) * Mesh.GetNumVertices
    Flags As Long = A combination of the CONST_D3DLOCKFLAGS, leave as 0 .
    Data As Any = The first element in the array that you want the data to be read into, should be an array of D3DVERTEX vertices
    Return Code As Long = Returns D3D_OK for success, or either of D3DERR_INVALIDCALL or E_INVALIDARG for an error
    تابع D3DXMeshVertexBuffer8SetData : اطلاعات یک بافر vertex را در یک شی D3DXMesh قرار می دهد :
    D3DXMeshVertexBuffer8SetData( D3DXMeshobj As Unknown, Offset As Long, Size As Long, Flags As Long, Data As Any) As Long
    D3DXMeshobj As Unknown = The D3DXMESH object that defines where you want the data to be placed
    Offset As Long = How far into the Destination vertex buffer you want to place the data
    Size As Long = The Size of the buffer in bytes, this will be Len(D3DVERTEX) * Mesh.GetNumVertices
    Flags As Long = A Combination of the CONST_D3DLOCKFLAGS, leave as 0
    Data As Any = The first element in the array of data you want placed in the mesh's vertex buffer
    Return Code As Long = D3D_OK for success or D3DERR_INVALIDCALL or E_INVALIDARG for failure
    عملیات انجام انیمیشن فریم کلیدی بصورت زیر است :
    load کردن اشیا از فایلهای X به درون شی D3DXMesh
    استخراج اطلاعات vertex از این شی
    انجام درون یابی بین فریمهای کلیدی
    قرار دادن اطلاعات vertex های درون یابی در یک شی D3DXMesh
    فرض می کنیم که انیمیشن ما همیشه از زمان صفر تا زمان n باشد – برحیب میلی ثانیه – بنابراین می توانیم از GetTickCount برای توابع زمانی خود استفاده کنیم . همچنین یک ساختار را برای هر فریم کلیدی بصورت زیر تعریف می کنیم :
    Private Type KeyFrame
    شی load شده از یک فایل’ Mesh As D3DXMesh
    آرایه material برای هر شی’ MatList() As D3DMATERIAL8
    آرایه Texture’ TexList() As Direct3DTexture8
    تعداد material ها و texture هایی که استفاده می کنیم’ nMaterials As Long
    داده های vertex برای این فریم کلیدی’ VertexList() As D3DVERTEX
    موقعیت این فریم کلیدی در انیمیشن’ TimeIndex As Long
    End Type
    حال باید تابعی بنویسیم که اطلاعات را از یک فایل X استخراج کرده و درون فریم کلیدی قرار دهد :
    Private Function CreateKeyFrameFromFile(Filename As String, TexturePrefix As String, Time As Long) As KeyFrame
    نام فایل X برای شی سه بعدی: Filename ’
    پوشه ای که اطلاعات texture این شی در آن قرار دارد : TexturePrefix ’
    اندیس زمان برای این فریم کلیدی : Time '
    Dim I As Long
    Dim XBuffer As D3DXBuffer
    Dim TextureFile As String
    Dim hResult As Long
    'خواندن اطلاعات از فایل ورودی به حافظه
    Set CreateKeyFrameFromFile.Mesh = D3DX.LoadMeshFromX(Filename, D3DXMESH_MANAGED, D3DDevice, Nothing, XBuffer, CreateKeyFrameFromFile.nMaterials)x
    تولید material ها و texture ها ‘
    ReDim CreateKeyFrameFromFile.MatList(CreateKeyFrameFromFile.nMaterials) As D3DMATERIAL8
    ReDim CreateKeyFrameFromFile.TexList(CreateKeyFrameFromFile.nMaterials) As Direct3DTexture8
    For I = 0 To CreateKeyFrameFromFile.nMaterials - 1
    D3DX.BufferGetMaterial XBuffer, I, CreateKeyFrameFromFile.MatList(I)x
    CreateKeyFrameFromFile.MatList(I).Ambient = CreateKeyFrameFromFile.MatList (I).diffuse
    TextureFile = D3DX.BufferGetTextureName(XBuffer, I)x
    If TextureFile < > "" Then
    Set CreateKeyFrameFromFile.TexList(I) = D3DX.CreateTextureFromFileEx(D3DDevice, TexturePrefix & TextureFile, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED ,
    D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR, 0, ByVal 0, ByVal 0)x
    End If
    Next I
    استخراج داده های vertex ’
    ReDim CreateKeyFrameFromFile.VertexList(CreateKeyFrameFromFile.Mesh.GetNumVertices) As D3DVERTEX
    hResult = D3DXMeshVertexBuffer8GetData(CreateKeyFrameFromFile.Mesh, 0, Len(CreateKeyFrameFromFile.VertexList(0)) * reateKeyFrameFromFile.Mesh.GetNumVertices, 0, CreateKeyFrameFromFile.VertexList(0 ((
    CreateKeyFrameFromFile.TimeIndex = Time
    End Function
    در تابع Initialize خطوط زیر را برای ساخت فریم های کلیدی اضافه می کنیم :
    nKeyFrames = 4
    kfAnimLength = 2500
    AnimLastStartAt = GetTickCount()x
    ReDim kfAnim(nKeyFrames - 1) As KeyFrame
    kfAnim(0) = CreateKeyFrameFromFile(App.Path & "frame0.x", App.Path & "", 0)x
    kfAnim(1) = CreateKeyFrameFromFile(App.Path & "frame1.x", App.Path & "", kfAnimLength * (1 / 3))x
    kfAnim(2) = CreateKeyFrameFromFile(App.Path & "frame2.x", App.Path & "", kfAnimLength * (2 / 3))x
    kfAnim(3) = CreateKeyFrameFromFile(App.Path & "frame3.x", App.Path & "", kfAnimLength)x
    kfCurrent = CreateKeyFrameFromFile(App.Path & "frame0.x", App.Path & "", 0 (
    دقت کنید که از یک اندیس زمان برای ساخت فریم های کلیدی استفاده شده است .
    حال باید کدی برای نمایش دادن انیمیشن بنویسیم . ابتدا باید به روشی تغییرات فریمها را کنترل کنیم :
    For I = 0 To nKeyFrames - 2
    If CurrentTimeIndex >= kfAnim(I).TimeIndex Then
    PrevFrame = I
    NextFrame = I + 1
    End If
    Next I
    سپس باید با توجه به زمان index دو فریم کلیدی و زمان جاری ، پارامتر درون یابی را محاسبه کنیم :
    sTime = kfAnim(PrevFrame).TimeIndex
    eTime = kfAnim(NextFrame).TimeIndex
    cTime = CurrentTimeIndex
    eTime = eTime - sTime
    cTime = cTime - sTime
    sTime = sTime - sTime
    InterpolateAmount = cTime / eTime
    سپس باید بر اساس این پارامتر عمل درون یابی را روی داده های vertex انجام دهیم :
    For I = 0 To kfCurrent.Mesh.GetNumVertices
    'درون یابی مختصاتها
    D3DXVec3Lerp vTemp3D, MakeVector(kfAnim(PrevFrame).VertexList(I).X, kfAnim(PrevFrame).VertexList(I).Y , _
    kfAnim(PrevFrame).VertexList(I).Z), MakeVector(kfAnim(NextFrame).VertexList(I).X, kfAnim(NextFrame).VertexList(I).Y , _
    kfAnim(NextFrame).VertexList(I).Z), InterpolateAmount
    kfCurrent.VertexList(I).X = vTemp3D.X
    kfCurrent.VertexList(I).Y = vTemp3D.Y
    kfCurrent.VertexList(I).Z = vTemp3D.Z
    'درون یابی نرمالها
    D3DXVec3Lerp vTemp3D, MakeVector(kfAnim(PrevFrame).VertexList(I).nx, kfAnim(PrevFrame).VertexList(I).ny , _
    kfAnim(PrevFrame).VertexList(I).nz), MakeVector(kfAnim(NextFrame).VertexList(I).nx, kfAnim(NextFrame).VertexList(I).ny , _
    kfAnim(NextFrame).VertexList(I).nz), InterpolateAmount
    kfCurrent.VertexList(I).nx = vTemp3D.X
    kfCurrent.VertexList(I).ny = vTemp3D.Y
    kfCurrent.VertexList(I).nz = vTemp3D.Z
    'درون یابی اطلاعات بافت
    D3DXVec2Lerp vTemp2D, MakeVector2D(kfAnim(PrevFrame).VertexList(I).tu, kfAnim(PrevFrame).VertexList(I).tv ), _
    MakeVector2D(kfAnim(NextFrame).VertexList(I).tu, kfAnim(NextFrame).VertexList(I).tv), InterpolateAmount
    kfCurrent.VertexList(I).tu = vTemp2D.X
    kfCurrent.VertexList(I).tv = vTemp2D.Y
    Next I
    حال باید داده تولید شده را به فرمت Mesh برگردانیم :
    hResult = D3DXMeshVertexBuffer8SetData(kfCurrent.Mesh, 0, Len(kfCurrent.VertexList(0)) * kfCurrent.Mesh.GetNumVertices, 0, kfCurrent.VertexList(0))x
    با استفاده از روش فوق می توانید هر تعداد فریم کلیدی را به انیمیشنتان اضافه کنید . اشکالی که روش فوق دارد اینست که اطلاعات texture برای تمام فریمهای کلیدی جداگانه ذخیره شده است در حالیکه texture در تمام فریمها ثابت است . در درسهای بعدی از روشی بنام texture pooling استفاده می کنیم تا تنها یک کپی از texture ها نگهداری کنیم .