美文网首页
修饰点线面

修饰点线面

作者: simulationer | 来源:发表于2016-11-11 22:48 被阅读29次

我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处。例如:点太小,难以看清楚;直线也太细,不舒服;或者想画虚线,但不知道方法只能用许多短直线,甚至用点组合而成。

这些问题将在本节被解决。下面就点、直线、多边形分别讨论。

设置点的大小

点的大小默认为1个像素,但也可以改变之。改变的命令为glPointSize,其函数原型如下:

void glPointSize(GLfloat size);

size必须大于0.0f,默认值为1.0f,单位为“像素”。

注意:对于具体的OpenGL实现,点的大小都有个限度的,如果设置的size超过最大值,则设置可能会有问题。

下面的例子中点的大小被设置为5个像素。

void myDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glPointSize(5.0f);
    glBegin(GL_POINTS);
    glVertex2f(0.0f, 0.0f);
    glVertex2f(0.5f, 0.5f);
    glEnd();
    glFlush();
}

修饰线段

宽度

直线可以指定宽度。

void glLineWidth(GLfloat width);

用法与glPointSize类似。

画虚线

首先,使用glEnable(GL_LINE_STIPPLE)来启动虚线模式(使用glDisable(GL_LINE_STIPPLE)可以关闭之)。

然后,使用glLineStipple来设置虚线的样式。

void glLineStipple(GLint factor, GLushort pattern);

pattern是由1和0组成的长度为16的序列,从最低位开始看,如果为1,则直线上接下来应该画的factor个点将被画为实的;如果为0,则直线上接下来应该画的factor个点将被画为虚的。

以下是一些例子:

绘制一些虚线

具体代码如下。

void myDisplay(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glEnable(GL_LINE_STIPPLE);
    glTranslatef(0.0f, -0.5f, 0.0f);
    glLineStipple(4, 0x0F0F);
    glLineWidth(3.0f);
    glBegin(GL_LINES);
    glVertex2f(-0.8f, 0.0f);
    glVertex2f(0.8f, 0.0f);
    glEnd();
        ..........
    glTranslatef(0.0f, 0.1f, 0.0f);
    glLineStipple(1, 0xfcac);
    glBegin(GL_LINES);
    glVertex2f(-0.8f, 0.0f);
    glVertex2f(0.8f, 0.0f);
    glEnd();
    glFlush();
}

多边形

多边形的内容较多,我们将讲述以下四个方面。

多边形的两面以及绘制方式

虽然我们目前还没有真正的使用三维坐标来画图,但是建立一些三维的概念还是必要的。

从三维的角度来看,一个多边形具有两个面。每一个面都可以设置不同的绘制方式:填充只绘制边缘轮廓线只绘制顶点,其中“填充”是默认的方式。可以为两个面分别设置不同的方式。

//设置正面为填充方式
glPolygonMode(GL_FRONT, GL_FILL);
//设置反面为边缘绘制方式
glPolygonMode(GL_BACK, GL_LINE);
//设置两面均为顶点绘制方式
glPolygonMode(GL_FRONT_AND_BACK, GL_POINT); 

** 反转 **

一般约定为“顶点以逆时针顺序出现在屏幕上的面”为“正面”,另一个面即成为“反面”。生活中常见的物体表面,通常都可以用这样的“正面”和“反面”,“合理的”被表现出来(请找一个比较透明的矿泉水瓶子,在正对你的一面沿逆时针画一个圆,并标明画的方向,然后将背面转为正面,画一个类似的圆,体会一下“正面”和“反面”。你会发现正对你的方向,瓶的外侧是正面,而背对你的方向,瓶的内侧才是正面。正对你的内侧和背对你的外侧则是反面。这样一来,同样属于“瓶的外侧”这个表面,但某些地方算是正面,某些地方却算是反面了)。

但也有一些表面比较特殊。例如“麦比乌斯带”(把一根纸条扭转180°后,两头再粘接起来做成的纸带圈,具有魔术般的性质。普通纸带具有两个面(即双侧曲面),一个正面,一个反面,两个面可以涂成不同的颜色;而这样的纸带只有一个面(即单侧曲面),一只小虫可以爬遍整个曲面而不必跨过它的边缘。这种纸带被称为“莫比乌斯带”(也就是说,它的曲面只有一个)),可以全部使用“正面”或全部使用“背面”来表示。

麦比乌斯带

可以通过glFrontFace函数来交换“正面”和“反面”的概念。

glFrontFace(GL_CCW); // 设置CCW方向为“正面”,CCWCounterClockWise,逆时针

glFrontFace(GL_CW); // 设置CW方向为“正面”,CWClockWise,顺时针

下面是一个示例程序,将glFrontFace(GL_CCW)修改为glFrontFace(GL_CW),观察结果的变化。

面的正反面
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.0f, 0.0f);
    glVertex2f(-0.5f, 0.0f);
    glEnd();

    glBegin(GL_POLYGON);  // 按顺时针绘制一个正方形,在右上方
    glVertex2f(0.0f, 0.0f);
    glVertex2f(0.0f, 0.5f);
    glVertex2f(0.5f, 0.5f);
    glVertex2f(0.5f, 0.0f);
    glEnd();

    glFlush();
}

**剔除多边形表面 **

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

首先,使用glEnable(GL_CULL_FACE);来启动剔除功能(使用glDisable(GL_CULL_FACE)可以关闭之)。然后,使用glCullFace来进行剔除。

