DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

การปรับขนาดของวัตถุ 3 มิติ

ในการปรับขนาดของวัตถุ 3 มิตินั้นผมได้พูดเกริ่นนำไปแล้วในตอนต้นว่า จะต้องกำหนดค่าทั้งในแกน X, Y และ Z โดยค่านี้เป็นทศนิยมบวกแบบ float โดยค่าน้อยกว่า 1.0f   (0.0f – 1.0f) หมายถึงการลดขนาด ในทางกลับกันค่าที่มากกว่า 1.0f จะเป็นการขยายขนาดให้แก่รูปทรง 3 มิติ   ที่จริงแล้วการปรับขนาดนั้นมีหลักการง่ายๆ คือเป็นการคูณ ค่าพิกัดในแกนนั้นๆ ของจุด Vertex กับค่าที่ใช้ปรับขนาดในแกนเดียวกัน ซึ่งถ้าเขียนเป็น Code ในภาษา C จะได้ดังนี้

for (int i = 0; i

{

VertexBuffer[i].x = VertexBuffer[i].x * scalingX;

VertexBuffer[i].y = VertexBuffer[i].y * scalingY;

VertexBuffer[i].z = VertexBuffer[i].z * scalingZ;

}

เมื่อ  scalingX, scalingY, และ scalingZ เป็นค่ากำหนดขนาดซึ่งเรากำหนดขึ้นและ VertexBuffer เป็นพอย์เตอร์ที่ชี้ไปยังหน่วยความจำที่เก็บข้อมูลของจุด Vertex เอาไว้  สำหรับฟังก์ชันที่ใช้ในการปรับขนาดของวัตถุ 3 มิติใน DirectX คือ

D3DXMATRIX * D3DXMatrixScaling(
     D3DXMATRIX * pOut,
     FLOAT sx,
     FLOAT sy,
     FLOAT sz
);

    pOut   คือพอย์เตอร์ที่ชี้ไปยังตัวแปรโครงสร้างข้อมูล D3DXMATRIX เป็นผลลัพธ์ที่ฟังก์ชันนี้จะคืนค่ากลับมา

    sx , sy และ sz  คือค่าที่กำหนดขนาดของวัตถุ 3 มิติทั้งในแนวแกน X ,Y และ Z

การเคลื่อนย้ายตำแหน่งของวัตถุ 3 มิติ

ในการเคลื่อนย้ายตำแหน่งของวัตถุ 3 มิตินั้น จะต้องกำหนดตำแหน่งใหม่ให้แก่วัตถุทั้งแกน X, Y และ Z ใน World Space โดยปรกติแล้วหากเราไม่ได้กำหนดตำแหน่งให้แก่วัตถุ 3 มิติ DirectX จะให้วัตถุนั้นอยู่ในตำแหน่งจุดกำเนิด (origin) ซึ่งมีค่าพิกัดในแกนทั้ง 3 แกนเป็น 0.0f (จุดกำเนิดคือจุดที่มีค่าแกนทั้ง 3 แกนเป็น 0.0 ซึ่งก็คือจุดกึ่งกลางของ World Space นั้นเอง)    ที่จริงแล้วการเคลื่อนย้ายตำแหน่งนั้นมีหลักการง่ายๆ ก็คือเป็นการบวกค่าพิกัดในแกนนั้นๆ ของจุด Vertex กับค่าตำแหน่งใหม่ในแกนเดียวกันซึ่งถ้าเขียนเป็น Code ในภาษา C จะได้ดังนี้

for (int i = 0; i

{

VertexBuffer[i].x = VertexBuffer[i].x + NewPosition.x;

VertexBuffer[i].y = VertexBuffer[i].y + NewPosition.y;

VertexBuffer[i].z = VertexBuffer[i].z + NewPosition.z;

}

เมื่อ NewPosition เป็นค่าพิกัดของตำแหน่งใหม่ของวัตถุ 3 มิติใน World Space และ VertexBuffe เป็นพอย์เตอร์ที่ชี้ไปยังหน่วยความจำที่เก็บข้อมูลของจุด Vertex เอาไว้ สำหรับฟังก์ชันที่ใช้ในการเคลื่อนย้ายตำแหน่งของวัตถุ 3 มิติใน DirectX คือ

D3DXMATRIX * D3DXMATRIXTranslation(
     D3DXMATRIX * pOut,
     FLOAT x,
     FLOAT y,
     FLOAT z
);

pOut   คือพอย์เตอร์ที่ชี้ไปยังตัวแปรโครงสร้างข้อมูล D3DXMATRIX ซึ่งผลลัพธ์ที่ฟังก์ชันที่จะคืนค่ากลับมา

x, y และ z   คือตำแหน่งใหม่ของวัตถุ 3 มิติใน World Space

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

การเปลี่ยนแปลง (Transformation) วัตถุ 3 มิติโดยใช้ Matrix

รูปแบบของการเปลี่ยนแปลงในโลก 3 มิติ

ในโลก 3 มิตินั้นสามารถแบ่งการเปลี่ยนแปลงของวัตถุ 3 มิติออกเป็น 3 แบบหลักๆ คือ

  • การเคลื่อนย้ายตำแหน่ง (Translation) เป็นการเปลี่ยนแปลงตำแหน่งของวัตถุ 3 มิติเมื่อเทียบกับจุดกำเนิด (Origin) ใน world space
  • การหมุน (Rotation) เป็นการหมุนวัตถุ 3 มิติรอบแกนสมมติทั้ง 3 แกน คือการหมุนรอบแกน X (เป็นการหมุนในแนวนอน หน้าไปหลังหรือหลังไปหน้า) การหมุนรอบแกน Y (เป็นการหมุนในแนวตั้ง ซ้ายไปขวาหรืขวาไปซ้าย) และการหมุนรอบแกน Z (เป็นการหมุนในแนวนอนเช่นกันแต่หมุนจาก ซ้ายไปขวาหรือขวาไปซ้าย)
  • การปรับขนาด (Scaling) เป็นการปรับขนาดให้แก่วัตถุ3 มิติทั้งในแนวแกน X, Y และ Z โดยค่าน้อยกว่า 1.0f หมายถึงการลดขนาด ในทางกลับกันค่าที่มากกว่า 1.0f ก็จะหมายถึงเป็นการขยายขนาดให้แก่วัตถุ 3 มิติ

รู้จัก Matrix

Matrix เป็นศาสตร์ทางคณิตศาสตร์อย่างหนึ่ง สามารถค้นคว้าหาข้อมูลได้จากตำราทางคณิตศาสตร์ทั่วไป Matrix เป็นกลุ่มของตัวเลขที่เรียงต่อกันเป็นแถวๆ หลายๆ แถวคล้ายๆ ตัวเลขที่อยู่ภายในตารางซึ่งมีทั้งด้าน คอลัมน์และด้านแถว ใน DirectX จะใช้ Matrix ขนาด 4X4 นั้นหมายความว่าเป็น Matrix ที่มีขนาดคอลัมน์ 4 คอลัมน์ แถวจำนวน 4 แถว สำหรับการเปลี่ยนแปลงของวัตถุ 3 มิตินั้นส่วนใหญ่จะกระทำผ่านทาง Matrix โดยจะทำการเก็บค่าจากการคำนวณไว้ในรูปของ Matrix    สำหรับการประกาศตัวแปรโครงสร้าง Matrix ของ DirectX มีดังนี้

struct{
FLOAT _11, FLOAT _12, FLOAT _13, FLOAT _14,
FLOAT _21, FLOAT _22, FLOAT _23, FLOAT _24,
FLOAT _31, FLOAT _32, FLOAT _33, FLOAT _34,
FLOAT _41, FLOAT _42, FLOAT _43, FLOAT _44);

}โดยค่าการหมุนจะเก็บอยู่ในตำแหน่ง _11, _12, _13, _21, _22, _23, _31, _32 และ _33    ค่าการเปลี่ยนแปลงตำแหน่งจะอยู่ในส่วนของ _41, _42 และ _43 ส่วนค่าที่อยู่ในตำแหน่ง _14 _24 _34 และ _44 จะกำหนดเป็น 0.0f, 0.0f, 0.0f, 1.0f ตามลำดับ

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

การวาด Primitive

ส่วนที่สำคัญแล้วคือการวาด Primitive หรือการ Render วัตถุ 3 มิตินั้นเอง หากยังจำบทความที่แล้วได้ (เริ่มต้นกับ DirectX ตอนที่ 2) ซึ่งได้กล่าวไปแล้วคร่าวๆ ว่า การ Render ภาพจะต้องทำหลังจากเรียกเมธอด BeginScene() และเมื่อทำการ Render ทุกอย่างจนเสร็จเรียบร้อยแล้วจึงเรียกเมธอด EndScene() ในการวาด Primitive นั้นเราจะใช้เมธอด

HRESULT DrawPrimitive(
D3DPRIMITIVETYPE PrimitiveType,
UINT StartVertex,
UINT PrimitiveCount
);

PrimitiveType รูปแบบในการวาด Primitive มีค่าให้เลือกคือ

D3DPT_POINTLIST เป็นการวาด Primitive แบบ Point List

D3DPT_LINELIST เป็นการวาด Primitive แบบ Line List

D3DPT_LINESTRIP เป็นการวาด Primitive แบบ Line Strip

D3DPT_TRIANGLELIST เป็นการวาด Primitive แบบ Triangle List

D3DPT_TRIANGLESTRIP เป็นการวาด Primitive แบบ Triangle Strip

D3DPT_TRIANGLEFAN เป็นการวาด Primitive แบบ Triangle Fan

StartVertex ตำแหน่งเริ่มต้นของ Vertex ใน Vertex Buffer ที่จะให้เริ่มต้นวาด

PrimitiveCount จำนวน Primitive ที่จะวาด

HRESULT DrawIndexedPrimitive(
D3DPRIMITIVETYPE Type,
INT BaseVertexIndex,
UINT MinIndex,
UINT NumVertices,
UINT StartIndex,
UINT PrimitiveCount
);

Type เหมือนกับ PrimitiveType ของฟังก์ชัน DrawPrimitive

BaseVertexIndex กำหนดให้เป็น 0

MinIndex กำหนดให้เป็น 0

NumVertices จำนวน Vertex ที่มีอยู่ทั้งหมด

StartIndex ตำแหน่ง Index ใน Index Buffer ที่จะให้เริ่มต้นวาด

PrimitiveCount จำนวน Primitive ที่จะวาดในครั้งนี้

แต่ก่อนที่จะเรียกใช้เมธอด DrawPrimitive หรือ DrawIndexedPrimitive ได้ จะต้องกำหนดรูปแบบของ Flexible Vertex Format และ Stream Source ที่เราใช้ให้ DirectX ทราบก่อน นอกจากนี้หากสร้างและใช้งาน Index และ Index Buffer จะต้องกำหนดใช้ Index Buffer ด้วย

HRESULT SetStreamSource(
UINT StreamNumber,
LPDIRECT3DVERTEXBUFFER9 pStreamData,
UINT OffsetInBytes,
UINT Stride
);

StreamNumber กำหนดให้เป็น 0
pStreamData LPDIRECT3DVERTEXBUFFER9 Interface ที่เราสร้างขึ้นและต้องการที่จะนำมาใช้วาด Primitive

OffsetInBytes กำหนดให้เป็น 0
Stride ขนาดของ Vertex เป็นจำนวนไบท์ อาจใช้ sizeof(Vertex)

HRESULT SetFVF(
DWORD FVF
);
FVF คือค่าคงที่ Flexible Vertex Format (FVF)
HRESULT SetIndices(
LPDIRECT3DINDEXBUFFER9 pIndexData
);

pIndexData คือ LPDIRECT3DINDEXBUFFER9 Interface ที่เราสร้างขึ้นมาและต้องการที่จะนำมาใช้วาด Primitive

lp3dDevice->Clear(0,NULL,D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER,

D3DCOLOR_COLORVALUE(0.5f,0.5f,0.5f,1.0f),1.0f,0 );

lp3dDevice->BeginScene();

//Disable light calculation

lp3dDevice->SetRenderState(D3DRS_LIGHTING,FALSE);

//Render Primitive

lp3dDevice->SetStreamSource(0,lpd3dVb,0,sizeof(SampleVector));

lp3dDevice->SetFVF(FVF_SAMPLE);

lp3dDevice->SetIndices(lpd3dIb);

lp3dDevice->DrawIndexedPrimitive(D3DPT_TRIANGLELIST,0,0,CountOfVertex,0,2);

//return to default value

lp3dDevice->SetRenderState(D3DRS_LIGHTING,TRUE);

lp3dDevice->EndScene();

lp3dDevice->Present(NULL,NULL,NULL,NULL);

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

การกำหนด View Space และ Projection Space

View Space เป็นมุมมองของรูปทรง 3 มิติที่เรากำลังมองอยู่ หรือเรียกอีกอย่างก็คือมุมมองของกล้องนั้นเอง มุมมองเหล่านี้อาจแตกต่างจากตำแหน่งหรือจุดที่เราทำการวางรูปทรง 3 มิติไว้ (จุดที่เราทำการวางรูปทรง 3 มิติไว้ เรียกว่า World Space) ซึ่งมุมมองของ View Space นั้นขึ้นอยู่กับการจัดวางตำแหน่งของกล้อง การกำหนด View Space นั้นทำได้โดยใช้ฟังก์ชันจาก D3DX Library

D3DXMATRIX * D3DXMATRIXLookAtLH(
     D3DXMATRIX * pOut,
     CONST D3DXVECTOR3 * pEye,
     CONST D3DXVECTOR3 * pAt,
     CONST D3DXVECTOR3 * pUp
);

pOut   เป็นพอย์เตอร์ชี้ไปยังโครงสร้างข้อมูล D3DXMATRIX ซึ่งจะคืนค่าข้อมูล View Space มาให้ในรูปแบบ Matrix

pEye   เป็นพอยเตอร์ชี้ไปยังโครงสร้างข้อมูล D3DXVECTOR3 ซึ่งเก็บตำแหน่งพิกัดในโลก 3 มิติ (World Space) ของกล้องหรือดวงตาไว้

pAt    เป็นพอยเตอร์ที่ชี้ไปยังโครงสร้างข้อมูล D3DXVECTOR3 ซึ่งเก็บตำแหน่งจุดที่เรากำลังมองอยู่ หรือจุดโฟกัส

pUp   เป็นพอย์เตอร์ที่ชี้ไปยังโครงสร้างข้อมูล D3DXVECTOR3 ซึ่งส่วนใหญ่กำหนดเป็น [0.0f, 1.0f, 0.0f ] หมายความว่าต้องการให้กล้องขึ้นลงในแกน Y

หากฟังก์ชันนี้ทำงานสำเร็จก็จะคืนค่าพอยเตอร์ค่าเดียวกับ pOut มาให้   และเมื่อได้  View Matrix (View Space ที่อยู่ในรูปแบบ Matrix) มาแล้ว เราจะทำการเรียกเมธอด SetTranform เพื่อนำ View Matrix ที่เรากำหนดขึ้นส่งไปให้ DirectX ซึ่งจะนำไปประมวลผลต่อไปดังตัวอย่าง

D3DXMATRIX  MatView;

D3DXECTOR3   Eye = D3DXECTOR3(0.0f,0.0f,-3.0f);

D3DXECTOR3 At = D3DXECTOR3(0.0f,0.0f,-1.0f);

D3DXECTOR3 Up = D3DXECTOR3(0.0f,1.0f,0.0f);

D3DXMATRIXLookAtLH(&MatView,&Eye,&At,&Up);

lpd3dDevice->SetTranform(D3DTS_VIEW,&MatView);

ส่วน Projection Space นั้นเป็นมุมมองของรูปทรง 3 มิติที่ถูกแสดงบนหน้าจอคอมพิวเตอร์ที่เป็นแบบ 2 มิติ มุมมองเหล่านี้ต่อเนื่องมาจาก View Space เป็นมุมมองแบบ Perspective การสร้าง Projection Space นั้นทำได้โดยใช้ฟังก์ชันจาก D3DX Library อีกเช่นกัน

D3DXMATRIX * D3DXMatrixPerspectiveFovLH(
     D3DXMATRIX * pOut,
     FLOAT fovy,
     FLOAT Aspect,
     FLOAT zn,
     FLOAT zf
);

pOut   เป็นพอย์เตอร์ชี้ไปยังโครงสร้างข้อมูล D3DXMATRIX ซึ่งจะคืนค่าข้อมูล Projection Space มาให้ในรูปแบบ Matrix

fovy   เป็นค่า Field of view  (FOV) ครับมีค่าเป็น Radians ค่านี้ส่วนใหญ่จะกำหนดให้เท่ากับ 45 องศา  ยิ่งมีองศามากขึ้นภาพก็จะยิ่งบีบเข้ามาจนน่าเวียนหัวครับ   ส่วนการเปลี่ยนจากองศาเป็น Radians นั้นคุณอาจใช้สูตร  องศา* ค่าพาย (Pi) / 180 หรืออาจใช้ฟังก์ชันจาก D3DX Library     D3DXToRadian() โดยเมื่อคุณแทนค่าองศาเข้าไปมันจะคืนค่า Radians ออกมาครับAspect   เป็นค่าอัตราส่วนของจอภาพหาได้โดยการนำ ขนาดความกว้างของจอภาพหารด้วยความสูงของจอภาพ หากคุณเลือกการแสดงผลแบบ Fullscreen Mode (โหมดเต็มจอ) ความกว้างและความสูงของจอภาพก็คือความกว้างและความสูงของ Back Buffer นั้นเอง หรือหากเลือกการแสดงผลแบบ Windowed Mode ความกว้างและความสูงของจอภาพก็คือขนาดของ Windows นั้นเอง

zn    เป็นค่าของแกน Z ที่ใกล้ที่สุด

zf    เป็นค่าของแกน Z ที่ไกลที่สุด

จากนั้นเมื่อได้ Projection Matrix (Projection Space ที่อยู่ในรูปแบบ Matrix) มาแล้ว เราจะทำการเรียกเมธอด SetTranform อีกเหมือนกับ View Matrix

D3DXMATRIX  MatProjection;

D3DXMatrixPerspectiveFovLH(&MatProjection, D3DXToRadian(45.0f),800.0f/600.0f,1.0f,5000.0f);

lpd3dDevice ->SetTranform(D3DTS_PROJECTION,&MatProjection);

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

จะเห็นได้ว่า DirectX มีรูปแบบการวาด Primitive ให้เลือกหลายแบบ เพื่อให้เราเลือกใช้อย่างเหมาะสมและลดการประมวลผลจุด Vertex ลงไปให้มากที่สุด แต่สิ่งที่ตามมาก็คือเราจะเลือกใช้วิธีใดในการวาด Primitiveในการวาด Primitive สิ่งแรกที่คุณต้องคำนึงถึงก็คือลักษณะของรูปทรง 3 มิติที่คุณต้องการจะวาด ซึ่งจะเป็นตัวกำหนดรูปแบบของการวาด Primitive ของคุณ  เช่น ถ้าคุณต้องการจะวาดจุดบนหน้าจอ คุณก็เลือกใช้แบบ Point List ได้เลย (เพราะมีวิธีให้เลือกเพียงวิธีเดียว) แต่ถ้าหากคุณต้องการจะวาดเส้นตรงและเส้นตรงแต่ละเส้นไม่มีความต่อเนื่องกันเลยคุณก็อาจใช้ Line List หรือหากเส้นตรงนั้นมีความต่อเนื่องกันคุณก็อาจใช้  Line Strip  ก็ได้   ส่วนในการวาดสามเหลี่ยมนั้นหากคุณต้องการวาดสามเหลี่ยมทั้งหมดทีเดียวและ  Vertex ของรูปทรง 3 มิติที่จะวาดมีไม่มากนักคุณก็อาจเลือกใช้ Triangle List ไปเลยเพื่อตัดความยุ่งยากในการกำหนดการวาดสามเหลี่ยม หากรูปทรง 3 มิติที่จะวาดมีความซับซ้อนและมีความต่อเนื่องกันก็อาจเลือกใช้ Triangle Strip และ Triangle Fan ได้ (Triangle Strip และ Triangle Fan ก็สามารถวาดสามเหลี่ยมที่ไม่ต่อเนื่องกันเหมือน Triangle List ได้เช่นกันครับโดยการกำหนดจุด Vertex ของสามเหลี่ยมเป็นกลุ่มๆ และทำการวาดสามเหลี่ยมทีละชุดๆ แทนที่จะวาดหมดในทีเดียว)

นอกจากนี้หากต้องการลดเวลาในการประมวลผลลงไปก็อาจใช้ Index เข้ามาช่วยในการวาด Primitive แต่จุดสำคัญก็คือจุด Vertex เหล่านั้นจะต้องมีความซ้ำซ้อนกันบ้างพอสมควร เพราะถ้าหากจุด Vertex ไม่มีความซ้ำซ้อนกันเลย การใช้ Index เข้ามาช่วยในการวาด Primitiveก็จะเป็นการเพิ่มภาระในการประมวลผลแทน

ต่อไปนี้จะเป็นตัวอย่างในการกำหนดจุด Vertex ให้แก่รูปทรง 3 มิติ (ในที่นี้ผมเลือกใช้รูปสี่เหลี่ยม ซึ่งต้องใช้รูปสามเหลี่ยม 2 รูป) โดยการเรียงลำดับจุด Vertex ให้แก่สามเหลี่ยมเป็นไปในลักษณะที่ตามเข็มนาฬิกา คือจากบนขวามาล่างขวาและจากล่างขวามายังล่างซ้าย หรือจากล่างขวามายังล่างซ้ายไปยังบนซ้าย หรือจากล่างซ้ายไปยังบนซ้ายและต่อไปยังล่างขวา

#define CUSTOM_FVF D3DFVF_XYZ|D3DFVF_DIFFUSE

struct Vertex

{

float x,y,z;

DWORD col

};

Vertex g_pVertex[] = {//การเรียงจุด Vertex แบบ Triangle List

{-1.0f,1.0f,0.0f, 0xffff0000, }, // x, y, z, color

{1.0f,-1.0f,0.0f, 0xffff0000, },

{-1.0f,-1.0f,0.0f, 0xffff0000, },

{-1.0f,1.0f,0.0f, 0xffff0000, },

{1.0f,1.0f,0.0f, 0xffff0000, },

{1.0f,-1.0f,0.0f, 0xffff0000, }

};

Vertex g_pVertex[] = {//การเรียงจุด Vertex แบบ Triangle Strip

{-1.0f,-1.0f,0.0f, 0xffff0000, }, // x, y, z, color

{-1.0f,1.0f,0.0f, 0xffff0000, },

{1.0f,-1.0f,0.0f, 0xffff0000, },

{1.0f,1.0f,0.0f, 0xffff0000, }

};

Vertex g_pVertex[] = {//การเรียงจุด Vertex แบบ Triangle Fan

{1.0f,-1.0f,0.0f, 0xffff0000, }, // x, y, z, color

{-1.0f,-1.0f,0.0f, 0xffff0000, },

{-1.0f,1.0f,0.0f, 0xffff0000, },

{1.0f,1.0f,0.0f, 0xffff0000, }

};

จากตัวอย่างทั้งหมดนี้เป็นการเรียงจุด Vertex แบบตามเข็มนาฬิกา และจะสังเกตเห็นว่าการจัดเรียง Vertex เพื่อใช้ในการวาดรูปสี่เหลี่ยมโดยใช้วิธีการวาด Primitive แบบ Triangle List นั้นใช้จำนวน Vertex ถึง 6 จุดแต่แบบ Triangle Strip และ Triangle Fan นั้นใช้จุด Vertex แค่ 4จุด        ก็เพียงพอซึ่งทำให้ลดการประมวลผลลงไปได้ และถ้าหากสังเกตจุด Vertex ของ Triangle List ดีๆ จะเห็นว่ามีค่าซ้ำกันอยู่หากเรานำ Index มาใช้ก็จะทำให้การประมวลผลลดลงไปได้ดังตัวอย่างการนำ Index มาใช้กับการจัดเรียงจุด Vertex แบบ Triangle List

Vertex g_pVertex[] = {//การเรียงจุด Vertex แบบ Triangle List ที่ใช้ Index

{-1.0f,1.0f,0.0f, 0xffff0000, }, // x, y, z, color

{1.0f,-1.0f,0.0f, 0xffff0000, },

{-1.0f,-1.0f,0.0f, 0xffff0000, },

{1.0f,1.0f,0.0f, 0xffff0000, }

};

UINT g_pIndex[]  ={

0,1,2,

0,3,1

};

ส่วนการนำจุด Vertex ที่เราได้ทำการจัดเรียงไว้เรียบร้อยแล้วเขียนลงไปใน Vertex Buffer นั้นทำได้โดยเรียกเมธอดของ LPDIRECT3DVERTEXBUFFER9 Interface โดยทุกครั้งที่มีการเขียนจุด Vertex ลงไปใน Vertex Buffer จะต้องทำการล็อค Buffer ก่อนจากนั้นจึงถ่ายหรือเขียนข้อมูล (จุด Vertex) ลงไปใน Buffer เมื่อเสร็จสิ้นแล้วจึงปลดล็อค Buffer อีกที ซึ่งการเขียน Index ลงไปใน Index Buffer ก็จะใช้หลักการนี้เช่นเดียวกัน

HRESULT Lock(
     UINT OffsetToLock,
     UINT SizeToLock,
     VOID ** ppbData,
     DWORD Flags
);

OffsetToLock   กำหนดเป็น 0 ได้เลย

SizeToLock   กำหนดเป็น 0 ได้เลยเช่นกัน

ppbData   คือพอยเตอร์ที่จะชี้ไปยังตำแหน่งของ Buffer ที่จะเป็นตัวแทนของ Vertex Buffer หรือ Index Buffer ซึ่งเมธอดจะคืนมาให้

Flags    เป็นรูปแบบของการล็อคข้อมูลมีค่าให้เลือกดังนี้

D3DLOCK_DISCARD

D3DLOCK_NO_DIRTY_UPDATE

D3DLOCK_NOSYSLOCK

D3DLOCK_READONLY

D3DLOCK_NOOVERWRITE

แต่ที่ใช้กันหลักๆ ก็คือ 0 D3DLOCK_READONLY และ D3DLOCK_DISCARD และD3DLOCK_NOSYSLOCK หากเมธอดนี้ทำงานสำเร็จก็จะคืนค่า D3D_OK กลับมา และในการเขียนข้อมูล (จุด Vertex และ Index) นั้นทำได้โดยถ่ายข้อมูลลงไปใน ppbData ได้เลยครับ และเมื่อทำการถ่ายข้อมูลลง Buffer เรียบร้อยแล้วจะต้องทำการปลดล็อค Vertex Buffer หรือ Index Buffer ด้วยเมธอด

HRESULT Unlock();

//Vertex Buffer

VOID *ptr = NULL;

lpd3dVb-> Lock(0,0,(void**)&ptr, 0);

memcpy(ptr,g_pVertex,CountOfVertices*sizeof(Vertex));

lpd3dVb->Unlock();

//Index Buffer

VOID *ptr = NULL;

lpd3dIb-> Lock(0,0,(void**)&ptr, 0);

memcpy(ptr,g_pIndex,CountOfIndex*sizeof(unsigned int ));

lpd3dIb->Unlock();

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

การกำหนดรูปแบบของ Polygon และ การเขียนข้อมูลลง Vertex Buffer และ Index Buffer

Polygon ใน DirectX มีอยู่ทั้งหมด 3 ประเภทด้วยกันคือ จุด เส้น และ สามเหลี่ยม ซึ่งทั้งสามประเภทนี้DirectXจะเรียกรวมๆ กันว่าPrimitiveการกำหนดจุด Vertex ให้แก่ Primitive แต่ละชนิดนั้นก็ขึ้นอยู่กับว่าคุณจะใช้วิธีใดในการวาดมัน หากคุณกำหนดจุด Vertex และวิธีการวาดผิด ผลที่ได้จะทำให้ DirectX วาด Primitive เหล่านั้นออกมาผิดพลาดเช่นกัน   สำหรับวิธีการวาด Primitive ของ DirectX นั้นก็จะมีลักษณะคล้ายๆ กับของ OpenGL คือ

Point List   เป็นการวาดจุดโดย ใช้Vertex 1 จุดเท่ากับจุด 1 จุด เรียงต่อกันไปเรื่อยๆ ดังนั้นหากคุณกำหนดจุด Vertex ให้แก่ Vertex Buffer 10 จุดก็จะสามารถวาดจุดได้ทั้งหมด 10 จุด ซึ่งวิธีนี้ไม่สามารถใช้กับการวาด Primitive แบบใช้ Index Buffer ได้

Line List   เป็นการวาดเส้นโดยใช้จุด Vertex 2 จุดต่อเส้น 1 เส้น ดังนั้นหากคุณกำหนดจุด Vertex ให้แก่ Vertex Buffer 10 จุดก็จะสามารถวาดเส้นได้ทั้งหมด 5 เส้น

Line Strip   เป็นการวาดเส้นโดยใช้จุด Vertex ที่สองของเส้นที่เพิ่งวาดไปนำมาเป็นจุดแรกของเส้นที่จะวาดต่อ ผลที่ได้ก็จะเป็นเส้นที่ต่อกันไปเรื่อยๆ

Triangle List   เป็นการวาดสามเหลี่ยมโดยใช้จุด Vertex 3 จุดต่อสามเหลี่ยม 1 รูป

Triangle Strip   เป็นการวาดสามเหลี่ยมโดยใช้จุด Vertex จุดที่ 2 และ 3 ของสามเหลี่ยมที่เพิ่งวาดไป นำมาเป็นจุดที่ 1 และ 2 ของสามเหลี่ยมที่จะวาด

Triangle Fan   เป็นการวาดสามเหลี่ยมโดยใช้จุด Vertex จุดแรกสุดเป็น Vertex ที่ 1 ของทุกๆ สามเหลี่ยมและ Vertex จุดที่ 3 ของสามเหลี่ยมที่เพิ่งวาดไปก็จะเป็น Vertex จุดที่ 2 ของสามเหลี่ยมที่จะวาดต่อ ลักษณะที่ได้จะคล้ายกับพัดจีน (จึงเรียกว่า Fan)

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

ตัวอย่าง

HRESULT hrl

hrl = lpd3dDevice ->CreateVertexBuffer(CountOfVertices ,sizeof(Vertex),0, CUSTOM_FVF,

D3DPOOL_DEFAULT,&lpd3dVb,NULL );

if(hrl != D3D_OK )return false;

//เมื่อ lpd3dDevice  คือ LPDIRECT3DDEVICE9 Interface

ส่วนในการใช้งาน Index Buffer นั้นก็จะคล้ายๆ กับ Vertex Buffer ครับโดยสิ่งแรกที่จะต้องทำคือการประกาศ Interface ของมัน   หลังจากนั้นจึงจะทำการสร้าง Interface ของ Index Buffer โดยใช้เมธอดของ LPDIRECT3DDEVICE9 เช่นกัน

LPDIRECT3DINDEXBUFFER9 lpd3dIb = NULL;

HRESULT CreateIndexBuffer(
      UINT Length,
     DWORD Usage,
     D3DFORMAT Format,
     D3DPOOL Pool,
    LPDIRECT3DINDEXBUFFER9* ppIndexBuffer,
     HANDLE* pSharedHandle
);

Length   คือ ขนาดของ Index Buffer เป็นจำนวนไบท์อาจใช้ จำนวน Index ทั้งหมดคูณด้วยขนาดของ Index เช่น

CountOfIndex * sizeof(unsigned int)  // ถ้า Index มีขนาด 32 บิท

CountOfIndex * sizeof(unsigned short)  // ถ้า Index มีขนาด 16 บิท

Usage   กำหนดให้เป็น 0 ได้เลย

Format   คือค่าคงที่ที่ใช้กำหนดขนาดของ Index Buffer ซึ่งมี 2 แบบคือ

D3DFMT_INDEX16 Index แต่ละ Index มีขนาด 16 บิท

D3DFMT_INDEX32 Index แต่ละ Index มีขนาด 32 บิท

Pool    สามารถกำหนดเป็น D3DPOOL_DEFAULT ได้เลย

ppIndexBuffer   คือพอยเตอร์ที่ชี้ไปยัง interface ของ LPDIRECT3DINDEXBUFFER9

pSharedHandle    กำหนดให้เป็น  NULL ได้เลย

หากเมธอดนี้ทำงานสำเร็จก็จะคืนค่า D3D_OK กลับมาและเราก็จะสามารถใช้คำสั่งที่อยู่ภายใน LPDIRECT3DINDEXBUFFER9 ต่อไปได้

ตัวอย่าง

hrl = lpd3dDevice ->CreateIndexBuffer(CountOfIndex *sizeof(UINT),0,D3DFMT_INDEX32,

D3DPOOL_DEFAULT,&lpd3dIb,NULL );

if(hrl != D3D_OK )return false;

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

Vertex Buffer และ Index Buffer ใน DirectX

ในการสร้างวัตถุ 3 มิติไม่ว่าจะเป็น DirectX หรือ OpenGL ก็ตามสิ่งแรกที่คุณจะต้องทำก็คือจะต้องกำหนดพิกัดจุด Vertex ให้กับวัตถุ 3 มิตินั้นๆ ก่อนจากนั้นจึงค่อยนำพิกัดจุด Vertex ไปประมวลผลต่างๆ ต่อไป สำหรับ DirectX คุณจะต้องสร้าง Vertex Buffer หรือ Index Buffer (หากจำเป็นต้องใช้) เพื่อทำหน้าที่ในการเก็บจุด Vertex ของวัตถุ 3 มิตินั้นๆไว้เพื่อรอการประมวลผลต่อไป ในการสร้าง Vertex Buffer นั้นสิ่งแรกคุณต้องประกาศ Interface ของมันก่อนครับ LPDIRECT3DVERTEXBUFFER9 lpd3dVb = NULL; หลังจากนั้นจึงจะทำการสร้าง Interface ของ Vertex Buffer โดยใช้เมธอดของ LPDIRECT3DDEVICE9 Interface (ซึ่งได้กล่าวไปแล้วในบทก่อน เรื่อง เริ่มต้นกับ DirectX ตอนที่ 2) HRESULT CreateVertexBuffer( UINT Length, DWORD Usage, DWORD FVF, D3DPOOL Pool, LPDIRECT3DVERTEXBUFFER9 * ppVertexBuffer, HANDLE* pSharedHandle ); Length คือ ขนาดของ Vertex Buffer เป็นจำนวนไบท์อาจใช้ จำนวน Vertex ทั้งหมดคูณด้วยขนาดของโครงสร้างข้อมูลของ Vertex เช่น CountOfVertices * sizeof(Vertex) Usage กำหนดให้เป็น 0 ได้เลย FVF คือค่าคงที่ Flexible Vertex Format ที่เรากำหนดไว้ในตอนต้น Pool สามารถกำหนดเป็น D3DPOOL_DEFAULT ได้เลย ppVertexBuffer คือพอยเตอร์ชี้ไปยัง interface ของ LPDIRECT3DVERTEXBUFFER9 ที่ประกาศไว้ในตอนต้น pSharedHandle กำหนดให้เป็น NULL ได้เลย หากเมธอดนี้ทำงานสำเร็จก็จะคืนค่า D3D_OK กลับมา หลังจากสร้าง Interface ของ Vertex Buffer แล้วเราก็จะสามารถใช้คำสั่งที่อยู่ภายใน LPDIRECT3DVERTEXBUFFER9 ต่อไปได้

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

รู้จัก Vertex Buffer และ Index Buffer

จากที่ได้กล่าวไปแล้วว่าวัตถุหนึ่งๆ ในโลก 3 มิติประกอบขึ้นมาจาก Polygon จำนวนตั้งแต่ 2 Polygon ขึ้นไปแต่ละ Polygon ก็จะมีจุด Vertex ตั้งแต่ 3 จุดขึ้นไป ลองนึกถึงกล่องสี่เหลี่ยมลูกบาศก์ดูซิครับว่าจะต้องมีจุด Vertex เท่าไหร่   หากวัตถุที่สร้างขึ้นมีความซับซ้อนกว่าลูกบาศก์อย่างมากอาจมีจุด Vertex ถึง 1000 จุดขึ้นไป   หาก DirectX ต้องทำการประมวลผลจุด Vertex เหล่านี้แล้วจึงจำเป็นที่จะต้องมีแหล่งที่เก็บข้อมูลของจุด Vertex หลายๆ จุดไว้ในที่เดียวกันเพื่อสะดวกต่อการคำนวณ (และเพิ่มความเร็วในการประมวลผล) เราเรียกแหล่งที่เก็บข้อมูลของจุด Vertex ว่า Vertex Buffer

ลองคิดถึงกล่องสี่เหลี่ยมลูกบาศก์เหมือนเดิมนะครับ แล้วคะเนจำนวนสามเหลี่ยมที่มีอยู่จะพบว่า มีสามเหลี่ยมทั้งหมด 12 รูป (กล่องลูกบาศก์มี 6 ด้าน มีสามเหลี่ยมด้านละ 2 รูป) ซึ่งจะมีจุด Vertex ถึง 36 จุด (สามเหลี่ยม 1 รูปมีจุด Vertex 3 จุด) แต่ถ้าเราสังเกตรูปลูกบาศก์ให้ดีจะพบว่าสามเหลี่ยมทุกรูปใช้จุด Vertex ร่วมกัน (มีค่าพิกัดของจุด Vertex ซ้ำกัน) แสดงว่าหากประมวลผลจุด Vertex เหล่านี้จะต้องประมวลผลซ้ำกันซึ่งเป็นสิ่งที่ไม่จำเป็นเลย    DirectX แก้ปัญหานี้โดยการสร้างรูปสามเหลี่ยมโดยใช้ Index ซึ่งเป็นค่าบอกตำแหน่งของจุด vertex ที่เก็บอยู่ที่ Vertex Buffer ในการอ้างถึงจุด Vertex ที่ประกอบเป็นรูปสามเหลี่ยมนั้นๆ แทนที่จะใช้จุดพิกัด Vertex โดยตรง ทำให้จำนวน Vertex ใน Vertex Buffer มีอยู่เฉพาะที่มีค่าไม่ซ้ำกันเท่านั้น ส่วนสามเหลี่ยมที่มีจุด Vertex ซ้ำกันนั้นสามเหลี่ยมแต่ละรูปก็เพียงแต่อ้างไปถึงตำแหน่งของจุด Vertex ใน Vertex Buffer ที่ตำแหน่งเดียวกันเท่านั้นเอง (มีค่า Index เท่ากัน) วิธีนี่จะเป็นการลดเวลาในการประมวลผลจุด Vertex ลง เราเรียกแหล่งที่เก็บข้อมูลของ Index หลายๆ ตัวรวมกันว่า Index Buffer   ในบางครั้งหากจุด Vertex ที่ใช้ค่อนข้างที่จะมีค่าพิกัดที่ซ้ำกันน้อยมากการใช้ Index ก็ไม่ค่อยจำเป็นมากนัก   แต่หากกรณีที่มีจุด Vertex ที่ซ้ำกันมากๆ  การใช้ Index ก็เป็นทางออกที่ดีในการลดการประมวลผลที่ซ้ำซ้อนกันลง

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

ระบบพิกัดมือซ้ายและมือขวา   (a) ระบบพิกัดมือขวา    (b) ระบบพิกัดมือซ้าย

โดยปรกติแล้วจุด Vertex ไม่ได้ประกอบด้วยจุดพิกัดในแกน X, แกน Y และแกน Z เพียงอย่างเดียวครับเพราะหากมีแค่นี้ก็ไม่อาจจะสร้างวัตถุ 3 มิติในโลก 3 มิติได้อย่างสมบูรณ์ มันยังประกอบด้วยอะไรๆ อีกหลายอย่างซึ่งก็แล้วแต่ผู้ออกแบบระบบจะต้องการให้มีและงานที่ต้องการจะใช้ แต่โดยส่วนใหญ่แล้วไม่ว่าจะเป็น DirectX หรือ OpenGL ก็จะคล้ายคลึงกันครับค่าที่เสริมเข้ามานี้อาจจะเป็นค่าสีของวัตถุในแต่ละจุด Vertex (diffuse color หรือ specular color) ค่าพิกัดของลวดลาย (Texture) ที่จะปะ (Mapping) ลงไปบนวัตถุ 3 มิติซึ่งเรียกว่า Texture coordinate หรือ พิกัด UV (เพราะใช้ค่า u และ v ในการระบุตำแหน่ง)

สำหรับการกำหนดจุด Vertex ของ DirectX จะใช้หลักการเดียวกับ OpenGL นั้นก็คือ Flexible Vertex Format (FVF) ซึ่งเป็นโครงสร้างข้อมูลที่จะบอก DirectX ว่าหนึ่งจุด Vertex ประกอบด้วยส่วนประกอบอะไรบ้าง โดยการกำหนดค่าคงที่ให้แก่ FVF ดังตัวอย่าง

#define CUSTOM_FVF D3DFVF_XYZ|D3DFVF_DIFFUSE|D3DFVF_TEX1

ค่า CUSTOM_FVF เป็นชื่อของค่าคงที่ที่ผู้ใช้เป็นผู้กำหนดเองขึ้นมา ส่วนค่า flags ต่างๆ ที่ตามมานั้นเป็นค่าคงที่ที่ DirectX กำหนดไว้ให้เพื่อเป็นตัวกำหนดว่า Vertex หนึ่งๆ ประกอบด้วยค่าอะไรบ้าง ซึ่งผู้ใช้จะต้องนำมากำหนดอีกทีโดยค่า Flags นั้นมีความหมายดังนี้

D3DFVF_XYZ   เป็นการกำหนดให้จุด Vertex ประกอบด้วย ค่าพิกัด X   Y และ Z

D3DFVF_NORMAL   เป็นการกำหนดให้จุด Vertex ประกอบด้วยค่าพิกัด Normal ซึ่งจะต้องนำไปใช้คำนวณค่าแสงที่ตกกระทบบนวัตถุ (ซึ่งผมจะกล่าวในบทต่อๆ ไปครับ)

D3DFVF_DIFFUSE   เป็นการกำหนดให้จุด Vertex ประกอบด้วยค่าสี Diffuse

D3DFVF_SPECULAR   เป็นการกำหนดให้จุด Vertex ประกอบด้วยค่าสี Specular

D3DFVF_TEX1 ถึง D3DFVF_TEX8   เป็นการกำหนดให้จุด Vertex ประกอบด้วยค่าพิกัด u และ v ซึ่งเป็นตำแหน่งของลวดลายที่จะปะลงไปบนวัตถุ (ซึ่งผมจะกล่าวถึงในบทต่อๆ ไปอีกเช่นกัน)

ค่า Flags มีมากกว่านี้ครับแต่ที่ใช้กันหลักๆ ก็มีอยู่เท่าที่ผมเสนอนี้ล่ะครับ ที่สำคัญหลังจากกำหนดค่าคงที่ FVF แล้วเราจำเป็นที่จะต้องกำหนดโครงสร้างข้อมูลให้แก่ Vertex ตามค่า FVF ที่ได้กำหนดไว้ก่อนหน้า    ที่สำคัญเป็นอย่างยิ่งคือคุณต้องเรียงลำดับตัวแปรในโครงสร้างข้อมูลให้ถูกต้องตามลำดับที่เรียงไว้กับค่าคงที่ครับ

D3DFVF_XYZ    กำหนดค่าพิกัด X, Y, Z เป็นตัวแปรแบบ float 3 ค่า ซึ่งอาจใช้โครงสร้างข้อมูล D3DXVECTOR3 ที่DirectX กำหนดมาให้แทนได้

D3DFVF_DIFFUSE คือค่าสี เป็นตัวแปรแบบ DWORD หรืออาจใช้ D3DCOLOR ที่DirectX กำหนดมาให้แทนได้

D3DFVF_SPECULAR เหมือนกับ D3DFVF_DIFFUSE ครับ

D3DFVF_NORMAL เหมือนกับ D3DFVF_XYZ ครับ

D3DFVF_TEX1 ถึง D3DFVF_TEX8 เป็นตัวแปรแบบ float 2 ค่าแทนค่าพิกัด U และ V

#define CUSTOM_FVF D3DFVF_XYZ|D3DFVF_NORMAL|D3DFVF_DIFFUSE|D3DFVF_TEX1

struct Vertex

{

float x,y,z;    // D3DFVF_XYZ

float nx,ny,nz; // D3DFVF_NORMAL

DWORD dif;      // D3DFVF_DIFFUSE

float u,v;      // D3DFVF_TEX1

};

หรือ

struct Vertex

{

D3DXECTOR3 Position;  // float x,y,z;

D3DXVECTOR3 Normal;   sp; // float nx,ny,nz;

D3DCOLOR Color;       // DWORD dif;

D3DXVECTOR2 TexCoord; // float u,v;

};

DirectX โลก 3 มิติ และ DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

ลก 3 มิติเกิดจากค่าพิกัด 3 ค่ารวมกัน (ความกว้าง, ความสูง, ความลึก หรือ แกน X, แกน Y, แกน Z) เรียกค่าพิกัดเหล่านี้ว่าจุด Vertex เมื่อนำจุด Vertex สามจุดมารวมกัน และใช้หลักการทางคณิตศาสตร์เรื่องเวคเตอร์ (Vector) และระบบระนาบ (Plane) เข้ามาเกี่ยวข้องก็จะทำให้เกิดรูป 3 เหลี่ยม (Triangle) หรือมากกว่า ซึ่งเรียกรวมๆ กันว่า Polygon (บางทีก็เรียกว่า Face) เมื่อนำ Polygon ทั้งแต่สอง Polygon มารวมเข้าด้วยกันจะทำให้เกิดวัตถุ 3 มิติ (3D geometry)

รูปแบบของวัตถุ 3 มิติ (3D geometry) ซึ่งเกิดจากการรวมตัวกันของ จุด Vertex และ Polygon

ค่าพิกัดในแต่ละแกนนั้นมีค่าได้ทั้งลบและบวกส่วนค่าที่เป็น 0 แสดงว่าเป็นจุดกำเนิด ซึ่งจุดที่พิกัดในแกน X ที่เท่ากับ 0 แกน Y ที่เท่ากับ 0 และแกน Z ที่เท่ากับ 0 นั้นเราจะเรียกว่าจุดกำเนิด (Origin) ซึ่งจะอยู่ตรงจุดกึ่งกลางของโลก 3 มิติ   ส่วนระบบพิกัดสามารถแบ่งออกได้เป็น 2 แบบคือระบบพิกัดมือซ้าย (Left-Hand Coordinate System) และระบบพิกัดมือขวา (Right-Hand Coordinate System)   สำหรับ DirectX คุณสามารถเลือกใช้ระบบพิกัดได้ทั้งระบบพิกัดมือซ้ายและมือขวาแต่โดยพื้นฐานแล้ว DirectX จะใช้ระบบพิกัดมือซ้าย (เป็นค่าdefault) ซึ่งต่างจาก OpenGL ที่ใช้ระบบพิกัดมือขวา

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

PresentationInterval   กำหนดเป็น D3DPRESENT_INTERVAL_IMMEDIATE

            D3DPRESENT_PARAMETERS d3dpp;

LPDIRECT3DDEVICE9 g_pd3dDevice;

ZeroMemory( &d3dpp, sizeof(d3dpp) );

d3dpp.Windowed = TRUE;

d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;

d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;

d3dpp. EnableAutoDepthStencil = TRUE;

d3dpp. AutoDepthStencilFormat = D3DFMT_D16;

g_lpD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp,
&g_lpd3dDevice );

