OpenGl学习进程(9)在3D空间的绘制实例

    本节将演示在3D空间中绘制图形的几个简单实例:

    (1)在3D空间内绘制圆锥体:

#include <GL/glut.h>
#include <math.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
#define PI 3.1416
GLfloat xRot = 0;
GLfloat yRot = 0;
GLfloat zRot = 0;

void Init(void)
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glColor3f(1.0f, 1.0f, 0.0f);
    // 把着色模式设置为单调着色
    glShadeModel(GL_FLAT); //glShadeModel(GL_SMOOTH);
    // 把顺时针环绕的多边形设为正面,这与默认是相反的,因为我们使用的是三角形扇
    glFrontFace(GL_CW);
    glOrtho(-1.0f,1.0f,-1.0f,1.0f,-1.0f,1.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;

    if (key==GLUT_KEY_F1) //绕着z轴旋转
        zRot+= 5.0f;

    // 使用新的坐标重新绘制场景
    glutPostRedisplay();
}
void RenderScene()
{
    // 存储坐标和角度
    GLfloat x, y, z, angle,x1,y1;
    // 用于三角形颜色的交替设置
    int iPivot = 1;
    // 用默认颜色设置背景色,并清除深度缓冲区(必须的,因为3D空间有视景深度)
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    //打开剔除功能(背面剔除,它用于消除一个表面的背面)
    //glEnable(GL_CULL_FACE);
    // 打开深度测试,如果不打开深度测试,3D锥体的显示就会与现实情况不符合
    glEnable(GL_DEPTH_TEST);

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

    glBegin(GL_TRIANGLE_FAN);
    // 三角形扇的共享顶点,z轴中心点上方
    glVertex3f(0.0f,0.0f,0.75);
    for (angle = 0.0f; angle < (2.0f * PI + PI / 8.0f); angle += (PI / 8.0f)) {
        // 计算下一个顶点的位置
        x = 0.50f * sin(angle);
        y = 0.50f * cos(angle);
        if ((iPivot % 2) == 0) {
            glColor3f(1.0f, 1.0f, 0.0f);
        }
        else{
            glColor3f(0.0f, 1.0f, 1.0f);
        }
        // 增加基准值,下次改变颜色
        ++iPivot;
        // 指定三角形扇的下一个顶点
        glVertex2f(x, y);
    }
    glEnd();

    // 绘制一个新的三角形扇,作为覆盖圆锥的底
    glBegin(GL_TRIANGLE_FAN);
    // 三角形扇的共享顶点,中心位于原点
    glVertex3f(0.0f, 0.0f,0.0f);
    for (angle = 0.0f; angle < (2.0f * PI + PI / 8.0f); angle += (PI / 8.0f)) {
        // 计算下一个顶点的位置
        x = 0.50f * sin(angle);
        y = 0.50f * cos(angle);
        if ((iPivot % 2) == 0) {
            glColor3f(0.5f, 0.0f, 0.5f);
        }
        else{
            glColor3f(1.0f, 0.0f, 1.0f);
        }
        // 增加基准值,下次改变颜色
        ++iPivot;
        // 指定三角形扇的下一个顶点
        glVertex2f(x, y);
    }
    glEnd();
    glPopMatrix();
    glutSwapBuffers();
}
int main(int argv,char *argc[]){

    glutInit(&argv,argc);
    glutInitDisplayMode(GLUT_RGB|GLUT_DOUBLE);
    glutInitWindowSize(400,400);
    glutInitWindowPosition(400,300);
    glutCreateWindow("3D空间绘制圆锥面");
    glutDisplayFunc(RenderScene);
    glutSpecialFunc(SpecialKeys);
    Init();
    glutMainLoop();
}

按F1键绕z轴旋转,按方向键绕x轴或y轴旋转:

    (2)在3D空间中模拟地球环绕太阳旋转:

#include <GL/glut.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.1416
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")
static int year = 0;

