فهميدن نحوه عملکرد texture map فوايد زيادي دارد . فرض کنيد مي خواهيد يک
سفينه يا يک موشک يا هر جسمي را روي صفحه به حرکت درآوريد . تا قبل از اين درس براي
انجام اين کار بايستي اين جسم را به کمک چند ضلعي ها و رنگ آميزي آنها رسم کنيم .
با texture map شما مي توانيد يک تصوير واقعي از
يک موشک را بگيريد و آنرا در صفحه حرکت دهيد . به نظر شما کدام روش بهتر است ؟
يک عکس يا يک شيء که با مثلث و مربع رسم شده است ؟ با texture map نه تنها تصوير نهايي بهتر
خواهد شد ، بلکه برنامه شما سريع تر اجرا خواهد شد . ( اين تيکه رو قبول ندارم هر
چند ...) يک موشک texture map شده يک مربع است که
در صفحه حرکت مي کند . يک موشک که با چند ضلعي ها رسم شده باشد ، از صدها و يا
هزاران چند ضلعي تشکيل شده است . يک مربعي که تنها texture map شده است پروسس کمتري مي گيرد و
منابع کمتري از سيستم مصرف مي کند . | ||
procedure glGenTextures(n: GLsizei; var textures: GLuint); stdcall; external Opengl32; | // ( NEW ) |
| procedure glBindTexture(target: GLenum; texture: GLuint); stdcall; external opengl32; | // ( NEW ) |
| var | |
| h_RC: HGLRC; | // Permanent Rendering Context |
| h_DC: HDC; | // Private GDI Device Context |
| keys: array [0..255] of BOOL; | // Array Used For The Keyboard Routine |
| xrot: GLfloat; | // X Rotation( NEW ) |
| yrot: GLfloat; | // Y Rotation( NEW ) |
| zrot: GLfloat; | // Z Rotation( NEW ) |
| texture: array [0..0] of GLuint; | // Storage For One Texture ( NEW ) |
حالا بلافاضله تابع مربوط به بارگزاري و اجراي الگو را مي نويسيم . کار اين بخش از کد بارگزاري يک فايل تصويري (Bitmap) است . اگر فايل وجود نداشته باشد ، از برنامه خارج خواهيم شد . قبل از اينکه شروع به کد نويسي کنيم چند مورد بسيار مهم وجود دارد که در رابطه با فايلهاي تصويريي که قرار است به عنوان الگو بکار بروند بايد بدانيد . نخست اينکه طول و عرض آنها بايد تواني از 2 باشد .
بايد حداقل 64 پيکسل داشته باشند و براي سازگاري بيشتر نبايد بيش از 256 رنگ داشته باشند . اگر تصوير شما داراي 64 ، 128 يا 256 پيکسل نيست ، با يک برنامه مخصوص
اينکار ( مثل Photoshop ) اندازه آن را درست کنيد .
راههاي مختلفي براي کنار گذاردن اين محدوديت وجود دارد ، ولي فعلاٌ با اندازه هاي
استاندارد الگوها کار مي کنيم . | ||
| procedure LoadGLTextures; | // Load Bitmaps And Convert To Textures |
| var | |
| texture1: TAUX_RGBImageRec; | |
| begin | |
| texture1 := auxDIBImageLoadA('Data/nehe.bmp'); | // Load Texture |
| if (not Assigned(texture1)) then | |
| Halt(1); |
حالا وقتي ما
تصوير را بارگزاري کرديم ، بايد يک الگو براي آن بسازيم . خط اول يعني
glGenTextures(1, texture[0])
به OpenGL مي گويد که ما مي
خواهيم يک نام براي الگوي ما بسازد . ( اگر تعداد بيشتري الگو را بارگزاري کرده ايد ، مقدار 1 را بيشتر کنيد ) . به ياد داشته باشيد که در ابتداي اين کد ما فضايي را براي يک الگو دخيره کرديم . | ||
| glGenTextures(1, texture[0]); | // Create The Texture |
| glBindTexture(GL_TEXTURE_2D, texture[0]); | // Typical Texture Generation Using Data From The Bitmap |
دو خط بعدي به OpenGLمي گويند که اگر تصوير بزرگتر از صفحه بود GL_TEXTURE_MAG_FILTER يا وقتي که کوچکتر بود GL_TEXTURE_MIN_FILTER از چه روشي براي فيلترينگ استفاده کند . من معمولاٌ از GL_LINEAR استفاده مي کنم . اينکار باعث مي شود تصوير بهتري بدست بيايد . و البته منابع بيشتري از cpu و کارت گرافيک شما مصرف مي کند . در مقابل GL_NEAREST منابع کمتري مصرف مي کند ولي مثلاً وقتي تصوير تغيير اندازه داده مي شود آنرا به صورت مربع مربع خواهيد ديد . البته شما مي توانيد ترکيبي از اين دو را بکار ببريد و نتيجه را ببينيد . | ||
| glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); | // Linear Filtering |
| glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); | // Linear Filtering |
در خط بعدي به OpenGLمي گوييم که يک الگوي واقعي را براي ما بسازد . اين خط به OpenGL مي گويد که اين الگو ، يک الگوي دو بعدي خواهد بودي . عدد صفر نمايانگر مشخصات تصوير است که معمولا صفر است . عدد سه معرف تعداد اجزاي تشکيل دهنده تصوير خواهد بود . چون تصوير ما از سه رنگ فرمز ، سبز و آبي تشکيل شده است ، پس تصوير ما از سه جزء تشکيل شده است . texture1^.sizeX عرض تصوير است . اگر عرض تصوير را مي دانيد عدد آنرا در اين قسمت قرار دهيد ولي آسانترين راه اين است که از اين روش استفاده کنيد تا اگر عرض ( و يا ارتفاع ) تصوير تغيير کرد نيازي به تغيير کد برنامه تان نباشد . texture1^.sizeY هم که ارتفاع تصوير است . صفر اندازه قاب يا حاشيه تصوير است . که معمولا صفر باقي مي ماند . GL_RGB به OpenGL مي گويد که اطلاعات تصوير کا از قرمز ، سبز و آبي به ترتيبي که نام برده شدند ، تشکيل شده است . GL_UNSIGNED_BYTE هم بدين معني است که اطلاعات تشکيل دهنده فايل تصويري ما از نوع بايت و بدون علامت هستند و در آخر هم texture1^.data به OpenGL مي گويد که اطلاعات الگو را از کجا دريافت کند . که در اينجا به محلي درون texture1 اشاره مي کند که اطلاعات تصوير بارگزاري شده در آن محل ذخيره شده بود . | ||
| glTexImage2D(GL_TEXTURE_2D, 0, 3, texture1^.sizeX, texture1^.sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1^.data); | // Generate The Texture |
| end; |
حالا بايد چند خطي را هم به روال InitGL اضافه کنيم . من تمام اين روال را اينجا دوباره مي آورم تا به راحتي خطوطي که اضافه شده اند و مکان اضافه شدن آنها قابل تشخيص باشد . اولين خط روال LoadGLTextures را صدا مي زند تا الگو بارگزاري و ساخته شود . سپس الگوي دوبعدي فعال مي شود . اگر اين کار را نکنيد اجسام شما سفيد نمايش داده خواهند شد که مطمئناً نمايش خوبي نخواهد بود . | ||
| procedure InitGL(Width: GLsizei; Height: GLsizei); | // All Setup For OpenGL Goes Here |
| var | |
| fWidth, fHeight: GLfloat; | |
| begin | |
| LoadGLTextures(); | // Load The Texture(s) |
| glEnable(GL_TEXTURE_2D); | // Enable Texture Mapping |
| glClearColor(0.0, 0.0, 1.0, 0.0); | // Clear The Background Color To Blue |
| glClearDepth(1.0); | // Enables Clearing Of The Depth Buffer |
| glDepthFunc(GL_LESS); | // The Type Of Depth Test To Do |
| glEnable(GL_DEPTH_TEST); | // Enables Depth Testing |
| glShadeModel(GL_SMOOTH); | // Enables Smooth Color Shading |
| glMatrixMode(GL_PROJECTION); | |
| glLoadIdentity(); | // Reset The Projection Matrix |
| fWidth := Width; | |
| fHeight := Height; | |
| gluPerspective(45.0,fWidth/fHeight,0.1,100.0); | // Calculate The Aspect Ratio Of The Window |
| glMatrixMode(GL_MODELVIEW); | |
| end; |
حالا ما مکعب را با الگو رسم مي کنيم . شما مي توانيد کد روال DrawGLScene را با کد زير
تعويض کنيد يا مي توانيد کدهاي اضافه شده را به متن اصلي مه در درس يک نوشته بوديم
اضافه کنيد . اين قسمت را به طور کامل شرح خواهيم داد تا فهميدن منظور آن راحتتر شود . | ||
| procedure DrawGLScene(); | |
| begin | |
| glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT); | // Clear The Screen And The Depth Buffer |
| glLoadIdentity(); | // Reset The View |
| glTranslatef(0.0,0.0,-5.0); |
در سه خط بعدي مکعب در محورهاي x و y و z چرخانده مي شود . مقدار اين چرخش به مقدار متغيرهاي xrot و yrot و zrot بستگي دارد . | ||
| glRotatef(xrot,1.0,0.0,0.0); | |
| glRotatef(yrot,0.0,1.0,0.0); | |
| glRotatef(zrot,0.0,0.0,1.0); |
در خط بعدي ما الگوي مورد نظر خود را انتخاب مي کنيم . اگر تعداد الگوهاي بيشتري را داشتيد مي توانيد به جاي عدد 0 از عدد مورد نظر خود براي استفاده از آن الگو استفاده کنيد . اگر بخواهيد از الگوي ديگري استفاده کنيد بايد آنرا انتخاب کنيد . چيزي که بايد به خاطر داشته باشيد آن است که شما نمي توانيد الگوي خود را بين دستورات glBegin و glEnd عوض کنيد . يعني اين کار بايد قبل ازglBegin و يا بعد از دستور glEnd انجام شود . | ||
| glBindTexture(GL_TEXTURE_2D, texture[0]); | // Select Our Texture |
براي اينکه يک مربع به طور صحيح با يک الگو پر شود بايد به خاطر داشته باشيد که بالا سمت راست الگو با قسمت
بالا سمت راست يک مربع تنظيم شده سپس بالا سمت چپ الگو با بالا سمت چپ مربع ، سپس
پايين سمت راست و در نهايت پايين سمت چپ آنها با هم منطبق مي شوند . اگر اندازه
الگو با مربع يکي نباشد ممکن است از کناره يا از بالاي مربع بيرون بزند و يا مربع را به طور کامل پر نکند . | ||
| glBegin(GL_QUADS); | |
| // Front Face | |
| glNormal3f( 0.0, 0.0, 1.0); | /// Normal Pointing Towards Viewer |
| glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); | // Bottom Left Of The Texture and Quad |
| glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); | // Bottom Right Of The Texture and Quad |
| glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); | // Top Right Of The Texture and Quad |
| glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); | // Top Left Of The Texture and Quad |
| // Back Face | |
| glNormal3f( 0.0, 0.0,-1.0); | |
| glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); | // Bottom Right Of The Texture and Quad |
| glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); | // Top Right Of The Texture and Quad |
| glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); | // Top Left Of The Texture and Quad |
| glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); | // Bottom Left Of The Texture and Quad |
| // Top Face | |
| glNormal3f( 0.0, 1.0, 0.0); | |
| glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); | // Top Left Of The Texture and Quad |
| glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, 1.0, 1.0); | // Bottom Left Of The Texture and Quad |
| glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, 1.0, 1.0); | // Bottom Right Of The Texture and Quad |
| glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); | // Top Right Of The Texture and Quad |
| // Bottom Face | |
| glNormal3f( 0.0,-1.0, 0.0); | |
| glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, -1.0, -1.0); | // Top Right Of The Texture and Quad |
| glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, -1.0, -1.0); | // Top Left Of The Texture and Quad |
| glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); | // Bottom Left Of The Texture and Quad |
| glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); | // Bottom Right Of The Texture and Quad |
| // Right face | |
| glNormal3f( 1.0, 0.0, 0.0); | |
| glTexCoord2f(1.0, 0.0); glVertex3f( 1.0, -1.0, -1.0); | // Bottom Right Of The Texture and Quad |
| glTexCoord2f(1.0, 1.0); glVertex3f( 1.0, 1.0, -1.0); | // Top Right Of The Texture and Quad |
| glTexCoord2f(0.0, 1.0); glVertex3f( 1.0, 1.0, 1.0); | // Top Left Of The Texture and Quad |
| glTexCoord2f(0.0, 0.0); glVertex3f( 1.0, -1.0, 1.0); | // Bottom Left Of The Texture and Quad |
| // Left Face | |
| glNormal3f(-1.0, 0.0, 0.0); | |
| glTexCoord2f(0.0, 0.0); glVertex3f(-1.0, -1.0, -1.0); | // Bottom Left Of The Texture and Quad |
| glTexCoord2f(1.0, 0.0); glVertex3f(-1.0, -1.0, 1.0); | // Bottom Right Of The Texture and Quad |
| glTexCoord2f(1.0, 1.0); glVertex3f(-1.0, 1.0, 1.0); | // Top Right Of The Texture and Quad |
| glTexCoord2f(0.0, 1.0); glVertex3f(-1.0, 1.0, -1.0); | // Top Left Of The Texture and Quad |
| glEnd(); |
حالا ما مقادير xrot و yrot و zrot را تغيير مي دهيم تا مکعب ما بچرخد . سعي کنيد مقادير را کم و زياد کنيد تا سرعت چرخش مکعب در آن راستا کم و يا زياد شود و يا مقادير را تغيير علامت دهيد تا تغيير جهت چرخش مکعب را ببينيد . | ||
| xrot := xrot + 0.3; | // X Axis Rotation |
| yrot := yrot + 0.2; | // Y Axis Rotation |
| zrot := zrot + 0.4; | // Z Axis Rotation |
| end; |
حالا شما درک بهتري از
texture map داريد . شما با texture map مي توانيد سطح هر مربعي
را با هر تصويري که بخواهيد بپوشانيد . وقتي احساس کرديد که با مفهوم texture map دوبعدي مشگلي نداريد سعي
کنيد که هر وجه از شش وجه مکعب را با يک تصوير بپوشانيد . | ||
| دريافت ليست دلفي نوشته شده توسط Brad Choate
| ||
|
درس هفتم -> |
<- درس پنجم | |