การแสดงผลออกสู่หน้าจอ

เมื่อสร้าง COM Interface ของ Direct3DDevice9 สำเร็จแล้ว คุณก็จะสามารถเรียกใช้เมธอดภายใน COM Interface ตัวนี้ได้แล้วครับ นั้นคือจะสามารถควบคุม Device เพื่อที่จะแสดงผลออกสู่หน้าจอได้

การแสดงผลออกสู่หน้าจอนั้นจะเกี่ยวข้องกับการเขียนข้อมูลลงไปบน BackBuffer ซึ่งขั้นแรกคุณจะต้องเคลียร์ Buffer ทั้งหมดไม่ว่าจะเป็น BackSurface, Z-Buffer หรือ stencil buffer เพื่อให้พร้อมต่อการประมวลผลภาพ (Render) จากนั้นจึงเริ่มเขียนข้อมูลลงไปบน BackBuffer โดยมีข้อแม้ว่าคุณจะต้องทำอยู่ระหว่างเมธอด BeginScene และ EndScene เมื่อประมวลผลภาพเสร็จแล้วจึงทำการสลับ Surface จาก Back Surface ไปเป็น Front Surface (แสดงผลออกสุ่หน้าจอนั้นเอง) โดยใช้เมธอด Present

HRESULT Clear(
     DWORD Count,
     CONST D3DRECT * pRects,
     DWORD Flags,
D3DCOLOR Color,
     float Z,
     DWORD Stencil
);