void init(void)
{
    glClearColor(0.2, 0.2, 0.2, 1.0);
    glShadeModel(GL_FLAT);
}
void paintLoopPlant()
{
    GLfloat x, z; int i;
    glColor3f(0.0f,1.0f,0.5f);
    glLineWidth(2.0f);
    glBegin(GL_LINE_LOOP);
    for (i = 0; i < 1000;i++)
   {
        x = 0.35*sin(i * 2 * PI / 1000-PI);
        z = 0.35*cos(i * 2 * PI / 1000-PI);
        glVertex3f(x,0,z);
    }
    glEnd();

    glLineWidth(5.0f);
    glColor3f(0.5,0,0);
    glBegin(GL_LINE_LOOP);
    for (i = 0; i < 1000; i++)
    {
        x = 3.5*sin(i * 2 * PI / 1000)-3.5;
        z = 3.5*cos(i * 2 * PI / 1000);
        glVertex3f(x, 0, z);
    }
    glEnd();
}
void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
    glColor3f(1, 0.0, 0.0);//设置太阳的颜色
    glPushMatrix();
    glPointSize(1.0f);
    //在坐标系中央画太阳
    glutWireSphere(0.8, 1000, 1000);
    //给太阳进平移
    glRotatef((GLfloat)year, 0.0, 1.0, 0.0);
    glTranslatef(3.5, 0.0, 0.0);
    //画地球
    glColor3f(0, 0.2, 1.0);
    glutWireSphere(0.15, 100, 80);
    paintLoopPlant();

    glPopMatrix();
    glutSwapBuffers();
}
void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(0.0, 6.0, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
    case ‘y‘:
        year = (year + 5) % 360;
        break;
    case ‘Y‘:
        year = (year - 5) % 360;
        break;
    case 27:
        exit(0);
        break;
    default:
        break;
    }
    glutPostRedisplay();
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowSize(500, 500);
    glutInitWindowPosition(300, 100);
    glutCreateWindow("RotateAroundSun");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutMainLoop();

    return 0;
}

    (3)在3D空间用OpenGL自带的库函数绘制立方体:

#include <GL/glut.h>
#pragma comment(linker,"/subsystem:\"windows\" /entry:\"mainCRTStartup\"")

GLfloat yRot = 0;

//用来画一个坐标轴的函数
void axis(double length)
{
    glColor3f(1.0f, 1.0f, 1.0f);
    glPushMatrix();
    glBegin(GL_LINES);
    glVertex3d(0.0, 0.0, 0.0);
    glVertex3d(0.0, 0.0, length);
    glEnd();
    //将当前操作点移到指定位置
    glTranslated(0.0, 0.0, length - 0.2);
    glColor3f(1.0, 0.0, 0.0);
    glutWireCone(0.04, 0.3, 8, 8);
    glPopMatrix();
}
void paint(void)
{
    glClear(GL_COLOR_BUFFER_BIT);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();

    glOrtho(-2.0, 2.0, -2.0, 2.0, -100, 100);
    glPointSize(1);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(1.3, 1.6, 2.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

    //画坐标系
    axis(2);

    glPushMatrix();
    glRotated(90.0, 0, 1.0, 0);//绕y轴正方向旋转90度
    axis(2);
    glPopMatrix();

    glPushMatrix();
    glRotated(-90.0, 1.0, 0.0, 0.0);//绕x轴负方向旋转
    axis(2);
    glPopMatrix();

    glPushMatrix();//旋转除坐标轴之外的物体
    glRotated(yRot, 0.0, yRot, 0.0);
    glPushMatrix();
    glColor3f(0.0f, 0.0f, 1.0f);
    glTranslated(0.125, 0.125, 0.125);
    glutWireCube(0.25);
    glPopMatrix();

    glPushMatrix();
    glTranslated(1.125,0.125,0.125);
    glutWireTeapot(0.25);
    glPopMatrix();

    glPushMatrix();
    glTranslated(0.125, 0.125, 1.125);
    glutWireSphere(0.25, 12, 8);
    glPopMatrix();

    glPushMatrix();
    glTranslated(1.125,0.125,1.125);
    glRotated(-90, 1.0, 0.0, 0.0);
    glutWireTorus(0.1, 0.25, 12, 12);
    glPopMatrix();

    glPushMatrix();
    glTranslated(0.125, 1.125, 0.125);
    glScaled(0.5*0.25, 0.5*0.25, 0.5*0.25);
    glRotated(-90, 0.0, 0.0, 1.0);
    glutWireDodecahedron();
    glPopMatrix();

    glPushMatrix();
    glTranslated(0.0, 1.0, 1.0);
    GLUquadricObj * quadricObj = gluNewQuadric();
    gluQuadricDrawStyle(quadricObj, GLU_LINE);
    gluCylinder(quadricObj, 0.2, 0.2, 0.3, 6, 6);
    glRotated(-90, 0.0, 0.0, 0.0);
    glPopMatrix();

    glPopMatrix();//用来整体绕y轴旋转
    glutSwapBuffers();
}
void Init()
{
    glClearColor(0.8,0.8,0.8,1.0);
}
void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    gluLookAt(1.3, 1.6, 5.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);
}
void SpecialKeys(int key, int x, int y)
{
    if (key == GLUT_KEY_LEFT)
        yRot -= 5.0f;

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

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

    if (key< -1.0f)
        yRot = 355.0f;
    glutPostRedisplay();
}
int main(int argv, char *argc[])
{
    glutInit(&argv, argc);
    glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
    glutInitWindowSize(400, 400);
    glutInitWindowPosition(400, 300);
    glutCreateWindow("3D空间绘制各种系统自带立方体");
    Init();
    glutDisplayFunc(paint);
    glutReshapeFunc(reshape);
    glutSpecialFunc(SpecialKeys);
    glutMainLoop();
}

