2012-03-27 38 views
0

我一直在嘗試使用OpenGL 3.x核心配置文件製作自己的基本.obj(Wavefront)渲染器。我正在使用OpenGL SuperBible 5th ed。和Swiftless教程作爲參考資料。OpenGL 3.x .obj加載程序與ADS Phong「炫麗」球體

幾何似乎正確加載,所以現在我試圖讓ADS Phong照明模型正常工作,但是有些東西是棘手的,而且我認爲它與我的OpenGL調用或者其他方式有關我正在加載我的法線,但我似乎無法弄清楚如何解決它。 (這也可能是其他一些問題,因爲我不是OpenGL的專家)。

當渲染一個簡單的立方體,它幾乎看起來正常,但有光的怪異點一側:

picture of cube

當渲染一個球體,照明顯示了「脈」:

picture of sphere

有些東西顯然是非常錯誤的我的代碼。以下是我認爲可能相關的代碼部分。如果需要,我會很樂意發佈更多/所有的代碼...讓我知道我是否應該發佈更多。

文件:objFileRenderer.cpp

#include "objFileRenderer.hpp" 

namespace def 
{ 

objFileRenderer::objFileRenderer(const char* fileToRender, float objScale) 
{ 
    windowWidth = 800; 
    windowHeight = 600; 
    settings.majorVersion = 3; 
    settings.minorVersion = 1; 
    app = NULL; 
    shader = NULL; 
    vaoID = NULL; 
    vboID = NULL; 
    iboID = NULL; 
    vaoID = new unsigned int[1]; 
    vboID = new unsigned int[3]; 
    iboID = new unsigned int[2]; 
    rotSpeed = 50.0f; 
    rot = 0.0f; 

    initSFML(); 
    initOpenGL(); 

    std::string objFilename(fileToRender); 
    std::vector<float> vertices; 
    std::vector< unsigned short > indices; 
    std::vector<float> normals; 
    std::vector< unsigned short > normalIndices; 

    loadObj(objFilename, vertices, indices, normals, normalIndices); 


    std::vector<float> colorA; 
    std::vector<float> colorD; 
    std::vector<float> colorS; 
    loadMtl(objFilename, colorA, colorD, colorS); 


    float* vertexArray = NULL; 
    int numVertices = 0; 
    unsigned short* indexArray = NULL; 
    int numFaces = 0; 
    vertexArray = vertexVectorToVertexArray(vertices, numVertices); 
    indexArray = indexVectorToIndexArray(indices, numFaces); 

    float* colorArrayA = NULL; 
    float* colorArrayD = NULL; 
    float* colorArrayS = NULL; 
    int numColoredObjects = 0; 
    colorVectorsToColorArrays(colorA, colorD, colorS, colorArrayA, colorArrayD, colorArrayS, numColoredObjects); 

    float* normalArray = NULL; 
    unsigned short* normalIndicesArray = NULL; 
    int numNormals = 0; 
    int numNormalIndices = 0; 
    normalVectorsToNormalArrays(normals, normalIndices, normalArray, normalIndicesArray, numNormals, numNormalIndices); 

    setupScene(); 

    putArraysIntoVAO(vertexArray, numVertices, indexArray, numFaces, normalArray, numNormals, normalIndicesArray, numNormalIndices); 

    mainLoop(numVertices, numFaces, colorArrayA, colorArrayD, colorArrayD, normalArray, objScale); 

    delete [] vertexArray; 
    delete [] indexArray; 
    delete [] colorArrayA; 
    delete [] colorArrayD; 
    delete [] colorArrayS; 
    delete [] normalArray; 
    delete [] normalIndicesArray; 
} 

objFileRenderer::~objFileRenderer() 
{ 
    shutdownSFML(); 
} 

void objFileRenderer::loadObj(std::string& objFilename, std::vector<float>& vertices, std::vector< unsigned short >& indices, std::vector<float>& normals, std::vector< unsigned short >& normalIndices) 
{ 
    std::ifstream objFile(objFilename.c_str()); 

    if (!objFile.is_open()) 
    { 
     std::cerr << "Error: unable to open .obj file: " << objFilename << std::endl; 
     exit(1); 
    } 

    std::string line; 
    while (objFile.good()) 
    { 
     getline(objFile, line); 

     // vertices 
     if (line[0] == 'v' && line[1] == ' ') // if line in .obj file contains vertices 
     { 
      std::vector<std::string> tmpStrVerts; 
      std::string subline; 
      subline = line.substr(2); 

      boost::split(tmpStrVerts, subline, boost::is_any_of("\t ")); 

      std::vector<std::string>::iterator it; 
      for (it = tmpStrVerts.begin(); it != tmpStrVerts.end(); it++) 
      { 
       float vertex; 
       std::stringstream ss; 
       ss << *it; 
       ss >> vertex; 
       vertices.push_back(vertex); 
      } 
     } 

     // normals 
     else if (line[0] == 'v' && line[1] == 'n') 
     { 
      std::vector<std::string> tmpStrNorms; 
      std::string subline; 
      subline = line.substr(3); 

      boost::split(tmpStrNorms, subline, boost::is_any_of("\t ")); 

      std::vector<std::string>::iterator it; 
      for (it = tmpStrNorms.begin(); it != tmpStrNorms.end(); it++) 
      { 
       float normal; 
       std::stringstream ss; 
       ss << *it; 
       ss >> normal; 
       normals.push_back(normal); 
       //std::cout << normal << std::endl; 
      } 
     } 

     // indices and normalIndices 
     else if (line[0] == 'f' && line[1] == ' ') // else if line in .obj file contains indices 
     { 
      std::vector<std::string> tmpStrIndices; 
      std::string subline; 
      subline = line.substr(2); 

      // indices 
      boost::split(tmpStrIndices, subline, boost::is_any_of("\t ")); 

      std::vector<std::string>::iterator it; 
      for (it = tmpStrIndices.begin(); it != tmpStrIndices.end(); it++) 
      { 
       unsigned short index; 
       std::stringstream ss; 
       ss << *it; 
       ss >> index; 
       indices.push_back(index); 
      } 

      // normalIndices 
      boost::split(tmpStrIndices, subline, boost::is_any_of("/")); 

      int count = 0; 
      std::vector<std::string>::iterator it2; 
      for (it2 = tmpStrIndices.begin(); it2 != tmpStrIndices.end(); it2++) 
      { 
       if (count == 2) 
       { 
        unsigned short index; 
        std::stringstream ss; 
        ss << *it2; 
        ss >> index; 
        normalIndices.push_back(index); 
        count = 0; 
       } 
       count++; 
      } 


     } 
    } 
    objFile.close(); 

    return; 
} 

void objFileRenderer::loadMtl(std::string& objFilename, std::vector<float>& colorA, std::vector<float>& colorD, std::vector<float>& colorS) 
{ 
    int extpos = objFilename.find('.'); 
    std::string mtlFilename = objFilename.substr(0, extpos+1) + "mtl"; 

    std::ifstream mtlFile(mtlFilename.c_str()); 

    if (!mtlFile.is_open()) 
    { 
     std::cerr << "Error: unable to open .mtl file: " << mtlFilename << std::endl; 
     exit(1); 
    } 

    std::string line; 
    while (mtlFile.good()) 
    { 
     getline(mtlFile, line); 

     if (line[0] == 'K' && line[1] == 'a') 
     { 
      std::vector<std::string> tmpStrColorA; 
      std::string subline; 
      subline = line.substr(3); 

      boost::split(tmpStrColorA, subline, boost::is_any_of("\t ")); 

      std::vector<std::string>::iterator it; 
      for (it = tmpStrColorA.begin(); it != tmpStrColorA.end(); it++) 
      { 
       float rgbValue; 
       std::stringstream ss; 
       ss << *it; 
       ss >> rgbValue; 
       colorA.push_back(rgbValue); 
      } 
     } 

     if (line[0] == 'K' && line[1] == 'd') 
     { 
      std::vector<std::string> tmpStrColorD; 
      std::string subline; 
      subline = line.substr(3); 

      boost::split(tmpStrColorD, subline, boost::is_any_of("\t ")); 

      std::vector<std::string>::iterator it; 
      for (it = tmpStrColorD.begin(); it != tmpStrColorD.end(); it++) 
      { 
       float rgbValue; 
       std::stringstream ss; 
       ss << *it; 
       ss >> rgbValue; 
       colorD.push_back(rgbValue); 
      } 
     } 

     if (line[0] == 'K' && line[1] == 's') 
     { 
      std::vector<std::string> tmpStrColorS; 
      std::string subline; 
      subline = line.substr(3); 

      boost::split(tmpStrColorS, subline, boost::is_any_of("\t ")); 

      std::vector<std::string>::iterator it; 
      for (it = tmpStrColorS.begin(); it != tmpStrColorS.end(); it++) 
      { 
       float rgbValue; 
       std::stringstream ss; 
       ss << *it; 
       ss >> rgbValue; 
       colorS.push_back(rgbValue); 
      } 
     } 

    } 
    mtlFile.close(); 

    return; 
} 

float* objFileRenderer::vertexVectorToVertexArray(std::vector<float>& vertices, int& numVertices) 
{ 
    numVertices = vertices.size()/3; 
    float* vertexArray = NULL; 
    vertexArray = new float[vertices.size()]; 

    for (unsigned int i = 0; i < vertices.size(); i++) 
    { 
     vertexArray[i] = vertices[i]; 
    } 

    return vertexArray; 
} 

unsigned short* objFileRenderer::indexVectorToIndexArray(std::vector< unsigned short >& indices, int& numFaces) 
{ 
    numFaces = indices.size()/3; 
    unsigned short* indexArray = NULL; 
    indexArray = new unsigned short[indices.size()]; 

    for (unsigned int i = 0; i < indices.size(); i++) 
    { 
     indexArray[i] = indices[i]-1; 
    } 

    return indexArray; 
} 

void objFileRenderer::colorVectorsToColorArrays(std::vector<float>& colorA, std::vector<float>& colorD, std::vector<float>& colorS, float*& colorArrayA, float*& colorArrayD, float*& colorArrayS, int& numColoredObjects) 
{ 
    numColoredObjects = colorA.size()/3; 

    colorArrayA = new float[numColoredObjects*3]; 
    colorArrayD = new float[numColoredObjects*3]; 
    colorArrayS = new float[numColoredObjects*3]; 

    for (int i = 0; i < numColoredObjects; i+=3) 
    { 
     colorArrayA[i] = colorA[i]; colorArrayA[i+1] = colorA[i+1]; colorArrayA[i+2] = colorA[i+2]; 
     colorArrayD[i] = colorD[i]; colorArrayD[i+1] = colorD[i+1]; colorArrayD[i+2] = colorD[i+2]; 
     colorArrayS[i] = colorS[i]; colorArrayS[i+1] = colorS[i+1]; colorArrayS[i+2] = colorS[i+2]; 
    } 

    return; 
} 

void objFileRenderer::normalVectorsToNormalArrays(std::vector<float>& normals, std::vector< unsigned short >& normalIndices, float*& normalArray, unsigned short*& normalIndicesArray, int& numNormals, int& numNormalIndices) 
{ 
    numNormals = normals.size()/3; 
    numNormalIndices = normalIndices.size(); 

    normalArray = new float[numNormalIndices]; 
    normalIndicesArray = new unsigned short[numNormalIndices]; 

    for (int i = 0; i < numNormalIndices; i+=3) 
    { 
     normalIndicesArray[i] = normalIndices[i]-1; 
     normalIndicesArray[i+1] = normalIndices[i+1]-1; 
     normalIndicesArray[i+2] = normalIndices[i+2]-1; 
    } 

    // load normals in index order 
    for (int i = 0; i < numNormalIndices; i+=3) 
    { 
     int index = normalIndicesArray[i]; 
     normalArray[i] = normals[index]; 
     normalArray[i+1] = normals[index+1]; 
     normalArray[i+2] = normals[index+2]; 
    } 

    return; 
} 

void objFileRenderer::putArraysIntoVAO(float* vertexArray, int& numVertices, unsigned short* indexArray, int& numFaces, float* normalArray, int& numNormals, unsigned short* normalIndicesArray, int& numNormalIndices) 
{ 
    glGenVertexArrays(1, &vaoID[0]); // create our vertex array object 
    glBindVertexArray(vaoID[0]); // bind our vertex array object so we can use it 

    glGenBuffers(2, &iboID[0]); // generate our index buffer object 
    glGenBuffers(2, &vboID[0]); // generate our vertex buffer object 

// normalArray holds normals in index order, so I shouldn't use this 
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[1]); // bind our normal index buffer object 
// glBufferData(GL_ELEMENT_ARRAY_BUFFER, (numNormalIndices) * sizeof(GLushort), normalIndicesArray, GL_STATIC_DRAW); // set the size and data of our IBO 

