我正在OpenGL 3.3中构建一个3D模型查看器,但我无法正确显示我的纹理 . 我很确定texcoords(来自我正在加载的对象)是正确的 .

这是我的代码:main.cpp

#include <stdio.h>
    #include <stdlib.h>
    #include <iostream>

    #include <GL/glew.h>
    #include <GLFW/glfw3.h>

    #include "glm/glm.hpp"
    #include "glm/gtc/matrix_transform.hpp"
    #include "glm/gtc/type_ptr.hpp"

    #include "InputState.h"
    #include "Viewer.h"
    #include "Shader.hpp"

    #define STB_IMAGE_IMPLEMENTATION
    #include "stb_image.h"

    #define TINYOBJLOADER_IMPLEMENTATION
    #include "tiny_obj_loader.h"

    std::string folder = "cube-tex/";
    std::string objPath = folder + "cube-tex.obj";
    std::vector<tinyobj::shape_t> shapes;
    std::vector<tinyobj::material_t> materials;
    std::vector<GLuint> texID;


    std::string meshMode = "WIREFRAME";
    std::string lightMode = "DIRECTIONAL";

    double startTime = glfwGetTime();

    float initScale = 1;
    float zoom = 0;
    float xRot, yRot;

    int winX = 500;
    int winY = 500;

    std::vector<unsigned int> vaoHandle;

    ObjectViewer *ObjCam;
    Viewer *Camera;

    glm::vec3 cameraPos(0.0f, 0.0f, -10.0f);

    // Data structure storing mouse input info
    InputState Input;

    unsigned int programID;
    unsigned int debugShader;
    unsigned int lightTexShader;

    //
    // Callbacks
    //
    void key_callback(GLFWwindow* window,
                      int key, int scancode, int action, int mods)
    {
        if (action == GLFW_PRESS) {
            switch(key)
                {
                case GLFW_KEY_S:
                  if (programID == lightTexShader) {
                    programID = debugShader;
                    meshMode = "WIREFRAME";
                    glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                  }
                  else {
                    programID = lightTexShader;
                    glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                  }
                  break;
                case GLFW_KEY_ESCAPE: // escape key pressed
                  glfwSetWindowShouldClose(window, GL_TRUE);
                  break;
                case GLFW_KEY_D:
                  if(programID == debugShader){
                    if(meshMode == "WIREFRAME") {
                      glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
                      meshMode = "NORMAL";
                    }else if(meshMode == "NORMAL"){
                      meshMode = "MATERIAL";
                    }else{
                      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
                      meshMode = "WIREFRAME";
                    }
                  }
                  break;
                case GLFW_KEY_L:
                  if(programID == lightTexShader){
                    if(lightMode == "DIRECTIONAL") {
                      lightMode = "HEADLIGHT";
                    }else if(lightMode == "HEADLIGHT"){
                      lightMode = "ROTATING";
                    }else{
                      lightMode = "DIRECTIONAL";
                    }
                  }
                  break;
                default:
                    break;
                }
        }

    }

    // Set the projection matrix. Takes into account window aspect ratio, so called
    // when the window is resized.
    void setProjection(unsigned int id)
    {
        glm::mat4 projection;

        projection = glm::perspective( (float)M_PI/3.0f, (float) winX / winY, 1.0f, 30.0f );

        // Load it to the shader program
        int projHandle = glGetUniformLocation(id, "projection");
        if (projHandle == -1) {
            std::cout << "Uniform: projection_matrix is not an active uniform label\n";
        }
        glUniformMatrix4fv( projHandle, 1, false, glm::value_ptr(projection) );
    }

    // Called when the window is resized.
    void reshape_callback( GLFWwindow *window, int x, int y )
    {
        winX = x;
        winY = y;
        setProjection(programID);
        glViewport( 0, 0, x, y );
    }

    void mouse_pos_callback(GLFWwindow* window, double x, double y)
    {
        // Use a global data structure to store mouse info
        // We can then use it however we want
        Input.update((float)x, (float)y);
    }

    void mouse_button_callback(GLFWwindow* window, int button, int action, int mods)
    {
        if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_PRESS) {
            Input.rMousePressed = true;
        }
        else if (button == GLFW_MOUSE_BUTTON_RIGHT && action == GLFW_RELEASE) {
            Input.rMousePressed = false;
        }
        else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
            Input.lMousePressed = true;
        }
        else if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_RELEASE) {
            Input.lMousePressed = false;
        }
    }

    int setupLight()
    {
      // light position uniform
      int lightposHandle = glGetUniformLocation(programID, "light_pos");
      if (lightposHandle == -1) {
        fprintf(stderr, "Error: can't find matrix uniforms\n");
        exit(1);
      }
      // Uniform lighting variables
      int lightambientHandle = glGetUniformLocation(programID, "light_ambient");
        int lightdiffuseHandle = glGetUniformLocation(programID, "light_diffuse");
        int lightspecularHandle = glGetUniformLocation(programID, "light_specular");
        if ( lightambientHandle == -1 ||
        lightdiffuseHandle == -1 ||
        lightspecularHandle == -1) {
        fprintf(stderr, "Error: can't find light uniform variables\n");
            return 1;
      }

      float lightPos[4];   // light position //= { 0.0f, 10.0f, 0.0f, 1.0f };

      float lightambient[3];    // ambient light components
      float lightdiffuse[3];    // diffuse light components
      float lightspecular[3];   // specular light components

      if(lightMode == "DIRECTIONAL"){
        lightambient[0] = 0.0f;
        lightambient[1] = 0.0f;
        lightambient[2] = 0.0f;
        lightdiffuse[0] = 0.5f;
        lightdiffuse[1] = 0.5f;
        lightdiffuse[2] = 1.0f;
        lightspecular[0] = 1.0f;
        lightspecular[1] = 1.0f;
        lightspecular[2] = 1.0f;

        lightPos[0] = -10.0f;
        lightPos[1] = -10.0f;
        lightPos[2] = -10.0f;
        lightPos[3] = 0.0f;

      }else if(lightMode == "HEADLIGHT"){
        lightambient[0] = 0.0f;
        lightambient[1] = 0.0f;
        lightambient[2] = 0.0f;
        lightdiffuse[0] = 1.0f;
        lightdiffuse[1] = 1.0f;
        lightdiffuse[2] = 1.0f;
        lightspecular[0] = 1.0f;
        lightspecular[1] = 1.0f;
        lightspecular[2] = 1.0f;

        glm::mat3 rotMat(Camera->getViewMtx());
        glm::vec3 d((Camera->getViewMtx())[3]);
        glm::vec3 tmp = -d * rotMat;
        lightPos[0] = tmp[0];
        lightPos[1] = tmp[1];
        lightPos[2] = tmp[2];
        lightPos[3] = 1.0f;

      }else if(lightMode == "ROTATING"){
        lightambient[0] = 0.0f;
        lightambient[1] = 0.0f;
        lightambient[2] = 0.0f;
        lightdiffuse[0] = 1.0f;
        lightdiffuse[1] = 1.0f;
        lightdiffuse[2] = 0.2f;
        lightspecular[0] = 1.0f;
        lightspecular[1] = 1.0f;
        lightspecular[2] = 0.2f;

        double now = glfwGetTime();
        lightPos[0] = 10 * cos((now - startTime));
        lightPos[1] = 0.0f;
        lightPos[2] = 10 * sin((now - startTime));
        lightPos[3] = 1.0f;
      }

      glUniform4fv(lightposHandle, 1, lightPos);

        glUniform3fv(lightambientHandle, 1, lightambient);
        glUniform3fv(lightdiffuseHandle, 1, lightdiffuse);
        glUniform3fv(lightspecularHandle, 1, lightspecular);

        return 0;   // return success
    }

    void computeInitScale(){
      float minX = 0;
      float minY = 0;
      float maxX = 0;
      float maxY = 0;

      for(int i = 0; i < shapes.size(); i++){
        for(int j = 0; j < shapes[i].mesh.positions.size()/3; j++){
          //max and min X
          if(shapes[i].mesh.positions[3*j+0] > maxX){
            maxX = shapes[i].mesh.positions[3*j+0];
          }else if(shapes[i].mesh.positions[3*j+0] < minX){
            minX = shapes[i].mesh.positions[3*j+0];
          }
          //max and min Y
          if(shapes[i].mesh.positions[3*j+1] > maxY){
            maxY = shapes[i].mesh.positions[3*j+1];
          }else if(shapes[i].mesh.positions[3*j+1] < minY){
            minY = shapes[i].mesh.positions[3*j+1];
          }
        }
      }

      initScale = 2 / std::max(maxX - minX, maxY - minY);
    }

    void loadRGBTexture(const char *path)
    {
        int x, y, n;

        // Load from file. Force RGB image pixel format
        unsigned char *data = stbi_load(path, &x, &y, &n, 3);

        // Copy to GPU as data for the currently active texture.
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, x, y, 0, GL_RGB, GL_UNSIGNED_BYTE, data);

        stbi_image_free(data);

        glGenerateMipmap(GL_TEXTURE_2D);
    }

    void setMaterials(int i){
      // material
      int mtlambientHandle = glGetUniformLocation(programID, "mtl_ambient");
      int mtldiffuseHandle = glGetUniformLocation(programID, "mtl_diffuse");
      int mtlspecularHandle = glGetUniformLocation(programID, "mtl_specular");

      if (mtlambientHandle == -1 || mtldiffuseHandle == -1 || mtlspecularHandle == -1) {
        fprintf(stderr, "Error: can't find material uniform variables\n");
      }

      float mtlambient[3];
      mtlambient[0] = materials[shapes[i].mesh.material_ids[0]].ambient[0];
      mtlambient[1] = materials[shapes[i].mesh.material_ids[0]].ambient[1];
      mtlambient[2] = materials[shapes[i].mesh.material_ids[0]].ambient[2];
      float mtldiffuse[3];
      mtldiffuse[0] = materials[shapes[i].mesh.material_ids[0]].diffuse[0];
      mtldiffuse[1] = materials[shapes[i].mesh.material_ids[0]].diffuse[1];
      mtldiffuse[2] = materials[shapes[i].mesh.material_ids[0]].diffuse[2];
      float mtlspecular[3];
      mtlspecular[0] = materials[shapes[i].mesh.material_ids[0]].specular[0];
      mtlspecular[1] = materials[shapes[i].mesh.material_ids[0]].specular[1];
      mtlspecular[2] = materials[shapes[i].mesh.material_ids[0]].specular[2];


      glUniform3fv(mtlambientHandle, 1, mtlambient);
      glUniform3fv(mtldiffuseHandle, 1, mtldiffuse);
      glUniform3fv(mtlspecularHandle, 1, mtlspecular);

    }

    void loadObj(){

      std::string err;
      bool ret = tinyobj::LoadObj(shapes, materials, err, objPath.c_str(), folder.c_str());

      if (!err.empty()) {
        std::cerr << err << std::endl;
      }

      if (!ret) {
        exit(1);
      }

      std::cout << "# of shapes    : " << shapes.size() << std::endl;
      std::cout << "# of materials : " << materials.size() << std::endl;

      for (size_t i = 0; i < shapes.size(); i++) {
        printf("shape[%ld].name = %s\n", i, shapes[i].name.c_str());
        printf("Size of shape[%ld].indices: %ld\n", i, shapes[i].mesh.indices.size());
        printf("Size of shape[%ld].material_ids: %ld\n", i, shapes[i].mesh.material_ids.size());
        assert((shapes[i].mesh.indices.size() % 3) == 0);
        for (size_t f = 0; f < shapes[i].mesh.indices.size() / 3; f++) {
          printf("  idx[%ld] = %d, %d, %d. mat_id = %d\n", f, shapes[i].mesh.indices[3*f+0], shapes[i].mesh.indices[3*f+1], shapes[i].mesh.indices[3*f+2], shapes[i].mesh.material_ids[f]);
        }

        printf("shape[%ld].vertices: %ld\n", i, shapes[i].mesh.positions.size());
        assert((shapes[i].mesh.positions.size() % 3) == 0);
        for (size_t v = 0; v < shapes[i].mesh.positions.size() / 3; v++) {
          printf("  v[%ld] = (%f, %f, %f)\n", v,
            shapes[i].mesh.positions[3*v+0],
            shapes[i].mesh.positions[3*v+1],
            shapes[i].mesh.positions[3*v+2]);
        }
      }

      for (size_t i = 0; i < materials.size(); i++) {
        printf("material[%ld].name = %s\n", i, materials[i].name.c_str());
        printf("  material.Ka = (%f, %f ,%f)\n", materials[i].ambient[0], materials[i].ambient[1], materials[i].ambient[2]);
        printf("  material.Kd = (%f, %f ,%f)\n", materials[i].diffuse[0], materials[i].diffuse[1], materials[i].diffuse[2]);
        printf("  material.Ks = (%f, %f ,%f)\n", materials[i].specular[0], materials[i].specular[1], materials[i].specular[2]);
        printf("  material.Tr = (%f, %f ,%f)\n", materials[i].transmittance[0], materials[i].transmittance[1], materials[i].transmittance[2]);
        printf("  material.Ke = (%f, %f ,%f)\n", materials[i].emission[0], materials[i].emission[1], materials[i].emission[2]);
        printf("  material.Ns = %f\n", materials[i].shininess);
        printf("  material.Ni = %f\n", materials[i].ior);
        printf("  material.dissolve = %f\n", materials[i].dissolve);
        printf("  material.illum = %d\n", materials[i].illum);
        printf("  material.map_Ka = %s\n", materials[i].ambient_texname.c_str());
        printf("  material.map_Kd = %s\n", materials[i].diffuse_texname.c_str());
        printf("  material.map_Ks = %s\n", materials[i].specular_texname.c_str());
        printf("  material.map_Ns = %s\n", materials[i].specular_highlight_texname.c_str());
        std::map<std::string, std::string>::const_iterator it(materials[i].unknown_parameter.begin());
        std::map<std::string, std::string>::const_iterator itEnd(materials[i].unknown_parameter.end());
        for (; it != itEnd; it++) {
          printf("  material.%s = %s\n", it->first.c_str(), it->second.c_str());
        }
        printf("\n");
      }

      computeInitScale();
    }

    void createVAO()
    {
      for(int i = 0; i < shapes.size(); i++){
        vaoHandle.push_back(0);
        glGenVertexArrays(1, &vaoHandle[i]);
        glBindVertexArray(vaoHandle[i]);

        unsigned int buffer[5];
        glGenBuffers(4, buffer);

        // Set vertex attribute
        glBindBuffer(GL_ARRAY_BUFFER, buffer[0]);
        glBufferData(GL_ARRAY_BUFFER,
                       sizeof(float) * shapes[i].mesh.positions.size(), &shapes[i].mesh.positions[0], GL_STATIC_DRAW);
        glEnableVertexAttribArray(0);
        glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);

        // Set vertex attribute
        glBindBuffer(GL_ARRAY_BUFFER, buffer[1]);
        glBufferData(GL_ARRAY_BUFFER,
                       sizeof(float) * shapes[i].mesh.normals.size(), &shapes[i].mesh.normals[0], GL_STATIC_DRAW);
        glEnableVertexAttribArray(1);
        glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 0, 0);

        // create material array
        float diffuse[shapes[i].mesh.indices.size() * 3];

        for(int j = 0; j<shapes[i].mesh.indices.size(); j++){
          int index = j*3;
          diffuse[index] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[0];
          diffuse[index + 1] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[1];
          diffuse[index + 2] = materials[shapes[i].mesh.material_ids[j/3]].diffuse[2];
        }

        // Set vertex attribute
        glBindBuffer(GL_ARRAY_BUFFER, buffer[2]);

        glBufferData(GL_ARRAY_BUFFER,
                       shapes[i].mesh.indices.size() * 3 * sizeof(float) , &diffuse[0], GL_STATIC_DRAW);

        glEnableVertexAttribArray(2);
        glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, 0);



        // Set element attributes. Notice the change to using GL_ELEMENT_ARRAY_BUFFER
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer[3]);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER,
                       sizeof(float) * shapes[i].mesh.indices.size(), &shapes[i].mesh.indices[0], GL_STATIC_DRAW);

        // load textures
        texID.push_back(0);
        glGenTextures(1, &texID[i] );
        glActiveTexture(GL_TEXTURE0);
        glBindTexture( GL_TEXTURE_2D, texID[i] );
        loadRGBTexture((folder + (std::string) materials[shapes[i].mesh.material_ids[0]].diffuse_texname).c_str());

        // load texture coordinates
        int texLoc = glGetAttribLocation(programID, "a_tex_coord");

        glBindBuffer(GL_ARRAY_BUFFER, buffer[4]);
        glBufferData(GL_ARRAY_BUFFER,
                      shapes[i].mesh.texcoords.size() * sizeof(float) , &shapes[i].mesh.texcoords[0], GL_STATIC_DRAW);
        glEnableVertexAttribArray(texLoc);
        glVertexAttribPointer(texLoc, 3, GL_FLOAT, GL_FALSE, 0, 0);


        // Un-bind
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArray(0);



      }
    }

    void render()
    {
      glUseProgram(programID);
      glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

      setProjection(programID);

      Camera->update(Input);

      glm::mat4 viewMatrix;
      viewMatrix = Camera->getViewMtx();

        // Load viex to the shader program
        int viewHandle = glGetUniformLocation(programID, "view");
        if (viewHandle == -1) {
            std::cout << "Uniform: view is not an active uniform label\n";
        }
        glUniformMatrix4fv( viewHandle, 1, false, glm::value_ptr(viewMatrix) );

      // Load the model matrix
      int modelUniformHandle = glGetUniformLocation(programID, "model");
      if (modelUniformHandle == -1)
        exit(1);

      // calculate zoom
      if(Input.rMousePressed){
        zoom += Input.yDiff/10;
        if (zoom < 0) zoom = 0;
        if (zoom > 1.5) zoom = 1.5;
      }

      glm::mat4 model;
      model = glm::scale( model, glm::vec3(initScale + zoom, initScale + zoom, initScale + zoom));
      glUniformMatrix4fv( modelUniformHandle, 1, false, glm::value_ptr(model) );

      if (programID == debugShader){
        // set colour mode
        int modeHandle = glGetUniformLocation(programID, "mode");
        if (modeHandle == -1) {
          std::cout << "Uniform: mode is not an active uniform label\n";
        }

        if(meshMode == "MATERIAL"){
          glUniform1i( modeHandle, 1);
        }else{
          glUniform1i( modeHandle, 0);
        }

      }else{
        setupLight();
      }

      // Load meshes
      for(int i = 0; i < shapes.size(); i++){
        glBindVertexArray(vaoHandle[i]);
        glDrawElements(GL_TRIANGLES, shapes[i].mesh.indices.size(), GL_UNSIGNED_INT, 0);

        if (programID == lightTexShader){
          setMaterials(i);
          int texHandle = glGetUniformLocation(programID, "texMap");
          if (texHandle == -1) {
            fprintf(stderr, "Could not find uniform variables\n");
            exit(1);
          }
          glBindTexture(GL_TEXTURE_2D, texID[i]);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
          glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_NEAREST);

        }
        glBindVertexArray(0);
      }
    }




    /**
     * Error callback for GLFW. Simply prints error message to stderr.
     */
    static void error_callback(int error, const char* description)
    {
        fputs(description, stderr);
    }

    int main (int argc, char **argv)
    {
      GLFWwindow* window;
      glfwSetErrorCallback(error_callback);

      if (!glfwInit()) {
          exit(1);
      }

      // Specify that we want OpenGL 3.3
      glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
      glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
      glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
      glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);

      // Create the window and OpenGL context
      window = glfwCreateWindow(winX, winY, "Modelling and viewing", NULL, NULL);
      if (!window)
      {
          glfwTerminate();
          exit(1);
      }

      glfwMakeContextCurrent(window);
      glfwSwapInterval(1);

        // Initialize GLEW
        glewExperimental = true; // Needed for core profile
        if (glewInit() != GLEW_OK) {
            fprintf(stderr, "Failed to initialize GLEW\n");
            exit(1);
        }

      // load shaders
      debugShader = LoadShaders("mview.vert", "mview.frag");
      lightTexShader = LoadShaders("light-texture.vert", "light-texture.frag");

      if (debugShader == 0 || lightTexShader == 0) {
        exit(1);
      }
      programID = debugShader;

      // Set OpenGL state we need for this application.
      glClearColor(0.5F, 0.5F, 0.5F, 0.0F);
        glEnable(GL_DEPTH_TEST);
        glUseProgram(programID);
      glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

      // Set up the scene and the cameras
      //setProjection(debugShader);
      //setProjection(lightTexShader);


      loadObj();
      createVAO();

      ObjCam = new ObjectViewer( cameraPos );
      Camera = ObjCam;

      // Define callback functions and start main loop
      glfwSetKeyCallback(window, key_callback);
      glfwSetCursorPosCallback(window, mouse_pos_callback);
      glfwSetMouseButtonCallback(window, mouse_button_callback);
      glfwSetFramebufferSizeCallback(window, reshape_callback);

      while (!glfwWindowShouldClose(window))
      {
          render();

          glfwSwapBuffers(window);
          glfwPollEvents();
      }

      glfwDestroyWindow(window);
      glfwTerminate();
      exit(0);

      return 0;
    }