Count   กำหนดเป็น 0

pRects   กำหนดเป็น NULL เพราะเราจะเคลียร์ทั้งหน้าจอ

Flags   ค่าซึ่งจะบอกว่าจะทำการเคลียร์Buffer ใดบ้างซึ่งมีให้เลือกดังนี้

D3DCLEAR_STENCIL เคลียร์ stencil bufer

D3DCLEAR_TARGET เคลียร์หน้าจอปัจจุบัน

D3DCLEAR_ZBUFFER เคลียร์ depth buffer หรือ Z-Buffer

ซึ่งค่าเหล่านี้คุณสามารถนำมารวมกันโดยใช้เครื่องหมาย | หากต้องการเคลียร์มากกว่าหนึ่ง Buffer อย่างเช่น

D3DCLEAR_TARGET |D3DCLEAR_STENCIL| D3DCLEAR_ZBUFFER เป็นการเคลียร์ Buffer ทั้งหมด

Color   สีที่จะใช้ในการเคลียร์หน้าจอ คุณสามารถใส่ค่าตัวเลขจำนวนเต็มไม่มีเครื่องหมายแทนค่าสีเข้าไปได้เลยหากคุณทราบรหัสแทนค่าสี หรืออาจใช้ D3DCOLOR_XRGB (ค่าสีแดง, ค่าสีเขียว, ค่าสีน้ำเงิน) ก็ได้ ค่าสีนี้แต่ละแม่สีอยู่ในช่วง 0 ถึง 255