在这个例子下按左右方向键也是可以让立方体绕y轴旋转的,在此不做演示。

    (4)相关知识:

1)OpenGL中的空间变换:(http://www.cnblogs.com/chengmin/archive/2011/09/12/2174004.html)

在使用OpenGL的三维虚拟程序中,当我们指定了模型的顶点之后,在屏幕上显示它们之前,一共会发生3种类型的变换:

视图变换、模型变换、投影变换。
1.视图变换:指定观察者(摄像机)的位置;
2.模型变换:在场景中移动物体;
3.投影变换:改变可视区域的大小;
视口变换:这是一种伪变换,它对窗口上的最终输出进行缩放。

1.视觉坐标:

  它表示一种虚拟的固定坐标系统,通常作为一种参考系使用。它是根据观察者(摄像机)的角度而言的,与可能发生的变换无关。我们接下来所讨论的所有变换都是根据它们相对于视觉坐标的效果进行描述的。

  用OpenGL在3D空间中进行绘图时,使用的是笛卡尔坐标系统。在不进行任何变换的情况下,这个坐标系统与视觉坐标系相同。

2.视图变换:

这是场景中所应用的第一个变换,它用于确定场景的观察点(拍摄点)。视图变换允许把观察点放在自己所希望的任何位置(观察点的位置任意),并允许在任何方向上观察场景(观察点的朝向任意)。确定视图变换就像在场景中放置照相机并让它指向某个方向。

  作为总体原则,在进行任何其他变换之前必须先指定视图变换。因为视图变换的效果相当于根据视觉坐标系统来移动当前所使用的坐标系统。然后,根据最新修改的坐标系统,进行其它所有的后续变换。

3.模型变换

  它可以移动物体,对它们进行旋转、平移或者缩放。并且,缩放可以是非一致的(物体的各个方向根据不同的数值进行伸缩)。 场景或物体的最终外观很大程度上取决于模型变换的应用顺序。因为每次变换都是在上次变换执行的基础上进行的。

4.投影变换:

  它是在模型视图变换之后应用于物体的顶点之上的。它实际上定义了可视区域,并建立了裁剪平面。其中,投影又有两种不同的类型:正投影(平行投影)和透视投影。正投影通常用于2D绘图,此时你所需要的是像素和绘图单位之间的准确对应。透视投影则用于渲染那些包含了需要应用透视缩短的物体的场景。并且在大多数情况下,3D图形所使用的都是透视投影。

下面是2D投影变换与3D透视投影变换的对比:

5.视口变换

  最终,场景的二维投影将被映射到屏幕上的某个窗口。这种到物理窗口坐标的映射是最后一个完成的变换,称为视口变换。

2)Win窗口坐标二维坐标与OpenGl的世界坐标:

1.Win的屏幕坐标的坐标系: 左上为坐标系原点,正右为X轴正方向, 正下方为Y轴正方向。视图类的窗口是这样的,如果是FrameWork的绘图区,则需要包含工具栏和状态栏的区域,二者是不一样的。

2.OpenGL中的屏幕坐标:以左下角为原点,正右方为x轴正方向,正上方为y轴正方向。

墨卡托坐标变换

      OPENGL-----3D到2D坐标变换 

      OPENGL-----3D到2D坐标变换

时间: 2024-08-15 01:52:24

OpenGl学习进程(9)在3D空间的绘制实例的相关文章

OpenGL学习进程(10)第七课:四边形绘制与动画基础

    本节是OpenGL学习的第七个课时,下面以四边形为例介绍绘制OpenGL动画的相关知识:     (1)绘制几种不同的四边形: 1)四边形(GL_QUADS) OpenGL的GL_QUADS图元用于绘制四边形,它根据每四个顶点绘制一个四边形. 注意:在使用四边形时必需记住四边形的四个角必须位于同一个平面中(不存在弯曲的四边形). 2)四边形带(GL_QUAD_STRIP) 该图元指定一个连接的四边形带.它们都保持相同方向的环绕. 3)通用多边形GL_POLYGON 我们可以用它绘制任意数

OpenGl学习进程(7)第五课:点、边和图形(二)边

