簡體   English   中英

繪制 OBJ model 時 OpenGL 未正確剔除面

[英]OpenGL is not culling faces properly when drawing OBJ model

我正在嘗試從 OBJ 文件中渲染茶壺 model。 我正在使用 Fixed Function 渲染管道,我無法更改為可編程管道。 我也想為場景應用一些基本的照明和材質,所以我的茶壺應用了綠色的 shiny 材質。 然而,當我圍繞 Y 軸旋轉茶壺時,我可以清楚地看到茶壺的背面。

茶壺

這是我到目前為止所嘗試的:

  • 改變 OpenGL 剔除面(GL_CCW、GL_CW、GL_FRONT、GL_BACK)的方式,沒有一個會產生正確的結果。

  • 更改 OpenGL 計算正面(GL_FRONT、GL_CCW、GL_BACK、GL_CW)的方式,並且沒有產生正確的結果。

  • 測試 OBJ 文件以確保其頂點正確排序。 當我將文件拖到https://3dviewer.net/中時,它顯示正確的茶壺不是透明的。

  • 改變照明,看看是否有任何作用。 在某些情況下,改變照明並不能阻止茶壺被透視。

  • 禁用 GL_BLEND。 這什么也沒做

這是我目前啟用的:

    glLightfv(GL_LIGHT0, GL_AMBIENT, light0Color);
    glLightfv(GL_LIGHT0, GL_DIFFUSE, light0DiffColor);
    glLightfv(GL_LIGHT0, GL_SPECULAR, light0SpecColor);
    glLightfv(GL_LIGHT0, GL_POSITION, position);
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientIntensity);
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_NORMALIZE);
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_CULL_FACE);
    glCullFace(GL_CCW);
    glFrontFace(GL_CCW);

以下是材料屬性:

    float amb[4] = {0.0215, 0.1745, 0.0215, 1.0};
    float diff[4] = {0.07568, 0.61424, 0.07568, 1.0};
    float spec[4] = {0.633, 0.727811, 0.633, 1.0};
    float shininess = 0.6 * 128;
    glMaterialfv(GL_FRONT, GL_AMBIENT, amb);
    glMaterialfv(GL_FRONT, GL_DIFFUSE, diff);
    glMaterialfv(GL_FRONT, GL_SPECULAR, spec);
    glMaterialf(GL_FRONT, GL_SHININESS, shininess);

這是渲染代碼:

    glClearColor(0.0, 0.0, 0.0, 1.0);
    glClearDepth(1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(0, 0, -150);
    glRotatef(r, 0.0, 1.0, 0.0);
    glScalef(0.5, 0.5, 0.5);
    r += 0.5;
    m.draw(0, 0, 0);

我不確定這是否是問題的原因,但我在下面包含了 model 加載代碼以防萬一:

            while(std::getline(stream, line))
            {
                if (line[0] == 'v' && line[1] == 'n') // If we see a vertex normal in the OBJ file
                {
                    line = line.substr(3, line.size() - 3); // Removes the 'vn ' from the line
                    std::stringstream ss(line);
                    glm::vec3 normal;
                    ss >> normal.x >> normal.y >> normal.z;
                    tempNormalData.push_back(normal);
                }

                if (line[0] == 'v') // If we see a vertex on this line of the OBJ file
                {
                    line = line.substr(2, line.size() - 2); // Removes the 'v ' from the line
                    std::stringstream ss(line);
                    glm::vec3 position;
                    ss >> position.x >> position.y >> position.z;
                    tempVertData.push_back(position);
                }

                if (line[0] == 'f') // If we see a face in the OBJ file
                {
                    line = line.substr(2, line.size() - 2); // Removes the 'f ' from the line
                    std::stringstream ss(line);
                    glm::vec3 faceData;
                    ss >> faceData.x >> faceData.y >> faceData.z;
                    tempFaceData.push_back(faceData);
                }
            }

            if (tempVertData.size() != tempNormalData.size() && tempNormalData.size() > 0)
            {
                std::cout << "Not the same number of normals as vertices" << std::endl;
            }
            else
            {
                for (int i = 0; i < (int)tempVertData.size(); i++)
                {
                    Vertex v;
                    v.setPosition(tempVertData[i]);
                    v.setNormal(tempNormalData[i]);
                    vertices.push_back(v);
                }

                for (int i = 0; i < tempFaceData.size(); i++)
                {
                    Vertex v1 = vertices[tempFaceData[i].x - 1];
                    Vertex v2 = vertices[tempFaceData[i].y - 1];
                    Vertex v3 = vertices[tempFaceData[i].z - 1];
                    Face face(v1, v2, v3);
                    faces.push_back(face);
                }
            }
        }