Z   ค่าที่ใช้ในการเคลียร์ depth buffer หรือ Z-Buffer มักกำหนดให้เป็น 1.0f

Stencil   ค่าที่ใช้ในการเคลียร์ stencil buffer มักกำหนดให้เป็น 0

HRESULT BeginScene();
HRESULT EndScene();
HRESULT Present(
     CONST RECT * pSourceRect,
     CONST RECT * pDestRect,
HWND hDestWindowOverride,
     CONST RGNDATA * pDirtyRegion
);

พารามิเตอร์ในเมธอด Present กำหนดให้ทุกค่าเท่ากับ NULL ได้เลยครับ

 

g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,255), 1.0f, 0 );

g_pd3dDevice->BeginScene();

// Rendering of scene objects happens here

g_pd3dDevice->EndScene();

g_pd3dDevice->Present( NULL, NULL, NULL, NULL );

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

หรือหากคุณต้องการที่จะใช้แค่โหมดที่ใช้อยู่ในปัจจุบันก็สามารถเรียกเมธอด GetAdapter DisplayMode ซึ่งจะคืนโหมดการแสดงผลในปัจจุบันกลับมาให้

HRESULT GetAdapterDisplayMode(
     UINT Adapter,
     D3DDISPLAYMODE * pMode
);

Adapter   คือ หมายเลขของการ์ดแสดงผล

pMode   คือพอยเตอร์ที่ชี้ไปยังโครงสร้างข้อมูล D3DDISPLAYMODE ซึ่งเก็บรายละเอียดของโหมดที่ใช้อยู่ไว้

เมื่อสามารถตรวจสอบโหมดการแสดงผลว่าการ์ดจอที่เราเลือกใช้สามารถแสดงผลได้แล้วต่อมาก็ถึงเวลาในการจองโหมดการแสดงผล (หรือการสร้าง COM Interface ของ Direct3DDevice9 ) กันแล้วโดยใช้เมธอด

HRESULT CreateDevice(
     UINT Adapter,
     D3DDEVTYPE DeviceType,
     HWND hFocusWindow,
     DWORD BehaviorFlags,
     D3DPRESENT_PARAMETERS * pPresentationParameters,
     IDirect3DDevice9 ** ppReturnedDeviceInterface
);

Adapter คือ หมายเลขของการ์ดแสดงผล

DeviceType คือรูปแบบของดีไวซ์ที่ใช้ซึ่งตรวจสอบโดยใช้เมธอดCheckDeviceType

hFocusWindow คือค่าHandle ของวินโดวส์ที่เราสร้างขึ้นโดยถ้าหากเราเลือกการแสดงผลแบบ fullscreen mode จะต้องเป็นแบบ top-level window

