十二面体没有正确显示

时间:2015-03-08 17:35:52

标签: c++ opengl visual-c++ geometry

我正在尝试手工绘制一个十二面体(没有过剩函数调用),但我有问题让脸部正确显示(我也没有使用背面剔除所以我理解它背后的数学)当我尝试使用键盘将变换应用到形状上时,它没有任何效果。

这是我的代码:

#include <cstdlib> //just in case
#include <stdlib.h> //just in case
#include <math.h> //powers, square roots, and trig functions are used
#include <gl/glut.h>
#ifndef magic
#define magic 1.618033989
#endif
#ifndef magic2
#define magic2 0.618033989
#endif
#ifndef PI
#define PI 3.1415926535
#endif
int faces[12][5] = 
{   
    {0, 16, 2, 10, 8}, 
    {0, 8, 4, 14, 12},
    {16, 17, 1, 12, 0},
    {1, 9, 11, 3, 17},
    {1, 12, 14, 5, 9},
    {2, 13, 15, 6, 10},
    {13, 3, 17, 16, 2},
    {3, 11, 7, 15, 13},
    {4, 8, 10, 6, 18},
    {14, 5, 19, 18, 4},
    {5, 19, 7, 11, 9},
    {15, 7, 19, 18, 6}
};
double points[20][3] = 
{
    {1, 1, 1},
    {1, 1, -1},
    {1, -1, 1},
    {1, -1, -1},
    {-1, 1, 1},
    {-1, 1, -1},
    {-1, -1, 1},
    {-1, -1, -1},
    {0, magic2, magic},
    {0, magic2, -magic},
    {0, -magic2, magic},
    {0, -magic2, -magic},
    {magic2, magic, 0},
    {magic2, -magic, 0},
    {-magic2, magic, 0},
    {-magic2, -magic, 0},
    {magic, 0, magic2},
    {magic, 0, -magic2},
    {-magic, 0, magic2},
    {-magic, 0, -magic2}
};
/*double radians(double d){ return d * PI / 180; }
double up[3][3] =
{
    {cos(radians(0.01)), -sin(radians(0.01)), 0},
    {sin(radians(0.01)), cos(radians(0.01)), 0},
    {0, 0, 1}
}; //up rotation matrix
double down[3][3] = 
{
    {cos(radians(-0.01)), -sin(radians(-0.01)), 0},
    {sin(radians(-0.01)), cos(radians(-0.01)), 0},
    {0, 0, 1}
}; //down rotation matrix
double left[3][3] = 
{
    {cos(radians(-0.01)), 0, sin(radians(-0.01))},
    {0, 1, 0},
    {-sin(radians(-0.01)), 0, cos(radians(-0.01))}
}; //left rotation matrix
double right[3][3] = 
{
    {cos(radians(0.01)), 0, sin(radians(0.01))},
    {0, 1, 0},
    {-sin(radians(0.01)), 0, cos(radians(0.01))}
}; //right rotation matrix
*/
void cross(double a[], double b[], double vec1[]){ //gets the cross product of a and b and stores it in vec1
    vec1[0] = a[1] * b[2] - a[2] * b[1];
    vec1[1] = a[2] * b[0] - a[0] * b[2];
    vec1[2] = a[0] * b[1] - a[1] * b[0];
}
void getNormal(int n, int m, int x, double vec1[]){ //gets the normal vector
    double a[] = {points[m][0] - points[n][0], points[m][1] - points[n][1], points[m][2] - points[n][2]};
    double b[] = {points[m][0] - points[x][0], points[m][1] - points[x][1], points[m][2] - points[x][2]};
    cross(a, b, vec1);
}
double dot(double a[], double b[]){ //dot product
    return a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
}
double mag(double a[]){ //magnitude of given vector
    return sqrt(pow(a[0], 2) + pow(a[1], 2) + pow(a[2], 2));
}
bool isForwardFacing(int face[5]){ 
    double vec1[3];
    getNormal(face[0], face[1], face[2], vec1); //vec1 is the normal vector
    double vec2[] = {points[face[1]][0], points[face[1]][1], points[face[1]][2]};
    double test = dot(vec1, vec2) / (mag(vec1) * mag(vec2));
    if(test > 0)
        return true;
    else
        return false;
}
//these rotations rotate the shape by 0.01 degrees
/*void rotateUp(){ //positive rotation about z axis
    for(int i = 0; i < 20; i++){
        for(int j = 0; j < 3; j++){
            points[i][j] = points[i][0] * up[0][j] + points[i][1] * up[1][j] + points[i][2] * up[2][j];
        }
    }
}
void rotateLeft(){ //negative rotation about y axis
    for(int i = 0; i < 20; i++){
        for(int j = 0; j < 3; j++){
            points[i][j] = points[i][0] * left[0][j] + points[i][1] * left[1][j] + points[i][2] * left[2][j];
        }
    }
}
void rotateDown(){ //negative rotation about z axis
    for(int i = 0; i < 20; i++){
        for(int j = 0; j < 3; j++){
            points[i][j] = points[i][0] * down[0][j] + points[i][1] * down[1][j] + points[i][2] * down[2][j];
        }
    }
}
void rotateRight(){ //positive rotation about y axis
    for(int i = 0; i < 20; i++){
        for(int j = 0; j < 3; j++){
            points[i][j] = points[i][0] * right[0][j] + points[i][1] * right[1][j] + points[i][2] * right[2][j];
        }
    }
} */
void myFunc(unsigned char key, int x, int y){
    if(key == 'w' || key == 'W'){
        glPopMatrix();
        glRotated(0.01, 0.0, 0.0, 1.0);
             glPushMatrix();
    }
    else if(key == 'a' || key == 'A'){
        glPopMatrix();
        glRotated(0.01, 0.0, -1.0, 0.0);
             glPushMatrix();
    }
    else if(key == 's' || key == 'S'){
        glPopMatrix();
        glRotated(0.01, 0.0, 0.0, -1.0);
             glPushMatrix();
    }
    else if(key == 'd' || key == 'D'){
        glPopMatrix();
        glRotated(0.01, 0.0, 1.0, 0.0);
             glPushMatrix();
    }
}
void display(){
    glClear(GL_COLOR_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glOrtho(-3.0, 3.0, -3.0, 3.0, -3.0, 3.0);

    glPushMatrix();

    for(int i = 0; i < 12; i++){
        if(isForwardFacing(faces[i])){
            glColor3f(1.0,0.0,0.0);
            glBegin(GL_TRIANGLE_FAN);
            for(int x = 0; x < 5; x++)
                glVertex3dv(points[faces[i][x]]);
            glEnd();
            glColor3f(0.0,1.0,0.0);
            glBegin(GL_LINES);
            for(int x = 0; x < 5; x++)
                glVertex3dv(points[faces[i][x]]);
            glEnd();
        }
    }
    glFlush();
}
int main(int argc, char **argv){
    //boilerplate stuff
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
    glutInitWindowSize(1000, 1000);
    glutCreateWindow("Dodecahedron");
    glutDisplayFunc(display);
    glutKeyboardFunc(myFunc); //animation function
    glutMainLoop();
    return 0;
}

1 个答案:

答案 0 :(得分:0)

您的代码有几个问题:

  1. 您始终在显示功能中重新初始化模型视图矩阵。因此,键盘功能中的任何矩阵修改都将无效。

  2. 您可能希望在glOrtho之后执行glMatrixMode(GL_PROJECTION)来电,因为您想在那里设置投影。

  3. 您也可以删除所有推送和弹出矩阵,因为您只需要修改当前矩阵,而不需要恢复以前的状态。

  4. 您需要键盘功能glutPostRedisplay才能触发重新显示。

  5. 您旋转0.01°,这是一个非常小的数量。尝试10°作为初学者,一旦你对所有其他人感到满意就进行调整。

  6. 您应该绘制GL_LINE_STRIP而不是GL_LINES,因为您不重复顶点。但即使这样,你也需要重复每个五边形的第一个顶点来关闭它。

  7. 您的isForwardFacing函数未考虑当前模型视图矩阵,因此会导致缺少面。我想我会将脸部剔除到OpenGL,或者只是渲染所有脸部。

  8. 如果您禁用向前检查,则由于您没有glEnable(GL_DEPTH_TEST),您可能会从前面的对象中获取对象。

  9. 您的glOrtho电话不考虑窗口的宽高比。

  10. 标题应称为<GL/glut.h>而不是<gl/glut.h>。在操作系统中,案例对文件名有所不同,这很重要。

  11. myFunc是一个功能相当不具名的名称。

  12. 您可以尝试这样的事情:

    void myFunc(unsigned char key, int x, int y){
        if(key == 'w' || key == 'W')
            glRotated(10.0, 0.0, 0.0, 1.0);                         // changed
        else if(key == 'a' || key == 'A')
            glRotated(10.0, 0.0, -1.0, 0.0);                        // changed
        else if(key == 's' || key == 'S')
            glRotated(10.0, 0.0, 0.0, -1.0);                        // changed
        else if(key == 'd' || key == 'D')
            glRotated(10.0, 0.0, 1.0, 0.0);                         // changed
        // all glPopMatrix() and glPushMatrix() calls removed       // removed
        glutPostRedisplay();                                        // added
    }
    
    void reshape(int w, int h){                                     // added
        double aspect = double(w) / double(h);                      // added
        glEnable(GL_DEPTH_TEST);                                    // added
        glMatrixMode(GL_PROJECTION);                                // added
        glOrtho(-3.0 * aspect, 3.0 * aspect, -3.0, 3.0, -3.0, 3.0); // changed
        glMatrixMode(GL_MODELVIEW); // rotations apply to this
    }
    
    void display(){
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);         // changed
        for (int i = 0; i < 12; i++) {
            // if (!isForwardFacing(faces[i])) continue;            // removed
            glColor3f(1.0,0.0,0.0);
            glBegin(GL_TRIANGLE_FAN);
            for(int x = 0; x < 5; x++)
                glVertex3dv(points[faces[i][x]]);
            glEnd();
            glColor3f(0.0,1.0,0.0);
            glBegin(GL_LINE_STRIP);                                 // changed
            for(int x = 0; x < 5; x++)
                glVertex3dv(points[faces[i][x]]);
            glVertex3dv(points[faces[i][0]]);                       // added
            glEnd();
        }
        glFlush();
    }
    
    int main(int argc, char **argv){
        //boilerplate stuff
        glutInit(&argc, argv);
        glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
        glutInitWindowSize(1000, 1000);
        glutCreateWindow("Dodecahedron");
        glutDisplayFunc(display);
        glutReshapeFunc(reshape);                                   // added
        glutKeyboardFunc(myFunc);
        glutMainLoop();
        return 0;
    }