glCullFace的参数可以是GL_FRONTGL_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] =
{
    0x00, 0x00, 0x00, 0x00,    //   这是最下面的一行
    0x00, 0x00, 0x00, 0x00,
    0x03, 0x80, 0x01, 0xC0,    //   麻
    0x06, 0xC0, 0x03, 0x60,    //   烦
    0x04, 0x60, 0x06, 0x20,    //   的
    0x04, 0x30, 0x0C, 0x20,    //   初
    0x04, 0x18, 0x18, 0x20,    //   始
    0x04, 0x0C, 0x30, 0x20,    //   化
    0x04, 0x06, 0x60, 0x20,    //   ,
    0x44, 0x03, 0xC0, 0x22,    //   不
    0x44, 0x01, 0x80, 0x22,    //   建
    0x44, 0x01, 0x80, 0x22,    //   议
    0x44, 0x01, 0x80, 0x22,    //   使
    0x44, 0x01, 0x80, 0x22,    //   用
    0x44, 0x01, 0x80, 0x22,
    0x44, 0x01, 0x80, 0x22,
    0x66, 0x01, 0x80, 0x66,
    0x33, 0x01, 0x80, 0xCC,
    0x19, 0x81, 0x81, 0x98,
    0x0C, 0xC1, 0x83, 0x30,
    0x07, 0xE1, 0x87, 0xE0,
    0x03, 0x3F, 0xFC, 0xC0,
    0x03, 0x31, 0x8C, 0xC0,
    0x03, 0x3F, 0xFC, 0xC0,
    0x06, 0x64, 0x26, 0x60,
    0x0C, 0xCC, 0x33, 0x30,
    0x18, 0xCC, 0x33, 0x18,
    0x10, 0xC4, 0x23, 0x08,
    0x10, 0x63, 0xC6, 0x08,
    0x10, 0x30, 0x0C, 0x08,
    0x10, 0x18, 0x18, 0x08,
    0x10, 0x00, 0x00, 0x08    // 这是最上面的一行
};

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

如果将这样的数据保存成图片,并用专门的工具进行编辑,显然会方便很多。下面介绍如何做到这一点。

首先,用Windows自带的画笔程序新建一副图片,取名为mask.bmp,注意保存时,应该选择“单色位图”。在“图象”->“属性”对话框中,设置图片的高度和宽度均为32。

用放大镜观察图片,并编辑之。黑色对应二进制0(镂空),白色对应二进制1(不镂空),编辑完毕后保存。

然后,就可以使用以下代码来获得这个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);

好的,现在请自己编辑一个图片作为mask,并用上述方法取得Mask数组,运行后观察效果。

绘制虚线时可以设置factor因子,但多边形的镂空无法设置factor因子。请用鼠标改变窗口的大小,观察镂空效果的变化情况。

多边形镂空
#include <stdio.h>
#include <stdlib.h>

void myDisplay(void)
{
    static GLubyte Mask[128];
    FILE *fp;
    errno_t err;
    err=fopen_s(&fp,"mask.bmp", "r");
    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.5f, 0.0f, 0.0f);   // 在左下方绘制一个有镂空效果的正方形
    glDisable(GL_POLYGON_STIPPLE);
    glRectf(0.0f, 0.0f, 0.5f, 0.5f);     // 在右上方绘制一个无镂空效果的正方形
    glFlush();
}

本节学习了绘制几何图形的一些细节。

  • 点可以设置大小。
  • 直线可以设置宽度;可以将直线画成虚线。
  • 多边形的两个面的绘制方法可以分别设置;在三维空间中,不可见的多边形可以被剔除;可以将填充多边形绘制成镂空的样式。

了解这些细节会使我们在一些图象绘制中更加得心应手。另外,把一些数据写到程序之外的文件中,并用专门的工具编辑之,有时可以显得更方便。

相关文章

  • 修饰点线面

    我们学习了如何绘制几何图形,但大家如果多写几个程序,就会发现其实还是有些郁闷之处。例如:点太小,难以看清楚;直线也...

  • C4D建模——编辑物体点线面

    编辑点线面

  • 产品思维8/30:单个勤奋的点,必须找到给他赋能的面

    关键词:点线面体 战略 选择 1 点线面体的战略选择非常重要。你再怎么优化产品、提升效率,一旦点线面体选错了,都是...

  • 产品思维学习笔记(二)

    机会判断:点线面体的判断 点线面体的选择非常重要。你再怎么优化产品、提升效率,一旦点线面体选错了,就会没有任何成效...

  • 产品入门之道04 机会判断

    点线面体 一个非常简洁的思考结构,叫 点线面体。 点线面体是曾鸣教授的理论,他在得到App的课程《智能商业20讲》...

  • 股票投资方法论

    之前写过一篇文章《点线面体概念与选择》,阐述了点线面体的概念。现在来说一下炒股与点线面体的关系。逻辑是这样的:体指...

  • 11.4日

    点线面 小事要点线面,大事更要点线面。拿下一个事儿,一定是先从一个点打开局面,突破到局部,最后赢得胜利。

  • 2019.3.25

    今天复习了上节课的点线面构成,运用点线面完成字母创作,让小朋友们用自己的姓来创作,现在小朋友们对点线面构成还处于刚...

  • 【坚持绘画72天】斑马路

    点线面的小作业

  • 开学第一课

    点线面块的表达

网友评论

      本文标题:修饰点线面

      本文链接:https://www.haomeiwen.com/subject/sxifpttx.html