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

مباحث پیشرفته Direct3D - بخش دوم

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

  1. کاربر ارشد

    تاریخ عضویت:
    ‏6/9/12
    ارسال ها:
    14,318
    تشکر شده:
    2,702
    امتیاز دستاورد:
    0
    حرفه:
    daneshjo
    [​IMG]
    در این درس در مورد روشهای ساخت انیمیشن در 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 می گذاریم و آنرا رندر می کنیم .