تبلیغات :
آکوستیک ، فوم شانه تخم مرغی، صداگیر ماینر ، یونولیت
دستگاه جوجه کشی حرفه ای
فروش آنلاین لباس کودک
خرید فالوور ایرانی
خرید فالوور اینستاگرام
خرید ممبر تلگرام

[ + افزودن آگهی متنی جدید ]




صفحه 1 از 6 12345 ... آخرآخر
نمايش نتايج 1 به 10 از 51

نام تاپيک: مباحث پیشرفته و کاربردی در Vb

  1. #1
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض مباحث پیشرفته و کاربردی در Vb

    سلام

    منبع همه مقالات : [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]

    ================================================== ===============
    فهرست مقالات و جلسات (این تاپیک)

    مقالات

    1. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    2. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    3. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    4. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    5. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]

    جلسات

    آموزش DirectX Input
    1. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    2. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    3. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]

    مباحث پيشرفته Direct3D
    1. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    2. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    3. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    4. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    5. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]

    TAPI در ويژوال بيسيک
    1. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    2. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    3. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    4. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    5. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    6. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    7. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]

    آشنايي با شی پرينتر در ويژوال بيسيک
    1. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    2. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    3. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]

    آموزش DirectX-Graphic
    1. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    2. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    3. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    4. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    5. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    6. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    7. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    8. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    9. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    10. [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    Last edited by A_M_IT2005; 26-01-2007 at 21:33.

  2. #2
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض

    سلام

    API های ویندوز

    امروز قصد دارم در مورد API هاي ويندوز و چگونگي استفاده از آنها در ويژوال بيسيک بطور خلاصه توضيح دهم و همچنين دو مثال پراستفاده را نيز در اين زمينه بيان کنم که عبارتند از چگونگي پخش فايلهاي Wav و ساخت يک تايمر با دقت بالا :

    ۱ - آشنايي با Windows API : واژه API مخفف Application Programming Interface مي باشد . API هاي ويندوز مجموعه اي از توابع از پيش آماده موجود در سيستم عامل هستند که شما مي توانيد آنها را در برنامه هاي خود فراخواني کنيد . اين توابع در چندين کتابخانه DLL ويندوز ذخيره شده اند . براي دسترسي به اين توابع در ويژوال بيسيک ابتدا بايد آنها را برنامه خود declare کنيد . براي مثال :

    Declare Function sndPlaySound Lib "winmm.dll" Alias "sndPlaySoundA" (ByVal lpszSoundName As String, ByVal uFlags As Long) As Long

    همانطور که مي بينيد مثال فوق يک Declare از تابع sndPlaySound مي باشد که اين تابع در کتابخانه Winmm.dll موجود است . کلمه Alias نشان مي دهد که اين تابع نام ديگري در dll دارد . ساير بخشها مربوط به تعريف پارامترهاي تابع مي باشند که در مورد مثال فوق ، اين تابع دو پارامتر ورودي و يک خروجي از نوع Long دارد .
    پس از Delare کردن API در برنامه مي توانيد از آن استفاده نمائيد .

    ۲ - پخش فايلهاي Wav : تابعي که براي پخش فايلهاي Wav استفاده مي شود تابع sndPlaySound است که در بالا با آن آشنا شديد . پارامتر lpzSoundName نام و مسير فايل Wavو پارامتر uFlags چگونگي پخش فايل را مشخص مي کند . مقادير ممکن اين پارامتر عبارتند از :
    - SND_ASYNC : اجازه مي دهد طوري فايل Wav پخش شود که آنرا بتوان وقفه داد . بعبارت ديگر قادر خواهيد بود فايل Wav تان را هر زمان که بخواهيد پخش کنيد و مطمئن باشيد که حتماً شنيده مي شود .
    - SND_LOOP : فايل Wav را بطور ممتد پخش مي کند .
    - SND_NODEFAULT : اگر فايل Wav پيدا نشود صداي ديگري پخش نخواهد شد ( مثلاً برخي صداهاي default ويندوز )
    - SND_SYNC : در طول پخش فايل Wav کنترل به برنامه داده نمي شود . اين پارامتر در زمانيکه مي خواهيد فايل Wav اي را در پس زمينه برنامه تان پخش کنيد مناسب نمي باشد .
    - SND_NOSTOP : اگر فايل Wav اي قبلاً در حال پخش باشد ، فايل Wav شما آنرا دچار وقفه نمي کند . از اين پارامتر زماني استفاده مي شود که بخواهيم فايل Wav مان هيچوقت در وسط کار قطع نشود .
    اگر بخواهيد از بيش از يکي از اين پارامترها استفاده کنيد توسط Or آنها را ترکيب نمائيد مثال :

    sndPlaySound App.path & "\ding.wav", SND_ASYNC or SND_LOOP


    نکته : براي استفاده از توابع صوتي پيچيده تر بايستي از DirectSound که يکي از اجزاي DirectX مي باشد استفاده کنيد . در مورد DirectSound بعداً صحبت خواهم کرد .

    ۳ - ساخت يک تايمر با دقت بالا : شايد تا بحال از کنترل تايمر موجود در نوار ابزار ويژوال بيسيک استفاده کرده باشيد . اين تايمر داراي دقت حدود ۵۵ ميلي ثانيه است . براي دستيابي به زمانهاي با دقت بالاتر اين کنترل مفيد نخواهد بود .
    تابع GetTickCount يک API موجود در کتابخانه Kernel32.dll است . اين تابع طول زماني را که سيستم شروع به کار کرده است را برحسب ميلي ثانيه برمي گرداند :

    Private Declare Function GetTickCount Lib "kernel32" () As Long
    براي بررسي طي شدن يک مدت زماني خاص شما ابتدا بايد مقدار اين تابع را در يک متغير کمکي مثل TempTime قرار دهيد سپس در يک حلقه Do-Loop بايد اختلاف زمان GetTickCount جديد و زمان TempTime را با مقدار زماني که مي خواهيد سپري شود مقايسه کنيد :

    TempTime = GetTickCount()x
    Do While DesiredTime < GetTickCount() - TempTime
    Do some things'
    Loop

    توسط کد بالا مي توان يک عمليات خاص را براي يک مدت زماني مشخص اجرا کرد .
    کد زير نشان مي دهد که چگونه مي توان دستورات خاصي را در فواصل زماني خاص اجرار کرد :

    ExitFunction = False
    TempTime = GetTickCount()x
    Do While not(ExitFunction)x
    If DesiredTime < GetTickCount() - TempTime then
    Reset the temporary variable'
    TempTime = GetTickCount()x
    Do some things'
    End If
    Loop

    همچنين از تابع GetTickCount مي توان براي benchmark برنامه ها استفاده کرد . بعبارت ديگر مي توان زمان اجراي يکسري دستورات خاص را بدست آورد .

    [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    Last edited by A_M_IT2005; 20-01-2007 at 21:39.

  3. این کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده است


  4. #3
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض

    سلام

    آموزش DirectX Input

    جلسه اول :

    گرفتن اطلاعات ورودی از کيبرد - ۱

    مقدمه

    Direct Input 8 همانطور که از نامش مشخص است به شما اجازه می دهد که بتوانيد برنامه هايي بنويسيد که توسط هر نوع دستگاه ورودی کنترل شود .
    Direct Input 8 دارای چندين مزيت نسبت به استفاده از کنترلهای ورودی خود ويژوال بيسيک دارد – کنترلهايي مثل Form_KeyUp, Form_KeyDown, Form_MouseMove - و همچنين قابليت کنترل بيشتری نسبت به توابع استاندارد Win32 از قبيل GetCursorPos, GetKeyState دارد .
    Direct Input 8 سريعتر ، کاراتر و قدرتمند تر بوده و برای ساخت بازيها طراحی شده بنابراين باعث کندی برنامه ها نخواهد شد .

    چگونگی کار با Direct Input 8 برای گرفتن ورودی از کيبرد

    دو روش برای استفاده از کيبرد در DirectX8 وجود دارد : روش polling و روش event-based که هر دو دارای مزايا و معايبی هستند .
    بطور کلی در اغلب طراحيها از روش event-based استفاده می شود زيرا کار با آن راحت تر اسن . در اين روش هر پيغام فرستاده شده ازطرف دستگاه ورودی log می شود و برنامه نيازی به هيچگونه پردازشی بمنظور منتظر ماندن برای يک پيغام از طرف ورودی ندارد ، بنابر اين کاراتر است . در روش polling کنترل کمی دقيقتر و راحتر است .
    اگر در مورد برنامه نويسی بر مبنای polling و بر مبنای event اطلاعات کافی نداريد می توانيد از منابع موجود در سايتهايي چون Gamasutra و GameDev استفاده کنيد .

    روش Polling

    مراحل اين روش عبارتند از :

    1 – تعريفات Declerations : يک فرم ايجاد کرده و يک TextBox به نام txtOutput با خصوصيات Multiline ، Locked و Vertical Scroll Bar در آن قرار دهيد . کدهای زير را در بخش کدنويسی اين فرم بنويسيد :

    Private Const UsePollingMethod As Boolean = True
    Private Const UseEventMethod As Boolean = False
    ‘نکته مهم اينست که تنها يکی از دو ثابت فوق بايستی True باشد .
    Private bRunning As Boolean
    ‘اين متغير برای polling استفاده می شود
    Private DX As DirectX8
    Private DI As DirectInput8
    ‘تعريف شی اصلی DirectX و شی DirectInput
    Private DIDevice As DirectInputDevice8
    Private DIState As DIKEYBOARDSTATE
    ‘اين دو شی برای دسترسی به دستگاه ورودی ( کيبرد ) استفاده می شوند
    Private KeyState(0 To 255) As Boolean
    ‘آرايه ای برای تشخيص فشرده شدن کليد
    Private Const BufferSize As Long = 10
    ‘ سايز بافر نگهدارنده event ها . در روش event-based اين مقدار برابر يک و در روش polling برابر 10 تا 20 است ( بسته به سرعت حلقه بازی )
    Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)x
    ‘ تابع Sleep برای متوقف کردن حلقه polling در صورت بالا بودن نرخ ورودی


    2- مقدار دهی اوليه Initialisation : اين بخش سه مرحله دارد :
    در مرحله اول اشيا و Device ها ساخته می شوند .
    در مرحله دوم تنظيمات مربوط به Device انجام می شود .
    در مرحله سوم به Device می گوئيم که می خواهيم شروع به استفاده از آن کنيم .

    در Form_Load کدهای زير را بنويسيد :

    Me.Show
    Dim I As Long
    Dim DevProp As DIPROPLONG
    Dim DevInfo As DirectInputDeviceInstance8
    Dim pBuffer(0 To BufferSize) As DIDEVICEOBJECTDATA
    If UsePollingMethod And UseEventMethod Then
    MsgBox "You must select only one of the constants before running"x
    Unload Me
    End
    End If

    If UsePollingMethod Then txtOutput.Text = "Using Polling Method" & vbCrLf
    If UseEventMethod Then txtOutput.Text = "Using Event Based Method" & vbCrLf

    ‘مقداردهی اوليه روش انتخاب شده
    Set DX = New DirectX8
    Set DI = DX.DirectInputCreate
    Set DIDevice = DI.CreateDevice("GUID_SysKeyboard")x

    DIDevice.SetCommonDataFormat DIFORMAT_KEYBOARD
    DIDevice.SetCooperativeLevel frmMain.hWnd, DISCL_BACKGROUND Or ISCL_NONEXCLUSIVE

    ‘برپاسازی بافر
    DevProp.lHow = DIPH_DEVICE
    DevProp.lData = BufferSize
    DIDevice.SetProperty DIPROP_BUFFERSIZE, DevProp

    ‘ به دايرکت ايکس می گوئيم که می خواهيم از دستگاه ورودی استفاده کنيم
    DIDevice.Acquire

    ‘استخراج اطلاعاتی در مورد دستگاه ورودی
    Set DevInfo = DIDevice.GetDeviceInfo()x
    txtOutput.Text = txtOutput.Text & "Product Name: " & DevInfo.GetProductName & vbCrLf
    txtOutput.Text = txtOutput.Text & "Device Type: " & DevInfo.GetDevType & vbCrLf
    txtOutput.Text = txtOutput.Text & "GUID: " & DevInfo.GetGuidInstance & vbCrLf


    ‘در صورتی که بخواهيم به برنامه خاتمه بدهيم کدهای زير را می نويسيم
    DIDevice.Unacquire
    Set DIDevice = Nothing
    Set DI = Nothing
    Set DX = Nothing
    Unload Me
    End


    3 – گرفتن ورودی از کيبرد : در اين بخش فرض کنيد بخواهيم يک بازی را در يک حلقه Do-Loop شبيه سازی کنيم . در اين حلقه هر بار فشرده شدن کليدهای کيبرد را چک می کنيم :

    If Not Err.Number Then bRunning = True

    Do While bRunning

    ‘دريافت اطلاعات شامل خواندن وضعيت کيبرد ، خواندن اطلاعات بافر و سپس خطا
    DIDevice.GetDeviceStateKeyboard DIState
    DIDevice.GetDeviceData pBuffer, DIGDD_DEFAULT
    If Err.Number = DI_BUFFEROVERFLOW Then
    Msgbox(“BUFFER OVERFLOW (Compensating)...")x
    GoTo ENDOFLOOP:
    End If
    ‘بررسی فشرده شدن کليدها
    For I = 0 To 255
    If DIState.Key(I) = 128 And (Not KeyState(I) = True) Then
    txtOutput.Text = txtOutput.Text & "{ DOWN } " & KeyNames(CInt(I))& vbCrLf
    txtOutput.SelStart = Len(txtOutput.Text)x
    KeyState(I) = True
    End If
    Next I

    ‘بررسی رها شدن کليد
    For I = 0 To BufferSize
    If KeyState(pBuffer(I).lOfs) = True And pBuffer(I).lData = 0 Then
    KeyState(pBuffer(I).lOfs) = False
    txtOutput.Text = txtOutput.Text & "{ UP } " & KeyNames(CInt(pBuffer(I).lOfs)) & vbCrLf
    txtOutput.SelStart = Len(txtOutput.Text)x
    End If
    Next I

    Sleep (50)x
    DoEvents
    ENDOFLOOP:
    Loop

    در کد فوق يک تابع KeyName وجود دارد که نام کليد فشارداده شده را بر می گرداند . بخشی از اين تابع را در زير می بينيد :


    Function KeyNames(iNum As Integer) As String

    Dim aKeys(0 To 255) As String

    aKeys(1) = "DIK_ESCAPE"
    aKeys(2) = "DIK_1 On main keyboard"x
    aKeys(3) = "DIK_2 On main keyboard"x
    aKeys(4) = "DIK_3 On main keyboard"x
    aKeys(5) = "DIK_4 On main keyboard"x
    aKeys(6) = "DIK_5 On main keyboard"x
    aKeys(7) = "DIK_6 On main keyboard"x
    aKeys(8) = "DIK_7 On main keyboard"x
    aKeys(9) = "DIK_8 On main keyboard"x
    aKeys(10) = "DIK_9 On main keyboard"x
    aKeys(11) = "DIK_0 On main keyboard"x
    aKeys(12) = "DIK_MINUS On main keyboard"x
    aKeys(13) = "DIK_EQUALS On main keyboard"x
    aKeys(14) = "DIK_BACK BACKSPACE"x
    aKeys(15) = "DIK_TAB"x
    aKeys(16) = "DIK_Q"x
    aKeys(17) = "DIK_W"x
    aKeys(18) = "DIK_E"x
    aKeys(19) = "DIK_R"x
    aKeys(20) = "DIK_T"x
    .
    .
    .
    KeyNames = aKeys(iNum)x

    End Function
    [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    Last edited by A_M_IT2005; 27-01-2007 at 02:23.

  5. این کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده است


  6. #4
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض

    سلام

    آموزش DirectX Input

    جلسه دوم :

    موضوع : کنترل کيبرد با روش Event-Based

    مقداردهی اوليه و مفاهيم اصلی در روش Event-Based مشابه روش Polling است و تنها بايستی ساختار بخش جمع آوری داده و حلقه پردازشی را تغيير دهيم . مراحل کار با روش Event-Based بصورت زير می باشد :

    ۱ - تعاريف و مقداردهی اوليه : در بخش تعاريف دو تعريف جديد بصورت زير داريم :

    Dim hEvent As Long
    Implements DirectXEvent8


    hEvent يک پارامتر هندل برای يک می باشد .
    نکته : زمانی که کليدی فشرده يا رها می شود ، DirectX اين امر با فراخوانی تابعی به اسم DirectXEvent8_DXCallback به برنامه شما اطلاع می دهد . ( اين نوع توابع را Call Back Function گويند ) . اين تابع به برنامه شما می گويد که يک رويداد اتفق افتاده است و بايستی بافرها را چک کند .

    تنها تغييری که در بخش مقداردهی اوليه نياز است ، برپاسازی يک event می باشد :

    If UseEventMethod Then
    hEvent = DX.CreateEvent(frmMain)x
    DIDevice.SetEventNotification hEvent
    End If


    در انتهای برنامه نيز کد زير را برای از بين بردن event اضافه کنيد :

    If hEvent <> 0 Then DX.DestroyEvent hEvent



    ۲ - استفاده از event : برای اين بخش کدهايي را در داخل تابع DirectXEvent8_DXCallback می نويسيم :

    Private Sub DirectXEvent8_DXCallback(ByVal eventid As Long)x
    'متغيرهای موردنياز
    Dim I As Long
    Dim pBuffer(0 To BufferSize) As DIDEVICEOBJECTDATA
    If eventid = hEvent Then
    If DIDevice Is Nothing Then Exit Sub
    'درصورت رخ دادن event داده را از کيبرد می گيريم
    DIDevice.GetDeviceStateKeyboard DIState
    DIDevice.GetDeviceData pBuffer, DIGDD_DEFAULT
    'چک کردن تمام کليدها برای اينکه متوجه شويم چه اتفاقی افتاده است
    For I = 0 To 255
    'عدد ۱۲۸ نشان دهنده key_down event است .
    If DIState.Key(I) = 128 Then
    If pBuffer(0).lData = 128 Then
    txtOutput.Text = txtOutput.Text & "{ DOWN } " & KeyNames(CInt(I)) & vbCrLf
    End If
    End If
    'کد فوق برای بررسی فشرده شدن يک کليد بود . کد زير رها شدن کليد را بررسی می کند
    If (pBuffer(0).lData = 0 And pBuffer(0).lOfs = I) Then
    txtOutput.Text = txtOutput.Text & "{ UP }" & KeyNames(CInt(I)) & vbCrLf
    End If

    txtOutput.SelStart = Len(txtOutput.Text)x
    Next I
    End If
    End Sub

    [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    Last edited by A_M_IT2005; 27-01-2007 at 02:25.

  7. این کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده است


  8. #5
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض آموزش DirectX Input

    سلام

    آموزش DirectX Input

    جلسه آخر :

    موضوع : کنترل ماوس با DirectX Input

    مقدمه :

    برای استفاده از ماوس در برنامه های مالتی مديا و بازيها همانند کی برد می توانيم از امکانات دايرکت ايکس استفاده کنيم . روش کنترل ماوس توسط DirectX Input بسيار ساده بوده و مشابه کنترل کيبرد می باشد بنابراين درصورتی که دو درس گذشته را نخوانده اين پيشنهاد می کنم ابتدا آنها را مطالعه کنيد .

    برپاسازی Device :

    علاوه بر متغيرهايي که در بخش کنترل کيبرد تعريف شد بايستی متغيرهای جديد زير را نيز در ابتدای برنامه تان تعريف کنيد :

    Private Const mSpeed As Single = 2
    Private Const BufferSize As Long = 10
    Private mPosition As Point


    mSpeed مقدار سرعت حرکت کرسر ماوس را مشخص می کند .
    BufferSize سايز بافر DI می باشد .
    mPosition موقعيت جاری کرسر ماوس را نشان می دهد .

    در مرحله بعدی بايستی مقداردهي های اوليه لازم را انجام دهيد :

    Set DIDevice = DI.CreateDevice("guid_SysMouse")x
    Call DIDevice.SetCommonDataFormat(DIFORMAT_MOUSE)x
    Call DIDevice.SetCooperativeLevel(frmMain.hWnd, DISCL_FOREGROUND Or DISCL_EXCLUSIVE)x


    تفاوت عمده کدهای فوق با کدهای مقداردهی اوليه در بخش کی برد آنست که cooperativelevel تغيير کرده است . در اينجا گفته شده که ما می خواهيم از ماوس بصورت انحصاری در برنامه استفاده کنيم . اين حالت برای برنامه های window-base مناسب نيست و بهترست از آن در بازيهايي که بصورت full screan هستند استفاده کنيد .

    خواندن ورودی از ماوس :

    در اين بخش می توانيد هم از روش polling و هم event-based استفاده کنيد . نکته مهمی که در اينجا وجود دارد آنست که Direct Input فقط حرکت داده شدن ماوس و کليک شدن يک دکمه را به شما اطلاع می دهد و برای تشخيص حالتهای double click و single click خودتان بايستی کد بنويسيد برای مثال اگر فاصله زمانی بين دو کليک کمتر از ۴۰ ميلی ثانيه باشد آنگاه اين يک double click بوده است .
    کد زير حرکت داده شدن ماوس و کليک يکی از سه دکمه آنرا اطلاع می دهد :

    Dim DevData(1 To BufferSize) As DIDEVICEOBJECTDATA
    Dim nEvents As Long
    Dim I As Long
    nEvents = DIDevice.GetDeviceData(DevData, DIGDD_DEFAULT)x
    For I = 1 To nEvents
    Select Case DevData(I).lOfs
    Case DIMOFS_X
    mPosition.x = mPosition.x + (DevData(I).lData * mSpeed)x
    If mPosition.x < 0 Then mPosition.x = 0
    If mPosition.x > frmMain.ScaleWidth Then mPosition.x = frmMain.ScaleWidth
    imgCursor.Top = mPosition.y
    imgCursor.Left = mPosition.x
    lablel(1).Caption = "Mouse Coordinates: [" & mPosition.x & ", " & mPosition.y & "]"x
    Case DIMOFS_Y
    mPosition.y = mPosition.y + (DevData(I).lData * mSpeed)x
    If mPosition.y < 0 Then mPosition.y = 0
    If mPosition.y > frmMain.ScaleHeight Then mPosition.y = frmMain.ScaleHeight
    imgCursor.Top = mPosition.y
    imgCursor.Left = mPosition.x
    lablel(1).Caption = "Mouse Coordinates: [" & mPosition.x & ", " & mPosition.y & "]"x
    Case DIMOFS_BUTTON0
    label(2).Caption = "Button 0 State: " & IIf(DevData(I).lData = 0, "Up", "Down")x
    Case DIMOFS_BUTTON1
    label(3).Caption = "Button 1 State: " & IIf(DevData(I).lData = 0, "Up", "Down")x
    Case DIMOFS_BUTTON2
    label(4).Caption = "Button 2 State: " & IIf(DevData(I).lData = 0, "Up", "Down")x
    Case DIMOFS_BUTTON3
    label(5).Caption = "Button 3 State: " & IIf(DevData(I).lData = 0, "Up", "Down")x
    End Select
    Next I


    برای استفاده از کد فوق در روش Polling ، بايستی آنرا در يک حلقه Do while-Loop قرار دهيد .
    برای استفاده از کد فوق در روش Event-Based ، بايستی آنرا درون روتين DirectXEvent8_DXCallback قرار دهيد .

    [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    Last edited by A_M_IT2005; 27-01-2007 at 02:26.

  9. 2 کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده اند


  10. #6
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض مباحث پيشرفته Direct3D

    سلام

    مباحث پيشرفته Direct3D

    جلسه اول

    موضوع : ساخت يک موتور گرافيکي سه بعدي

    در اين درس يک Engine سه بعدي ساخته و از امکانات آن در يک برنامه نمونه استفاده خواهيم کرد .
    اين engine داراي دو کلاس است :
    1 – کلاس MainD3D
    2 – کلاس D3Dobject
    در کلاس MainD3D متغيرها و توابع لازم براي ساخت يک device سه بعدي ، تنظيمات ماتريسي ، تابع رندر و غيره موجود مي باشد .
    متغيرهاي عمومي اين کلاس عبارتند از :
    Public g_DX As New DirectX8
    Public g_D3D As Direct3D8
    Public g_D3DX As New D3DX8
    Public g_D3DDevice As Direct3DDevice8
    Public NTextures As Long
    روتين ها و توابع اين کلاس عبارتند از :
    1 - InitD3D : اين روتين ، اشيا D3D و D3Ddevice را مي سازد و پارامترهاي آنها را تنظيم مي کند .
    2 – ApplyCameraChanges : روتين ايجاد ماتريس View
    3 – SetupMatrices : روتين ايجاد ماتريس Projection
    4 – StartRender : در اين روتين عمليات لازم براي شروع عمل رندر صورت مي گيرد .
    5 – RenderObject : اين تابع ، يک شي سه بعدي از نوع کلاس D3Dobject را مي گيرد و بردارهاي مورد نياز و نيز بافت شي را تنظيم مي کند و در پايان شي را ترسيم مي کند .
    6 – FinishRender : در اين روتين به عمليات رندر پايان داده مي شود .
    7 – Cleanup: روتين از بين بردن اشيا Direct3D
    8 – CreateVector : تابع ساخت يک بردار سه بعدي
    9 – CreateTextures : روتين ساخت يک بافت جديد
    10 – InitTexture: تابع مقداردهي به يک بافت
    در کلاس D3Dobject متغيرها و توابع لازم براي ايجاد يک شي سه بعدي و اختصاص بافت به آن موجود مي باشد .
    در اين کلاس دو type عمومي تعريف شده است :
    1 - NormalVERTEX
    2 - TeturedVERTEX
    همچنين روتين ها و توابع اين کلاس عبارتند از :
    1 – InitObject : تابعي که تنظيمات اوليه vertex ها و بافت شي را انجام مي دهد .
    2 – Vertex : روتين ايجاد vertex هاي مورد نياز
    3 – GetRenderingMode: تابعي که مد رندر را مشخص مي کند .
    و نيز يکسري تابع ساخت vertex نرمال و ساخت vertex داراي بافت و غيره

    اين دو کلاس در يک پروژه ويژوال بيسيک قرارداده شده و پروژه با نام D3Dengine.dll کامپايل شده است .
    حال با استفاده از اين engine مي خواهيم يک منظره سه بعدي را ايجاد کنيم :
    اين منظره شامل سه object است : ديوار ، آسمان و زمين.

    ابتدا بايد يک شي از کلاس MainD3D تعريف کنيم :

    Dim D3D8Main As MainD3D8
    در متد Form Load نيز سه شي Floor ، Sky و Wall را بصورت زير تعريف مي کنيم :

    Dim Floor As D3DObject
    Dim Sky As D3DObject
    Dim Walls As D3Dobject

    سپس اين سه شي را به اضافه شي D3D8Main ، ايجاد مي کنيم :

    Set D3D8Main = New D3DEngine.MainD3D8
    Set Floor = New D3DEngine.D3DObject
    Set Sky = New D3DEngine.D3DObject
    Set Walls = New D3DEngine.D3Dobject
    در ابتدا شي MainD3D را Initial مي کنيم و سپس بافتهاي مورد نيز خود را مي سازيم :

    D3D8Main.InitD3D True, Me.hWnd
    D3D8Main.CreateTextures 3
    D3D8Main.InitTexture 1, App.Path + "\floor.jpg"
    D3D8Main.InitTexture 2, App.Path + "\sky.bmp"
    D3D8Main.InitTexture 3, App.Path + "\wall.bmp"

    حال به سراغ ايجاد و مقداردهي vertex هاي floor مي رويم . floor شامل شش vertex مي باشد و بنابراين دو face مثلثي دارد :

    Floor.InitObject 6, 2, TriangleList, True, 1

    Floor.Vertex 0, -55, -2, -55, vbWhite, 0, 10
    Floor.Vertex 1, 55, -2, -55, vbWhite, 10, 10
    Floor.Vertex 2, 55, -2, 55, vbWhite, 10, 0
    Floor.Vertex 3, -55, -2, -55, vbWhite, 0, 10
    Floor.Vertex 4, 55, -2, 55, vbWhite, 10, 0
    Floor.Vertex 5, -55, -2, 55, vbWhite, 0, 0
    سپس به سراغ ايجاد و مقداردهي vertex هاي wall مي رويم . wall شامل بيست و چهار vertex مي باشد و بنابراين هشت face مثلثي دارد :

    Walls.InitObject 24, 8, TriangleList, True, 3

    Walls.Vertex 0, -55, -2, -55, &HBCE8FC, 0, 1
    Walls.Vertex 1, 55, -2, -55, &HBCE8FC, 5, 1
    Walls.Vertex 2, 55, 8, -55, &HBCE8FC, 5, 0
    Walls.Vertex 3, -55, -2, -55, &HBCE8FC, 0, 1
    Walls.Vertex 4, 55, 8, -55, &HBCE8FC, 5, 0
    Walls.Vertex 5, -55, 8, -55, &HBCE8FC, 0, 0

    Walls.Vertex 6, -55, -2, 55, &HBCE8FC, 0, 1
    Walls.Vertex 7, 55, -2, 55, &HBCE8FC, 5, 1
    Walls.Vertex 8, 55, 8, 55, &HBCE8FC, 5, 0
    Walls.Vertex 9, -55, -2, 55, &HBCE8FC, 0, 1
    Walls.Vertex 10, 55, 8, 55, &HBCE8FC, 5, 0
    Walls.Vertex 11, -55, 8, 55, &HBCE8FC, 0, 0

    Walls.Vertex 12, -55, -2, 55, &HBCE8FC, 0, 1
    Walls.Vertex 13, -55, -2, -55, &HBCE8FC, 5, 1
    Walls.Vertex 14, -55, 8, -55, &HBCE8FC, 5, 0
    Walls.Vertex 15, -55, -2, 55, &HBCE8FC, 0, 1
    Walls.Vertex 16, -55, 8, -55, &HBCE8FC, 5, 0
    Walls.Vertex 17, -55, 8, 55, &HBCE8FC, 0, 0

    Walls.Vertex 18, 55, -2, 55, &HBCE8FC, 0, 1
    Walls.Vertex 19, 55, -2, -55, &HBCE8FC, 5, 1
    Walls.Vertex 20, 55, 8, -55, &HBCE8FC, 5, 0
    Walls.Vertex 21, 55, -2, 55, &HBCE8FC, 0, 1
    Walls.Vertex 22, 55, 8, -55, &HBCE8FC, 5, 0
    Walls.Vertex 23, 55, 8, 55, &HBCE8FC, 0, 0

    حال به سراغ ايجاد و مقداردهي vertex هاي sky مي رويم . sky شامل شش vertex مي باشد و بنابراين دو face مثلثي دارد :

    Sky.InitObject 6, 2, TriangleList, True, 2

    Sky.Vertex 0, -55, 8, -55, &HBCE8FC, 0, 1
    Sky.Vertex 1, 55, 8, -55, &HBCE8FC, 0, 1
    Sky.Vertex 2, 55, 8, 55, &HBCE8FC, 0, 1
    Sky.Vertex 3, -55, 8, -55, &HBCE8FC, 0, 1
    Sky.Vertex 4, 55, 8, 55, &HBCE8FC, 0, 1
    Sky.Vertex 5, -55, 8, 55, &HBCE8FC, 0, 1

    در پايان تابع رندر را صدا مي کنيم . البته در هر بار عمل رندر کردن ، دوربين يک درجه در صفحه X-Z دوران مي کند تا کل ديوار قابل مشاهده باشد :

    Dim Angle As Double
    PI = 3.1415
    Angle = 0
    Do
    DoEvents
    D3D8Main.StartRender vbBlack
    D3D8Main.RenderObject Sky
    D3D8Main.RenderObject Floor
    D3D8Main.RenderObject Walls
    D3D8Main.FinishRender
    If Sqr(Angle ^ 2) = 360 Then Angle = 0
    Angle = Angle + 1
    D3D8Main.CamLookAtX = Sin((Angle * 2 * PI) / 360)
    D3D8Main.CamLookAtZ = Cos((Angle * 2 * PI) / 360)
    D3D8Main.ApplyCameraChanges
    Loop

    [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    Last edited by A_M_IT2005; 27-01-2007 at 02:36.

  11. این کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده است


  12. #7
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض (جلسه دوم)مباحث پيشرفته Direct3D

    سلام

    مباحث پيشرفته Direct3D

    جلسه دوم :

    موضوع : استفاده از object هاي 3D Studio Max در Direct3D
    تا بحال ما هر شيي را که مي خواستيم در Direct3D بسازيم خودمان بوسيله کد نويسي آنرا توصيف کرده ايم . ممکنست اين سوال برايتان پيش آمده باشد که بازيهاي تجاري براي توليد کاراکترهاي و اشيا پيچيده سه بعدي چگونه عمل مي کنند ؟
    منطقي بنظر نمي رسد که اينگونه مدلهاي پيچيده بصورت کد وارد برنامه شده اند زيرا نياز به هزاران خط برنامه براي هر فريم خواهد بود . بجاي اينکار ما object هاي خود را توسط برنامه هاي ديگري مي سازيم و آنها را در برنامه خودمان load مي کنيم سپس بافتها و material هاي مورد نظر را به آنها اختصاص داده و در پايان آنها را رندر مي کنيم . مزيت ديگر اينکار اينست که شما مي توانيد براحتي فايل object خود را تغيير دهيد و مدلهايي با جزئيات متفاوت براي برنامه خود قرار دهيد .
    مراحل ساخت چنين برنامه هايي بصورت زير است :

    ۱ - ساخت object سه بعدي :
    اولين چيزي که بايستي بدانيد داشتن دانش پايه اي از چگونگي مدلسازي سه بعدي است . همچنين نياز به يک نرم افزار مدلسازي مثل 3D Studio Max داريد .

    بعد از ساخت مدل خود در Max نياز به يک Convertor داريد تا فايلهاي Max را به فايلهاي Direct3D که با فرمت "X." هستند تبديل کنيد .
    Convertor هاي زيادي براي تبديل فايلهاي نرم افزارهاي مدلسازي به فايلهاي "X." وجود دارند که برخي از آنها عبارتند از :
    - برنامه PolyTrans3D System Translation
    - برنامه Deep Exploration 2.0
    - برنامه Quick3D
    - برنامه 3DWin
    - DirectX Explorer Plugin
    - ابزارهاي موجود در DirectX 8.0 SDK که عبارتند از :
    برنامه Conv3DS براي تبديل فايلهاي 3DS به فايلهاي X
    DX SDK Exporter Plugin براي تبديل فايلهاي 3DS و Max به فايلهاي X
    از بين اين برنامه ها و plugin ها من برنامه Deep Exploration را به شما پيشنهاد مي کنم .

    در آدرس زير مي توانيد اطلاعات بيشتري در مورد اين برنامه بدست آوريد و همچنين آنرا Download کنيد :
    [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    s/n: 0XE2A0000000000
    Authorization s/n: REJ1HYXSR1A77Q10

    2 - Load کردن يک Object ساخته شده :
    زمانيکه فايل X شي مورد نظر را ساختيد ، load کردن آن در direct3D ساده است . براي اينکار نياز به يک مش داريم که اطلاعات شي ما را نگهداري کند :

    Dim Mesh As D3DXMesh
    همچنين براي اختصاص material و texture به شي ، نياز به تعريف متغيرهاي زير داريم :

    Dim MeshMaterial As D3DMATERIAL8
    Dim MeshTexture As Direct3DTexture8

    حال به سراغ بازنويسي روتين InitGeometry مي رويم :
    - تعريف متغيرهاي مورد نياز :

    Dim mtrlBuffer as D3DXBuffer
    Dim TextureFile as String
    Dim n as Long

    - گرفتن داده هاي شي از فايل X :

    Set Mesh=D3DX.LoadMeshFromX app.path&"\"&"yourfilename",D3DMESH_MANAGED,D3DDev ice,Nothing,mtrlBuffer,n

    - استخراج اطلاعات materiasl شي و تنظيم پارامتر Ambient :

    D3DX.BufferGetMaterial mtrlBuffer,0,MeshMaterial
    MeshMaterial.Ambient=MeshMaterial.Diffuse

    - استخراج نام بافت بکار رفته براي شي :

    TextureFile=D3DX.BufferGetTextureName(mtrlBuffer,0 )x
    - ساخت بافت :

    If TextureFile<>"" Then
    Set MeshTexture=D3DX.CreateTextureFromFile D3DDevice,app.path&"\"&TextureFile,128,128,D3DX_DE FAULT,0,
    D3DFMT_UNKNOWN,D3DPOOL_MANAGED,D3DX_FILTER_LINEAR, D3DX_FILTER_LINEAR,0,Byval 0,Byval 0
    End If

    ۳ - رندر نمودن شي : رندر نمودن شي چندان مشکل نيست اما همچنان بايد ماتريسها و تبديلاتي را که مي خواهيد ، خودتان مديريت کنيد .

    D3DDevice.SetMaterial MeshMaterial
    D3DDevice.SetTexture 0,MeshTexture
    Mesh.DrawSubset 0

    [ برای مشاهده لینک ، با نام کاربری خود وارد شوید یا ثبت نام کنید ]
    Last edited by A_M_IT2005; 27-01-2007 at 02:44.

  13. این کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده است


  14. #8
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض مباحث پيشرفته Direct3D

    سلام
    اگه زحمتی نیست یه نظری هم بدین که من بفهمم به درد کسی خورده یا نه.

    مباحث پيشرفته Direct3D

    جلسه سوم :

    موضوع : مباحث تکميلي نورپردازي در Direct3D

    در بخش اول آموزش Direct3D با مباني نورپردازي آشنا شديد . در اين درس قصد دارم آن مباحث را کاملتر برايتان مطرح کنم .
    نورپردازي يکي از بخشهاي مهم طراحي يک بازي و يا يک انيميشن سه بعدي است . بمنظور پياده سازي نورپردازي يک صحنه ابتدا بايد با تئوري آن آشنا شويد .
    تئوري نورپردازي : نورپردازي در Direct3D تخميني از چگونگي عملکرد نور در دنياي واقعي مي باشد . چهار نوع اصلي نور در Direct3D قابل استفاده است ( همچنين شما مي توانيد خودتان انواع جديدي از نور ايجاد کنيد که موضوع ما نيست ) :
    ۱ - Point Light : توسط يک نقطه در فضاي سه بعدي ايجاد مي شود و داراي سه پارامتر رنگ ، دامنه و تضعيف مي باشد . دامنه يک نور مسافتي است که نور مي تواند طي کند . تضعيف ، مقدار کاهش نور در اثر افزايش مسافت مي باشد . نور نقطه اي در تمام جهات تششع مي کند - شبيه يک لامپ حبابي و يا يک شمع
    ۲ - Spot Light : داراي يک موقعيت و يک جهت است و تنها نور را در يک جهت خاص مي تاباند - شبيه يک چراغ قوه . اين نور داراي يک زاويه مخروطي و يک دامنه است .
    ۳ - Directional Light : داراي موقعيت نيست و براي پياده سازي نورهايي که از فاصله بسيار دور مي آيند - مثل خورشيد - مناسب است .
    ۴ - Ambient Light : اين نور تضمين مي کند که تمام vertex هاي يک صحنه تاريکتر از يک رنگ خاص نباشند .
    عملي کردن نورپردازي : ضمن اينکه اغلب کارت هاي گرافيک سه بعدي از نورپردازي پشتيباني مي کنند اما اين نکته بايد مورد توجه قرار گيرد که با افزايش تعداد نور در يک صحنه محاسبات Direct3D بيشتر مي شود و اين باعث کند شدن رندر صحنه خواهد شد و بنابراين کارت هاي گرافيکي سه بعدي نيز داراي يک ماکزيمم تعداد نور هستند - مثلاً ۱۶ نور در GeForce 2 - همچنين توجه داشته باشيد که نورهاي مختلف داراي زمان پردازشي متفاوتي هستند . نور ambient سريعترين زمان پردازشي را دارد ، سپس نورdirectional ، سپس نور point و کندترين آنها Spot Light است .
    همچنين نکته ديگري که بايد توجه کنيد دامنه نور است . اگر نور ، يک منطقه بزرگي را پوشش دهد بر تعداد زيادي از vertex ها تاثير مي گذارد و اين باعث افزايش محاسبات مي شود .
    نورپردازي Specular - که در درسهاي بعدي در مورد آن صحبت مي کنم و براي ايجاد اشيا درخشان استفاده مي شود - نيز زمان پردازشي زيادي دارد و بهتر است کمتر از آن استفاده شود .
    پارامتر ديگري که بايد در نظر بگيريد جزئيات هندسه شما مي باشد . هر چه پيچيدگي صحنه بيشتر باشد ، نورپردازي نيز زمان بيشتري را مصرف مي کند .
    سايه زني نيز يک بخش بسيار پيچيده در مدل سازي نور است و محاسبات آن بسيار زمان گير خواهد بود بنابراين Direct3D مستقيماً محاسبات سايه زني را انجام نمي دهد بلکه رنگ نور را بر مبناي جهت هر مثلث scale مي کند بنابراين قسمت پشتي يک شي که رو به نور نيست ، هيچ نوري را دريافت نمي کند .

    بردار نرمال : Direct3D هر vertex را بر مبناي بک بردار نرمال نورپردازي مي کند و نوري که يک vertex دريافت مي کند به زاويه بين نور و بردار نرمال آن vertex بستگي دارد . بردار نرمال توسط سه vertex يک face مثلثي ايجاد مي شود و اين بردار نرمال ساخته شده به vertex ها اختصاص مي يابد . بردار نرمال در واقع سمت يک مثلث را مشخص مي کند بنابراين اگر نور پشت مثلث باشد ، مثلث هيچ نوري را دريافت نميکند . بردار نرمال بايستي داراي طول ۱ باشد .
    مراحل توليد بردار نرمال يک face مثلثي :
    ۱ - مطمئن شويد که face در جهت عقربه هاي ساعت ساخته شده است .
    ۲ - يک بردار از vertex شماره صفر به vertex شماره يک بسازيد .
    ۳ - يک بردار از vertex شماره صفر به vertex شماره دو بسازيد .
    ۴ - حاصلضرب برداري ( cross droduct ) اين دو بردار را بدست آوريد .
    ۵ - نتيجه حاصلضرب را نرمال کنيد .

    Private Function GenerateTriangleNormals(p0 As UnlitVertex, p1 As UnlitVertex, p2 As UnlitVertex) As D3DVECTOR
    Dim v01 As D3DVECTOR
    Dim v02 As D3DVECTOR
    Dim vNorm As D3DVECTOR
    D3DXVec3Subtract v01, MakeVector(p1.X, p1.Y, p1.Z), MakeVector(p0.X, p0.Y, p0.Z)x
    D3DXVec3Subtract v02, MakeVector(p2.X, p2.Y, p2.Z), MakeVector(p0.X, p0.Y, p0.Z)x
    D3DXVec3Cross vNorm, v01, v02
    D3DXVec3Normalize vNorm, vNorm
    GenerateTriangleNormals.X = vNorm.X
    GenerateTriangleNormals.Y = vNorm.Y
    GenerateTriangleNormals.Z = vNorm.Z
    End Function


    اگر دو face در يک vertex مشترک باشند ( مثل گوشه دو ديوار ) براي توليد نرمال اين vertex ابتدا نرمال دو face را با روش فوق بدست آوريد سپس دو بردار نرمال را با هم جمع کنيد و در پايان بردار حاصلجمع را نرمال کنيد .

    برپاسازي نورپردازي : اولين چيزي که قبل از برپاسازي نورپردازي بايستي اعمال کنيم تغيير ساختار vertex است . براي اينکار بايد پارامتر color را از ساختار vertex حذف و سه پارامتر را براي نگهداري نرمال اضافه کنيم :

    Private Type UnlitVertex
    X As Single
    Y As Single
    Z As Single
    nx As Single
    ny As Single
    nz As Single
    tu As Single
    tv As Single
    End Type
    Const Unlit_FVF = (D3DFVF_XYZ Or D3DFVF_NORMAL Or D3DFVF_TEX1)x

    همچنين بايد براي تمام vertex هاي شي خود بردار نرمال را محاسبه کنيد براي مثال اگر شي شما يک مکعب است براي هر ۱۲ face آن بردار نرمال را بدست آوريد . در زير من کد لازم براي ساخت نرمال يکي از اين face ها را نوشته ام :

    Cube2(0) = CreateVertex(-1, -1, 1, 0, 0, 0, 0, 0)x
    Cube2(1) = CreateVertex(1, 1, 1, 0, 0, 0, 1, 1)x
    Cube2(2) = CreateVertex(-1, 1, 1, 0, 0, 0, 0, 1)x
    vN = GenerateTriangleNormals(Cube2(0), Cube2(1), Cube2(2))x
    Cube2(0).nx = vN.X: Cube2(0).ny = vN.Y: Cube2(0).nz = vN.Z
    Cube2(1).nx = vN.X: Cube2(1).ny = vN.Y: Cube2(1).nz = vN.Z
    Cube2(2).nx = vN.X: Cube2(2).ny = vN.Y: Cube2(2).nz = vN.Z

    براي برپا سازي نور ابتدا بايستي يک material به device خود اضافه کنيد :

    Dim Mtrl As D3DMATERIAL8, Col As D3DCOLORVALUE
    Col.a = 1: Col.r = 1: Col.g = 1: Col.b = 1
    Mtrl.Ambient = Col
    Mtrl.diffuse = Col
    D3DDevice.SetMaterial Mtrl

    سپس بايستي طوري device خود را تنظيم کنيد که نور شما را بشناسد - lights يک شي از نوع D3DLight8 است - يکبار که اين خط را بنويسيد مي توانيد از نور استفاده کنيد اما اگر خصوصيات نور را تغيير دهيد بايستي دوباره اين دستور را فراخواني کنيد :

    D3DDevice.SetLight 0, Lights

    حال بايد نور را روشن کنيد :

    D3DDevice.LightEnable 0, 1

    و در پايان بايد به Direct3D بگوئيد که نورپردازي را براي شما انجام دهد :

    D3DDevice.SetRenderState D3DRS_LIGHTING, 1

    چگونگي ايجاد يک نور : براي ايجاد هر يک از ۴ نوع اصلي نور بايد به روشي خاص عمل کنيد :
    ۱ - نورپردازي Ambient : اين نوع نورپردازي بسيار ساده است و تنها با فراخواني تابع SetRenderState ايجاد مي شود . رنگ ambient يک عدد هگزادسيمال بصورت RRGGBB است :

    D3DDevice.SetRenderState D3DRS_AMBIENT, &H202020

    ۲ - نورپردازي Directional : داراي دو پارامتر رنگ و جهت مي باشد :

    Lights.Type = D3DLIGHT_DIRECTIONAL
    Lights.diffuse.r = 1
    Lights.diffuse.g = 1
    Lights.diffuse.b = 1
    Lights.Direction = MakeVector(0, -1, 0)x

    3 - نورپردازي Point : داراي سه پارامتر موقعيت ، رنگ و تضعيف مي باشد :

    Lights.Type = D3DLIGHT_POINT
    Lights.position = MakeVector(5, 0, 2)x
    Lights.diffuse.b = 1
    Lights.Range = 100
    Lights.Attenuation1 = 0.05

    ۴ - نورپردازي Spot : اين نور داراي دو مخروط است که نقاط خارج مخروط اول روشنتر از نقاط داخل آن هستند . دو زاويه براي مخروط وجود دارد - زاويه داخلي theta و زاويه خارجي phi - که برحسب راديان هستند :


    Lights.Type = D3DLIGHT_SPOT
    Lights.position = MakeVector(-4, 0, 0)x
    Lights.Range = 100
    Lights.Direction = MakeVector(1, 0, 0)x
    Lights.Theta = 30 * (Pi / 180)x
    Lights.Phi = 50 * (Pi / 180)x
    Lights.diffuse.g = 1
    Lights.Attenuation1 = 0.05

  15. 2 کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده اند


  16. #9
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض مباحث پيشرفته Direct3D

    سلام

    مباحث پيشرفته Direct3D

    جلسه چهارم :

    موضوع : استفاده از Index Buffer براي ذخيره سازي اشکال سه بعدي

    مقدمه : مکعبي که در درسهاي قبلي ساختيم را درنظر بگيريد . با دانشي که اکنون داريد ، دو راه براي ساخت يک مکعب داريم : ۱ - استفاده از 36 عدد vertex براي تعريف face هاي مکعب ۲ - ساخت مکعب با استفاده از يک مدلساز و ذخيره آن با فرمت X
    روش اول غيرکارامد است زيرا شما بايستي از تعداد زيادي vertex براي يک شکل بسيار ساده استفاده کنيد . روش دوم مناسب است اما زمانيکه بخواهيم رنگها و بافتها را تغيير دهيم دچار مشکل خواهيم شد . روش جديدي که امروز در مورد آن صحبت مي کنم استفاده ار Index Buffer است .
    Index Buffer شامل يکسري عدد integer است که اين اعداد مرجعي براي vertex هاي ذخيره شده در يک Vertex Buffer هستند . براي مثال فرض کنيد يک Vertex Buffer شامل 8 عدد vertex داريم که يک مکعب را براي ما توصيف مي کند . ما مي توانيم يک Index Buffer با ۳۶ عضو بسازيم بطوريکه ترتيب اتصال vertex ها را براي ما مشخص کنند . مثلاً Index هاي ۰ و ۱و ۳ براي مشخص کردن face شماره ۱ مکعب بکار مي روند . بنابراين بجاي استفاده از ۳۶ عدد vertex مي توانيم مکعب را با ۸ عدد vertex و يک Index Buffer بسازيم .
    گرچه استفاده از Index Buffer بسيار کارامد است اما چندين محدوديت در استفاده از آن وجود دارد . مهمترين آنها اينست که تمام انديسهايي که يک vertex مشابه را share مي کنند بايستي خصوصيات مشابهي داشته باشند - موقعيت ، رنگ ، بافت و نرمال يکسان - براي مثال نمي توانيد مکعبي بسازيد که هر face آن يک رنگ داشته باشد .

    ساخت Index Buffer : ابتدا به متغيرهاي زير نياز داريم :

    Dim VBuffer as Direct3DVertexBuffer8
    Dim IBuffer as Direct3DIndexBuffer8
    Dim Vlist(0 to 7) as LITVERTEX
    Dim Ilist(0 to 35) as Integer


    تابع InitGeometry بصورت زير بازنويسي مي شود:
    ۱- توليد هشت vertex براي مکعب :

    Vlist(0) = CreateLitVertex(-1, -1, -1, &HFF0000, 0, 0, 0)x
    Vlist(1) = CreateLitVertex(-1, 1, -1, &HFF00&, 0, 0, 0)x
    Vlist(2) = CreateLitVertex(1, -1, -1, &HFF&, 0, 0, 0)x
    Vlist(3) = CreateLitVertex(1, 1, -1, &HFF00FF, 0, 0, 0)x
    Vlist(4) = CreateLitVertex(-1, -1, 1, &HFFFF00, 0, 0, 0)x
    Vlist(5) = CreateLitVertex(-1, 1, 1, &HFFFF, 0, 0, 0)x
    Vlist(6) = CreateLitVertex(1, -1, 1, &HFFCC00, 0, 0, 0)x
    Vlist(7) = CreateLitVertex(1, 1, 1, &HFFFFFF, 0, 0, 0)x


    ۲ - ايجاد Vertex Buffer توسط تابع CreateVertexBuffer :

    Set VBuffer = D3DDevice.CreateVertexBuffer(Len(Vlist(0)) * 8, 0, Lit_FVF, D3DPOOL_DEFAULT)x
    D3DVertexBuffer8SetData VBuffer, 0, Len(Vlist(0)) * 8, 0, Vlist(0)x


    ۳ - توليد index ها :

    front '
    Ilist(0) = 0: Ilist(1) = 1: Ilist(2) = 2
    Ilist(3) = 1: Ilist(4) = 3: Ilist(5) = 2
    Right '
    Ilist(6) = 2: Ilist(7) = 3: Ilist(8) = 6
    Ilist(9) = 3: Ilist(10) = 7: Ilist(11) = 6
    Back '
    Ilist(12) = 6: Ilist(13) = 7: Ilist(14) = 4
    Ilist(15) = 7: Ilist(16) = 5: Ilist(17) = 4
    Left '
    Ilist(18) = 4: Ilist(19) = 5: Ilist(20) = 0
    Ilist(21) = 5: Ilist(22) = 1: Ilist(23) = 0
    Top '
    Ilist(24) = 1: Ilist(25) = 5: Ilist(26) = 3
    Ilist(27) = 5: Ilist(28) = 7: Ilist(29) = 3
    Bottom '
    Ilist(30) = 2: Ilist(31) = 6: Ilist(32) = 0
    Ilist(33) = 6: Ilist(34) = 4: Ilist(35) = 0


    ۴ - ايجاد Index Buffer توسط تابع CreateIndexBuffer :

    Set IBuffer = D3DDevice.CreateIndexBuffer(Len(Ilist(0)) * 36, 0, D3DFMT_INDEX16, D3DPOOL_DEFAULT)x
    D3DIndexBuffer8SetData IBuffer, 0, Len(Ilist(0)) * 36, 0, Ilist(0)x


    تابع Render : براي رندر کردن اين مکعب دو روش وجود دارد :
    ۱ - استفاده از تابع DrawIndexedPrimitive : در اين روش از VBuffer و IBUffer و آرايه vertex ها استفاده مي شود :

    Public Sub Render()x
    D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, 0, 1#, 0
    D3DDevice.BeginScene
    D3DDevice.SetStreamSource 0, VBuffer, Len(Vlist(0))x
    D3DDevice.SetIndices IBuffer, 0
    D3DDevice.DrawIndexedPrimitive D3DPT_TRIANGLELIST, 0, 36, 0, 12
    D3DDevice.EndScene
    D3DDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
    End Sub


    ۲ - استفاده از تابع DrawIndexedPrimitiveUP : در اين روش از آرايه هاي vertex و index استفاده مي شود :

    Public Sub Render()x
    D3DDevice.Clear 0, ByVal 0, D3DCLEAR_TARGET Or D3DCLEAR_ZBUFFER, 0, 1#, 0
    D3DDevice.BeginScene
    D3DDevice.DrawIndexedPrimitiveUP D3DPT_TRIANGLELIST, 0, 8, 12, Ilist(0), D3DFMT_INDEX16, Vlist(0), Len(Vlist(0))x
    D3DDevice.EndScene
    D3DDevice.Present ByVal 0, ByVal 0, 0, ByVal 0
    End Sub

  17. 2 کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده اند


  18. #10
    اگه نباشه جاش خالی می مونه A_M_IT2005's Avatar
    تاريخ عضويت
    Oct 2005
    محل سكونت
    بین جهنم و بهشت
    پست ها
    331

    پيش فرض مباحث پيشرفته Direct3D

    سلام

    مباحث پيشرفته Direct3D

    جلسه آخر :

    موضوع : Vertex/Mesh Animation
    در اين درس در مورد روشهاي ساخت انيميشن در Direct3D صحبت خواهيم کرد . انيميشن در فضاي سه بعدي در حالتهاي مختلفي مي تواند ايجاد شود که بسته به engine گرافيکي شما و ابزارهايي که ايجاد کرده ايد ، دارد . سه روش اصلي ساخت انيميشن وجود دارد که عبارتند از :
    - Tween سازي دستي / درون يابي خطي ( manual tweening/linear interpolation )
    - درون بابي برداري ( vector interpolation )
    - درون يابي بر اساس فريم کليدي ( keyframe interpolation )

    1 – روش اول يکي از ساده ترين راههاي ساخت انيميشن است . اين روش در زمانيکه با مدلهاي پيچيده سر و کار داريد مناسب نيست – و يا مدلهايي با تعداد زيادي vertex – اين روش نوعي tween کردن است که از مزيت index buffer ها استفاده مي کند .
    درون يابي ، چگونگي تغييرات شيي در طول يک زمان مشخص مي باشد . در درسهاي قبلي شما درون يابي رنگ را روي يک شي ديديد که در آن يک رنگ بطور ملايم به رنگ ديگري تبديل مي شد ( fadeشدن ( . درون يابي خطي نيز مشابه آن است . براي درون يابي خطي از موقعيت A به موقعيت B از فرمول زير استفاده مي شود :
    (B*V)+A*(1-V)
    که A و B مختصاتهاي مبدا و مقصد هستند و V ضريب درون يابي است که عددي بين صفر و يک مي باشد . اين فرمول مختصات نقطه tween را در هر لحظه مشخص مي کند .
    همانطور که مي بينيد بکار بردن اين فرمول براي يک شي با تعداد زيادي vertex بسيار وقت گير بوده و fram rate را پايين مي آورد .
    تابع زير دو vertex و يک مقدار ضريب درون يابي را مي گيرد تا نقطه tween را محاسبه کند :

    Private Function TweenVertices(Source As LITVERTEX, Dest As LITVERTEX, TweenAmount As Single) As LITVERTEX
    TweenVertices.X = (Dest.X * TweenAmount) + Source.X * (1# - TweenAmount)x
    TweenVertices.Y = (Dest.Y * TweenAmount) + Source.Y * (1# - TweenAmount)x
    TweenVertices.Z = (Dest.Z * TweenAmount) + Source.Z * (1# - TweenAmount)x
    TweenVertices.color = Source.color
    End Function


    اگر شما از vertex هاي UNLIT استفاده کنيد – vertex هايي با بردار نرمال – در اينصورت بايد کد فوق را تغيير دهيد و بايد tween را از نرمال مبدا به نرمال مقصد نيز انجام دهيد .
    همانطور که مي بينيد رنگ tween vertex نيز تنظيم شده است . در يک تابع tweening مناسبتر مي توانيد رنگها ، مختصات بافت و مقادير specular را نيز tween کنيد .
    محدوديتي که اين روش دارد اينست که خطي است و براي مدل کردن حرکتهاي غير خطي درست کار نمي کند .
    حال مي خواهيم از تابع tween استفاده کنيم تا يک مکعب را در يک انيميشن به يک هرم تبديل کنيم . ابتدا سه شي را بصورت زير تعريف مي کنيم :

    در ابتداي انيميشن ، شي current cube همان source cube است’
    CubeVertices(0) = CreateLitVertex(-1, -1, -1, &HFF0000, 0, 0, 0)x
    CubeVertices(1) = CreateLitVertex(-1, 1, -1, &HFF00&, 0, 0, 0)x
    CubeVertices(2) = CreateLitVertex(1, -1, -1, &HFF&, 0, 0, 0)x
    CubeVertices(3) = CreateLitVertex(1, 1, -1, &HFF00FF, 0, 0, 0)x
    CubeVertices(4) = CreateLitVertex(-1, -1, 1, &HFFFF00, 0, 0, 0)x
    CubeVertices(5) = CreateLitVertex(-1, 1, 1, &HFFFF, 0, 0, 0)x
    CubeVertices(6) = CreateLitVertex(1, -1, 1, &HFFCC00, 0, 0, 0)x
    CubeVertices(7) = CreateLitVertex(1, 1, 1, &HFFFFFF, 0, 0, 0)x
    مکعب اوليه’
    CubeVerticesSource(0) = CreateLitVertex(-1, -1, -1, &HFF0000, 0, 0, 0)x
    CubeVerticesSource(1) = CreateLitVertex(-1, 1, -1, &HFF00&, 0, 0, 0)x
    CubeVerticesSource(2) = CreateLitVertex(1, -1, -1, &HFF&, 0, 0, 0)x
    CubeVerticesSource(3) = CreateLitVertex(1, 1, -1, &HFF00FF, 0, 0, 0)x
    CubeVerticesSource(4) = CreateLitVertex(-1, -1, 1, &HFFFF00, 0, 0, 0)x
    CubeVerticesSource(5) = CreateLitVertex(-1, 1, 1, &HFFFF, 0, 0, 0)x
    CubeVerticesSource(6) = CreateLitVertex(1, -1, 1, &HFFCC00, 0, 0, 0)x
    CubeVerticesSource(7) = CreateLitVertex(1, 1, 1, &HFFFFFF, 0, 0, 0)x
    هرم مقصد’
    CubeVerticesDest(0) = CreateLitVertex(-1, -1, -1, &HFF0000, 0, 0, 0)x
    CubeVerticesDest(1) = CreateLitVertex(-0.1, 1, -0.1, &HFF00&, 0, 0, 0)x
    CubeVerticesDest(2) = CreateLitVertex(1, -1, -1, &HFF&, 0, 0, 0)x
    CubeVerticesDest(3) = CreateLitVertex(0.1, 1, -0.1, &HFF00FF, 0, 0, 0)x
    CubeVerticesDest(4) = CreateLitVertex(-1, -1, 1, &HFFFF00, 0, 0, 0)x
    CubeVerticesDest(5) = CreateLitVertex(-0.1, 1, 0.1, &HFFFF, 0, 0, 0)x
    CubeVerticesDest(6) = CreateLitVertex(1, -1, 1, &HFFCC00, 0, 0, 0)x
    CubeVerticesDest(7) = CreateLitVertex(0.1, 1, 0.1, &HFFFFFF, 0, 0, 0)x


    حال بايد در يک حلقه با استفاده از تابع twen پيکسلهاي CubeVertices را update کنيم :

    Private Sub UpdateAnimation()x
    Dim I As Integer
    به روز کردن پارامترهاي زمان و جهت'
    If AnimTweenDir = True Then
    AnimTweenFactor = AnimTweenFactor + (((GetTickCount() - LastTimeTweened) / 1000)*1#)
    LastTimeTweened = GetTickCount
    If AnimTweenFactor >= 1# Then
    AnimTweenFactor = 1#
    AnimTweenDir = False
    End If
    Else
    AnimTweenFactor = AnimTweenFactor - (((GetTickCount() - LastTimeTweened) / 1000)*1#)
    LastTimeTweened = GetTickCount
    If AnimTweenFactor <= 0# Then
    AnimTweenFactor = 0#
    AnimTweenDir = True
    End If
    End If
    به روز کردن اطلاعات vertex ها '
    For I = 0 To 7
    CubeVertices(I) = TweenVertices(CubeVerticesSource(I), CubeVerticesDest(I), AnimTweenFactor)x
    Next I
    به روز کردن بافر vertex’
    If D3DVertexBuffer8SetData(VBuffer, 0, Len(CubeVertices(0)) * 8, 0, CubeVertices(0)) = D3DERR_INVALIDCALL Then GoTo Error:
    Exit Sub
    Error:
    Debug.Print “Error occured whilst updating the animation…”x
    End Sub


    زمان پايه انيميشن توسط عبارت زير تنظيم مي شود :
    (((GetTickCount() - LastTimeTweened) / 1000) * 1#)
    همانطور که مي دانيد دو نوع انيميشن وجود دارد : انيميشن بر مبناي frame و انيميشن بر مبناي زمان . در انيميشن بر مبناي frame شماره فريم با يک مقدار ثابت در زمان افزايش مي يابد اما اگر اينکار باعث مي شود کيفيت انيميشن در کامپيوترهاي با سرعت متفاوت تغيير کند . بنابراين انيميشن را بر مبناي زمان توليد کرده ايم . انيميشن هاي بر مبناي زمان بجاي " 1 فريم در هر سيکل " ، " 30 فريم در هر ثانيه " هستند .

    2 – روش دوم از توابع کتابخانه D3DX براي انجام عمل tweening استفاده مي کند و بنابراين بهبودي در سرعت انيميشن نسبت به روش بالا حاصل مي شود . با استفاده از کتابخانه D3DX مي توانيم عمل درون يابي خطي را براي تمام اجزا اصلي يک vertex انجام دهيم . ليست زير توابعي را براي اينکار نشان مي دهد :
    - تابع D3DXVec3Lerp : انجام درون يابي براي موقعيت و نرمال :

    D3DXVec3Lerp( VOut as D3DVECTOR, V1 as D3DVECTOR, V2 as D3DVECTOR, S as Single)x
    - VOut = The result of the interpolation
    - V1 = The source coordinates
    - V2 = The destination coordinates
    - S = The interpolation amount - between, but not limited to, 0.0 - 1.0 scale; where 0 is the source and 1 is the destination


    - تابع D3DXColorLerp : انجام درون يابي براي رنگهاي vertex :

    D3DXColorLerp( COut as D3DCOLORVALUE, C1 as D3DCOLORVALUE, C2 as D3DCOLORVALUE, S as Single)x
    - COut = The resulting colour
    - C1 = The source colour
    - C2 = The destination colour
    - S = The interpolant,

    on a 0.0 to 1.0 scale
    - تابع D3DXVec2Lerp : انجام درون يابي براي مختصاتهاي دوبعدي :

    - VOut = The result of this interpolation
    - V1 = The source coordinates
    - V2 = The destination coordinates
    - S = The interpolant on a 0.0 to 1.0 scale

    - تابع D3DXVec3Hermite : توليد يک مسير منحني که از دو نقطه کنترل عبور مي کند :

    D3DXVec3Hermite( VOut as D3DVECTOR, V1 as D3DVECTOR, T1 as D3DVECTOR, V2 as D3DVECTOR, T2 as D3DVECTOR, S as Single)x
    - VOut = The Result
    - V1 = The Source Coordinate
    - T1 = The Tangent at the Source coordinate, this is the direction and speed the line will leave the source point.
    - V2 = The Destination Coordinate
    - T2 = The Tangent at the Destination coordinate, this is the direction and speed the line will enter the destination point.
    - S = The Interpolant Value

    براي اينکه بتوانيم از کتابخانه D3DX استفاده کنيم بايد توصيف vertex هايمان را تغيير دهيم و بايستي يکسري مقادير ARGB اضافي را به ساختار vertex اضافه کنيم :

    Private Type LITVERTEX
    X As Single
    Y As Single
    Z As Single
    color As Long
    specular As Long
    tu As Single
    tv As Single
    ColorEx As D3DCOLORVALUE
    End Type


    حال تابع tween را بصورت زير مي نويسيم :

    Private Function TweenVertices(Source As LITVERTEX, Dest As LITVERTEX, TweenAmount As Single) As LITVERTEX
    Dim vResult As D3DVECTOR
    Dim vResult2 As D3DVECTOR2
    Tween کردن موقعيت vertex ها ‘
    D3DXVec3Lerp vResult, MakeVector(Source.X, Source.Y, Source.Z), MakeVector(Dest.X, Dest.Y, Dest.Z), TweenAmount
    TweenVertices.X = vResult.X
    TweenVertices.Y = vResult.Y
    TweenVertices.Z = vResult.Z
    Tween کردن اطلاعات texture ’
    D3DXVec2Lerp vResult2, MakeVector2D(Source.tu, Source.tv), MakeVector2D(Dest.tu, Dest.tv), TweenAmount
    TweenVertices.tu = vResult2.X
    TweenVertices.tv = vResult2.Y
    Tween کردن اطلاعات رنگ ‘
    D3DXColorLerp TweenVertices.ColorEx, Source.ColorEx, Dest.ColorEx, TweenAmount
    With TweenVertices.ColorEx
    TweenVertices.color = RGB(.B * 255, .G * 255, .R * 255)x
    End With
    End Function

    نکته اي که بايد به آن توجه کنيد اينست که در تابع فوق براي اشاره به vertex ، يک بردار ساخته شده است ( توسط تابع MakeVector ) .

    3 – روش سوم پر استفاده ترين روش انيميشن سازي است . اگر شما انيميشن هاي پيچيده با تعداد زيادي شي در آن داشته باشيد و اگر بخواهيد تغييرات اشيا را در هر فريم ذخيره کنيد ، به حجم بالايي از منابع ذخيره سازي نياز است . بجاي آن ما با استفاده از يکسري فريم کليدي ، فريمهاي مياني را پيش بيني مي کنيم .
    براي انجام درون يابي فريم کليدي ، بايستي مقدار vertex را در هر فريم کليدي بدانيم و نيز بدانيم هر فريم کليدي در چه زماني ظاهر مي شود . بنابراين بايد براي هر انيميشن چند فايل را بعنوان فريم کليدي ذخيره کنيم .
    در اين درس ما داده هاي کليدي انيميشن را از يکسري فايل load مي کنيم بنابراين تمام ثابتهاي زمان keyframe درون برنامه قرار داده مي شود ( شما مي توانيد خودتان يک ماژول بنويسيد که انيميشن هاي عمومي تر را نيز مديريت کند . اين ماژول بايد قادر باشد که يک فرمت استاندارد فايل را import کند ، اشيا و texture هاي مربوطه را load نمايد و سپس خودش ساخت انيميشن را بطور اتوماتيک انجام دهد و برنامه اصلي فقط روتين render و يا update را فراخواني کند ) . پس از جمع آوري اطلاعات فريم هاي کليدي ، بايد در هر زمان محاسبه کنيم که چه مدتي از شروع انيميشن گذشته است و بنابراين انيميشن در چه موقعيتي قرار دارد . سپس محاسبه مي کنيم که فريم کليدي قبلي و فريم کليدي بعدي چيست همچنين حساب مي کنيم در چه فاصله زماني از ايندو قرار داريم . سرانجام يک درون يابي نرمال را انجام مي دهيم تا اطلاعات فريم جاري بدست آيد و اين اطلاعات را درون يک شي Mesh مي گذاريم و آنرا رندر مي کنيم .
    در درسهاي قبلي در مورد 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(CreateKeyFrameFromF ile.nMaterials) As D3DMATERIAL8
    ReDim CreateKeyFrameFromFile.TexList(CreateKeyFrameFromF ile.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(CreateKeyFrameFr omFile.Mesh.GetNumVertices) As D3DVERTEX
    hResult = D3DXMeshVertexBuffer8GetData(CreateKeyFrameFromFil e.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 ها نگهداري کنيم .

  19. 3 کاربر از A_M_IT2005 بخاطر این مطلب مفید تشکر کرده اند


صفحه 1 از 6 12345 ... آخرآخر

Thread Information

Users Browsing this Thread

هم اکنون 1 کاربر در حال مشاهده این تاپیک میباشد. (0 کاربر عضو شده و 1 مهمان)

User Tag List

قوانين ايجاد تاپيک در انجمن

  • شما نمی توانید تاپیک ایحاد کنید
  • شما نمی توانید پاسخی ارسال کنید
  • شما نمی توانید فایل پیوست کنید
  • شما نمی توانید پاسخ خود را ویرایش کنید
  •