【学习OpenGL】(三)——3D空间中的点与线

本文介绍了如何使用OpenGL在3D空间中绘制点和线的基本方法,包括设置绘图环境、控制旋转、调整视口等,并提供了完整的代码示例。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.3D空间中的点

#include <gl/glut.h>
#include <math.h>

#define GL_PI 3.1415f

static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;

void RenderScene(void)
{
    GLfloat x, y, z, angle; // 存储坐标和角度

    // 用当前颜色清除窗口
    glClear(GL_COLOR_BUFFER_BIT);

    // 保存矩阵状态并进行旋转
    glPushMatrix();
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);

    // 对所有剩余的点只调用一次
    glBegin(GL_POINTS);

    z = -50.0f;
    for(angle = 0.0f; angle <= (2.0*GL_PI)*3.0f; angle += 0.1f)
    {
        x = 50.0f*sin(angle);
        y = 50.0f*cos(angle);

        // 指定点并稍稍变化Z值
        glVertex3f(x, y, z);
        z += 0.5f;
    }

    glEnd();

    // 恢复变换
    glPopMatrix();

    // 刷新绘图命令
    glutSwapBuffers();
}

// 在渲染环境下进行初始化工作
void SetupRC()
{
    // 黑色背景
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);

    // 绘图颜色为绿色
    glColor3f(0.0f, 1.0f, 0.0f);
}

// 键盘箭头键控制旋转图形
void SpecialKeys(int key, int x, int y)
{
    if(key == GLUT_KEY_UP)
        xRot-= 5.0f;

    if(key == GLUT_KEY_DOWN) 
        xRot += 5.0f;

    if(key == GLUT_KEY_LEFT)
        yRot -= 5.0f;

    if(key == GLUT_KEY_RIGHT)
        yRot += 5.0f;

    if(key > 356.0f)
        xRot = 0.0f;

    if(key < -1.0f)
        xRot = 355.0f;

    if(key > 356.0f)
        yRot = 0.0f;

    if(key < -1.0f)
        yRot = 355.0f;

    // 刷新窗口
    glutPostRedisplay();
}

// 修改可视区域的视口,当窗口改变时被调用
void ChangeSize(int w, int h)
{
    GLfloat nRange = 100.0f;

    // 防止被0除
    if(h == 0)
        h = 1;

    // 将视口设置为窗口尺寸
    glViewport(0, 0, w, h);

    // 重置投影矩阵堆栈
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    //建立裁剪区(左,右,下,上,近,远)
    if (w <= h) 
        glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
    else 
        glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

    // 重置模型视图矩阵堆栈
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

void main()
{
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutCreateWindow("Points Example");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);
    SetupRC();
    glutMainLoop();
}

运行结果:
初始为一个由点组成的圆,这是因为从Z轴直接正面观察这张图。

这里写图片描述

通过键盘键上下左右键旋转这张图形:

这里写图片描述

设置3D画布

// 修改可视区域的视口,当窗口改变时被调用
void ChangeSize(int w, int h)
{
    GLfloat nRange = 100.0f;

    // 防止被0除
    if(h == 0)
        h = 1;

    // 将视口设置为窗口尺寸
    glViewport(0, 0, w, h);

    // 重置投影矩阵堆栈
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    //建立裁剪区(左,右,下,上,近,远)
    if (w <= h) 
        glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
    else 
        glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

    // 重置模型视图矩阵堆栈
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}

这里写图片描述

如图为一个简单的可视区域,这个可视区域包围的区域就是一个笛卡尔坐标空间。在所有的3个轴(X,Y和Z)中,它们的范围都是从-100至+100,这个区域就是三维画布,可以用OpenGL命令和函数在上面进行绘图。

3D空间中的点:顶点

glVertex3f(50.0f50.0f0.0f)

这行代码就描绘了一个X轴上为50个单位,Y轴上为50个单位,Z轴上为0个单位的三维空间中的点。
接受2个参数的glVertex2f函数,则只指定X与Y的值,而默认Z坐标为0.0。
接受4个参数的glVertex4f函数,使用第四个坐标值W用来表示缩放度(一般默认为1.0)。

图元

图元是一组顶点的集合,她们构成了在屏幕上所绘制的形状,如图所示,OpenGL共有10种图元,从空间中的一个点到任意数量边的闭合多边形。
这里写图片描述

绘制图元的方式是使用glBegin命令告诉OpenGL开始对一组顶点进行解释,把它作为一个特定的图元,然后调用glEnd命令结束组成这个图元的列表。

// 绘制点
glBegin(GL_POINTS);    // 选择点作为图元
        glVertex3f(0.0f0.0f0.0f);  // 指定点
        glVertex3f(0.0f0.0f0.0f)  ; 
glEnd( );       // 完成绘点

设置点的大小

