2
\$\begingroup\$

Using OpenGL tutorials found here, I constructed an .obj file loader as well as a texture file loader using SOIL. I have an issue with drawing a textured object. (Shown here) Assuming I created the loaders correctly, my issue is within my rendering method (actually drawing the triangles on the screen). As you can see my texture seems to bend and warp in a very strange way. I've asked a couple of different sources and they can't seem to explain why it happens. My (admittedly messy) code is like this:

Shaders:

#version 120
//VShader
attribute vec3 verPos;
attribute vec2 UV;

varying vec2 f_UV;

uniform mat4 MVP;

void main()
{     
    vec4 v = vec4(verPos, 1.0);
    v = MVP * v;
    gl_Position = v;
    f_UV = UV;
}

#version 120
//FShader
uniform sampler2D TextSamp2D;
varying vec2 f_UV;

void main()
{
    gl_FragColor = texture2D(TextSamp2D, f_UV);
}

And this is all of the renderering code compressed into one main file (no I don't frame limit, but my computer is super junky, hence the GLSL 120) :

#include <fstream>
#include <string>
#include <vector>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <cmath>
#define GLM_FORCE_RADIANS
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/vec3.hpp>
#include <glm/vec2.hpp>
#include <glm/gtx/euler_angles.hpp>
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>

#include <SDL2/SDL.h>
#include <GL/glew.h>
#include <GL/glu.h>
#include <SDL2/SDL_opengl.h>
#include "SDL2/SDL_image.h"
#include "SOIL/SOIL.h"

bool initGL();
void close();
void Move();
GLuint loadImage(const char*);
GLuint LoadShaders(const char*, const char*);

//The window we'll be rendering to
SDL_Window* window = NULL;

SDL_GLContext glContext;

//Screen dimension constants
bool gameRunning = true;                       
bool arrows[] = {0, 0, 0, 0};

GLuint programID;

glm::vec3 direction;
glm::vec3 myPos;
glm::vec3 myAngle;
glm::vec3 forwardVec;

glm::mat4 projectionMatrix = glm::perspective(glm::radians(45.0f), 4.0f / 3.0f, 0.1f, 1000.0f);
glm::mat4 viewMatrix = glm::mat4(1.0f);

int main(int argc, char* args[]){
    if(SDL_Init(SDL_INIT_VIDEO) < 0){
        std::cout << "Init Error: " << SDL_GetError() << std::endl;
        gameRunning = false;
    }

    window = SDL_CreateWindow("Eximius", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 480, SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN);

    if(window == NULL){
        printf("Window could not be created! SDL_Error: %s\n", SDL_GetError());
        gameRunning = false;
    }
    if(!initGL()){
        std::cout << "OpenGL Init Failed" << std::endl;
        gameRunning = false;
    }

    SDL_Event e;

    programID = LoadShaders("vshade.txt", "fshade.txt");

    myPos.y = 0.0f;

    static const GLfloat g_vertex_buffer_data[] = { 
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
         1.0f, 1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
         1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
         1.0f,-1.0f,-1.0f,
         1.0f, 1.0f,-1.0f,
         1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
         1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
        -1.0f,-1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
        -1.0f,-1.0f, 1.0f,
         1.0f,-1.0f, 1.0f,
         1.0f, 1.0f, 1.0f,
         1.0f,-1.0f,-1.0f,
         1.0f, 1.0f,-1.0f,
         1.0f,-1.0f,-1.0f,
         1.0f, 1.0f, 1.0f,
         1.0f,-1.0f, 1.0f,
         1.0f, 1.0f, 1.0f,
         1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f,-1.0f,
         1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f,-1.0f,
        -1.0f, 1.0f, 1.0f,
         1.0f, 1.0f, 1.0f,
        -1.0f, 1.0f, 1.0f,
         1.0f,-1.0f, 1.0f
    };

    static const GLfloat g_uv_buffer_data[] = { 
        0.000059f, 1.0f-0.000004f, 
        0.000103f, 1.0f-0.336048f, 
        0.335973f, 1.0f-0.335903f, 
        1.000023f, 1.0f-0.000013f, 
        0.667979f, 1.0f-0.335851f, 
        0.999958f, 1.0f-0.336064f, 
        0.667979f, 1.0f-0.335851f, 
        0.336024f, 1.0f-0.671877f, 
        0.667969f, 1.0f-0.671889f, 
        1.000023f, 1.0f-0.000013f, 
        0.668104f, 1.0f-0.000013f, 
        0.667979f, 1.0f-0.335851f, 
        0.000059f, 1.0f-0.000004f, 
        0.335973f, 1.0f-0.335903f, 
        0.336098f, 1.0f-0.000071f, 
        0.667979f, 1.0f-0.335851f, 
        0.335973f, 1.0f-0.335903f, 
        0.336024f, 1.0f-0.671877f, 
        1.000004f, 1.0f-0.671847f, 
        0.999958f, 1.0f-0.336064f, 
        0.667979f, 1.0f-0.335851f, 
        0.668104f, 1.0f-0.000013f, 
        0.335973f, 1.0f-0.335903f, 
        0.667979f, 1.0f-0.335851f, 
        0.335973f, 1.0f-0.335903f, 
        0.668104f, 1.0f-0.000013f, 
        0.336098f, 1.0f-0.000071f, 
        0.000103f, 1.0f-0.336048f, 
        0.000004f, 1.0f-0.671870f, 
        0.336024f, 1.0f-0.671877f, 
        0.000103f, 1.0f-0.336048f, 
        0.336024f, 1.0f-0.671877f, 
        0.335973f, 1.0f-0.335903f, 
        0.667969f, 1.0f-0.671889f, 
        1.000004f, 1.0f-0.671847f, 
        0.667979f, 1.0f-0.335851f
    };
    GLuint vBuffer;
    glGenBuffers(1, &vBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, vBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);

    GLuint uvBuffer;
    glGenBuffers(1, &uvBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(g_uv_buffer_data), g_uv_buffer_data, GL_STATIC_DRAW);

    GLuint tex;
    tex = loadImage("uvtemplate.tga");

    GLuint verPosAttrib = glGetAttribLocation(programID, "verPos");
    GLuint UVAttrib = glGetAttribLocation(programID, "UV");
    GLuint sampID = glGetAttribLocation(programID, "TextSamp2D");
    GLuint mvpID = glGetUniformLocation(programID, "MVP");
    float i = 0.0f;

    myPos.z = 20.0f;
    while(gameRunning){
        Move();

        forwardVec = glm::vec3(-sin(glm::radians(myAngle.y)), 0.0f, -cos(glm::radians(myAngle.y)));
        glUseProgram(programID);

        viewMatrix = glm::lookAt(myPos, myPos + forwardVec, glm::vec3(0,1,0));

        glDepthMask(GL_TRUE);

        glUniform1i(sampID, 0);

        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);     

        //Just the scale of the model matrix
        glm::mat4 modelScale = glm::scale(glm::vec3(5.0f, 5.0f, 5.0f));
        i += 0.01f;
        glm::quat myQuat;
        myQuat = glm::quat(myAngle);
        glm::mat4 modelRot = glm::eulerAngleYXZ(i, 0.0f, 0.0f);

        glm::mat4 model = modelScale * modelRot;
        glm::mat4 MVP = projectionMatrix * viewMatrix * model;
        glUniformMatrix4fv(mvpID, 1, GL_FALSE, &MVP[0][0]);

        glEnableVertexAttribArray(verPosAttrib);
        glBindBuffer(GL_ARRAY_BUFFER, vBuffer);
        glVertexAttribPointer(
            verPosAttrib, 
            3, 
            GL_FLOAT,
            GL_FALSE,
            0, 
            (GLvoid*)0
        );

        glEnableVertexAttribArray(UVAttrib);
        glBindBuffer(GL_ARRAY_BUFFER, uvBuffer);
        glVertexAttribPointer(
            UVAttrib,
            2, 
            GL_FLOAT,
            GL_FALSE,
            0, 
            (GLvoid*)0
        );

        glActiveTexture(GL_TEXTURE0 + 0);
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);

        glDrawArrays(GL_TRIANGLES, 0, 36);

        SDL_GL_SwapWindow(window);

        glDisableVertexAttribArray(verPosAttrib);
        glDisableVertexAttribArray(UVAttrib);

        while(SDL_PollEvent(&e) != 0){
            if(e.type == SDL_QUIT){
                gameRunning = false;
            }
            else if(e.type == SDL_KEYDOWN){
                switch(e.key.keysym.sym){
                    case SDLK_DOWN:
                        arrows[3] = true;
                    break;
                    case SDLK_LEFT:
                        arrows[2] = true;
                    break;
                    case SDLK_RIGHT:
                        arrows[0] = true;
                    break;
                    case SDLK_UP:
                        arrows[1] = true;
                    break;
                }
            }
            else if(e.type == SDL_KEYUP){
                switch(e.key.keysym.sym){
                    case SDLK_DOWN:
                        arrows[3] = false;
                    break;
                    case SDLK_LEFT:
                        arrows[2] = false;
                    break;
                    case SDLK_RIGHT:
                        arrows[0] = false;
                    break;
                    case SDLK_UP:
                        arrows[1] = false;
                    break;
                }
            }
        }
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    }
    close();
    return 0;
}
bool initGL(){
    glContext = SDL_GL_CreateContext(window);

    if(glContext == NULL){
        std::cout << "OpenGL context Failed: " << SDL_GetError() << std::endl;
        return false;
    }

    glewExperimental = GL_TRUE;
    GLenum err = glewInit();
    if(GLEW_OK != err){
        std::cout << "GLEW FAILED" << glewGetErrorString(err) << std::endl;
        return false;
    }
    if(glewIsSupported("GL_VERSION_4_0")){
        printf("Ready for OpenGL 4.0\n");
    }

    GLuint vaID;
    glGenVertexArrays(1, &vaID);
    glBindVertexArray(vaID);

    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
    SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);

    SDL_GL_SetSwapInterval(1);
    SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8);
    SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8);

    SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
    SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);

    glEnable(GL_DEPTH_TEST);
    glShadeModel(GL_SMOOTH);
    glDepthFunc(GL_LEQUAL);
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);

    return true;
}
void close(){
    //Destroy window
    SDL_DestroyWindow(window);
    SDL_GL_DeleteContext(glContext);
    //IMG_Quit();
    SDL_Quit();
}
GLuint loadImage(const char * image){
    GLuint texID;
    glActiveTexture(GL_TEXTURE_2D);

    texID = SOIL_load_OGL_texture(image, SOIL_LOAD_AUTO, SOIL_CREATE_NEW_ID, SOIL_FLAG_INVERT_Y | SOIL_FLAG_NTSC_SAFE_RGB);
    glBindTexture(GL_TEXTURE_2D, texID);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    if(texID == 0){
        std::cout << "FAILED TO LOAD TEXTURE" << std::endl;
    }
    else return texID;
}