顶点着色器

#version 330

 uniform mat4 projection_matrix;
 uniform mat4 modelview_matrix;
 //uniform mat3 normal_matrix;

 layout (location = 0) in vec3 a_vertex;
 layout (location = 1) in vec3 a_normal;
 layout (location = 2) in vec3 a_diffuse;
 in vec2 a_tex_coord;

 uniform mat4 projection;
 uniform mat4 view;
 uniform mat4 model;
 //uniform int mode;
 uniform vec3 mtl_diffuse;

 out vec4 vertex; // vertex position in eye space
 out vec3 normal; // the eye space normal
 out vec2 st;

 void main(void)
 {
   vertex = view * model * vec4(a_vertex, 1.0);
   //normal = normalize(normal_matrix * a_normal);
   normal = a_normal;
   st = a_tex_coord;
   gl_Position =  projection * view * model * vec4(a_vertex, 1.0);
 }

片段着色器

#version 330

in vec4 vertex;
in vec3 normal;
in vec2 st;

out vec4 fragColour;

uniform sampler2D texMap;

uniform vec4 light_pos;

uniform vec3 light_ambient;     // Light ambient RGBA values
uniform vec3 light_diffuse;     // Light diffuse RGBA values
uniform vec3 light_specular;    // Light specular RGBA values