    glBindBuffer(GL_ARRAY_BUFFER, vboID[1]); // bind our normal vertex buffer object 
    glBufferData(GL_ARRAY_BUFFER, (numNormalIndices) * sizeof(GLfloat), normalArray, GL_STATIC_DRAW); // set the size and data of our VBO and set it to STATIC_DRAW 
    glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0); // set up our vertex attributes pointer 
    glEnableVertexAttribArray(1); 

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, iboID[0]); // bind our index buffer object 
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, (numFaces*3) * sizeof(GLushort), indexArray, GL_STATIC_DRAW); // set the size and data of our IBO 

    glBindBuffer(GL_ARRAY_BUFFER, vboID[0]); // bind our vertex buffer object 
    glBufferData(GL_ARRAY_BUFFER, (numVertices*3) * sizeof(GLfloat), vertexArray, GL_STATIC_DRAW); // set the size and data of our VBO and set it to STATIC_DRAW 
    glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); // set up our vertex attributes pointer 
    glEnableVertexAttribArray(0); 

    glBindVertexArray(0); 
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); 

    return; 
} 

void objFileRenderer::setupScene() 
{ 
    app->setFramerateLimit(60); // max 60 FPS 

    glClearColor(0.4f, 0.6f, 0.9f, 0.0f); 
    glEnable(GL_DEPTH_TEST); 
    glDepthFunc(GL_LEQUAL); 
    glEnable(GL_CULL_FACE); 

    shader = new Shader("shader.vert", "shader.frag"); 
    projectionMatrix = glm::perspective(60.0f, (float)windowWidth/(float)windowHeight, 0.1f, 100.0f); 

    return; 
} 

