[دروس] تعلم كيفية الاستفادة من ذاكرة التقنيع Stencil الجزء الثاني ( إنشاء الظلال)

الناقل : elmasry | الكاتب الأصلى : time1 | المصدر : www.arabteam2000-forum.com

بسم الله الرحمن الرحيم

السلام عليكم ورحمة الله وبركاته :

كنا قد تكلمنا في السابق عن ذاكرة التقنيع "Stencil" وقد وضحنا اهمية هذه الذاكرة , وعرضنا بعض الامثلة على استخدام هذه الذاكرة , مثل : " إنشاء المرايا , إنشاء الظل للاجسام "

وقد تكلمنا بالجزء الأول عن كيفية إنشاء المرايا , للإطلاع على الجزء الأول
مــن هنـــا

سنكمل الحديث اليوم عن هذه الذاكرة وسنستعرض المثال الثاني , الظل .

********************************************************************************
******************

اولا : نقوم بإنشاء مشهد بسيط مثلا :
غرفة بداخلها مرآة وفي منتصفها ابريق شاي " Teapot "

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

ارفق صورة : monthly_07_2008/post-82612-1215671243.jpg

الان وبعد تجهيز المشهد نقوم بكتابة الدالة Set_Shadow والتي ستقوم بإنشاء الظل .

ثانيا : انشاء الظل .

اولا نقوم بملأ ذاكرة Stencil بالقيمة صفر من خلال المنهج Clear

 Device->Clear(0,0,D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER | D3DCLEAR_STENCIL,0xffffffff,1.0f,0);


الوسيط السادس يحدد لنا القيمة التي سنملأ بها ذاكرة التقنيع .

بعدها نكتب الدالة Shadow :
اولا: نقوم بتفعيل ذاكرة التقنيع
Device->SetRenderState(D3DRS_STENCILENABLE,true);


بعد ذلك نحدد القيمة المرجعيه Ref وهنا سنغير القيمة المرجعية إلى صفر , بدلا من 1 كما في الدرس السابق لأننا نرغب بإظهار الظل على اي مكان , بخلاف المرآة .

Device->SetRenderState(D3DRS_STENCILREF,0x0);


بعدها نحدد قيمة القناع mask لحجب بتات من ref و value وقناع الكتابة الذي يحجب بتات اي قيمة نقوم بكتابتها داخل ذاكرة Stencil
   Device->SetRenderState(D3DRS_STENCILMASK,0xffffffff);
        Device->SetRenderState(D3DRS_STENCILWRITEMASK,0xffffffff);


بعد ذلك تأتي مرحلة الاختبار او المقارنة , وقد تكلمنا في الدرس السابق عن مجموعة الحالات الممكنة للاختبار او المقارنة .

سنستخدم في هذه المرة D3DCMP_EQUAL اي ينجح الاختبار في حال تساوي طرفي المقارنة .
Device->SetRenderState(D3DRS_STENCILFUNC,D3DCMP_EQUAL)


بعدها نقوم بتحديث ذاكرة التقنيع من خلال :
1 - تحديد الطريقة التي يتم فيها تحديث اي حجرة من حجرات ذاكرة التقنيع في حال فشل التقنيع لأي بيكسل
2- تحديد الطريقة التي يتم فيها تحديث اي حجرة من حجرات ذاكرة التقنيع في حال فشل العمق Z-Buffer لأي بيكسل
3-تحديد الطريقة التي يتم فيها تحديث اي حجرة من حجرات ذاكرة التقنيع في حال نجاح اختبار التقنيع والعمق Z-Buffer لأي بيكسل
ستبقى حجارات الذاكرة Stencil كما هي في حال فشل ذاكرة التقنيع او العمق , اما في حال نجاح اختبار التقنيع او العمق فسنستخدم في هذه المرة الثابت D3DSTENCILOP_INCR والذي يعني بأن قيمة الحجرة ستزيد , وهذا يفيدنا في منع الكتابة على اي بكسل تم الكتابة عليه سابقا , مما يعني عدم حصول مزج مضاعف لانه عند الكتابة لأول مرة على اي بكسل فإن الاختبار سينجح , عندها الثابت D3DSTENCILOP_INCR يفيد بزيادة حجرة التقنيع للبكسل من 0x0 إلى 0x1 بالتالي سيفشل الاختبار عند محاولة الكتابة مرة اخرى على البكسل نفسه , مما يخلصنا من مشكلة المزج المضاعف .
        Device->SetRenderState(D3DRS_STENCILFAIL,D3DSTENCILOP_KEEP);
        Device->SetRenderState(D3DRS_STENCILZFAIL,D3DSTENCILOP_KEEP);
        Device->SetRenderState(D3DRS_STENCILPASS,D3DSTENCILOP_INCR);


المرحلة التالية هي انشاء خامة الظل .
سنقوم اولا بتفعيل المزج
        Device->SetRenderState(D3DRS_ALPHABLENDENABLE,true);


بعدها نحدد عوامل المزج المناسبة , على سبيل المثال قمنا بتحديد العامل D3DBLEND_SRCALPHA للمصدر , والعامل D3DBLEND_INVSRCALPHA للهدف .

        Device->SetRenderState(D3DRS_SRCBLEND,D3DBLEND_SRCALPHA);
        Device->SetRenderState(D3DRS_DESTBLEND,D3DBLEND_INVSRCALPHA);


بعدها ننشأ المادة التي ستمثل ظل الابريق , وبعد الانتهاء من انشاء المادة سنقوم بتحديد درجة الشافية إلى 50 %
TeapotMaterial.Diffuse.a=0.5f;


المرحلة التالية , هي التجهيز للرسم .
اولا سنقوم بتحديد المستوى الذي سيرسم عليه الظل , وقد تكلمنا في الدرس السابق عن كيفية تحديد المستويات , على سبيل المثال , في مثالنا الحالي سنقوم بتحديد المركبة y بالقيمة 1-
        D3DXPLANE plane(0.0f,-1.0f,0.0f,0.0f);


بعد ذلك سنقوم بتعريف شعاع رباعي لتحديد مكان الضوء اذا كان نقطيا , او اتجاه الضوء اذا كان متوازيا .
D3DXVECTOR4 Dir(-1,-1,-1, 0.0f);

سأتكلم عن المركبة الرابعه w .
اذا كانت w= 1 عندها المركبات الثلاث الاولى تصف موقع الضوء النقطي .
اذا كانت w=0 عندها المركبات الثلاث الاولى تصف اتجاه الضوء المتوازي .

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

D3DXMatrixShadow(&S,&Dir,&plane);


بعد ذلك نقوم بكتابة مصفوفة Translation لتحديد مكان الظل على ان يكون هو نفسه مكان الابريق ,
كما يمكننا تعريف متجه عام لتمثل مركباته موقع الابريق والظل في حال الرغبة بتحريك الابريق .
D3DXMatrixTranslation(&T,x,y,z);


الان نقوم بضرب المصفوفتين مع مراعاة الترتيب T اولا ثم S

        W=T*S;
        Device->SetTransform(D3DTS_WORLD,&W);


بعدها نقوم بتعطيل اختبار العمق وذلك للتخلص مما يسمى Z-Fighting والذي يحدث عندما يكون لسطحين نفس القيم في ذاكرة العمق .
Device->SetRenderState(D3DRS_ZENABLE,false);


المرحلة التالية هي رسم الابريق :
نقوم بتحديد المادة التي انشائنها قبل قليل ومن ثم رسم الابريق
        Device->SetMaterial(&TeapotMaterial);
        Teapot->DrawSubset(0);


المرحلة الاخيرة هي اعادة تفعيل اختبار العمق , وتعطيل كلا من المزج و التقنيع
        Device->SetRenderState(D3DRS_ZENABLE,true);
        Device->SetRenderState(D3DRS_ALPHABLENDENABLE,false);
        Device->SetRenderState(D3DRS_STENCILENABLE,false);


لتصبح النتيجة :

ارفق صورة : monthly_07_2008/post-82612-1215671268.jpg

ارفق صورة : monthly_07_2008/post-82612-1215672047.jpg

هذا واسأل المولى القدير ان اكون قد وفقت في كتابتي لهذا الدرس , واعتذر عن تأخري في كتابته نظرا لظروفي الدراسية في التيرم السابق .

تحياتي . .