My cube:
#define _CRT_SECURE_NO_WARNINGS
#include <glad/glad.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include "stb/stb_image.h"
#include <cglm/cglm.h>
typedef struct WindowData {
GLFWwindow* window;
int status;
} WindowData;
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow* window);
unsigned int setUpShader(const char* vertSource, const char* fragSource);
WindowData buildWindow();
unsigned int setUpTexture();
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
//shaders
const char* vertexShaderSource3 = "#version 330 core\n" // vert // projection shader
"layout(location = 0) in vec3 aPos;\n"
"layout (location = 1) in vec3 aColor;\n"
"layout(location = 2) in vec2 aTexCoord;\n"
"out vec3 vertexColor;\n"
"out vec2 TexCoord;\n"
"out vec3 vertexPos;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"void main()\n"
"{\n"
" vertexColor = aColor; \n"
" vertexPos = aPos;\n"
" gl_Position = projection * view * model * vec4(aPos, 1.0);\n"
" TexCoord = aTexCoord;\n"
"}\n";
const char* fragmentShaderSource4 = "#version 330 core\n" //frag // texture RGB shader
"out vec4 FragColor;\n"
"in vec3 vertexColor;\n"
"in vec2 TexCoord;\n"
"uniform sampler2D ourTexture;\n"
"void main()\n"
"{\n"
" FragColor = texture(ourTexture, TexCoord) * vec4(vertexColor, 1.0);\n"
"}\n\0";
int main(int argc, char* argv[])
{
// SETUP WINDOW
WindowData windowBuildResult = buildWindow();
if(windowBuildResult.status == -1) {
return -1;
}
GLFWwindow* window = windowBuildResult.window;
// GLAD: LOAD ALL OpenGL FUNCTION POINTERS
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
printf("Failed to initialize GLAD\n");
return -1;
}
// SET UP SHADERS AND TEXTURES
unsigned int modelShader = setUpShader(vertexShaderSource3, fragmentShaderSource4);
glEnable(GL_DEPTH_TEST);
// SET UP VERTEX DATA AND VBOs/VAOs/EBO
float cube1verts[] = {
//---position---// //----color----// // texture coordinates
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 0
0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 1
-0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 2
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 3
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 4
0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 5
0.5f, 0.5f, 0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 6
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 7
-0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 7
-0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 3
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 2
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 4
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 6
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 0
0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 1
0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 5
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 2
0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 1
0.5f, -0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 5
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 4
-0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // 3
0.5f, 0.5f, -0.5f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, // 0
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 0.0f, 1.0f, 0.0f, // 6
-0.5f, 0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, // 7
};
unsigned int indices[] = {
0, 1, 3, // 1st triangle
1, 2, 3, // 2nd triangle
4, 5, 6, // 3rd triangle
6, 7, 4, // 4th triangle
7, 3, 2, // 5th triangle
2, 4, 7, // 6th triangle
6, 0, 1, // 7th triangle
1, 5, 6, // 8th triangle
2, 1, 5, // 9th triangle
5, 4, 2, // 10th triangle
3, 0, 6, // 11th triangle
6, 7, 3, // 12th triangle
};
unsigned int VBOs[1], VAOs[1], EBOs[1];
glGenVertexArrays(1, VAOs);
glGenBuffers(1, VBOs);
glGenBuffers(1, EBOs);
// SETUP TEXTURES
unsigned int texture = setUpTexture();
// SETUP RENDERING
// CUBE
glBindVertexArray(VAOs[0]);
glBindBuffer(GL_ARRAY_BUFFER, VBOs[0]);
glBufferData(GL_ARRAY_BUFFER, sizeof(cube1verts), quad2verts, GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[0]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(3 * sizeof(float)));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
glEnableVertexAttribArray(2);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
// RENDER LOOP
while (!glfwWindowShouldClose(window))
{
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// DRAW TEXTURED CUBE IN PERSPECTIVE
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[0]);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUseProgram(modelShader);
mat4 model = GLM_MAT4_IDENTITY_INIT;
mat4 view = GLM_MAT4_IDENTITY_INIT;
mat4 projection = GLM_MAT4_IDENTITY_INIT;
glm_rotate(model, (float)glfwGetTime(), (vec3){ 0.5f, 1.0f, 0.0f });
glm_translate(view, (vec3){0.0f, 0.0f, -3.0f});
glm_perspective(glm_rad(45.0f), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f, projection);
unsigned int modelLoc = glGetUniformLocation(modelShader, "model");
unsigned int viewLoc = glGetUniformLocation(modelShader, "view");
unsigned int projectionLoc = glGetUniformLocation(modelShader, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, (const GLfloat*) model);
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, (const GLfloat*) view);
glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, (const GLfloat*) projection);
glBindVertexArray(VAOs[0]);
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, 0);
// SWAP BUFFERS AND CHECK FOR USER INPUTS
glfwSwapBuffers(window);
glfwPollEvents();
}
// DE-ALLOCATE RESOURCES
glDeleteVertexArrays(1, VAOs);
glDeleteBuffers(1, VBOs);
glDeleteBuffers(1, EBOs);
glDeleteProgram(modelShader);
// CLEAR ALL RESOURCES AND STOP OpenGL
glfwTerminate();
return 0;
}
// CHANGE WINDOW SIZE AND VIEWPORT
void framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void processInput(GLFWwindow* window) {
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS) {
glfwSetWindowShouldClose(window, 1);
}
}
unsigned int setUpShader(const char* vertSource, const char* fragSource) {
unsigned int vertexShader;
vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertSource, NULL);
glCompileShader(vertexShader);
int success;
char infoLog[512];
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(vertexShader, 512, NULL, infoLog);
printf("ERROR::SHADER::VERTEX::COMPILATION_FAILED\n%s\n", infoLog);
}
unsigned int fragmentShader;
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragSource, NULL);
glCompileShader(fragmentShader);
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success);
if (!success) {
glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog);
printf("ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n%s\n", infoLog);
}
unsigned int shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success);
if (!success) {
glGetProgramInfoLog(shaderProgram, 512, NULL, infoLog);
printf("ERROR::SHADER::PROGRAM::LINKING_FAILED\n%s\n", infoLog);
}
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
return shaderProgram;
}
WindowData buildWindow() {
// INIT GLFW
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
// CHANGE SETTINGS BASED ON OS
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// BUILD WINDOW
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
WindowData windowData = { window, 0 };
if (window == NULL)
{
printf("Failed to create GLFW window\n");
glfwTerminate();
windowData.status = -1;
return windowData;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
return windowData;
}
unsigned int setUpTexture(){
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
int width, height, nrChannels;
stbi_set_flip_vertically_on_load(1);
unsigned char* data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
if (data) {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
}
else {
printf("ERROR::TEXTURE::LOAD::FAILED\n");
}
stbi_image_free(data);
return texture;
}
...doesn't render the texture correctly on all sides, only on the front facing side and back facing side, but the left/right/top/bottom sides have the textures stretched:
I've tried changing the texture setup properties from GL_LINEAR
to GL_REPEAT
to no luck. I've changed the texture coordinates hoping that might fix it, but also no luck. I'm pretty sure I have the EBO
setup properly but I could be wrong.
I am using version 3.3 of OpenGL.
The only two things I can think of that might be an issue are:
z
coordinate for my texture data in the vertex data.indices
was not properly set up. The new indices
array looks like this:
unsigned int indices[] = {
//front face
0, 1, 3, // 1st triangle
1, 2, 3, // 2nd triangle
//back face
4, 5, 6, // 3rd triangle
6, 7, 4, // 4th triangle
//left face
8, 9, 11, // 5th triangle
9, 10, 11, // 6th triangle
//right face
12, 13, 15, // 7th triangle
13, 14, 15, // 8th triangle
//bottom face
16, 17, 19, // 9th triangle
17, 18, 19, // 10th triangle
//top face
20, 21, 23, // 11th triangle
21, 22, 23, // 12th triangle
};
When properly setting up how you want the cube to render, make sure that you are using the index of a specific set of vertex data and not just a vertex order. Make sure you are also putting the indexes in the correct order or else the triangles will be drawn incorrectly. This is not explicitly mentioned in the learnopengl.com tutorials when it goes over EBOs so be aware of it.