BehaviorFlags มีค่าให้เลือกหลักๆ คือ

D3DCREATE_HARDWARE_VERTEXPROCESSING และ

D3DCREATE_SOFTWARE_VERTEXPROCESSING

pPresentationParameters คือพอยเตอร์ที่ชี้ไปยังโครงสร้างข้อมูล D3DPRESENT_PARAMETERS ที่เราจะต้องกำหนดค่าภายในก่อนที่จะเรียกใช้เมธอดนี้

ppReturnedDeviceInterface  คือพอยเตอร์ที่ชี้ไปยังพอย์เตอร์ของ Direct3DDevice9 Interface

หากเมธอดนี้ทำงานสำเร็จก็จะคืนค่า D3D_OK กลับมา ส่วนโครงสร้างข้อมูล D3DPRESENT_PARAMETERS ซึ่งเราจะต้องกำหนดก่อนเรียกใช้เมธอดนั้นมีดังนี้


struct{
UINT BackBufferWidth, BackBufferHeight;
D3DFORMAT BackBufferFormat;
UINT BackBufferCount;
D3DMULTISAMPLE_TYPE MultiSampleType;
DWORD MultiSampleQuality;
D3DSWAPEFFECT SwapEffect;
HWND hDeviceWindow;
BOOL Windowed;
BOOL EnableAutoDepthStencil;
D3DFORMAT AutoDepthStencilFormat;
DWORD Flags;
UINT FullScreen_RefreshRateInHz;
UINT PresentationInterval;
} 