uniform vec3 mtl_ambient;  // Ambient surface colour
uniform vec3 mtl_diffuse;  // Diffuse surface colour
uniform vec3 mtl_specular; // Specular surface colour

const float shininess = 32;


vec3 phongPointLight(in vec4 position, in vec3 norm)
{
    vec3 s = normalize(vec3(light_pos - position));
    if(light_pos.w == 0.0){
      s = -normalize(light_pos.xyz);
    }

    vec3 v = normalize(-position.xyz);
    vec3 r = reflect( -s, norm );

    vec3 ambient = light_ambient * mtl_ambient;

    // The diffuse component
    float sDotN = max( dot(s,norm), 0.0 );
    vec3 diffuse = light_diffuse * mtl_diffuse * sDotN;

    // The specular component BLINN
    vec3 spec = vec3(0.0);
    vec3 halfwayDir = normalize(s + v);

    if ( sDotN > 0.0 )
    spec = light_specular * mtl_specular * pow(max(dot(normalize(normal), halfwayDir), 0.0), 32.0);

    return ambient + diffuse + spec;
}

void main(void)
{
    fragColour = vec4(phongPointLight(vertex, normalize(normal)), 1.0) * texture(texMap, st);
}

enter image description here

这是结果 . 正如您所看到的,纹理没有正确定位在汽车上 .