当我们绘制一个点时,在默认情况下点的大小是一个像素,我们可以通过glPointSize函数修改点的大小。该函数接受一个参数,它用于指定被绘点的近似直径(以像素计),但是点的大小是存在限制的。可以通过以下代码实现:

GLfloat sizes[2];  // 存储受支持的点的大小范围
GLfloat step;  // 存储受支持的点的大小增量

// 获得受支持的点的大小范围以及增量大小
glGetFloatv(GL_POINT_SIZE_RANGE,sizes);
glGetFloatv(GL_POINT_SIZE_GRANULARITY,&step);

其中sizes数组将包含两个元素,分别表示glPointSize的最小和最大有效值,step表示点大小范围之内最小允许的步进值。

二. 3D空间中的线

#include <gl/glut.h>    
#include <math.h>


// 为PI的值定义一个常量
#define GL_PI 3.1415f

static GLfloat xRot = 0.0f;
static GLfloat yRot = 0.0f;


// Called to draw scene
void RenderScene(void)
    {
        GLfloat x,y,z,angle; // Storeage for coordinates and angles

    // Clear the window with current clearing color
    glClear(GL_COLOR_BUFFER_BIT);

    // Save matrix state and do the rotation
    glPushMatrix();
    glRotatef(xRot, 1.0f, 0.0f, 0.0f);
    glRotatef(yRot, 0.0f, 1.0f, 0.0f);

    // Call only once for all remaining points
    glBegin(GL_LINES);

    z = 0.0f;
    for(angle = 0.0f; angle <= GL_PI; angle += (GL_PI / 20.0f))
        {
        // Top half of the circle
        x = 50.0f*sin(angle);
        y = 50.0f*cos(angle);
        glVertex3f(x, y, z);

        // Bottom half of the circle
        x = 50.0f*sin(angle+GL_PI);
        y = 50.0f*cos(angle+GL_PI);
        glVertex3f(x, y, z);    
        }

    // Done drawing points
    glEnd();

    // Restore transformations
    glPopMatrix();

    // Flush drawing commands
    glutSwapBuffers();
    }

// This function does any needed initialization on the 
// rendering context. 
void SetupRC()
    {
    // Black background
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f );

    // Set drawing color to green
    glColor3f(0.0f, 1.0f, 0.0f);
    }

///////////////////////////////////////////////////////////
// Respond to arrow keys
void SpecialKeys(int key, int x, int y)
    {
    if(key == GLUT_KEY_UP)
        xRot-= 5.0f;

    if(key == GLUT_KEY_DOWN)
        xRot += 5.0f;

    if(key == GLUT_KEY_LEFT)
        yRot -= 5.0f;

    if(key == GLUT_KEY_RIGHT)
        yRot += 5.0f;

    if(key > 356.0f)
        xRot = 0.0f;

    if(key < -1.0f)
        xRot = 355.0f;

    if(key > 356.0f)
        yRot = 0.0f;

    if(key < -1.0f)
        yRot = 355.0f;

    // Refresh the Window
    glutPostRedisplay();
    }

///////////////////////////////////////////////////////////
// Window has changed size, recalculate projection
void ChangeSize(int w, int h)
    {
    GLfloat nRange = 100.0f;

    // Prevent a divide by zero
    if(h == 0)
        h = 1;

    // Set Viewport to window dimensions
    glViewport(0, 0, w, h);

    // Reset coordinate system
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    // Establish clipping volume (left, right, bottom, top, near, far)
    if (w <= h) 
        glOrtho (-nRange, nRange, -nRange*h/w, nRange*h/w, -nRange, nRange);
    else 
        glOrtho (-nRange*w/h, nRange*w/h, -nRange, nRange, -nRange, nRange);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    }

///////////////////////////////////////////////////////////
// Main Program Entry Point
void main()
{
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(800,600);
    glutCreateWindow("Lines Example");
    glutReshapeFunc(ChangeSize);
    glutSpecialFunc(SpecialKeys);
    glutDisplayFunc(RenderScene);
    SetupRC();
    glutMainLoop();
}

运行结果:

这里写图片描述

绘制直线

选择绘制直线的图元GL_LINES,指定两个顶点,在它们之间绘制一条直线。

glBegin(GL_LINES);    // 选择线作为图元
        glVertex3f(0.0f0.0f0.0f);  // 指定点
        glVertex3f(50.0f50.0f50.0f)   ; 
glEnd( );       // 完成绘线

注意,这里用两个顶点指定了一个图元,每两个指定的顶点用于绘制一条直线。如果指定奇数个顶点,那么最后一个顶点会被忽略。

线带与线环

GL_LINE_STRIP:线带,它允许指定一个顶点列表,并绘制一条经过所有这些顶点的连续的线。
GL_LINE_LOOP:线环,它与线带非常类似,会在顶点列表的最后一个顶点和第一个顶点之间也绘制一条直线。因此会形成一个闭合的图形。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值