OpenGL學習進程(9)在3D空間的繪製實例

    本節將演示在3D空間中繪製圖形的幾個簡單實例:html

 

    (1)在3D空間內繪製圓錐體:windows

#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自帶的庫函數繪製立方體:oop

#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)相關知識:spa

    1)OpenGL中的空間變換:(http://www.cnblogs.com/chengmin/archive/2011/09/12/2174004.html)3d

      在使用OpenGL的三維虛擬程序中,當咱們指定了模型的頂點以後,在屏幕上顯示它們以前,一共會發生3種類型的變換:code

視圖變換、模型變換、投影變換。 
1.視圖變換:指定觀察者(攝像機)的位置; 
2.模型變換:在場景中移動物體;
3.投影變換:改變可視區域的大小;
視口變換:這是一種僞變換,它對窗口上的最終輸出進行縮放。

      1.視覺座標:htm

  它表示一種虛擬的固定座標系統,一般做爲一種參考系使用。它是根據觀察者(攝像機)的角度而言的,與可能發生的變換無關。咱們接下來所討論的全部變換都是根據它們相對於視覺座標的效果進行描述的。

  用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-----2D到3D座標變換

相關文章
相關標籤/搜索