BackBufferWidth, BackBufferHeight   คือความกว้างและสูงของโหมดการแสดงผล หาก Windowed มีค่าเป็น TRUE ค่าทั้งสองให้กำหนดให้เป็น 0 ครับ

BackBufferFormat   ค่าบิทต่อพิกเซลที่ต้องการ หาก Windowed มีค่าเป็น TRUE ค่านี้จะต้องเท่ากับ D3DFMT_UNKNOWN
BackBufferCount
  คือจำนวน BackBuffer ที่จะใช้

MultiSampleType กำหนดเป็น D3DMULTISAMPLE_NONE
MultiSampleQuality   กำหนดเป็น 0
SwapEffect   กำหนดรูปแบบการสลับ Back และ front Surface มีให้เลือก 3 รูปแบบคือ D3DSWAPEFFECT_DISCARD,

D3DSWAPEFFECT_FLIP และ D3DSWAPEFFECT_COPY
hDeviceWindow   คือค่า Handle ของวินโดวส์ที่เราสร้างขึ้น
Windowed   มีค่าเป็น TRUE เมื่อต้องการกำหนดการแสดงผลแบบ Windowed Mode และมีค่าเป็น FALSE เมื่อต้องการแสดงผลแบบ FullScreen Mode
EnableAutoDepthStencil   กำหนดค่าเป็น TRUE
AutoDepthStencilFormat   คือรูปแบบของ Depth และ Stencil Buffer มีค่าให้เลือกหลักๆ ดังนี้
D3DFMT_D16 depth buffer 16 บิท
D3DFMT_D32 depth buffer 32 บิท
D3DFMT_D24S8 depth buffer 24 บิท และ stencil buffer 8 บิท

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