GLuint LoadShaders(const char * vertexFPath, const char * fragmentFPath){
    GLuint vSID = glCreateShader(GL_VERTEX_SHADER);
    GLuint fSID = glCreateShader(GL_FRAGMENT_SHADER);

    std::string VertexShaderCode;
    std::ifstream VertexShaderStream(vertexFPath, std::ios::in);
    if(VertexShaderStream.is_open()){
        std::string Line = "";
        while(getline(VertexShaderStream, Line))
            VertexShaderCode += "\n" + Line;
        VertexShaderStream.close();
    }
    std::string FragmentShaderCode;
    std::ifstream FragmentShaderStream(fragmentFPath, std::ios::in);
    if(FragmentShaderStream.is_open()){
        std::string Line = "";
        while(getline(FragmentShaderStream, Line))
            FragmentShaderCode += "\n" + Line;
        FragmentShaderStream.close();
    }
    GLint Result = GL_FALSE;
    int InfoLogLength;

    std::cout << "Compiling Shader: " << vertexFPath << std::endl;
    char const * VSource = VertexShaderCode.c_str();
    glShaderSource(vSID, 1, &VSource, NULL);
    glCompileShader(vSID);

    glGetShaderiv(vSID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(vSID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> VertexShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(vSID, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
    fprintf(stdout, "%s\n", &VertexShaderErrorMessage[0]);


    std::cout << "Compiling Shader: " << fragmentFPath << std::endl;
    char const * FSource = FragmentShaderCode.c_str();
    glShaderSource(fSID, 1, &FSource, NULL);
    glCompileShader(fSID);

    glGetShaderiv(fSID, GL_COMPILE_STATUS, &Result);
    glGetShaderiv(fSID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> FragmentShaderErrorMessage(InfoLogLength);
    glGetShaderInfoLog(fSID, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
    fprintf(stdout, "%s\n", &FragmentShaderErrorMessage[0]);

    std::cout << "Linking Program" << std::endl;
    GLuint ProgramID = glCreateProgram();
    glAttachShader(ProgramID, vSID);
    glAttachShader(ProgramID, fSID);
    glLinkProgram(ProgramID);

    glGetProgramiv(ProgramID, GL_LINK_STATUS, &Result);
    glGetProgramiv(ProgramID, GL_INFO_LOG_LENGTH, &InfoLogLength);
    std::vector<char> ProgramErrorMessage(std::max(InfoLogLength, int(1)));
    glGetProgramInfoLog(ProgramID, InfoLogLength, NULL, &ProgramErrorMessage[0]);
    fprintf(stdout, "%s\n", &ProgramErrorMessage[0]);

    glDeleteShader(vSID);
    glDeleteShader(fSID);
    return ProgramID;
}

void Move(){
    if(arrows[0]){
        myAngle -= glm::radians(45.f);
    }
    if(arrows[1]){
        myPos = myPos + forwardVec * 0.2f;
    }
    if(arrows[2]){
       myAngle.y += glm::radians(45.f);
    }
    if(arrows[3]){
        myPos = myPos - forwardVec * 0.2f;
    }
}

My question is, why does the texture bend and warp when I rotate the view matrix on the y axis? That is, at what horrifically easy juncture did I go so wrong?

UPDATE:

I tried removing model scale and it didn't stop the texture warping. I've also rechecked the code, and I cannot seem to find where it would cause the warping.

UPDATE 2:

I've taken all of the code that has to do with rendering and compressed it into a few files so that I can show every step I've taken in case something went wrong somewhere unexpected. The issue appears the same way as it did before (tested on my Linux box).

\$\endgroup\$
  • \$\begingroup\$ Do you happen to have a screenshot that demonstrates the problem? \$\endgroup\$ – Panda Pajama Jun 22 '15 at 14:12
  • \$\begingroup\$ Better, I have a video that does. I posted it here, youtube.com/watch?v=OfOHd88mXNI&feature=youtu.be \$\endgroup\$ – Devmane144 Jun 22 '15 at 14:40
  • \$\begingroup\$ I don't know what your geometry looks like, but I think your problem is in your matrix math. I'm not familiar with the library you're using, but you may want to simplify on your matrix operations, and perhaps try to multiply them in inverse order to see if you can find more information. Also, you're setting three vertex attribute arrays, yet you're only using two. Also you're not using some of your variants, so you may want to clean up your code to a bare minimum and work your way up from there \$\endgroup\$ – Panda Pajama Jun 22 '15 at 15:59
  • \$\begingroup\$ I flicked the display into polygon mode using glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); and saw that all of the geometry was straightforward and expected, but the UVs seem to have the issue here. Do I need to apply the transformations to the UVs or similar? \$\endgroup\$ – Devmane144 Jun 22 '15 at 23:51
  • \$\begingroup\$ Also I cleaned some of my junk-code out. \$\endgroup\$ – Devmane144 Jun 23 '15 at 0:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.