بسم الله الرحمن الرحيم
اخواني الاعزاء , اقدم لكم اليوم درس حول كيفية تصميم كاميرا على طريقة Frank.Luna
بداية سنقوم بتعريف نوعين من الكاميرا , وهي AirCraft والتي تسمح للمستخدم التحرك والانتقال بكل حرية داخل فضاء المشهد وتستخدم في الالعاب التي تحاكي الطيران , وLandObject والتي تحاكي الانتقال المقيد وهي مفيدة وتستخدم في ألعاب الرماية واطلاق الرصاصات ...إلخ
الخطوة رقم 1
نبدأ الـClass بتعريف نوعين من الكاميرا ,
enum CameraType{AirCraft,LandObject};
يتم تعريف الكاميرا من خلال ثلاثة متجهات , Right,Up,Look
واخيرا نقوم بتعريف متجه يحدد لنا موضع الكاميرا Pos
وتحديد القيم هذه جميعا سنقوم بها من خلال الباني حيث سياخذ وسيط واحد يقوم بتحديد نوع الكاميرا وبعدها يقوم بإعطاء القيم للمتجهات
Camera::Camera(CameraType t)
{
Type=t;
Pos=D3DXVECTOR3(0.0f,1.0f,10.0f);
Look=D3DXVECTOR3(0.0f,0.0f,-1.0f);
Right=D3DXVECTOR3(-1.0f,0.0f,0.0f);
Up=D3DXVECTOR3(0.0f,1.0f,0.0f);
}
الخطوة رقم 2 : تكوين مصفوفة العرض
مصفوفة العرض ستكون على الشكل التالي :
ولتحقيق ذلك سنقوم بالخطوات التالية :
1- تنظيم المتجهات وجعلها متعامدة:
نقوم بتنظيم متجه وضربه ضرب اتجاهي مع متجه اخر ونعلم عندها بأن ناتج هذه العملية سيكون متجه ثالث عمودي على المتجهين , نقوم بتنظيم المتجه الناتج ونكرر الخطوة على المتجهات الاخرى .
D3DXVec3Normalize(&Look,&Look);
D3DXVec3Cross(&Up,&Look,&Right);
D3DXVec3Normalize(&Up,&Up);
D3DXVec3Cross(&Right,&Up,&Look);
D3DXVec3Normalize(&Right,&Right);
2- نوجد الانسحاب من خلال p- لانه p-p=0 للموقع pos
float x=-D3DXVec3Dot(&Right,&Pos);
float y=-D3DXVec3Dot(&Up,&Pos);
float z=-D3DXVec3Dot(&Look,&Pos);
3- نكون بعدها المصفوفة على الشكل السابق:
(*V)(0,0)=Right.x;(*V)(0,1)=Up.x;(*V)(0,2)=Look.x;(*V)(0,3)=0;
(*V)(1,0)=Right.y;(*V)(1,1)=Up.y;(*V)(1,2)=Look.y;(*V)(1,3)=0;
(*V)(2,0)=Right.z;(*V)(2,1)=Up.z;(*V)(2,2)=Look.z;(*V)(2,3)=0;
(*V)(3,0)= x;(*V)(3,1)= y;(*V)(3,2)= z;(*V)(3,3)=1;
الخطوة رقم 3 :الدوران حول المحاور
وهناك ثلاثة انواع من الدوران وهي :
Pitch : الدوران حول محور Right
Yaw: الدوران حول محور Up
Roll: الدوران حول محور Look
اولا الدوران نحو اليمين Pitch
نقوم بكتابة التابع الذي يمثل لنا الدوران حول اليمين Pitch وذلك من خلال الدوران حول محور Right باستخدام التابع D3DXMatrixRotationAxis والذي يأخذ الوسيط الاول مصفوفة الدوران والثاني الشعاع او المتجه المراد الدوران حوله والثالث مقدار الدوران .
بعد ذلك نجري التحويل على المتجهات الاخرى كما يلي :
D3DXMATRIX T;
D3DXMatrixRotationAxis(&T,&Right,angle);
D3DXVec3TransformCoord(&Look,&Look,&T);
D3DXVec3TransformCoord(&Up,&Up,&T);
ثانيا الدوران حول محورUp والذي يسمى Yaw
وهو مشابه للسابق باختلاف اننا سنضع قيدا على الكاميرا LandObject كما يلي
D3DXMATRIX T;
if(Type==LandObject)
D3DXMatrixRotationY(&T,angle);
else
D3DXMatrixRotationAxis(&T,&Up,angle);
D3DXVec3TransformCoord(&Right,&Right,&T);
D3DXVec3TransformCoord(&Look,&Look,&T);
ثالثا الدوران حول محور Look والذي يسمى Roll
هذا الدوران فقط اذا كانت الكاميرا AirCraft وهو ايضا مشابه لسابقيه , كما يلي :
D3DXMATRIX T;
if(Type==AirCraft)
{
D3DXMatrixRotationAxis(&T,&Look,angle);
D3DXVec3TransformCoord(&Up,&Up,&T);
D3DXVec3TransformCoord(&Right,&Right,&T);
}
الخطوة رقم 4 :المشي والطيران
اولا المشي Walk
يتم التعامل هنا في هذه الخطوة بأكملها مع المتجه Pos ( موضع الكاميرا ) فعلى سبيل المثال , اذا كانت الكاميرا AirCraft وكنا نرغب بالتقدم او المشي بمقدار Z فأننا سنقوم بضرب المتجه Look في المقدار z ونجعل المتجه Pos يساوي Pos+حاصل الضرب .
if(Type==AirCraft)
Pos+=Look*z;
else
Pos+=D3DXVECTOR3(Look.x,0.0f,Look.z);
اما اذا كانت الكاميرا LandObject عندها كما رأينا فأننا نفرض قيد على الكاميرا بعدم التحرك بحرية في الفضاء عند المشي وانما تبقى مسايرة للارض .
ثانيا الطيران :
كذلك الامر في الطيران فأن الكاميرا AirCraft تأخذ الحرية في الطيران والتحليق في الفضاء , بينما الكاميرا LandObject فالطيران يمثل الارتفاع فقط .
if(Type==AirCraft)
Pos+=Up*u;
else
Pos.y+=u;
واخيرا سنقوم بعرض الكود كاملا :
class Camera
{
public:
enum CameraType{AirCraft,LandObject};
Camera(CameraType);
void Set_Camera(CameraType);
void Set_VeiwMatrix(D3DXMATRIX *V);
////////////////////////////////////////////
void Pitch(float);
void Yaw(float );
void Roll(float);
/////////////////////////////////////////
void Walk(float);
void Fly(float);
void Strafe(float);
private:
D3DXVECTOR3 Pos;
D3DXVECTOR3 Look;
D3DXVECTOR3 Right;
D3DXVECTOR3 Up;
CameraType Type;
};
Camera::Camera(CameraType t)
{
Type=t;
Pos=D3DXVECTOR3(0.0f,1.0f,10.0f);
Look=D3DXVECTOR3(0.0f,0.0f,-1.0f);
Right=D3DXVECTOR3(-1.0f,0.0f,0.0f);
Up=D3DXVECTOR3(0.0f,1.0f,0.0f);
}
void Camera::Set_Camera(CameraType t)
{
Type=t;
}
void Camera::Set_VeiwMatrix(D3DXMATRIX *V)
{
D3DXVec3Normalize(&Look,&Look);
D3DXVec3Cross(&Up,&Look,&Right);
D3DXVec3Normalize(&Up,&Up);
D3DXVec3Cross(&Right,&Up,&Look);
D3DXVec3Normalize(&Right,&Right);
///////////////////////////////////////////////
float x=-D3DXVec3Dot(&Right,&Pos);
float y=-D3DXVec3Dot(&Up,&Pos);
float z=-D3DXVec3Dot(&Look,&Pos);
///////////////////////////////////////////////
(*V)(0,0)=Right.x;(*V)(0,1)=Up.x;(*V)(0,2)=Look.x;(*V)(0,3)=0;
(*V)(1,0)=Right.y;(*V)(1,1)=Up.y;(*V)(1,2)=Look.y;(*V)(1,3)=0;
(*V)(2,0)=Right.z;(*V)(2,1)=Up.z;(*V)(2,2)=Look.z;(*V)(2,3)=0;
(*V)(3,0)= x;(*V)(3,1)= y;(*V)(3,2)= z;(*V)(3,3)=1;
}
///////////////////////////////////////////////////////////////
void Camera::Pitch(float angle)
{
D3DXMATRIX T;
D3DXMatrixRotationAxis(&T,&Right,angle);
D3DXVec3TransformCoord(&Look,&Look,&T);
D3DXVec3TransformCoord(&Up,&Up,&T);
}
void Camera::Yaw(float angle)
{
D3DXMATRIX T;
if(Type==LandObject)
D3DXMatrixRotationY(&T,angle);
else
D3DXMatrixRotationAxis(&T,&Up,angle);
D3DXVec3TransformCoord(&Right,&Right,&T);
D3DXVec3TransformCoord(&Look,&Look,&T);
}
void Camera::Roll(float angle)
{
D3DXMATRIX T;
if(Type==AirCraft)
{
D3DXMatrixRotationAxis(&T,&Look,angle);
D3DXVec3TransformCoord(&Up,&Up,&T);
D3DXVec3TransformCoord(&Right,&Right,&T);
}
}
void Camera::Walk(float z)
{
if(Type==AirCraft)
Pos+=Look*z;
else
Pos+=D3DXVECTOR3(Look.x,0.0f,Look.z);
}
void Camera::Fly(float u)
{
if(Type==AirCraft)
Pos+=Up*u;
else
Pos.y+=u;
}
واخيرا , تستطيع التعديل على الClass السابق كما تشاء وابتكار انواع جديدة من الكاميرات مناسبة لاحتياجاتك , لتكون في النهاية كاميرا تخدم لعبتك بشكل مناسب كما في الصورة :
,اتمنى ان اكون قد وفقت في هذا الدرس ,
تمنياتي لكم بالتوفيق ..