void objFileRenderer::renderScene(int& numVertices, int& numFaces, float*& colorArrayA, float*& colorArrayD, float*& colorArrayS, float*& normalArray, float objScale) 
{ 
    sf::Time elapsedTime = clock.getElapsedTime(); 
    clock.restart(); 

    if (rot > 360.0f) 
     rot = 0.0f; 
    rot += rotSpeed * elapsedTime.asSeconds(); 

    float lightPosition[3] = { -100.0, -100.0, 100.0 }; 

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); 
    viewMatrix = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, -3.0f, -10.0f)); // move back by 5 units 
    modelMatrix = glm::scale(glm::mat4(1.0f), glm::vec3(objScale)); // change last arg to 0.5f to shrink model by half 
    modelMatrix *= glm::rotate<float>(glm::mat4(1.0f), rot, glm::vec3(0, 1, 0)); 

    shader->bind(); 

    int projectionMatrixLocation = glGetUniformLocation(shader->id(), "projectionMatrix"); 
    int viewMatrixLocation   = glGetUniformLocation(shader->id(), "viewMatrix"); 
    int modelMatrixLocation   = glGetUniformLocation(shader->id(), "modelMatrix"); 
    int ambientLocation    = glGetUniformLocation(shader->id(), "ambientColor"); 
    int diffuseLocation    = glGetUniformLocation(shader->id(), "diffuseColor"); 
    int specularLocation   = glGetUniformLocation(shader->id(), "specularColor"); 
    int lightPositionLocation  = glGetUniformLocation(shader->id(), "lightPosition"); 
    int normalMatrixLocation  = glGetUniformLocation(shader->id(), "normalMatrix"); 

    glUniformMatrix4fv(projectionMatrixLocation, 1, GL_FALSE, &projectionMatrix[0][0]); 
    glUniformMatrix4fv(viewMatrixLocation, 1, GL_FALSE, &viewMatrix[0][0]); 
    glUniformMatrix4fv(modelMatrixLocation, 1, GL_FALSE, &modelMatrix[0][0]); 
    glUniform3fv(ambientLocation, 1, colorArrayA); 
    glUniform3fv(diffuseLocation, 1, colorArrayD); 
    glUniform3fv(specularLocation, 1, colorArrayS); 
    glUniform3fv(lightPositionLocation, 1, lightPosition); 
    glUniformMatrix3fv(normalMatrixLocation, 1, GL_FALSE, normalArray); 


    glBindVertexArray(vaoID[0]); 

    glDrawRangeElements(GL_TRIANGLES, 0, numFaces*3, numFaces*3, GL_UNSIGNED_SHORT, NULL); 

    glBindVertexArray(0); 

    shader->unbind(); 

    app->display(); 

    return; 
} 