เมื่อสามารถเลือกการ์ดแสดงผลได้แล้วต่อไปเราจะต้องมาตรวจสอบความละเอียดของหน้าจอ และจำนวนบิทต่อพิกเซลว่าการ์ดแสดงผลที่เราจะเลือกใช้นั้นสามารถรองรับได้หรือไม่โดยใช้เมธอด GetAdapterModeCount ซึ่งเมธอดนี้จะคืนจำนวนโหมดการแสงผลทั้งหมดที่การ์ดแสดงผลนั้นๆ สามารถที่จะรองรับได้กลับมา

UINT GetAdapterModeCount(
UINT Adapter,
D3DFORMAT Format
);

Adapter คือ หมายเลขของการ์ดแสดงผลซึ่งได้กล่าวไปแล้ว

Format คือรูปแบบของบิทต่อพิกเซลที่เราจะใช้โดยหลักๆ ค่านี้มีให้เลือกดังนี้

D3DFMT_R8G8B8 เป็นแบบ 24 บิท

D3DFMT_A8R8G8B8 เป็นแบบ 32 บิทโดย 24 บิทเป็นค่าสีส่วนอีก 8 บิทเป็นค่า alpha channel

D3DFMT_X8R8G8B8 เป็นแบบ 32 บิทโดยใช้แค่ 24 บิทเป็นค่าสี

D3DFMT_R5G6B5 เป็นแบบ 16 บิท

ค่า Format มีให้เลือกมากกว่านี้สามารถหาข้อมูลเพิ่มเติมได้จากเอกสารที่แถมมากับ DirectX SDK เมื่อได้จำนวนโหมดการแสดงผลที่ต้องการแล้วเราจะทำการวนลูปเป็นจำนวนครั้งเท่ากับจำนวนโหมดการแสดงผลพร้อมทั้งเรียกเมธอด EnumAdapterModes เพื่อตรวจสอบรายละเอียดของโหมดการแสดงผลนั้นๆ

HRESULT EnumAdapterModes(
UINT Adapter,
D3DFORMAT Format,
UINT Mode,
D3DDISPLAYMODE* pMode
);

Adapter คือ หมายเลขของการ์ดแสดงผลซึ่งได้กล่าวไปแล้ว Format คือรูปแบบของบิทต่อพิกเซลที่เราจะใช้ Mode คือหมายเลขโหมดซึ่งมีค่าตั้งแต่ 0 ถึง จำนวนโหมดการแสดงผลที่มีอยู่ในการ์ดแสดงผลนั้นๆ pMode พอยเตอร์ชี้ไปยังโครงสร้างข้อมูล D3DDISPLAYMODE ซึ่งเก็บรายละเอียดของโหมดนั้นๆ ไว้ซึ่งมีโครงสร้างข้อมูลดังนี้

struct{

UINT Width;

UINT Height;

UINT RefreshRate;

D3DFORMAT Format;

}

หากเมธอดนี้ทำงานสำเร็จก็จะคืนค่า D3D_OK กลับมา ส่วนข้างล่างนี้แสดงตัวอย่างการตรวจสอบโหมดการแสดงผลที่ความละเอียด 800X600 ที่ 16 บิท

UINT ModeCount = g_lpD3D->GetAdapterModeCount(D3DADAPTER_DEFAULT, D3DFMT_R5G6B5);

for(unsigned int i = 0;i

{

D3DDISPLAYMODE mode;

g_lpD3D->EnumAdapterModes(D3DADAPTER_DEFAULT, D3DFMT_R5G6B5, i ,&mode);

if(mode.Width == 800 && mode.Height == 600)return true;

}

return false;

DirectX

หัวข้อพิเศษไอที, DirectX No Comments »

หากเมธอดนี้ทำงานสำเร็จจะคืนค่า D3D_OK กลับมา และส่วนที่สำคัญที่สุดของโครงสร้างข้อมูลนี้ก็คือ Description ซึ่งจะเก็บชื่อของการ์ดแสดงผลไว้ส่วนค่าคงที่ MAX_DEVICE_IDENTIFIER _STRING นั้นมีค่าเท่ากับ 512 ครับ ต่อมาจะต้องเรียกเมธอด CheckDeviceType เพื่อตรวจสอบว่าการ์ดแสดงผลนั้นๆ จะสามารถประมวลผลภาพทางด้าน 3 มิติได้หรือไม่

HRESULT CheckDeviceType(
UINT Adapter,
D3DDEVTYPE DeviceType,
D3DFORMAT DisplayFormat,
D3DFORMAT BackBufferFormat,
BOOL Windowed
);

Adapter คือ หมายเลขของการ์ดแสดงผลซึ่งได้กล่าวไปแล้ว DeviceType มีให้เลือก 2 แบบหลักๆ คือ D3DDEVTYPE_HALเป็นการประมวลผลภาพโดยใช้ฮาร์ดแวร์(การประมวลผลโดยใช้การ์ดแสดงผล) D3DDEVTYPE_REF เป็นการประมวลผลภาพส่วนใหญ่โดยใช้ซอฟแวร์ (หรือ CPU) DisplayFormat เป็นรูปแบบของการ์ดแสดงผลที่เรากำหนดให้โดยสามารถกำหนดเป็นD3DFMT_ X8R8G8B8 เป็นรูปแบบ 32 บิทคือ แดง 8 บิท เขียว 8 บิท น้ำเงิน 8 บิทว่างอีก 8 บิทD3DFMT_ R5G6B5 เป็นรูปแบบ 16 บิทคือ แดง 5 บิท เขียว 6 บิท และ น้ำเงิน 5 บิทBackBufferFormat เป็นรูปแบบของ BackBuffer คือค่าบิทต่อพิกเซลที่ต้องการแสดง (ซึ่งผมจะกล่าวต่อไป)

Windowed มีค่าเป็น TRUE ถ้าจะกำหนดแบบ Windowed Mode และมีค่าเป็น FALSE ถ้าจะกำหนดแบบ FullScreen Mode

เมธอดจะคืนค่า D3D_OK กลับมาถ้าหาก DeviceType ที่เราเลือกไว้สามารถใช้งานได้ ตัวอย่างการใช้งานเมธอดนี้คือ ถ้าหากผมต้องการตรวจสอบว่าการ์ดแสดงผลหลักสามารถประมวลผล ภาพ 3 มิติที่การแสดงผลแบบ FullScreen Mode ได้หรือไม่ก็สามารถทำการตรวจสอบได้โดย

HRESULT hrl;

hrl = g_lpD3D-> CheckDeviceType(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL,

D3DFMT_X8R8G8B8, D3DFMT_X8R8G8B8,FALSE);

If(hrl == D3D_OK)return true;

return false;


   Designed By:  SadhWeb Directory  &  WP Theme

Sponsored By:  Affiliate Marketing Blog  &  Paid Directory