OpenGL平面着色 - 奇怪的照明行为

时间:2013-03-08 17:20:05

标签: c++ opengl sfml lighting

我的OpenGL灯光有点问题。

它正在渲染模型(犹他茶壶)很好,但我有一些奇怪的光照模式。模型应该是平面阴影,只有一个环境光照亮了场景,但最终我的茶壶上遍布着斑驳的光线:

Teapot image

使用SFML在C ++中构建模型加载器只是一个简单的练习。

代码如下:

bool modelLoader(string fileName, vector<GLfloat>& vertices, vector<GLushort>& indices, vector<GLfloat>& normals)
{
    fstream object;
    string face;
    string dataLine;
    string lineChar;
    GLfloat point;
    GLfloat uvs;
    GLfloat storedNorm;
    GLushort ind;
    vector<GLfloat> storedNormals;
    vector<GLfloat> storedUVs;
    vector<GLfloat> localNormals , localVertices;
    vertices.clear();
    indices.clear();

    object.open(fileName);
    if(!object.is_open())
    {
        printf("Cannot open file: %f \n", fileName);
        return false;
    }
    while(object>>lineChar)
    {
            if(lineChar == "v" /*|| dataLine.find("vt ") == 0*/ || lineChar == "f" || lineChar == "vn")
            {
                if(lineChar == "v")
                {
                    //cout<<"v ";
                    for(int i=0;i<3;++i)
                    {
                        object >> point;
                        //cout << point << " ";
                        localVertices.push_back(point);
                    }
                    //cout<<endl;
                }
                else if(lineChar == "vn")
                {
                    //cout<<"vn";
                    for(int j=0;j<3;++j)
                    {
                        object >> point;
                        //cout<<point<<" ";
                        localNormals.push_back(point);
                    }
                    //cout<<endl;
                }
                else if(lineChar == "f")
                {
                    for(int k=0;k<3;++k)
                    {
                        getline(object, face, '/');
                        ind = atoi(face.c_str());
                        indices.push_back(ind-1);
                        object.ignore(2);
                        //getline(object, face, '/');
                        //uvs = atoi(face.c_str());
                        //storedUVs.push_back(uvs);
                        getline(object, face, ' ');
                        storedNorm = atoi(face.c_str());
                        storedNormals.push_back(storedNorm);
                    }
                }

            }
    }
    for (unsigned int i=0; i<indices.size(); ++i )
    {
        vertices.push_back(localVertices[indices[i]*3]);
        vertices.push_back(localVertices[indices[i]*3 + 1]);
        vertices.push_back(localVertices[indices[i]*3 + 2]);

        normals.push_back(localNormals[(unsigned int) storedNormals[i]*3]);
        normals.push_back(localNormals[(unsigned int) storedNormals[i]*3 + 1]);
        normals.push_back(localNormals[(unsigned int) storedNormals[i]*3 + 2]);
    }

    return true;
}

主循环:

int main()
{
    // Create the main window
     sf::Window App(sf::VideoMode(SC_WIDTH, SC_HEIGHT, 32), "SFML OpenGL");

    // Create a clock for measuring time elapsed
    sf::Clock Clock;

    //output version of OpenGL to the console
     cout<<"OpenGL version: "<<glGetString(GL_VERSION)<<endl;

     // Create the vectors to hold the object data
     vector<GLfloat> vertices;
     vector<GLushort> indices;
     vector<GLfloat> normals;

     //Load model
     if(!modelLoader("teapot2.obj", vertices, indices, normals))
     {
         printf("Failed to load model. Make sure the .obj file has no errors.");
         system("pause");
         return 0;
     }

     //enable the use of vertex arrays
     glEnableClientState(GL_VERTEX_ARRAY);
     glEnableClientState(GL_NORMAL_ARRAY);

     // tell OpenGL where the vertices are with glVertexPointer()
     glVertexPointer(3, GL_FLOAT, 0, &vertices[0]);
     glNormalPointer(GL_FLOAT, 0, &normals[0]);


    //*************************************************************
    // Set color and depth clear value
    glClearDepth(1.f);
    glClearColor(0.f, 0.f, 0.f, 0.f);

    // Enable Z-buffer read and write

    glDepthMask(GL_TRUE);

    // Set up lighting for the scene
    GLfloat ambient[4] = {0.f,0.5f,0.5f, 1.f};
    glLightfv(GL_LIGHT0, GL_AMBIENT, ambient);

    glEnable(GL_DEPTH_TEST);
    glEnable(GL_LIGHT0);
    glEnable(GL_LIGHTING);  
    glEnable(GL_COLOR_MATERIAL);

    // Setup a perspective projection
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(90.f, 1.f, 1.f, 500.f);

    // Start game loop
    while (App.IsOpened())
    {
        // Process events
        sf::Event Event;
        while (App.GetEvent(Event))
        {
            // Close window : exit
            if (Event.Type == sf::Event::Closed)
                App.Close();

            // Escape key : exit
            if ((Event.Type == sf::Event::KeyPressed) && (Event.Key.Code == sf::Key::Escape))
                App.Close();

            // Resize event : adjust viewport
            if (Event.Type == sf::Event::Resized)
                glViewport(0, 0, Event.Size.Width, Event.Size.Height);
        }

        // Set the active window before using OpenGL commands
        // It's useless here because active window is always the same,
        // but don't forget it if you use multiple windows or controls
        App.SetActive();


        if((float)Clock.GetElapsedTime()>REFRESH_RATE){
            // Clear colour and depth buffer
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

            // Apply some transformations
            glMatrixMode(GL_MODELVIEW);
            glLoadIdentity();



            glTranslatef(0.f, 0.f, -5.f);
            glRotatef(45.f, 1.f, 1.f, 1.f);

            glPushMatrix();
            //draw the triangles with glDrawArrays() and then with glDrawElements()
            glDrawArrays(GL_TRIANGLES, 0, vertices.size()/3);
            //glDrawElements(GL_TRIANGLES, vertices.size(), GL_UNSIGNED_SHORT, &indices[0]);
            //glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, &indices[0]);
            glPopMatrix();


            Clock.Reset();
        }


        // Finally, display rendered frame on screen
        App.Display();
    }
    //delete the vertex arrays using glDisableClientState()
    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);


    return EXIT_SUCCESS;
}

有人有任何想法吗?

1 个答案:

答案 0 :(得分:1)

OpenGL灯具有所有属性的默认值(例如GL_AMBIENTGL_DIFFUSE等)。在GL_LIGHT0的情况下,漫反射属性不会设置为零(这是您只需要获得环境光照所需的)。要解决这个问题,你需要做

GLfloat  black[] = { 0.0f, 0.0f, 0.0f, 1.0f };
glLightfv( GL_LIGHT0, GL_DIFFUSE, black );

因为,IIRC,其余的光属性已经为零,这应该为您提供仅环境照明,这将消除照明的方向分量。此外,glColorMaterial的默认模式是GL_AMBIENT_AND_DIFFUSE,它将环境和漫反射材质属性设置为传入的顶点颜色。您也可以考虑将其切换到仅环境(glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT );)。

然而,我认为阴影奇怪的根本原因可能是由于非单位长度法线。您可以尝试在进行光照计算之前添加glEnable( GL_NORMALIZE );