第4课:OpenGL几何图原——多边形

来源:互联网 发布:网络尖兵设置 编辑:程序博客网 时间:2024/05/27 09:47
 看下面一个关于多边形的程序:     

#include<windows.h>      
#include 
<GL/glut.h>      

void myDisplay(void)      
{      
    glClear(GL_COLOR_BUFFER_BIT);      
    glPolygonMode(GL_FRONT, GL_FILL); 
// 设置正面为填充模式      
    glPolygonMode(GL_BACK, GL_LINE);  // 设置反面为线形模式      
    glFrontFace(GL_CCW);              // 设置逆时针方向为正面      
    glBegin(GL_POLYGON);              // 按逆时针绘制一个正方形,在左下方      
        glVertex2f(-0.5f-0.5f);      
        glVertex2f(
0.0f-0.5f);      
        glVertex2f(
0.0f0.0f);      
        glVertex2f(
-0.5f0.0f);      
    glEnd();      
    glBegin(GL_POLYGON);              
// 按顺时针绘制一个正方形,在右上方      
        glVertex2f(0.0f0.0f);      
        glVertex2f(
0.0f0.5f);      
        glVertex2f(
0.5f0.5f);      
        glVertex2f(
0.5f0.0f);      
    glEnd();      
    glFlush();      
}      

int main(int argc, char *argv[])      
{      
    glutInit(
&argc, argv);      
    glutInitDisplayMode(GLUT_RGB 
| GLUT_SINGLE);      
    glutInitWindowPosition(
100100);      
    glutInitWindowSize(
400400);      
    glutCreateWindow(
"画多边形(正面为填充模式,反面为线形模式)");      
    glutDisplayFunc(
&myDisplay);      
    glutMainLoop();      
    
return 0;      
}      
运行效果图如下:    
 
填充模式有如下几种:     
         填充模式                                  解释说明     
glPolygonMode(GL_FRONT, GL_FILL);                                       设置正面为填充方式     
glPolygonMode(GL_BACK, GL_LINE);                                         设置反面为边缘绘制方式     
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT);           设置两面均为顶点绘制方式     

例如, 我们将程序中如下句     
glPolygonMode(GL_FRONT, GL_FILL); // 设置正面为填充模式     
glPolygonMode(GL_BACK, GL_LINE);  // 设置反面为线形模式     
改为     
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 设置两面均为顶点绘制方式     
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); // 设置两面均为顶点绘制方式     

效果图如下:
      
可以通过glFrontFace函数来交换“正面”和“反面”的概念,如下:     

glFrontFace(GL_CCW);  // 设置CCW方向为“正面”,CCW即CounterClockWise,逆时针     
glFrontFace(GL_CW);   // 设置CW方向为“正面”,CW即ClockWise,顺时针     

若将程序中glFrontFace(GL_CCW);换成glFrontFace(GL_CW);则效果图如下:  
下面我想借用网络上的例子来说明一下自己的心得,其中部分文字来自网络。 

剔除多边形表面 

在三维空间中,一个多边形虽然有两个面,但我们无法看见背面的那些多边形,而一些多边形虽然是正面的,但被其他多边形所遮挡。如果将无法看见的多边形和可见的多边形同等对待,无疑会降低我们处理图形的效率。在这种时候,可以将不必要的面剔除。 

使用glEnable(GL_CULL_FACE);来启动剔除功能(使用glDisable(GL_CULL_FACE)可以关闭之) 

使用glCullFace来进行剔除。 

glCullFace的参数可以是GL_FRONT,GL_BACK或者GL_FRONT_AND_BACK,分别表示剔除正面、剔除反面、剔除正反两面的多边形。 

注意:剔除功能只影响多边形,而对点和直线无影响。例如,使用glCullFace(GL_FRONT_AND_BACK)后,所有的多边形都将被剔除,所以看见的就只有点和直线。 

镂空多边形 

这个可是很好玩的啊~~ 

直线可以被画成虚线,而多边形则可以进行镂空。 