void objFileRenderer::handleEvents() 
{ 
    sf::Event event; 

    while (app->pollEvent(event)) 
    { 
     if (event.type == sf::Event::Closed) 
     { 
      app->close(); 
     } 

     if ((event.type == sf::Event::KeyPressed) && (event.key.code == sf::Keyboard::Escape)) 
     { 
      app->close(); 
     } 

     if (event.type == sf::Event::Resized) 
     { 
      glViewport(0, 0, event.size.width, event.size.height); 
     } 
    } 

    return; 
} 

void objFileRenderer::mainLoop(int& numVertices, int& numFaces, float*& colorArrayA, float*& colorArrayD, float*& colorArrayS, float*& normalArray, float objScale) 
{ 
    while (app->isOpen()) 
    { 
     renderScene(numVertices, numFaces, colorArrayA, colorArrayD, colorArrayS, normalArray, objScale); 
     handleEvents(); 
    } 
} 


} 

文件:shader.cpp

#include "shader.h" 
#include <string.h> 
#include <iostream> 
#include <stdlib.h> 

using namespace std; 

static char* textFileRead(const char *fileName) { 
    char* text = NULL; 

    if (fileName != NULL) { 
     FILE *file = fopen(fileName, "rt"); 

     if (file != NULL) { 
      fseek(file, 0, SEEK_END); 
      int count = ftell(file); 
      rewind(file); 

      if (count > 0) { 
       text = (char*)malloc(sizeof(char) * (count + 1)); 
       count = fread(text, sizeof(char), count, file); 
       text[count] = '\0'; 
      } 
      fclose(file); 
     } 
    } 
    return text; 
} 

Shader::Shader() { 

} 

Shader::Shader(const char *vsFile, const char *fsFile) { 
    init(vsFile, fsFile); 
} 

void Shader::init(const char *vsFile, const char *fsFile) { 
    shader_vp = glCreateShader(GL_VERTEX_SHADER); 
    shader_fp = glCreateShader(GL_FRAGMENT_SHADER); 

    const char* vsText = NULL; 
    const char* fsText = NULL; 
    vsText = textFileRead(vsFile); 
    fsText = textFileRead(fsFile); 

    if (vsText == NULL) 
    { 
     cerr << "Error: vertex shader file not found" << endl; 
    } 
    if (fsText == NULL) { 
     cerr << "Error: fragment shader file not found." << endl; 
    } 
    if (vsText == NULL || fsText == NULL) 
     return; 

    glShaderSource(shader_vp, 1, &vsText, 0); 
    glShaderSource(shader_fp, 1, &fsText, 0); 

    glCompileShader(shader_vp); 
    glCompileShader(shader_fp); 

    shader_id = glCreateProgram(); 
    glAttachShader(shader_id, shader_fp); 
    glAttachShader(shader_id, shader_vp); 
    glLinkProgram(shader_id); 

    glBindAttribLocation(shader_id, 0, "in_Position"); 
    //glBindAttribLocation(shader_id, 1, "in_Color"); 
    glBindAttribLocation(shader_id, 1, "in_Normal"); 
} 

Shader::~Shader() { 
    glDetachShader(shader_id, shader_fp); 
    glDetachShader(shader_id, shader_vp); 

    glDeleteShader(shader_fp); 
    glDeleteShader(shader_vp); 
    glDeleteProgram(shader_id); 
} 

unsigned int Shader::id() { 
    return shader_id; 
} 

void Shader::bind() { 
    glUseProgram(shader_id); 
} 

void Shader::unbind() { 
    glUseProgram(0); 
} 

文件:shader.vert

#version 150 core 

in vec3 in_Position; 
in vec3 in_Normal; 

uniform mat4 projectionMatrix; 
uniform mat4 viewMatrix; 
uniform mat4 modelMatrix; 
uniform vec3 lightPosition; 
uniform mat3 normalMatrix; 

smooth out vec3 vVaryingNormal; 
smooth out vec3 vVaryingLightDir; 

void main() 
{  
    // derive MVP and MV matrices 
    mat4 modelViewProjectionMatrix = projectionMatrix * viewMatrix * modelMatrix; 
    mat4 modelViewMatrix = viewMatrix * modelMatrix; 

    // get surface normal in eye coordinates 
    vVaryingNormal = normalMatrix * in_Normal; 

    // get vertex position in eye coordinates 
    vec4 vPosition4 = modelViewMatrix * vec4(in_Position, 1.0); 
    vec3 vPosition3 = vPosition4.xyz/vPosition4.w; 

    // get vector to light source 
    vVaryingLightDir = normalize(lightPosition - vPosition3); 


    // Set the position of the current vertex 
    gl_Position = modelViewProjectionMatrix * vec4(in_Position, 1.0); 

} 

文件:shader.frag

#version 150 core 

out vec4 out_Color; 

uniform vec3 ambientColor; 
uniform vec3 diffuseColor; 
uniform vec3 specularColor; 

smooth in vec3 vVaryingNormal; 
smooth in vec3 vVaryingLightDir; 

void main() 
{ 
    // dot product gives us diffuse intensity 
    float diff = max(0.0, dot(normalize(vVaryingNormal), normalize(vVaryingLightDir))); 

    // multiply intensity by diffuse color, force alpha to 1.0 
    out_Color = vec4(diff * diffuseColor, 1.0); 

    // add in ambient light 
    out_Color += vec4(ambientColor, 1.0); 

    // specular light 
    vec3 vReflection = normalize(reflect(-normalize(vVaryingLightDir), normalize(vVaryingNormal))); 
    float spec = max(0.0, dot(normalize(vVaryingNormal), vReflection)); 

    if (diff != 0) 
    { 
     float fSpec = pow(spec, 128.0); 
     // Set the output color of our current pixel 
     out_Color.rgb += vec3(fSpec, fSpec, fSpec); 
    } 
} 

我知道需要了解很多內容,但我很樂意爲您解決此問題提供一些幫助,所以請提前感謝任何有時間幫助我解決問題的人!

+1

它不相關的問題,但你有內存泄漏。儘管使用malloc爲它們分配內存,但絕不會刪除shader.cpp中的vsText或psText。的確,你永遠不需要使用malloc。在這種情況下,我會傳遞一個std :: vector的引用,將矢量調整爲文件的大小,填充它,然後使用它來代替原始char *。你也可以使用std :: shared_ptr 來保存你的char數組並從函數中接收它。除malloc之外的任何東西! :-)。 – Robinson 2012-03-27 22:04:00

回答

2

我不認爲你正確對待索引。在opengl中解析OBJ是很棘手的,因爲它們使用無用的多索引格式提供數據。基本上你必須分解所有的頂點和法線,並重建索引,使得每個頂點都是位置/正常/顏色/不管它們共享相同的索引。對它們重新排序並不是一項簡單的任務,但如果你在線查看「obj頂點緩衝區」,我相信你會找到數百個關於它的參考和文章。

嘗試讀這篇文章,看看它是否會更有意義:http://aresio.blogspot.com/2009/07/wavefront-obj-files-vertex-buffer.html

+0

我認爲你是對的,我正在做法線/正常指數錯誤。它看起來像normalVectorsToNormalArrays()我只是增加一個正常的每張臉。我認爲我應該做的事情(並糾正我,如果我錯了),我應該爲每個頂點添加一個法線。我會盡力解決這個問題,看看我能否獲得更好的照明效果。感謝指針! – Defcronyke 2012-03-28 02:37:26

+0

我現在正在爲每個頂點加載一個法線(是對的,還是應該是每個面的法線?)。但我正在以.obj文件的索引順序加載法線,所以這顯然仍然不能正常工作,因爲就像你說的,法線和頂點**必須共享相同的索引** ...我是很難想象如何實現這一點,並且你給我的鏈接上的僞代碼對我來說並沒有太多意義(我一直在閱讀它),谷歌也沒有出現任何有用的。我會繼續嘗試的東西,但你(或某人)能給我更多的建議嗎? – Defcronyke 2012-03-28 19:49:42

+1

我的第一個建議就是不要重新發明輪子,去下載Assimp(http://assimp.sourceforge.net/),這樣你就可以開始更有趣的事情:)。我沒有時間做完整的解釋,但如果你想自己做,它可以歸結爲:創建一個名爲「頂點」的結構的新向量,包含position,normal,texcoord等。然後通過obj文件,並且每當您找到一對唯一的位置/正常/ texcoord時,將數據複製到一個新的頂點以便它們都在一起(STL映射對於檢測重複項很有用)。然後使用這個新的矢量來繪製。 – Tim 2012-03-28 19:56:27