السلام عليكم ..
هذه سلسلة من التطبيقات التي سنعملها معا .. لمحاولة فهم آلية الاكساء .. في opengl .
ماهو الاكساء ..
وضع صورة على شكل ما .. بابسط تعبير .
شاهد الصورة ( للاعضاء ) ,
أتمنى ان لاتنتقل من خطوة الا وانت فاهمها .. لاني وضعت عدة تطبيقات متتابعة ..لاتترك شيء الا وانت فاهمه .. لان الدروس متصلة ..
في OpenGL يمر الاكساء في ثلاث مراحل رئيسية :
1- تقوم بتحميل الصورة التي تريد .
قد يتطلب الامر سطر واحد اذا كنت تستخدم دوال جاهزة .. وقد يتطلب الامر منك 50 سطر اذا لم تستخدم دوال جاهزة .
في opengl يوجد دالة مساعدة لتحميل ملفات bmp .
وبالتالي تحمل الصورة في اقل من سطرين .
لكن هناك بعض الانساق مثل tga و pcx و jpg .. التي تتميز اما بوجود قناة الفا .. او بصغر الحجم ...... الخ .. وبالتالي يتطلب الامر قراءة تلك الصور من الصفر او تستخدم مكتبة مساعدة.
2- بعد ان حملت الصورة ... تخبر opengl بانك تريد ان تضع هذه الصورة كاكساء .. وايضا تضع فلاتر الاكساء التي تريد .. هل تريد الاكساء واضح وخالي من التشويش .. او تريد اداء اسرع وبالتالي اكساء اقل دقة ..
وايضا تخبر Opengl بعرض وطول الصورة التي تريدها كاكساء . . الخ .
3- تعين الاكساء على الشكل الذي تريده .. وذلك بان تضع الاحداثيات المناسبة .
دعنا نطبق ...
انسخ هذا الكود وألصقه :
/*1*/ GLuint ID_1;
/*2*/ void LoadTexture(char *FileName , GLuint *ID)
/*3*/ {
/*4*/ FILE *File=NULL;
/*5*/ File=fopen(FileName,"r");
/*6*/ if (File)
/*7*/ {
/*8*/ fclose(File);
/*9*/ }
/*10*/ AUX_RGBImageRec *TextureImage=new(AUX_RGBImageRec);
/*11*/ memset(TextureImage,0,sizeof(void *)*1);
/*12*/ TextureImage = auxDIBImageLoad(FileName);
/*13*/ glGenTextures(1, ID);
/*14*/ glBindTexture(GL_TEXTURE_2D,*ID);
/*15*/ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
/*16*/ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
/*17*/ glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
/*18*/ free(TextureImage->data);
/*19*/ free(TextureImage);
/*20*/ }
1- السطر الاول : انشأنا متغير من نوع Gluint ليحمل الاكساء الذي نريد لاحقا ... لابد ان يكون من نوع Gluint .
2- السطر الثاني اعلنا عن دالة ... وسمها ماشئت .. الهدف تنظيمي فقط .
نريد تمرير بارمترين لها .. الاول مكان الصورة .. الثاني المتغير الذي سيحمل الاكساء ..
لاحظ اننا وضعنا المتغير مؤشر .. حتى يظل محتفظا بقيمته حتى بعد الخروج من هذه الدالة . .
راجع المؤشرات في السي .. للمزيد .. من التوضيح .
3- من السطر الرابع الى التاسع فتحنا ملف للقراءة وهذا الملف هو ماسيكون في بارمتر الدالة الاول .
ثم اذا سار كل شيء على مايرام .. اغلق الملف .. وانتهى الامر .
طبعا نحن هنا سنتفتح صورة ما ... وذلك تمهيدا للقراءة من تلك الصورة .
4- السطر العاشر اعلنا عن تركيب جديد من نوع AUX_RGBImageRec .. صيغته :
typedef struct _AUX_RGBImageRec {
GLint sizeX, sizeY;
unsigned char *data;
} AUX_RGBImageRec;
اذا التركيب مكون من طول وعرض وبيانات الصورة التي نريد ان نفتحها .. عندما نقرأ الصورة بعد قليل سيتم تخزين البيانات الثلاث (الطول والعرض والمحتوى) في هذا التركيب ..
5- السطر الثاني عشر حملنا الصورة .... عن طريق الدالة auxDIBImageLoad هذه الدالة تطلب بارمتر واحد هو الصورة التي نريد فتحها .. طبعا سنمرره بعد قليل .
وتعيد هذه الدالة قيمة تمثل تركيب من نوع AUX_RGBImageRec بالتالي محتوى الصورة المفتوحة وطولها وعرضها سينتقلان الى تركيبنا " TextureImage" .. الان انتهينا من اول خطوة وهو فتح صورة من نوع BMP .
بالتالي
TextureImage->sizeX يمثل عرض الصورة
TextureImage->sizeYيمثل طول الصورة
TextureImage->data يمثل محتوى او بيانات تلك الصورة
ننتقل الى الخطو التالية وهي تعيين الصورة التي فتحناها كاكساء .
/*21*/ glGenTextures(1, ID);
/*22*/ glBindTexture(GL_TEXTURE_2D, *ID);
/*23*/ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
/*24*/ glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
/*25*/ glTexImage2D(GL_TEXTURE_2D, 0, 3, TextureImage->sizeX, TextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, TextureImage->data);
/*26*/ free(TextureImage->data);
/*27*/ free(TextureImage);
/*28*/ }
1- في السطر الواحد والعشرين نقول لـ opengl احجز لنا موقعا لاكساء واحد نريد ان نستخدمه (glGenTextures)
حيث البارمتر الاول عدد الاكساءات التي تريد .. وهنا نريد اكساء واحد .
البارمتر الثاني عنوان المتغير الذي سيحمل هذا الاكساء ...
2- في السطر الثاني والعشرين .. نعمل للمتغير الذي يحمل الاكساء Bind يعني أي عملية تالية ستؤثر على هذا الاكساء ..
نوضح اكثر .. لنفرض عندنا اكسائين ..
glGenTextures(1, ID);
glGenTextures(1, ID2);
الان نريد التعديل على الاكساء الاول :
glBindTexture(GL_TEXTURE_2D, *ID);
.
.
.
الان نريد التعديل على الاكساء الثاني :
glBindTexture(GL_TEXTURE_2D, *ID2);
بالنسبة للبارمتر الاول دائما نضعه GL_TEXTURE_2D افضل .. واسهل
3- السطر الثالث والعشرين والرابع والعشرين نعين فلاتر الاكساء ... بصراحة الطريقة صعبة وعقيمة ..
بالعربي
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
اكساء ليس بدقة عالية .
اما
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
اكساء بدقة عالية ..
4- السطر الخامس والعشرين .. glTexImage2D تضع بيانات الصورة التي حملناها في المتغير ID .
بالبتالي المتغير ID صار يحمل بيانات تلك الصورة ... ومتوافق مع opengl وبالتالب احاجة لنا بالتركيب TextureImage
اذا /
نفرغه من الذاكرة
free(TextureImage->data);
free(TextureImage);
تفصيل اكثر حول glTexImage2D
هذه الدالة تطلب معلومات عن الصورة . طولها وعرضها ومحتواها الخ ..
وبالتالي نستطيع استخدام هذه الصورة كاكساء .
صيغتها :
glTexImage2D (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels);
******
البارمتر الاول دائما :GL_TEXTURE_2D ..
البارمتر الثاني دائما صفر ( هذا خاص بالاكساء السمى MIPMAPPING ,, سنعرفه لاحقا ) ,
البارمتر الثالث : عدد قنوات الالوان .. عندنا اربع قنوات RED و GREEN و BLUE و ALPHA .
اذا كتبنا " 1 " يعني red فقط .. اذا كتبنا 2 ,,يعني red , alpha واذا كتبت " 3 " يعني RGB .. واذا كتبنا 4 يعنيRGBA
مو مهم شرحها الان
البارمتر الرابع والخامس .. عرض وارتفاع الصورة .
البارمتر السادس : حدود الصورة .. دائما نضع صفر .
البارمتر السابع : يأخذ احد القيم التالية :
GL_COLOR_INDEX
GL_STENCIL_INDEX
GL_DEPTH_COMPONENT
GL_RED
GL_GREEN
GL_BLUE
GL_ALPHA
GL_RGB
GL_RGBA
GL_LUMINANCE
GL_LUMINANCE_ALPHA
ضع GL_RGB .. حيث نريد استخدام ثلاث قنوات .. حيث هذا هو تنسيق الصورة .
البارمتر الثامن البيانات التي تريد تحميلها من أي نوع ؟ .. هنا من نوع GL_UNSIGNED_BYTE ..
حيث ان TextureImage->data من نوع unsigned char .
بهذا انهينا نصف المشوار ...
لكن لن يعلم تطبيقنا عن دالة الاكساء شيء ..
بعد ان تنشئ النافذة .. وتضع اعدادات opengl ... اضف هذا السطر . .الى الاعدادات
glEnable(GL_TEXTURE_2D);
LoadTexture("image.bmp" ,&D_1)
فعلنا الاكساء .. ثم استدعينا الدالة التي انشاناها قبل قليل ..
الان ID_1 يحمل الصورة ..image.bmp
في دالة الرسم render ..
/*1*/ void Render()
/*2*/ {
/*3*/ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
/*4*/ glLoadIdentity();
/*5*/ glTranslatef(-1.0f,0, -3.0f );
/*6*/ glBindTexture(GL_TEXTURE_2D, ID_1);
/*7*/ glBegin(GL_QUADS);////
/*8*/ glTexCoord2f(0.0f, 0.0f);
/*9*/ glVertex2f(-0.5f, -0.5f );
/*10*/ glTexCoord2f(1.0f, 0.0f);
/*11*/ glVertex2f( 0.5f, -0.5f );
/*12*/ glTexCoord2f(1.0f, 1.0f);
/*13*/ glVertex2f( 0.5f, 0.5f );
/*14*/ glTexCoord2f(0.0f, 1.0f);
/*15*/ glVertex2f(-0.5f, 0.5f );
/*16*/ glEnd();
/*17*/ }
السطر السادس قمنا باختيار المتغير الذي يحمل قيمة الاكساء تمهيدا لوضعه على المجسم ..
الدالة glTexCoord2f تحدد احداثيات الاكساء لجسم ..
سنتحدث عن احداثيات الاكساء في جلسة مقبلة ... ان شاء الله .
الخلاصة : 1- نحمل الصورة التي نريد .. ويهمنا ثلاث معلومات .. الطول والعرض ومحتوى الصورة..
2- نعد الاكساء ونعين خصائصه .
3- نفعل الاكساء ثم نعين احداثياته .
4- يجب ان تكون ابعاد الصورة .. 2*2 او 4*4 او 8*8 او 16*16 او 32*32 او 64*64 او 128 *128 الخ .. يعني (2^n)
ولكن احيانا نزيد 2 بيكسل للصورة وذلك كحدود .. فتصبح مثلا 66*66 .
المرفقات ,,,
ملف مرفق(ملفات)