首先,使用glEnable(GL_POLYGON_STIPPLE);来启动镂空模式(使用glDisable(GL_POLYGON_STIPPLE)可以关闭之)。 

然后,使用glPolygonStipple来设置镂空的样式。 
void glPolygonStipple(const GLubyte *mask); 
其中的参数mask指向一个长度为128字节的空间,它表示了一个32*32的矩形应该如何镂空。其中:第一个字节表示了最左下方的从左到右(也可以是从右到左,这个可以修改)8个像素是否镂空(1表示不镂空,显示该像素;0表示镂空,显示其后面的颜色),最后一个字节表示了最右上方的8个像素是否镂空。 

但是,如果我们直接定义这个mask数组,像这样: 
static GLubyte Mask[128=  
{  
    
0x000x000x000x00,   //  这是最下面的一行  
    0x000x000x000x00,  
    
0x030x800x010xC0,   //  麻  
    0x060xC00x030x60,   //  烦  
    0x040x600x060x20,   //  的  
    0x040x300x0C0x20,   //  初  
    0x040x180x180x20,   //  始  
    0x040x0C0x300x20,   //  化  
    0x040x060x600x20,   //  ,  
    0x440x030xC00x22,   //  不  
    0x440x010x800x22,   //  建  
    0x440x010x800x22,   //  议  
    0x440x010x800x22,   //  使  
    0x440x010x800x22,   //  用  
    0x440x010x800x22,  
    
0x440x010x800x22,  
    
0x660x010x800x66,  
    
0x330x010x800xCC,  
    
0x190x810x810x98,  
    
0x0C0xC10x830x30,  
    
0x070xE10x870xE0,  
    
0x030x3F0xFC0xC0,  
    
0x030x310x8C0xC0,  
    
0x030x3F0xFC0xC0,  
    
0x060x640x260x60,  
    
0x0C0xCC0x330x30,  
    
0x180xCC0x330x18,  
    
0x100xC40x230x08,  
    
0x100x630xC60x08,  
    
0x100x300x0C0x08,  
    
0x100x180x180x08,  
    
0x100x000x000x08   // 这是最上面的一行  
};  

这样一堆数据非常缺乏直观性,我们需要很费劲的去分析,才会发现它表示的竟然是一只苍蝇。 

我们看一看源程序及其运行效果图吧 : 

#include<windows.h>  
#include 
<GL/glut.h>  
void myDisplay(void)  
{  
    
static GLubyte Mask[128=  
{  
    
0x000x000x000x00,   //  这是最下面的一行  
    0x000x000x000x00,  
    
0x030x800x010xC0,   //  麻  
    0x060xC00x030x60,   //  烦  
    0x040x600x060x20,   //  的  
    0x040x300x0C0x20,   //  初  
    0x040x180x180x20,   //  始  
    0x040x0C0x300x20,   //  化  
    0x040x060x600x20,   //  ,  
    0x440x030xC00x22,   //  不  
    0x440x010x800x22,   //  建  
    0x440x010x800x22,   //  议  
    0x440x010x800x22,   //  使  
    0x440x010x800x22,   //  用  
    0x440x010x800x22,  
    
0x440x010x800x22,  
    
0x660x010x800x66,  
    
0x330x010x800xCC,  
    
0x190x810x810x98,  
    
0x0C0xC10x830x30,  
    
0x070xE10x870xE0,  
    
0x030x3F0xFC0xC0,  
    
0x030x310x8C0xC0,  
    
0x030x3F0xFC0xC0,  
    
0x060x640x260x60,  
    
0x0C0xCC0x330x30,  
    
0x180xCC0x330x18,  
    
0x100xC40x230x08,  
    
0x100x630xC60x08,  
    
0x100x300x0C0x08,  
    
0x100x180x180x08,  
    
0x100x000x000x08   // 这是最上面的一行  
};  
glClear(GL_COLOR_BUFFER_BIT);  
glEnable(GL_POLYGON_STIPPLE);  
    glPolygonStipple(Mask);  
    glRectf(
-0.5f-0.5f0.0f0.0f);  // 在左下方绘制一个有镂空效果的正方形  
    glDisable(GL_POLYGON_STIPPLE);  
    glRectf(
0.0f0.0f0.5f0.5f);    // 在右上方绘制一个无镂空效果的正方形  
    glFlush();  

}  

int main(int argc, char *argv[])  
{  
    glutInit(
&argc, argv);  
    glutInitDisplayMode(GLUT_RGB 
| GLUT_SINGLE);  
    glutInitWindowPosition(
100100);  
    glutInitWindowSize(
400400);  
    glutCreateWindow(
"画多边形(镂空)");  
    glutDisplayFunc(
&myDisplay);  
    glutMainLoop();  
    
return 0;  
}  

效果图是这样的: 
 
首先,用Windows自带的画笔程序新建一副图片,取名为mask.bmp,注意保存时,应该选择“单色位图”。在“图象”->“属性”对话框中,设置图片的高度和宽度均为32。 
用放大镜观察图片,并编辑之。黑色对应二进制零(镂空),白色对应二进制一(不镂空),编辑完毕后保存。 
然后,就可以使用以下代码来获得这个Mask数组了。 

static GLubyte Mask[128];  
FILE 
*fp;  
fp 
= fopen("mask.bmp""rb");  
if!fp )  
    exit(
0);  
// 移动文件指针到这个位置,使得再读sizeof(Mask)个字节就会遇到文件结束  
// 注意-(int)sizeof(Mask)虽然不是什么好的写法,但这里它确实是正确有效的  
// 如果直接写-sizeof(Mask)的话,因为sizeof取得的是一个无符号数,取负号会有问题  
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )  
    exit(
0);  
// 读取sizeof(Mask)个字节到Mask  
if!fread(Mask, sizeof(Mask), 1, fp) )  
    exit(
0);  
fclose(fp);  

