2016-10-09 37 views
0

私は、カメラを中心球の周りに回転させる関数moveCamera()を持っています。OpenGLとgluLookAt関数

void moveCamera() 
{ 
    glLoadIdentity(); 
    int vec = ceil(theta/3.1415); 
    int y; 
    if (vec%2) 
     y = 1; 
    else 
     y = -1; 
    gluLookAt(e_x, e_y, e_z, 0, 0, 0, 0, y, 0); 
} 

この機能は、すべてが正常に動作します。このような状況で表示()

void display() 
{ 
    glClearColor(0, 0, 0, 1); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glLoadIdentity(); 

    moveCamera(); 

    glCallList(idList); 

    GLfloat pos[] = {0, 0, 0, 1}; 
    glLightfv(GL_LIGHT0, GL_POSITION, pos); 

    glFinish(); 
} 

の内側と呼ばれています。しかし、私は説明できないことに気づいた。例えば

、私はこの

void display() 
{ 
    glClearColor(0, 0, 0, 1); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glLoadIdentity(); 

    glColor3ub(255, 0, 0); 
    glLineWidth(5); 
    glBegin(GL_LINES); 
     glVertex3i(0, 0, 0); 
     glVertex3i(1000, 0, 0); 
    glEnd(); 

    moveCamera(); 

    glCallList(idList); 

    GLfloat pos[] = {0, 0, 0, 1}; 
    glLightfv(GL_LIGHT0, GL_POSITION, pos); 

    glFinish(); 
} 

のような方向のX軸に赤い線を描画するためのディスプレイ()関数を変更した場合...何も起こりませんでした。なぜ???

glClear()の後にglLoadIdentity()を削除すると、赤い線が描画されますが、キーボードボタンでカメラを移動すると、この線のレンダリングにバグがあります。それを見るために、私のコードを実行します。

フルコード:スタートのために

#include <iostream> 
#include <glut.h> 
#include <math.h> 
#include <QDebug> 
using namespace std; 

#define WIDTH 1024 
#define HEIGHT 600 

void display(); 
void reshape(int width, int height); 
void keyboard(unsigned char key, int x, int y); 
void moveCamera(); 
void init(); 
void mkList(); 
void enableLight(); 
//double z(const double &x, const double &y); 
void printMatrix(double *m) 
{ 
    for (int i = 0; i < 4; i++) 
     qDebug() << QString("%1 %2 %3 %4").arg(m[i*4]).arg(m[i*4+1]).arg(m[i*4+2]).arg(m[i*4+3]); 
    qDebug() << "\n"; 
} 

GLuint idList = 0; 

double e_x = 0; 
double e_y = 0; 
double e_z = 0; 
double r = 300; 
double phi = 0; 
double theta = 1.5; 

int main(int argc, char **argv) 
{ 
    glutInit(&argc, argv); 
    glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH); 
    glutInitWindowSize(WIDTH, HEIGHT); 
    glutInitWindowPosition(30, 100); 
    glutCreateWindow("Lab#2"); 
    glutDisplayFunc(display); 
    glutReshapeFunc(reshape); 
    glutKeyboardFunc(keyboard); 

    glEnable(GL_DEPTH_TEST); 
    init(); 
    mkList(); 
    enableLight(); 

    glutMainLoop(); 
    return 0; 
} 

void display() 
{ 
    glClearColor(0, 0, 0, 1); 
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
    glLoadIdentity(); 

    glColor3ub(255, 0, 0); 
    glLineWidth(5); 
    glBegin(GL_LINES); 
     glVertex3i(0, 0, 0); 
     glVertex3i(1000, 0, 0); 
    glEnd(); 

    moveCamera(); 

    glCallList(idList); 

    GLfloat pos[] = {0, 0, 0, 1}; 
    glLightfv(GL_LIGHT0, GL_POSITION, pos); 

    glFinish(); 
} 

void reshape(int width, int height) 
{ 
    glViewport(0, 0, width, height); 
    glMatrixMode(GL_PROJECTION); 
    glLoadIdentity(); 
    gluPerspective(45, 2, 100, 2000); 
    glMatrixMode(GL_MODELVIEW); 
    glLoadIdentity(); 
} 

void keyboard(unsigned char key, int x, int y) 
{ 
#define ESCAPE '\033' 

    switch (key) 
    { 
    case ESCAPE: 
     exit(0); 
     break; 
    case 's': 
     theta += 0.1; 
     break; 
    case 'w': 
     theta -= 0.1; 
     break; 
    case 'a': 
     phi += 0.1; 
     break; 
    case 'd': 
     phi -= 0.1; 
     break; 
    case 'q': 
     r-=5; 
     break; 
    case 'e': 
     r+=5; 
     break; 
    default: 
     break; 
    } 
    e_x = r * sin(theta) * cos(phi); 
    e_z = r * sin(theta) * sin(phi); 
    e_y = r * cos(theta); 
    glutPostRedisplay(); 
} 

