close
دانلود فیلم
مباحث پیشرفته 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

استفاده از 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 کنید :

Deep Exploration 2.0
s/n: 0XE2A0000000000
Authorization s/n: REJ1HYXSR1A77Q10

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,D3DDevice,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_DEFAULT,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

مباحث تکمیلی نورپردازی در Direct3D
تئوری نورپردازی : نورپردازی در Direct3D تخمینی از چگونگی عملکرد نور در دنیای واقعی می باشد . چهار نوع اصلی نور در Direct3D قابل استفاده است ( همچنین شما می توانید خودتان انواع جدیدی از نور ایجاد کنید که موضوع ما نیست ) :

Point Light : توسط یک نقطه در فضای سه بعدی ایجاد می شود و دارای سه پارامتر رنگ ، دامنه و تضعیف می باشد . دامنه یک نور مسافتی است که نور می تواند طی کند . تضعیف ، مقدار کاهش نور در اثر افزایش مسافت می باشد . نور نقطه ای در تمام جهات تششع می کند - شبیه یک لامپ حبابی و یا یک شمع

Spot Light :  دارای یک موقعیت و یک جهت است و تنها نور را در یک جهت خاص می تاباند - شبیه یک چراغ قوه . این نور دارای یک زاویه مخروطی و یک دامنه است .

Directional Light :  دارای موقعیت نیست و برای پیاده سازی نورهایی که از فاصله بسیار دور می آیند - مثل خورشید - مناسب است .

Ambient Light :  این نور تضمین می کند که تمام vertex های یک صحنه تاریکتر از یک رنگ خاص نباشند .

 

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

بردار نرمال : هر 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 است :

3DDevice.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)

نورپردازی 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
Vertex/Mesh Animation



لینک کوتاه پست
مطالب مرتبط با پست جاری
  • نکات مهم
    1- لطفا نظر خود را با زبان فارسی بیان کنید
    2- رایتم نظرات اسپم و تبلیغی شما را تایید نمی کند
    3- لطفا نظرات شما بدون ابهام و واضح باشد
  • نام
    ایمیل (منتشر نمی‌شود) (لازم)
    وبسایت
    :):(;):D;)):X:?:P:*=((:O@};-:B/:):S
    نظر خصوصی
    مشخصات شما ذخیره شود ؟[حذف مشخصات] [شکلک ها]
    کد امنیتی
به کانال تلگرام سایت ما بپیوندید