[注意] 关于文件操作,可以查阅C语言程序设计相关图书。 

这里我在Mask.bmp上写了一个“易”字。 

看如下经过改进后的程序及其运行结果: 

#include<windows.h>  
#include 
<GL/glut.h>  
#include 
<stdio.h>  
#include 
<stdlib.h>  
void myDisplay(void)  
{  
    
static GLubyte Mask[128];  
    FILE 
*fp;  
    fp 
= fopen("D:/abc/Mask.bmp""rb");  
    
if!fp )  
        exit(
0);  
    
if( fseek(fp, -(int)sizeof(Mask), SEEK_END) )  
        exit(
0);  
    
if!fread(Mask, sizeof(Mask), 1, fp) )  
        exit(
0);  
    fclose(fp);  
    glClear(GL_COLOR_BUFFER_BIT);  
    glEnable(GL_POLYGON_STIPPLE);  
    glPolygonStipple(Mask);  
    glRectf(
-0.5f-0.5f0.0f0.0f);  // 在左下方绘制一个有镂空效果的正方形  
    glDisable(GL_POLYGON_STIPPLE);  
    glRectf(
0.0f0.0f0.5f0.5f);    // 在右上方绘制一个无镂空效果的正方形  
    glFlush();  
}  

int main(int argc, char *argv[])  
{  
    glutInit(
&argc, argv);  
    glutInitDisplayMode(GLUT_RGB 
| GLUT_SINGLE);  
    glutInitWindowPosition(
100100);  
    glutInitWindowSize(
400400);  
    glutCreateWindow(
"画多边形(镂空)");  
    glutDisplayFunc(
&myDisplay);  
    glutMainLoop();  
    
return 0;  
}  

运行效果如下: 
[注意] 

我的运行环境是VC++ 6.0。 

我在第一次运行时,这一句fp = fopen("D://abc//Mask.bmp", "rb");我用的是相对路径 fp = fopen("Mask.bmp", "rb");结果没有成功,但是在Micosoft Studio 2005中用相对路径应该可以实现的,所以绝对路径是一种选择。