void moveCamera() 
{ 
    glLoadIdentity(); 
    int vec = ceil(theta/3.1415); 
    int y; 
    if (vec%2) 
     y = 1; 
    else 
     y = -1; 
    gluLookAt(e_x, e_y, e_z, 0, 0, 0, 0, y, 0); 
} 

void init() 
{ 
    e_x = r * sin(theta) * cos(phi); 
    e_z = r * sin(theta) * sin(phi); 
    e_y = r * cos(theta); 
} 

void mkList() 
{ 
    int idInnerList = glGenLists(1); 
    glNewList(idInnerList, GL_COMPILE); 

    glColor3ub(255, 0, 0); 
    glPushMatrix(); 
    glTranslatef(-200, 0, 0); 
    glutWireSphere(50, 10, 10); 
    glPopMatrix(); 

    glColor3ub(0, 255, 0); 
    glPushMatrix(); 
    glTranslatef(200, 0, 0); 
    glutSolidCube(100); 
    glPopMatrix(); 

    glEndList(); 

    idList = glGenLists(1); 
    glNewList(idList, GL_COMPILE); 
    glCallList(idInnerList); 

    glPushMatrix(); 
    glTranslatef(0, 0, 200); 
    glCallList(idInnerList); 
    glPopMatrix(); 

    glPushMatrix(); 
    glTranslatef(0, 0, -200); 
    glCallList(idInnerList); 
    glPopMatrix(); 
    glEndList(); 
} 

void enableLight() 
{ 
    glEnable(GL_LIGHTING); 

    glEnable(GL_COLOR_MATERIAL); 
    glColorMaterial(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE); 

    GLfloat diffuse[] = {0.7, 0.7, 0.7, 1}; 

    glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); 

    glEnable(GL_LIGHT0); 
} 
+0

私は、その関数moveCamera()とそのgluLookAt()を表示関数()で必ず呼び出さなければならないことに気付きました。なぜ??? – van9petryk

答えて

0

は、私はこれを言いたい:それは2016年だ - レガシーOpenGLを使用しないでください。あなたのお気に入りの検索エンジンの助けを借りて最新のOpenGLを読んでください。

「何も起こらない」とは、「私は赤い線が見えませんでした」という意味で、コードが正しく理解されていれば、線が完全にクリップされるからです。私に説明させてください。

display()内の頂点変換に影響する最初の作業は、glLoadIdentity()です。これにより、現在の行列スタックの上端が単位行列Iに設定されます。その後、あなたのラインがクリップ空間にローカル空間から、次の変換を受けることになる、reshape()内の1つのセットである、のは、現在のスタックがMODELVIEWと現在の射影行列、Pであると仮定しよう:モデルということを考えると

Vx_clip = P * I * Vx_local 
Vy_clip = P * I * Vy_local 

-view行列はIDであり、両方のローカル座標はクリップ空間に変換される前にワールド空間で同じままである。あなたの近くの飛行機がz=-100にあるので、ラインは、飛行機から完全に外れている、すなわち、近くの飛行機と遠い飛行機との間の空間ではなく、したがって完全にクリップされる。数学的にはもう少し複雑ですが、概念的には正確です。あなたは今、この

glVertex3i(-500, 0, -100); 
glVertex3i(500, 0, -100); 

のような赤い線を定義することによって、自分自身を納得させることができ

それは部分的に近いと交差するので、ラインの一部が、でも、IDモデルビュー行列で、あなたの錐台の内側に内側になります完全にクリップされてはならない。

あなたは赤いラインをレンダリング前moveCamera()を呼び出すことにより、最初の非同一モデルビュー行列を適用した場合、あなたはまた、部分的に赤い線を確認できるようになります。どうして?さて、あなたの極座標を選択して、カメラがまだ方向(0, 0, -z)で見えるようにして、与えられた半径でワールド空間でカメラが(0、0、300)になるように定義します。gluLookAt()はマップします両方の頂点に単に(0、0、-300)の平行移動を加える変換行列に変換する。

ラインの初期定義と新しいモデル - ビューマトリックスが与えられた場合、ラインの頂点は、モデル - ビューマトリックスを左乗りした後に(0, 0, -300)(1000, 0, -300)になります。投影行列を左に掛けることによってクリップ空間に変換した後、線は部分的にしかクリップされず、したがって可視になる。

私が言ったように、これははるかに関わっており、実際には完全な頂点変換パイプラインの一部に過ぎません。頂点変換の対象を数学的に扱うには、thisthisを読んでください。それはコンピューターグラフィックス101です。そして、残念ながらそこに見えるレガシーAPIの使用ではなく、数学に焦点を当ててください。

関連する問題