最后,當我繪制面時,我只需遍歷面列表並在面 object 上調用繪圖 function。 face draw function 只包裝了一個 glBegin(GL_TRIANGLES) 和一個 glEnd() 調用:

    for (int i = 0; i < (int)faces.size(); i++)
    {
        auto& f = faces[i];
        f.draw(position);
    }

面圖function:

glBegin(GL_TRIANGLES);
                glVertex3f(position.x + v1.getPosition().x, position.y + v1.getPosition().y, position.z + v1.getPosition().z);
                glNormal3f(v1.getNormal().x, v1.getNormal().y, v1.getNormal().z);

                glVertex3f(position.x + v2.getPosition().x, position.y + v2.getPosition().y, position.z + v2.getPosition().z);
                glNormal3f(v2.getNormal().x, v2.getNormal().y, v2.getNormal().z);

                glVertex3f(position.x + v3.getPosition().x, position.y + v3.getPosition().y, position.z + v3.getPosition().z);
                glNormal3f(v3.getNormal().x, v3.getNormal().y, v3.getNormal().z);
        glEnd();

我真的不想實現我自己的 Z-Buffer 剔除算法,我希望有一個非常簡單的方法可以解決我剛剛遺漏的問題。

解決方案(感謝 Genpfault)

我沒有向 OpenGL 請求深度緩沖區。 我使用 Qt 作為我的窗口 API,所以我必須從我的格式 object 中請求它,如下所示:
 format.setDepthBufferSize(32);

這需要一個 32 位的深度緩沖區,從而解決了這個問題。

為了使面部剔除工作,您需要:

  1. 定義纏繞規則

    glFrontFace(GL_CCW); // or GL_CW depends on your model and coordinate systems
  2. 設置要跳過的面

    glEnable(GL_CULL_FACE); glCullFace(GL_BACK); // or GL_FRONT depends on what you want to achieve

    如您所見,這是您的代碼中存在錯誤的地方,因為您使用錯誤的參數調用它很可能導致新的glError條目。

  3. 如果是凹面網格,您還需要深度緩沖區

    glEnable(GL_DEPTH_TEST);

    但是,您的 OpenGL 上下文必須在上下文創建期間以其pixelformat分配深度緩沖區位。 最安全的值是 16 位和 24 位,但是現在任何像樣的 gfx 卡也可以處理 32 位。 如果您需要更多,則需要使用 FBO。

  4. 具有一致多邊形纏繞的網格

    波前 obj 文件因繞組不一致而臭名昭著,因此如果您看到一些三角形翻轉了網格文件本身中最有可能出現的錯誤。

    這可以通過使用一些 3D 工具或通過檢測錯誤的三角形並反轉它們的頂點並翻轉法線來解決。

此外,您的渲染代碼glBegin/glEnd以非常低效的方式編寫:

glVertex3f(position.x + v1.getPosition().x, position.y + v1.getPosition().y, position.z + v1.getPosition().z);
glNormal3f(v1.getNormal().x, v1.getNormal().y, v1.getNormal().z);

for each of the component/operand you call some class member function and even making arithmetics... The position can be done with simple glTranslate in actual GL_MODELVIEW matrix and if you got some 3D vector class try to access its components as pointer and use glVertex3fvglNormal3fv會快得多。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM