الفريق العربي للبرمجةأرشيف المنتديات · 2000 – 2023
نسخة أرشيفية للقراءة فقط — التسجيل والمشاركة مغلقان، والمحتوى محفوظ كما كان.

الربط بين ال2d و ال3d

بدأه General Of World في 9 مارس 2008 · 3 رد · 1,261 مشاهدة · في قسم برمجة الألعاب و الرسوميات العام
مشاركة: واتساب X فيسبوك تيليجرام
#1 صاحب الموضوع

لو سمحت لو حد يعرف هنا طريقة عامة للربط بين ضغطة الماوس التو دي و اى مجسم ثري دي و محدش يقول الطريقة ديه مستحيلة لأنها موجودة في العاب كثيرة زى الالعاب الاستراتيجية

و شكرا

#2

اعتقد انك تقصد picking ray

llback.jpg

اشهد ان لا إله إلا الله وان محمدا ً رسول الله

#3

نعم انا سمعت انو بيخرج ray و بيتحقق من مكان الcollision حاجة زى كدة حد يعرف اكواد او كدة ؟ :)

و اكون شاكر له جدا

#4

السلام عليكم, :)

سأحاول ان اشرح الفكرة العامة التي تستطيع من خلالها عمل Mouse Picking مع تقديم معلومات مختصرة عن الأساسيات المطلوبة, يجب أن تكون قد فهمت كيفية رسم المشاهد المجسمة لكي تستطيع فهم وإستخدام الطريقة بحسب الأدوات التي تستخدمها (DirectX, OpenGL, Irrlicht, ...).

لنبدأ, هنالك عدة أنواع من الفضاءات Spaces التي يجب إستخدامها لحساب المشهد المجسم الذي تراه في النهاية في نافذة ثنائية الأبعاد, وهي مرتبطة بالـ Graphics Pipeline, المقصود بالفضاء هنا هو موقع الأشياء بالنسبة لبعضها, مثلاً موقع صندوق مرسوم بالنسبة للكاميرا المستخدمة للرسم, أي إن الفضاء هو أشبه ما يكون بمعادلة تستطيع إستخدامها لتحويل الأشكال المرسومة من مكانها الحالي إلى مكانها المرغوب, يمثل الفضاء رياضياً بمصفوفة من القيم تمثل النقل, الدوران, والتحجيم المطلوب.

الفضاءات التي تهمنا هنا (وهي الأساسية), هي كالتالي:

  • الفضاء المحلي أو فضاء النموذج (Local or Model Space) وهو الفضاء الذي تقوم بصنع الشكل المجسم فيه, في حالة إستخدامك لثري دي ستوديو ماكس مثلاً فإن فضاء البرنامج هو نفسه الفضاء المحلي, أي إنه يمثل إحداثيات موقع النموذج من نقطة الأصل في البرنامج.
  • فضاء العالم (World Space): وهو الفضاء الذي سترسم المشهد فيه عن طريق Direct3D أو OpenGL, يجب أن تعين مصفوفة عالم لكل نموذج ترغب في رسمه, تقوم مصفوفة العالم بالتحويل من الفضاء المحلي إلى فضاء العالم (المشهد), أو بمعنى أدق, تحويل النموذج (نقل وتدوير,وتحجيم) من مكانه الأصلي إلى المكان الذي تريد أن ترسمه فيه. إذا كنت تريد أن يُرسم النموذج في نفس مكانه الأصلي تقوم بتمرير Identity Matrix كمصفوفة عالم.
  • فضاء العرض أو فضاء الكاميرا (View or Camera Space): وهو الفضاء الذي تكون فيه الكاميرا أشبه بنقطة أصل تتمحور جميع الأشكال المرسومة بالنسبة لها.
  • فضاء الإسقاط (Projection Space): هذا الفضاء يستخدم لحساب مساحه العرض التي تراها في النهاية على الشاشة, وهو يقوم بتحويل المشهد إلى المسقط المطلوب.
  • فضاء الشاشة (Screen Space): وهو ما تراه في النهاية في النافذة, الصورة الثنائية الأبعاد.

والآن لأوضح الصورة أكثر, سأشرح مالذي يجب أن يحصل لكي تتمكن من رسم نموذج للشاشة:

  • النموذج يكون في فضاءه المحلي عند تحميله.
  • يتم تحويل النموذج من فضاءه المحلي إلى فضاء العالم الذي تحدده أنت, النموذج الآن موجود في العالم.
  • يتم تحويل النموذج من فضاء العالم إلى فضاء العرض, النموذج الآن موجود في مكان بالنسبة للكاميرا المستخدمة, فلنفترض إن النموذج موجود أمام الكاميرا.
  • يتم تحويل النموذج من فضاء العرض إلى فضاء الإسقاط, أي إن النموذج الآن موجود في المربع الذي تراه على الشاشة (بما إنه أمام الكاميرا).

والآن يتم الرسم ويكون ما يظهر على الشاشة في فضاء الشاشة.

عندما تضغط بالماوس على أي جزء من الشاشة الموجود فيها المشهد, فإن كل ما تحصل عليه من نظام الإدخال هو الإحداثيات ثنائية الأبعاد لموقع الماوس بالنسبة للنافذة التي يتم رسم المشهد فيها, تلك الإحداثيات موجودة في فضاء الشاشة.

ما يجب أن تقوم به الآن هو تقريباً عكس عملية تحويل الصندوق المبينة سابقاً, أول خطوة هي تحويل الإحداثيات من فضاء الشاشة إلى فضاء الإسقاط, وذلك عن طريق معادلة تحتسب من مصفوفة الإسقاط.

بعدها نقوم بإحتساب مقلوب مصفوفة العرض, ثم نستخدمها لتحويل إحداثيات الماوس التي حصلنا عليها من فضاء الإسقاط إلى فضاء العرض, سنولد شعاعاً Ray يبدأ من نقطة إحداثي الماوس ويتجه بشكل عمودي إلى داخل الشاشة.

سأبين العملية بإستخدام Direct3D (كود عام):

المصفوفات الرئيسية التي سيتم إستخدامها:

D3DXMATRIX viewMat; // View Matrix
D3DXMATRIX projMat; // Projection Matrix
//.....etc

لنفترض إننا حصلنا الآن على موقع الماوس, وهو إحداثي بالمدى (0,0) - (width,height) بالنسبة للنافذة, كما إن لدينا إرتفاع وعرض النافذة المستخدمة:

float mx; // Mouse X position
float my; // Mouse Y position
float width; // Window width
float height; //Window height

إنتبه إلى إن عرض وإرتفاع نافذة الرسم الحقيقية لا يكون دائماً مساوي لعرض وإرتفاع نافذة الوندوز المستخدمة بالنسبة لـ Direct3D (بسبب شريط العنوان, والقوائم التي يجب أن لا تحتسب), لكي تحصل على القيم الصحيحة, إستخدم

D3DVIEWPORT9 viewport_structure;
d3dDevic->GetViewport( &viewport_structure );
width = viewport_structure.Width;
height = viewport_structure.Height;

لنحسب موقع الماوس بالنسبة لمصفوفة الإسقاط (أو لنحول النقطة من فضاء الشاشة إلى فضاء الإسقاط):

tx = ( ( ( 2.0f * mx ) / width ) - 1.0f ) / projMat._11; // projMat_11: العنصر الموجود في العمود الأول الصف الأول
ty = - ( ( ( 2.0f * my ) / height ) - 1.0f ) / projMat_22;

والآن سنحسب مركز الشعاع وإتجاهه بإستخدام النقطة التي حسبناها:

D3DXVECTOR3 rayPos, rayDir;
// الشعاع موجود حالياً في فضاء العرض
rayPos = D3DXVECTOR3( 0.0f, 0.0f, 0.0f );
rayDir = D3DXVECTOR3( tx, ty, 1.0f );

والآن, الخطوة الأخيرة هي تحويل الشعاع من فضاء العرض إلى فضاء العالم عن طريق ضربه بمقلوب مصفوفة العرض:

D3DXMATRIX vim; // ستمثل مقلوب مصفوفة العرض
D3DXMatrixInverse( &vim, NULL, &viewMat );
// حول الشعاع إلى فضاء العالم
D3DXVec3TransformCoord( &rayPos, &rayPos, &vim );
D3DXVec3TransformNormal( &rayDir, &rayDir, &vim );
D3DXVec3Normalize( &rayDir, &rayDir );

تهانينا! لديك الآن شعاع في العالم.

يجب عليك الآن أن تقوم بعملية فحص جميع النماذج الموجودة في المشهد لمعرفة ما إذا كانت تتقاطع مع الشعاع (بإستخدام الصندوق المحيطي Bounding Box أو الكرة المحيطية Bounding Sphere) ثم إذا كانت تتقاطع حساب المسافة بينها وبين مركز الشعاع, أقرب جسم يتقاطع مع الشعاع هو الجسم الذي تم الضغط عليه...

أتمنى أن تستفيد من هذا الرد... كان الأفضل أن أضع موضوعاً جديداً يبين الطريقة بدل وضع رد طويل عريض هنا, قد أقوم بذلك في المستقبل.

تم تعديل هذه المشاركة بواسطة SandHawk في 12 مارس 2008 في 22:54

مواضيع مشابهة