本节是OpenGL学习的第五个课时,下面介绍OpenGL边的相关知识: (1)边的概念: 数学上的直线没有宽度,但OpenGL的直线则是有宽度的.同时,OpenGL的直线必须是有限长度,而不是像数学概念那样是无限的.可以认为,OpenGL的“直线”概念与数学上的“线段”接近,它可以由两个端点来确定.     (2)如何绘制边: 1)OpenGL支持绘制三种类型的边: GL_LINES :指定两个顶点,在它们之间绘制一条直线.如果为GL_LINES指定了奇数个顶点,那么最后一个顶点会被忽略. GL

OpenGl学习进程(8)第六课:点、边和图形(三)绘制图形

本节是OpenGL学习的第六个课时,下面介绍OpenGL图形的相关知识:     (1)多边形的概念: 多边形是由多条线段首尾相连而形成的闭合区域.OpenGL规定,一个多边形必须是一个“凸多边形”.通过点.直线和多边形,就可以组合成各种几何图形.一段弧可以看成是是很多短的直线段相连,这些直线段足够短,以至于其长度小于一个像素的宽度.通过位于不同平面的相连的小多边形,还可以组成一个“曲面”. 什么是凸边形: 凸边形:多边形内任意两点所确定的线段都在多边形内,由此也可以推导出,凸多边形不能是空心的

在3D空间中绘制四边形

在3D空间中绘制四边形 四边形 GL_QUADS OpenGL的GL_QUADS图元用于绘制四边形,它根据每四个顶点绘制一个四边形. 注意,在使用四边形时,必需记住一个重要规则:一个四边形的四个角必须位于同一个平面中(不存在弯曲的四边形).如图所示 四边形带 GL_QUAD_STRIP 该图元指定一个连接的四边形带.它们都保持相同方向的环绕.如图所示 通用多边形 GL_POLYGON 我们可以用它绘制任意数量的多边形.与四边形一样,多边形的所有顶点也必须位于同一平面中.如果想越过这个规则,可以采

OpenGL学习进程(11)第八课:颜色绘制的详解

    本节是OpenGL学习的第八个课时,下面将详细介绍OpenGL的颜色模式,颜色混合以及抗锯齿.     (1)颜色模式: OpenGL支持两种颜色模式:一种是RGBA,一种是颜色索引模式. RGBA模式与索引模式的区别: 计算机必须为每个像素保存一些数据,在RGBA模式中数据就代表了颜色:而颜色索引模式中数据代表了一个索引,要获取真正的颜色值还需要查索引表.数据的数量是由帧缓存中的位面决定的.一个位面为一个像素的一个位的数据.假如是8位面的颜色,每个像素就有8个颜色位,因此就有2的8次方

OpenGL学习进程(4)第二课:绘制图形

本节是OpenGL学习的第二个课时,下面介绍如何用点和线来绘制图形:     (1)用点的坐标来绘制矩形: #include <GL/glut.h> void display(void) { // clear all pixels glClear(GL_COLOR_BUFFER_BIT); // draw yellow polygon (rectangle) with corners at glColor3f(1.0, 1.0, 0.0); glBegin(GL_POLYGON); //绘制开

OpenGL学习进程(6)第四课:点、边和图形(一)点

本节是OpenGL学习的第四个课时,下面介绍OpenGL点的相关知识:     (1)点的概念:     数学上的点,只有位置,没有大小.但在计算机中,无论计算精度如何提高,始终不能表示一个无穷小的点.一般情况下,OpenGL中的点将被画成单个的像素,虽然它可能足够小,但并不会是无穷小.同一像素上,OpenGL可以绘制许多坐标只有稍微不同的点,但该像素的具体颜色将取决于OpenGL的实现. 点是OpenGL中绘制一切的基础.     (2)如何绘制点: 1)OpenGL为点的绘制提供了一系列函数

OpenGL学习进程(5)第三课:视口与裁剪区域

本节是OpenGL学习的第三个课时,下面介绍如何运用显示窗体的视口和裁剪区域:     (1)知识点引入:     1)问题现象: 当在窗体中绘制图形后,拉伸窗体图形形状会发生变化: #include <GL/glut.h> #include <math.h> const float Pi = 3.1415926f; const int n = 1000; const float R = 0.8f; void init(void) { glClearColor(0.0,0.0,0.

OpenGL学习进程(3)第一课:初始化窗体

    本节是OpenGL学习的第一个课时,下面介绍如何初始化一个窗体:     (1)显示一个有蓝色背景的窗体: #include <GL/glut.h> #include <stdlib.h> void display(void) { /* clear all pixels */ glClear (GL_COLOR_BUFFER_BIT); glFlush (); } int main(int argc, char** argv) { glutInit(&argc, a