I'm trying to learn displaying Texture using Shader program using OpenGL 3.30. I'm able to load the image but I can't get it displayed correctly on each cube's face.
The code below defines properties of a Vertex, which is its vertices and texture coordinates associated with each cube's vertex. Then 2 VBOs are created, one holds cube vertices and the other one holds textures information.
I think I'm very closed to the final result: I got the cube, loaded image successfully, able to get image information. So what did I do wrongly here?
I'm using stblib to load the image.
This is my code:
#include <windows.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stddef.h> /* must include for the offsetof macro */
#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 <stdlib.h>
#include "utils.h"
#include "stb_image.h"
struct Vertex {
GLdouble position[3];
GLdouble texture[2];
};
/* These pointers will receive the contents of our shader source code files */
GLchar *vertexsource, *fragmentsource;
/* These are handles used to reference the shaders */
GLuint vertexshader, fragmentshader;
/* This is a handle to the shader program */
GLuint shaderprogram;
GLuint vbo[1]; /* Create handles for our Vertex Array Object and One Vertex Buffer Object */
//GLuint text_2d_1;
const struct Vertex plane[24] = {
// Front Face
{{1.0f, 1.0f, 1.0f}, {0.0, 0.0}},
{{-1.0f, 1.0f, 1.0f}, {1.0, 0.0}},
{{-1.0f, -1.0f, 1.0f}, {1.0, 1.0}},
{{ 1.0f, -1.0f, 1.0f}, {0.0, 1.0}},
// Back Face
{{-1.0f, -1.0f, -1.0f}, {1.0, 0.0}},
{{-1.0f, 1.0f, -1.0f}, {1.0, 1.0}},
{{ 1.0f, 1.0f, -1.0f}, {0.0, 1.0}},
{{ 1.0f, -1.0f, -1.0f}, {0.0, 0.0}},
// Top Face
{{-1.0f, 1.0f, -1.0f}, {0.0, 1.0}},
{{-1.0f, 1.0f, 1.0f}, {0.0, 0.0}},
{{ 1.0f, 1.0f, 1.0f}, {1.0, 0.0}},
{{ 1.0f, 1.0f, -1.0f}, {1.0, 1.0}},
// Bottom Face
{{-1.0f, -1.0f, -1.0f}, {1.0, 1.0}},
{{ 1.0f, -1.0f, -1.0f}, {0.0, 1.0}},
{{ 1.0f, -1.0f, 1.0f}, {0.0, 0.0}},
{{-1.0f, -1.0f, 1.0f}, {1.0, 0.0}},
// Right face
{{1.0f, -1.0f, -1.0f}, {1.0, 0.0}},
{{1.0f, 1.0f, -1.0f}, {1.0, 1.0}},
{{1.0f, 1.0f, 1.0f}, {0.0, 1.0}},
{{1.0f, -1.0f, 1.0f}, {0.0, 0.0}},
// Left Face
{{-1.0f, -1.0f, -1.0f}, {0.0, 0.0}},
{{-1.0f, -1.0f, 1.0f}, {1.0, 0.0}},
{{-1.0f, 1.0f, 1.0f}, {1.0, 1.0}},
{{-1.0f, 1.0f, -1.0f}, {0.0, 1.0}}
};
void SetupGeometry() {
/* Allocate and assign One Vertex Buffer Object to our handle */
glGenBuffers(1, vbo);
/* Bind our VBO as being the active buffer and storing vertex attributes (coordinates + colors) */
glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
/* Copy the vertex data from plane to our buffer */
/* 12 * sizeof(GLfloat) is the size of the tetrahedrom array, since it contains 12 Vertex values */
glBufferData ( GL_ARRAY_BUFFER, 24 * sizeof ( struct Vertex ), plane, GL_STATIC_DRAW );
/* Specify that our coordinate data is going into attribute index 0, and contains three doubles per vertex */
/* Note stride = sizeof ( struct Vertex ) and pointer = ( const GLvoid* ) 0 */
glVertexAttribPointer ( ( GLuint ) 0, 3, GL_DOUBLE, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
/* Enable attribute index 0 as being used */
glEnableVertexAttribArray(0);
/* Specify that our color data is going into attribute index 1, and contains three floats per vertex */
/* Note stride = sizeof ( struct Vertex ) and pointer = ( const GLvoid* ) ( 3 * sizeof ( GLdouble ) ) i.e. the size (in bytes)
occupied by the first attribute (position) */
glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );
/* Enable attribute index 1 as being used */
glEnableVertexAttribArray ( 1 );/* Bind our fourth VBO as being the active buffer and storing vertex attributes (texture) */
printf("vertex %d\n", offsetof(struct Vertex,position));
printf("texture %d\n", offsetof(struct Vertex,texture));
}
void SetupShaders(void) {
/* Read our shaders into the appropriate buffers */
vertexsource = filetobuf("plane/plane.vert");
fragmentsource = filetobuf("plane/plane.frag");
/* Assign our handles a "name" to new shader objects */
vertexshader = glCreateShader(GL_VERTEX_SHADER);
fragmentshader = glCreateShader(GL_FRAGMENT_SHADER);
/* Associate the source code buffers with each handle */
glShaderSource(vertexshader, 1, (const GLchar**)&vertexsource, 0);
glShaderSource(fragmentshader, 1, (const GLchar**)&fragmentsource, 0);
/* Compile our shader objects */
glCompileShader(vertexshader);
glCompileShader(fragmentshader);
/* Assign our program handle a "name" */
shaderprogram = glCreateProgram();
glAttachShader(shaderprogram, vertexshader);/* Attach our shaders to our program */
glAttachShader(shaderprogram, fragmentshader);
glBindAttribLocation(shaderprogram, 0, "in_Position"); /* Bind attribute 0 (coordinates) to in_Position and attribute 1 (colors) to in_Texture */
glBindAttribLocation(shaderprogram, 1, "in_Texture");
glLinkProgram(shaderprogram);/* Link our program, and set it as being actively used */
glUseProgram(shaderprogram);
}
void Render(int i) {
GLfloat angle;
glm::mat4 Projection = glm::perspective(45.0f, 1.0f, 0.1f, 100.0f);
angle = (GLfloat) (i % 360);
glm::mat4 View = glm::mat4(1.);
View = glm::translate(View, glm::vec3(0.f, 0.f, -5.0f));
View = glm::rotate(View, angle * -1.0f, glm::vec3(1.f, 0.f, 0.f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.f, 1.f, 0.f));
View = glm::rotate(View, angle * 0.5f, glm::vec3(0.f, 0.f, 1.f));
glm::mat4 Model = glm::mat4(1.0);
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(glGetUniformLocation(shaderprogram, "mvpmatrix"), 1, GL_FALSE, glm::value_ptr(MVP));
/* Bind our modelmatrix variable to be a uniform called mvpmatrix in our shaderprogram */
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawArrays(GL_QUADS, 0, 24);
/* Invoke glDrawArrays telling that our data consists of individual triangles */
}
int reverse = 1;
static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) {
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(window, GL_TRUE);
if ((key == GLFW_KEY_R) && action == GLFW_PRESS)
reverse = 1 - reverse; // togrls reverse from 0 to 1 to o to ...
}
int main( void ) {
int k = 0;
GLFWwindow* window;
if( !glfwInit() ) {
printf("Failed to start GLFW\n");
exit( EXIT_FAILURE );
}
window = glfwCreateWindow(640, 480, "Hello World", NULL, NULL);
if (!window) {
glfwTerminate();
printf("GLFW Failed to start\n");
return -1;
}
/* Make the window's context current */
glfwMakeContextCurrent(window); // IMPORTANT: Must be done so glew recognises OpenGL
glewExperimental = GL_TRUE;
int err = glewInit();
if (GLEW_OK != err) {
/* Problem: glewInit failed, something is seriously wrong. */
fprintf(stderr, "Error: %s\n", glewGetErrorString(err));
}
fprintf(stderr, "Glew done\n");
glfwSetKeyCallback(window, key_callback);
fprintf(stderr, "GL INFO %s\n", glGetString(GL_VERSION));
SetupGeometry();
SetupShaders();
int w, h, n, O;
char *filename = "plane/rock.bmp";
unsigned char * data = stbi_load(filename, &w, &h, &n, 0); //image data
if(data == NULL) {
print("Image not loaded");
const char *error = stbi_failure_reason();
printf("Failure reason %s\n", error);
exit(0);
}else{
print("Image loaded successfully");
}
printf("Image Stats %d %d %d\n", w, h, n);
// for(int d = 0; d < w * h * 3; d++)
// printf("img content: %i\n",data[d]);
printf (" first 4 bytes are: %i %i %i %i\n", data[ 0], data[ 1], data[ 2], data[ 3] );
GLuint tex;
glGenTextures(1, &tex);
Print("Texture");
Print(GL_TEXTURE0);
print((int) tex);
//glActiveTexture(GL_TEXTURE0);
/*
* To get the texture to activate, take the base texture GL_TEXTURE0 and add the value of the generated texture.
* This needs checking with more than one texture.
* beware of NIDIA specific.
*/
//glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, data);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
stbi_image_free(data); // free up image data
//glDisable(gl_te)
glEnable(GL_DEPTH_TEST);
glClearColor(0.0, 0.0, 0.0, 1.0);/* Make our background black */
while( !glfwWindowShouldClose(window) ) {// Main loop
Render(k);// OpenGL rendering goes here...
if(reverse)
k--;
else
k++;
Sleep(20);
glfwSwapBuffers(window);// Swap front and back rendering buffers
glfwPollEvents();
}
glfwTerminate();// Close window and terminate GLFW
exit( EXIT_SUCCESS );// Exit program
}
The vertex shader:
#version 330
precision highp float;
in vec3 in_Position;
in vec2 in_Texture;
// mvpmatrix is the result of multiplying the model, view, and projection matrices */
uniform mat4 mvpmatrix;
out vec2 UV;
void main(void) {
// Multiply the mvp matrix by the vertex to obtain our final vertex position
gl_Position = mvpmatrix * vec4(in_Position, 1.0);
UV = in_Texture;
}
Fragment shader:
#version 330
precision highp float;
in vec2 UV;
out vec3 color;
uniform sampler2D myTexture;
void main(void) {
color = texture(myTexture, UV).rgb;
}
This is input image:
This is output of the program:
There is some inconsistency in the data types you are using. The declaration of your struct uses doubles for both position and texture coordinates:
struct Vertex {
GLdouble position[3];
GLdouble texture[2];
};
During attribute setup, you're using different types:
glVertexAttribPointer ( ( GLuint ) 0, 3, GL_DOUBLE, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );
The texture coordinates are used as GL_FLOAT here. Also, you specify 3 components here, where the struct has only 2.
There's very rarely a good reason to use doubles for coordinates. OpenGL will use 32-bit precision internally anyway. So if you specify attributes as doubles, you will only add conversions, and use more memory.
To use float for everything, the struct should be declared like this:
struct Vertex {
GLfloat position[3];
GLfloat texture[2];
};
The attribute specification then looks like this:
glVertexAttribPointer ( ( GLuint ) 0, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof (struct Vertex,position) );
glVertexAttribPointer ( ( GLuint ) 1, 2, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) ); // bug );
The problem lies here:
/* Specify that our color data is going into attribute index 1,
and contains three floats per vertex */
/* Note stride = sizeof ( struct Vertex ) and
pointer = ( const GLvoid* ) ( 3 * sizeof ( GLdouble ) )
i.e. the size (in bytes) occupied by the first attribute
(position) */
glVertexAttribPointer ( ( GLuint ) 1, 3, GL_FLOAT, GL_FALSE, sizeof ( struct Vertex ), ( const GLvoid* ) offsetof(struct Vertex,texture) );
The vertex texture coordinate attribute has two elements, but you're telling OpenGL that there were 3 elements in succession. This obviously neither matches your vertex data nor the shader vertex attribute type. Adjust the element size to 2 and it should work. Oh, and you don't have to explicitly cast a number literal to GLuint.
Related
I have been able to create a 3D cube in OpenGL but need assistance with positioning it in the upper left-hand corner of the window. No matter what I try I cannot seem to get the cube in the upper left-hand corner of the window. Currently, the 3D Cube is position close to the center of the window. I have provided the C++ OpenGL code below for reference. Can someone please let me know where I am going wrong?
#include <iostream> // cout, cerr
#include <cstdlib> // EXIT_FAILURE
#include <GL/glew.h> // GLEW library
#include <GLFW/glfw3.h> // GLFW library
// GLM Math Header inclusions
#include <glm/glm.hpp>
#include <glm/gtx/transform.hpp>
#include <glm/gtc/type_ptr.hpp>
using namespace std; // Standard namespace
/*Shader program Macro*/
#ifndef GLSL
#define GLSL(Version, Source) "#version " #Version " core \n" #Source
#endif
// Unnamed namespace
namespace
{
const char* const WINDOW_TITLE = "3D Cube"; // Macro for window title
// Variables for window width and height
const int WINDOW_WIDTH = 800;
const int WINDOW_HEIGHT = 600;
// Stores the GL data relative to a given mesh
struct GLMesh
{
GLuint vao; // Handle for the vertex array object
GLuint vbos[2]; // Handles for the vertex buffer objects
GLuint nIndices; // Number of indices of the mesh
};
// Main GLFW window
GLFWwindow* gWindow = nullptr;
// Triangle mesh data
GLMesh gMesh;
// Shader program
GLuint gProgramId;
}
/* User-defined Function prototypes to:
* initialize the program, set the window size,
* redraw graphics on the window when resized,
* and render graphics on the screen
*/
bool UInitialize(int, char*[], GLFWwindow** window);
void UResizeWindow(GLFWwindow* window, int width, int height);
void UProcessInput(GLFWwindow* window);
void UCreateMesh(GLMesh &mesh);
void UDestroyMesh(GLMesh &mesh);
void URender();
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint &programId);
void UDestroyShaderProgram(GLuint programId);
/* Vertex Shader Source Code*/
const GLchar * vertexShaderSource = GLSL(440,
layout (location = 0) in vec3 position; // Vertex data from Vertex Attrib Pointer 0
layout (location = 1) in vec4 color; // Color data from Vertex Attrib Pointer 1
out vec4 vertexColor; // variable to transfer color data to the fragment shader
//Global variables for the transform matrices
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = projection * view * model * vec4(position, 1.0f); // transforms vertices to clip coordinates
vertexColor = color; // references incoming color data
}
);
/* Fragment Shader Source Code*/
const GLchar * fragmentShaderSource = GLSL(440,
in vec4 vertexColor; // Variable to hold incoming color data from vertex shader
out vec4 fragmentColor;
void main()
{
fragmentColor = vec4(vertexColor);
}
);
int main(int argc, char* argv[])
{
if (!UInitialize(argc, argv, &gWindow))
return EXIT_FAILURE;
// Create the mesh
UCreateMesh(gMesh); // Calls the function to create the Vertex Buffer Object
// Create the shader program
if (!UCreateShaderProgram(vertexShaderSource, fragmentShaderSource, gProgramId))
return EXIT_FAILURE;
// Sets the background color of the window to black (it will be implicitely used by glClear)
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// render loop
// -----------
while (!glfwWindowShouldClose(gWindow))
{
// input
// -----
UProcessInput(gWindow);
// Render this frame
URender();
glfwPollEvents();
}
// Release mesh data
UDestroyMesh(gMesh);
// Release shader program
UDestroyShaderProgram(gProgramId);
exit(EXIT_SUCCESS); // Terminates the program successfully
}
// Initialize GLFW, GLEW, and create a window
bool UInitialize(int argc, char* argv[], GLFWwindow** window)
{
// GLFW: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// GLFW: window creation
// ---------------------
*window = glfwCreateWindow(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_TITLE, NULL, NULL);
if (*window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return false;
}
glfwMakeContextCurrent(*window);
glfwSetFramebufferSizeCallback(*window, UResizeWindow);
// GLEW: initialize
// ----------------
// Note: if using GLEW version 1.13 or earlier
glewExperimental = GL_TRUE;
GLenum GlewInitResult = glewInit();
if (GLEW_OK != GlewInitResult)
{
std::cerr << glewGetErrorString(GlewInitResult) << std::endl;
return false;
}
// Displays GPU OpenGL version
cout << "INFO: OpenGL Version: " << glGetString(GL_VERSION) << endl;
return true;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
void UProcessInput(GLFWwindow* window)
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
// glfw: whenever the window size changed (by OS or user resize) this callback function executes
void UResizeWindow(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
// Functioned called to render a frame
void URender()
{
// Enable z-depth
glEnable(GL_DEPTH_TEST);
// Clear the frame and z buffers
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// 1. Scales the object by 2
glm::mat4 scale = glm::scale(glm::vec3(2.0f, 2.0f, 2.0f));
// 2. Rotates shape by 15 degrees in the x axis
glm::mat4 rotation = glm::rotate(45.0f, glm::vec3(2.0f, 2.0f, 1.0f));
// 3. Place object at the origin
glm::mat4 translation = glm::translate(glm::vec3(0.0f, 0.0f, 0.0f));
// Model matrix: transformations are applied right-to-left order
glm::mat4 model = translation * rotation * scale;
// Transforms the camera: move the camera back (z axis)
glm::mat4 view = glm::translate(glm::vec3(0.0f, 0.0f, -5.0f));
// Creates a orthographic projection
glm::mat4 projection = glm::ortho(-5.0f, 5.0f, -5.0f, 5.0f, 0.1f, 100.0f);
// Set the shader to be used
glUseProgram(gProgramId);
// Retrieves and passes transform matrices to the Shader program
GLint modelLoc = glGetUniformLocation(gProgramId, "model");
GLint viewLoc = glGetUniformLocation(gProgramId, "view");
GLint projLoc = glGetUniformLocation(gProgramId, "projection");
glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection));
// Activate the VBOs contained within the mesh's VAO
glBindVertexArray(gMesh.vao);
// Draws the triangles
glDrawElements(GL_TRIANGLES, gMesh.nIndices, GL_UNSIGNED_SHORT, NULL); // Draws the triangle
// Deactivate the Vertex Array Object
glBindVertexArray(0);
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
glfwSwapBuffers(gWindow); // Flips the the back buffer with the front buffer every frame.
}
// Implements the UCreateMesh function
void UCreateMesh(GLMesh &mesh)
{
// Position and Color data
GLfloat verts[] = {
// Vertex Positions // Colors (r,g,b,a)
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, // Top Right Vertex 0
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, // Bottom Right Vertex 1
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, // Bottom Left Vertex 2
-0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, // Top Left Vertex 3
0.5f, -0.5f, -1.0f, 0.5f, 0.5f, 1.0f, 1.0f, // 4 br right
0.5f, 0.5f, -1.0f, 1.0f, 1.0f, 0.5f, 1.0f, // 5 tl right
-0.5f, 0.5f, -1.0f, 0.2f, 0.2f, 0.5f, 1.0f, // 6 tl top
-0.5f, -0.5f, -1.0f, 1.0f, 0.0f, 1.0f, 1.0f // 7 bl back
};
// Index data to share position data
GLushort indices[] = {
0, 1, 3, // Triangle 1
1, 2, 3, // Triangle 2
0, 1, 4, // Triangle 3
0, 4, 5, // Triangle 4
0, 5, 6, // Triangle 5
0, 3, 6, // Triangle 6
4, 5, 6, // Triangle 7
4, 6, 7, // Triangle 8
2, 3, 6, // Triangle 9
2, 6, 7, // Triangle 10
1, 4, 7, // Triangle 11
1, 2, 7 // Triangle 12
};
const GLuint floatsPerVertex = 3;
const GLuint floatsPerColor = 4;
glGenVertexArrays(1, &mesh.vao); // we can also generate multiple VAOs or buffers at the same time
glBindVertexArray(mesh.vao);
// Create 2 buffers: first one for the vertex data; second one for the indices
glGenBuffers(2, mesh.vbos);
glBindBuffer(GL_ARRAY_BUFFER, mesh.vbos[0]); // Activates the buffer
glBufferData(GL_ARRAY_BUFFER, sizeof(verts), verts, GL_STATIC_DRAW); // Sends vertex or coordinate data to the GPU
mesh.nIndices = sizeof(indices) / sizeof(indices[0]);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.vbos[1]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
// Strides between vertex coordinates is 6 (x, y, z, r, g, b, a). A tightly packed stride is 0.
GLint stride = sizeof(float) * (floatsPerVertex + floatsPerColor);// The number of floats before each
// Create Vertex Attribute Pointers
glVertexAttribPointer(0, floatsPerVertex, GL_FLOAT, GL_FALSE, stride, 0);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, floatsPerColor, GL_FLOAT, GL_FALSE, stride, (char*)(sizeof(float) * floatsPerVertex));
glEnableVertexAttribArray(1);
}
void UDestroyMesh(GLMesh &mesh)
{
glDeleteVertexArrays(1, &mesh.vao);
glDeleteBuffers(2, mesh.vbos);
}
// Implements the UCreateShaders function
bool UCreateShaderProgram(const char* vtxShaderSource, const char* fragShaderSource, GLuint &programId)
{
// Compilation and linkage error reporting
int success = 0;
char infoLog[512];
// Create a Shader program object.
programId = glCreateProgram();
// Create the vertex and fragment shader objects
GLuint vertexShaderId = glCreateShader(GL_VERTEX_SHADER);
GLuint fragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
// Retrive the shader source
glShaderSource(vertexShaderId, 1, &vtxShaderSource, NULL);
glShaderSource(fragmentShaderId, 1, &fragShaderSource, NULL);
// Compile the vertex shader, and print compilation errors (if any)
glCompileShader(vertexShaderId); // compile the vertex shader
// check for shader compile errors
glGetShaderiv(vertexShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(vertexShaderId, 512, NULL, infoLog);
std::cout << "ERROR::SHADER::VERTEX::COMPILATION_FAILED\n" << infoLog << std::endl;
return false;
}
glCompileShader(fragmentShaderId); // compile the fragment shader
// check for shader compile errors
glGetShaderiv(fragmentShaderId, GL_COMPILE_STATUS, &success);
if (!success)
{
glGetShaderInfoLog(fragmentShaderId, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::FRAGMENT::COMPILATION_FAILED\n" << infoLog << std::endl;
return false;
}
// Attached compiled shaders to the shader program
glAttachShader(programId, vertexShaderId);
glAttachShader(programId, fragmentShaderId);
glLinkProgram(programId); // links the shader program
// check for linking errors
glGetProgramiv(programId, GL_LINK_STATUS, &success);
if (!success)
{
glGetProgramInfoLog(programId, sizeof(infoLog), NULL, infoLog);
std::cout << "ERROR::SHADER::PROGRAM::LINKING_FAILED\n" << infoLog << std::endl;
return false;
}
glUseProgram(programId); // Uses the shader program
return true;
}
void UDestroyShaderProgram(GLuint programId)
{
glDeleteProgram(programId);
}
The unit of the angle of glm::rotate is radians, not degrees:
glm::mat4 rotation = glm::rotate(45.0f, glm::vec3(2.0f, 2.0f, 1.0f));
glm::mat4 rotation = glm::rotate(glm::radians(45.0f), glm::vec3(2.0f, 2.0f, 1.0f));
The size of the size of the cube is 1x1x1. The cube is scaled by 2. Because of the orthographic projection
(glm::mat4 projection = glm::ortho(-5.0f, 5.0f, -5.0f, 5.0f, 0.1f, 100.0f);)
the bottom left of the view port is (-5, -5) and the top right is (5, 5).
Because of the orthographic projection and scale, the bottom left corner of the cube is (-1, -1) and the top right corner is (1, 1). If you want to move the cube to the top left, don't rotate the cube, but move it 4 units to the left and 4 units up:
glm::mat4 scale = glm::scale(glm::vec3(2.0f, 2.0f, 2.0f));
glm::mat4 rotation = glm::mat4(1.0f);
glm::mat4 translation = glm::translate(glm::vec3(-4.0f, 4.0f, 0.0f));
glm::mat4 model = translation * rotation * scale;
I'm using OpenGL 3.3 on Mac OSX 11.5.2. I have 6 fragment shaders, 3 that works and 3 that crashes with EXC_BAD_ACCESS. They all use the same vertex shader. There have been many questions about this problem, but I've made sure to:
Unbind my previous state.
Made sure attribute arrays enabled and used.
Am only using a single-thread, i.e. no concurrency.
The shaders that crash are all using one array of offsets and a kernel to do post-processing effects. If I replace texture_coordinate.st + offsets[i] with just texture_coordinate.st, it'll work just fine. As this makes the offsets array unused and optimized out, I have a suspicion that it could be due to a register allocation bug as mentioned in the comments in this question, but can't confirm.
I've also checked for other problems, such as loading them in different orders, using different compiler flags, but the crashes are consistent.
Here's a minimal, reproducible example (dependent on glad and glfw3, compiled with c++17) with one of the problematic shaders.
#include <glad/glad.h>
#include <GLFW/glfw3.h>
const char VERTEX_POST[] = R"(
#version 330 core
layout (location = 0) in vec2 position;
layout (location = 1) in vec2 in_texture_coordinate;
out vec2 texture_coordinate;
void main()
{
gl_Position = vec4(position.x, position.y, 0.0, 1.0);
texture_coordinate = in_texture_coordinate;
}
)";
const char FRAGMENT_POST[] = R"(
#version 330 core
in vec2 texture_coordinate;
out vec4 FragColor;
uniform sampler2D image;
const float offset = 1.0 / 300.0;
void main()
{
vec2 offsets[9] = vec2[](
vec2(-offset, offset), // top-left
vec2( 0.0f, offset), // top-center
vec2( offset, offset), // top-right
vec2(-offset, 0.0f), // center-left
vec2( 0.0f, 0.0f), // center-center
vec2( offset, 0.0f), // center-right
vec2(-offset, -offset), // bottom-left
vec2( 0.0f, -offset), // bottom-center
vec2( offset, -offset) // bottom-right
);
float kernel[9] = float[](
-1, -1, -1,
-1, 9, -1,
-1, -1, -1
);
vec3 sample_texture[9];
for(int i = 0; i < 9; i++)
sample_texture[i] = vec3(texture(image, texture_coordinate + offsets[i]));
vec3 color = vec3(0.0);
for (int i = 0; i < 9; i++)
color += sample_texture[i] * kernel[i];
FragColor = vec4(color, 1.0);
}
)";
float vertices[] = {
// Positions // Texture coords
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f,
-1.0f, 1.0f, 0.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f,
1.0f, -1.0f, 0.0f, 1.0f, 0.0f,
1.0f, 1.0f, 0.0f, 1.0f, 1.0f
};
GLuint create_shader(const char* source, GLenum type)
{
GLuint id = glCreateShader(type);
glShaderSource(id, 1, &source, nullptr);
glCompileShader(id);
int success;
glGetShaderiv(id, GL_COMPILE_STATUS, &success);
assert(success);
return id;
}
int main()
{
// ---- INIT GLFW & GLAD ----
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
glfwWindowHint(GLFW_OPENGL_DEBUG_CONTEXT, GLFW_TRUE);
GLFWwindow* window = glfwCreateWindow(800, 800, "Temp", nullptr, nullptr);
if (window == nullptr) return -1;
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) return -1;
// ---- CREATE QUAD ----
GLuint quad, vbo;
glGenVertexArrays(1, &quad);
glGenBuffers(1, &vbo);
glBindVertexArray(quad);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (void*)(3 * sizeof(float)));
glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
// ---- CREATE TEXTURE ----
GLuint texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
char data[800 * 800 * 4] = {};
for (char& i : data) i = 127;
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 800, 800, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
// ---- CREATE SHADER PROGRAM ----
GLuint vertex_shader = create_shader(VERTEX_POST, GL_VERTEX_SHADER);
GLuint fragment_shader = create_shader(FRAGMENT_POST, GL_FRAGMENT_SHADER);
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
glValidateProgram(program);
int success;
glGetProgramiv(program, GL_LINK_STATUS, &success);
assert(success);
// ---- MAIN LOOP ----
while (!glfwWindowShouldClose(window))
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(program);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glUniform1i(glGetUniformLocation(program, "image"), 0);
glBindVertexArray(quad);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers(window);
glfwPollEvents();
}
return 0;
}
The example gives me a grey image when not including offsets and otherwise exhibits the crash. What could be causing this?
I am using OpenGL and GLM library, and I try to pass the model matrix off to the shader and make the triangle rotate. I have already got the basic code and getting the IDs of the variables in the vertex shader. While I have no idea how to actually setting them.
#include <GL/GLEW.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <glm/vec3.hpp> // glm::vec3
#include <glm/vec4.hpp> // glm::vec4
#include <glm/mat4x4.hpp> // glm::mat4
#include <glm/gtc/matrix_transform.hpp> // glm::translate/rotate/scale/etc
#include <glm/gtc/type_ptr.hpp> // glm::value_ptr
#define BUFFER_OFFSET(i) ((char *)NULL + (i))
glm::mat4 M;
glm::mat4 V;
glm::mat4 P;
glm::mat4 trans;
glm::mat4 rot;
float rotAmount = 0.0f;
GLint umM;
GLint umV;
GLint umP;
void func(GLuint LocationMVP, float Translate, glm::vec2 const & Rotate)
{
glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.f);
glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate));
glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f));
glm::mat4 View = glm::rotate(ViewRotateX, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f));
glm::mat4 MVP = Projection * View * Model;
glUniformMatrix4fv(LocationMVP, 1, GL_FALSE, glm::value_ptr(MVP));
}
void render()
{
trans = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, -1));
rot = glm::rotate(glm::mat4(1.0f), rotAmount, glm::vec3(0, 1, 0));
M = trans*rot;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, 9, GL_UNSIGNED_INT, NULL);
glutSwapBuffers();
glutPostRedisplay();
}
void specialKeys(int key, int x, int y) {
switch (key) {
case GLUT_KEY_UP: printf("The UP key was pressed\n"); break;
case GLUT_KEY_DOWN: printf("The DOWN key was pressed\n"); break;
}
}
void mousePressed(int button, int state, int x, int y)
{
if ((button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) {
//printf("Mouse clicked at %d %d\n", x, y);
}
}
void mouseMoved(int x, int y) {
//printf("Mouse moved at %d %d\n", x, y);
}
void mouseDragged(int x, int y) {
//printf("Mouse dragged at %d %d\n", x, y);
}
int main(int argc, char** argv)
{
glutInit(&argc, argv); // Initialize GLUT
glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); // Set up buffers
glutInitWindowPosition(200, 200); // Optional: position the upper-left of the window
glutInitWindowSize(800, 600); // Set the window size
glutCreateWindow("Lab 5"); // Create the window and give it a title
glewInit(); // Ask the driver for all the OpenGL functions
// Some callback functions
glutDisplayFunc(render); // Use the render function to draw
glutSpecialFunc(specialKeys); // Use the specialKeys function for Up/Down/Left/Right keys
glutMouseFunc(mousePressed); // Use for mouse clicks
glutMotionFunc(mouseDragged); // Use for mouse dragging
glutPassiveMotionFunc(mouseMoved); // Use for mouse moving
#pragma region SHADER_STUFF
// ========= SHADER STUFF ===============
const GLchar* vertexShaderCode = "#version 150\n\
in vec4 vPosition;\n\
in vec4 vColor;\n\
out vec4 color;\n\
void main () {\n\
color = vColor;\n\
\tgl_Position = vPosition;\n\
}\n";
const GLchar* fragmentShaderCode = "#version 150\n\n\
out vec4 fColor;\n\
in vec4 color;\n\
void main () {\
fColor = color;\n\
}";
// Vertex Shader
GLint vertexShaderID = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShaderID, 1, &vertexShaderCode, NULL);
glCompileShader(vertexShaderID);
GLint compiled = -10;
glGetShaderiv(vertexShaderID, GL_COMPILE_STATUS, &compiled);
printf("Vertex compile status %d!\n", compiled);
printf("Vertex shader ID is %d\n", vertexShaderID);
// Fragment Shader
GLint fragmentShaderID = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShaderID, 1, &fragmentShaderCode, NULL);
glCompileShader(fragmentShaderID);
GLint compiled2 = -19;
glGetShaderiv(fragmentShaderID, GL_COMPILE_STATUS, &compiled2);
printf("Fragment compile status %d!\n", compiled2);
printf("Fragment shader ID is %d\n", fragmentShaderID);
// Make the program
GLint shaderProgram;
shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShaderID);
glAttachShader(shaderProgram, fragmentShaderID);
glLinkProgram(shaderProgram);
GLint linkedStatus = 14;
glGetProgramiv(shaderProgram, GL_LINK_STATUS, &linkedStatus);
printf("Link status is %d\n", linkedStatus);
printf("Shader program ID is %d\n", shaderProgram);
glUseProgram(shaderProgram);
#pragma endregion SHADER_STUFF
// Positions
GLfloat vertices[] = { -0.5f, -0.5f, 0.0f, // 0
-0.25f, 0.0f, 0.0f, // 1
0.0f, 0.5f, 0.0f, // 2
0.0f, -0.5f, 0.0f, // 3
0.25f, 0.0f, 0.0f, // 4
0.5f, -0.5f, 0.0f, // 5
};
// Color information
GLfloat colors[] = { 1.0f, 0.73f, 0.0f, 1.0f, //0
1.0f, 1.0f, 0.0f, 1.0f, // 1
1.0f, 1.0f, 0.0f, 1.0f, // 2
1.0f, 0.73f, 0.0f, 1.0f, // 3
1.0f, 0.65f, 0.0f, 1.0f, // 4
1.0f, 0.65f, 0.0f, 1.0f, // 5
};
// Connect the dots
GLuint index_buffer[] = { 0, 3, 1, 2, 1, 4, 4, 3, 5 };
int numVertices = 6;
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao); // Use the Vertex Array Object we created above
GLuint vbo; // The Vertex Buffer Object ID
glGenBuffers(1, &vbo); // Ask the GPU driver for a buffer array. "vbo" now has the ID
glBindBuffer(GL_ARRAY_BUFFER, vbo); // Make this buffer the active one for subsequent operations (below)
// Specify how big the buffer is, but don't pass the data yet (see NULL). We *could* have, but I wanted to show glBufferSubData
glBufferData(GL_ARRAY_BUFFER, numVertices * 7 * sizeof(GLfloat), NULL, GL_STATIC_DRAW);
// NOW we copy the data in as a separate step. There is an "offset" of 0 - meaning the beginning of the buffer.
// We specify the size of the data we want to copy, followed by a pointer to the actual data
glBufferSubData(GL_ARRAY_BUFFER, 0, numVertices * 3 * sizeof(GLfloat), vertices);
glBufferSubData(GL_ARRAY_BUFFER, numVertices * 3 * sizeof(GLfloat), numVertices * 4 * sizeof(GLfloat), colors);
// Figure out where vPosition is in our shader and get its ID
GLuint loc = glGetAttribLocation(shaderProgram, "vPosition");
GLuint loc2 = glGetAttribLocation(shaderProgram, "vColor");
glEnableVertexAttribArray(loc);
glEnableVertexAttribArray(loc2);
printf("vPosition ID is %d\n", loc);
printf("vColor ID is %d\n", loc2);
// When it's time for vPosition to find information, we need to tell it where the data is (or how the data should be parsed)
// Here, we're saying that "vPosition" (loc from above) should look for 3 GLfloats. The data isn't normalized or interlaced,
// and starts at index 0 (the beginning of the current buffer)
glVertexAttribPointer(loc, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(loc2, 4, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(numVertices * 3 * sizeof(GLfloat)));
GLuint index_vbo;
// Ask the graphics card (driver) for another buffer – same as the old code
glGenBuffers(1, &index_vbo);
// We still want the VAO active to remember these settings
glBindVertexArray(vao);
// Here's where we tell the driver that it's an index buffer.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_vbo);
// This time, we'll just go ahead and pass the data off to the buffer because
// we're not packing multiple data sets into the buffer - only indices
umM = glGetUniformLocation(shaderProgram, "mM"); // Find the mM variable
umV = glGetUniformLocation(shaderProgram, "mV"); // Find the mV variable
umP = glGetUniformLocation(shaderProgram, "mP"); // Find the mP variable
if (umP != -1)
{
glUniformMatrix4fv(umP, 1, GL_FALSE, glm::value_ptr(P));
}
if (umV != -1)
{
glUniformMatrix4fv(umV, 1, GL_FALSE, glm::value_ptr(V));
}
glBufferData(GL_ELEMENT_ARRAY_BUFFER, 9*sizeof(GLuint), index_buffer, GL_STATIC_DRAW);
P = glm::perspective(-60.0f, 1.3f, 0.1f, 1000.0f);
V = glm::translate(glm::mat4(1.0f), glm::vec3(0, 0, 0));
glm::mat4 T = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 0.0f));
glm::mat4 Rx = glm::rotate(T, rotation_x, glm::vec3(1.0f, 0.0f, 0.0f));
glm::mat4 Ry = glm::rotate(Rx, rotation_y, glm::vec3(0.0f, 1.0f, 0.0f));
glm::mat4 M = glm::rotate(Ry, rotation_z, glm::vec3(0.0f, 0.0f, 1.0f));
glm::mat4 MVP = P*V*M;
glutMainLoop(); // Start listening for events
}
and also my shader file is like
#version 150
in vec4 vPosition;
uniform mat4 mM; // The matrix for the pose of the model
uniform mat4 mV; // The matrix for the pose of the camera
uniform mat4 mP; // The perspective matrix
void main()
{
gl_Position = mP*mV*mM*vPosition;
}
Could any one help me, or teach me how to setting them?
With OpenGL shaders, I want to draw a triangle on the screen, where the vertex colours are specified in the data structure alongside the vertex coordinates. The structure has 7 floats for each vertex -- 3 for coordinates, followed by 4 for colour:
static std::vector<GLfloat> vertices = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
};
I then tell OpenGL how to interpret this structure by using glVertexAttribPointer():
// Vertex coordinates
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), 0);
// Vertex colour
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float)));
And then tell my vertex shader to read the coordinates and colour:
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 vertex_colour;
However, no matter what values I use for the colour component, the triangle is always drawn in red. Changing the coordinates in the structure affects the image as expected, but changing the colour in the structure does nothing.
I believe that this is a problem with my C++ code, rather than the shader code, because I have debugged the shader and it is always reading (1.0, 0.0, 0.0, 1.0) for the colour, even though I am passing it (0.0, 0.0, 1.0, 1.0) for each vertex.
Any ideas on what I'm doing wrong?
Here is my complete code:
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <cmath>
#include <assert.h>
#include <vector>
#include <GL/glew.h>
#include <GL/glut.h>
#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include <glm/ext.hpp>
GLuint buffer;
GLuint projection_matrix_location;
GLuint view_matrix_location;
glm::mat4 view_matrix;
glm::mat4 projection_matrix;
int num_vertices = 0;
static void RenderScene()
{
// Clear the buffers.
glClear(GL_COLOR_BUFFER_BIT);
glClear(GL_DEPTH_BUFFER_BIT);
// Set the matrices
glUniformMatrix4fv(projection_matrix_location, 1, GL_FALSE, glm::value_ptr(projection_matrix));
glUniformMatrix4fv(view_matrix_location, 1, GL_FALSE, glm::value_ptr(view_matrix));
// Specify how to read the vertex buffer
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
// Vertex coordinates
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 7 * sizeof(float), 0);
// Vertex colour
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 7 * sizeof(float), (void*)(3 * sizeof(float)));
// Draw the vertex buffer
glDrawArrays(GL_TRIANGLES, 0, num_vertices);
glDisableVertexAttribArray(0);
// Swap the buffers
glutSwapBuffers();
}
static void MakeBuffers()
{
// Set the vertices
static std::vector<GLfloat> vertices = {
-1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
1.0f, -1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f
};
num_vertices = (1.0 / 7.0) * vertices.size();
// Fill the buffer with the vertices
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, num_vertices * 7 * sizeof(GL_FLOAT), &vertices[0], GL_STATIC_DRAW);
}
static GLuint MakeShader(GLenum shader_type, std::string shader_filename)
{
// Load the source code
std::ifstream file_in;
file_in.open(&shader_filename[0]);
std::stringstream file_stream;
file_stream << file_in.rdbuf();
std::string file_string = file_stream.str();
const GLchar* ptr_file_string = &file_string[0];
const GLchar** ptr_file_strings = &ptr_file_string;
int string_lengths[] = {(int)file_string.length()};
// Compile the shader
GLuint shader = glCreateShader(shader_type);
glShaderSource(shader, 1, ptr_file_strings, &string_lengths[0]);
glCompileShader(shader);
// Check
GLint is_success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &is_success);
if (!is_success)
{
std::cerr << "Error" << std::endl;
return -1;
}
return shader;
}
static void MakeShaderProgram()
{
// Make the shaders
GLuint vertex_shader = MakeShader(GL_VERTEX_SHADER, "../src/vertex-shader.glsl");
GLuint fragment_shader = MakeShader(GL_FRAGMENT_SHADER, "../src/fragment-shader.glsl");
// Create the program
GLuint program = glCreateProgram();
glAttachShader(program, vertex_shader);
glAttachShader(program, fragment_shader);
glLinkProgram(program);
// Check
GLint is_success = 0;
glGetProgramiv(program, GL_LINK_STATUS, &is_success);
if (!is_success)
{
std::cout << "Error" << std::endl;
return;
}
glValidateProgram(program);
glGetProgramiv(program, GL_VALIDATE_STATUS, &is_success);
if (!is_success)
{
std::cout << "Error" << std::endl;
return;
}
// Use the program
glUseProgram(program);
// Get the location of the uniform variables
view_matrix_location = glGetUniformLocation(program, "view_matrix");
assert(view_matrix_location != 0xFFFFFFFF);
projection_matrix_location = glGetUniformLocation(program, "projection_matrix");
assert(projection_matrix_location != 0xFFFFFFFF);
}
int main(int argc, char** argv)
{
// Initialize GLUT
glutInit(&argc, argv);
// Configure some GLUT display options:
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
// Specify the GLUT window parameters and create the window
glutInitWindowSize(1000, 750);
glutInitWindowPosition(500, 200);
glutCreateWindow("Test");
// Specify the display callback
glutDisplayFunc(RenderScene);
// Initialize GLEW, which must be done after GLUT is initialized.
GLenum glut_result = glewInit();
if (glut_result != GLEW_OK)
{
std::cout << "Error" << std::endl;
return -1;
}
// Set the clear colour.
glClearColor(0.5f, 0.5f, 0.5f, 0.0f);
// Enable depth testing so that only the nearest vertex is sent to the colour buffer (also needed to read the depth of each pixel using glReadPixels())).
glEnable(GL_DEPTH_TEST);
// Make the vertex and index buffers.
MakeBuffers();
// Make the shader program.
MakeShaderProgram();
// Create the view matrix.
glm::vec3 eye(0.0f, 0.0f, -3.0f);
glm::vec3 centre(0.0f, 0.0f, 0.0f);
glm::vec3 up(0.0f, 1.0f, 0.0f);
view_matrix = glm::lookAt(eye, centre, up);
// Create the projection matrix.
float fov_y = 45.0;
float aspect_ratio = 1.5;
float near_clip = 1;
float far_clip = 1000;
projection_matrix = glm::perspective(fov_y, aspect_ratio, near_clip, far_clip);
// Start the GLUT internal loop.
glutMainLoop();
}
And here is my shader code:
// Vertex shader
#version 330
layout (location = 0) in vec3 position;
layout (location = 1) in vec4 vertex_colour;
uniform mat4 projection_matrix;
uniform mat4 view_matrix;
out vec4 frag_colour;
void main()
{
gl_Position = projection_matrix * view_matrix * vec4(position, 1.0f);
frag_colour = vertex_colour;
}
// Fragment shader
#version 330
in vec4 frag_colour;
void main()
{
gl_FragColor = frag_colour;
}
I can't debug your code now,but based on what I see here you forgot to enable second attribute array.See this example for reference.
But even if I am wrong,I would like to point you to some bad practices you have in your code.You are using GL 3.3 which is good.This is modern OpenGL baseline.But you are still mixing old API (pre 3.3) with the new one.From the end:
In your fragment shader you should use custom output attribute rather than the GLSL built in gl_FragColor.
#version 330
in smooth vec4 frag_colour;
out vec4 frag_out;
void main()
{
frag_out = frag_colour;
}
Now,regarding your OpenGL commands.You shouldn't bind vertex buffers directly but use VAO and bind it to the context.In fact some driver version (I experienced on NVIDIA) produce no rendering results at all when VAO is not used with core profile.
I'm trying to rotate a triangle with OpenGL 4 using matrixes, but the triangle appears to reverse direction when halfway. It's obviously not rotating directions, so I must have the depth buffer wrong somewhere. I've tried resolving this but I haven't found any examples of a rotation with OpenGL 4, only ones that use depreciated functions. Here is my code:
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <stdio.h>
#include <math.h>
#include <iostream>
#include "maths_funcs.h"
#include "maths_funcs.cpp"
const char* vertex_shader =
"#version 400\n"
"layout(location = 0) in vec3 vertex_position;"
"layout(location = 1) in vec3 vertex_colour;"
"uniform mat4 pmatrix;"
"uniform mat4 rmatrix;"
"uniform mat4 smatrix;"
"out vec3 colour;"
"void main () {"
" colour = vertex_colour;"
" gl_Position = smatrix * rmatrix * vec4 (vertex_position, 1.0);"
"}";
const char* fragment_shader =
"#version 400\n"
"in vec3 colour;"
"out vec4 frag_colour;"
"void main () {"
" frag_colour = vec4 (colour, 1.0);"
"}";
float angle = 0.0f;
int main () {
// start GL context and O/S window using the GLFW helper library
if (!glfwInit ()) {
fprintf (stderr, "ERROR: could not start GLFW3\n");
return 1;
}
GLFWwindow* window = glfwCreateWindow (640, 480, "Triangle Rotation test", NULL, NULL);
if (!window) {
fprintf (stderr, "ERROR: could not open window with GLFW3\n");
glfwTerminate();
return 1;
}
glfwMakeContextCurrent (window);
// start GLEW extension handler
glewExperimental = GL_TRUE;
glewInit ();
// get version info
const GLubyte* renderer = glGetString (GL_RENDERER); // get renderer string
const GLubyte* version = glGetString (GL_VERSION); // version as a string
printf ("Renderer: %s\n", renderer);
printf ("OpenGL version supported %s\n", version);
// tell GL to only draw onto a pixel if the shape is closer to the viewer
glEnable (GL_DEPTH_TEST); // enable depth-testing
glDepthFunc (GL_LESS); // depth-testing interprets a smaller value as "closer"
float points[] = {
0.0f, 0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, -0.5f, 0.0f
};
float colours[] = {
1.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 1.0f
};
float pmatrix[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
float rmatrix[] = {
cos(10), 0.0f, sin(10), 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
-sin(10), 0.0f, cos(10), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
float smatrix[] = {
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, cos(10), sin(10), 0.0f,
0.0f, -sin(10), cos(10), 0.0f,
0.0f, 0.0f, 0.0f, 1.0f
};
GLuint vbo = 0;
glGenBuffers (1, &vbo);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), points, GL_STATIC_DRAW);
unsigned int colours_vbo = 0;
glGenBuffers (1, &colours_vbo);
glBindBuffer (GL_ARRAY_BUFFER, colours_vbo);
glBufferData (GL_ARRAY_BUFFER, 9 * sizeof (float), colours, GL_STATIC_DRAW);
GLuint vao = 0;
glGenVertexArrays (1, &vao);
glBindVertexArray (vao);
glEnableVertexAttribArray (0);
glBindBuffer (GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer (0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer (GL_ARRAY_BUFFER, colours_vbo);
glVertexAttribPointer (1, 3, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
GLuint vs = glCreateShader (GL_VERTEX_SHADER);
glShaderSource (vs, 1, &vertex_shader, NULL);
glCompileShader (vs);
GLuint fs = glCreateShader (GL_FRAGMENT_SHADER);
glShaderSource (fs, 1, &fragment_shader, NULL);
glCompileShader (fs);
GLuint shader_programme = glCreateProgram ();
glAttachShader (shader_programme, fs);
glAttachShader (shader_programme, vs);
glLinkProgram (shader_programme);
int pmatrix_location = glGetUniformLocation (shader_programme, "pmatrix");
int rmatrix_location = glGetUniformLocation (shader_programme, "rmatrix");
int smatrix_location = glGetUniformLocation (shader_programme, "smatrix");
while (!glfwWindowShouldClose (window)) {
// wipe the drawing surface clear
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram (shader_programme);
rmatrix[0] = cos(angle);
rmatrix[2] = sin(angle);
rmatrix[8] = -sin(angle);
rmatrix[10] = cos(angle);
smatrix[5] = cos(angle);
smatrix[6] = sin(angle);
smatrix[9] = -sin(angle);
smatrix[10] = cos(angle);
glUniformMatrix4fv (pmatrix_location, 1, GL_FALSE, pmatrix);
glUniformMatrix4fv (rmatrix_location, 1, GL_FALSE, rmatrix);
glUniformMatrix4fv (smatrix_location, 1, GL_FALSE, smatrix);
glBindVertexArray (vao);
// draw points 0-3 from the currently bound VAO with current in-use shader
glDrawArrays (GL_TRIANGLES, 0, 3);
// update other events like input handling
glfwPollEvents ();
// put the stuff we've been drawing onto the display
glfwSwapBuffers (window);
angle+=0.01f;
if (angle >= 3.14f) {
angle = -3.14f;
}
}
// close GL context and any other GLFW resources
glfwTerminate();
return 0;
}
Since you are not using a projection matrix, you have to invert the z-coordinate in your vertex shader. Change this line:
gl_Position = smatrix * rmatrix * vec4 (vertex_position, 1.0);
To something like this:
vec4 eyePos = smatrix * rmatrix * vec4 (vertex_position, 1.0);
gl_Position = vec4(eyePos.xy, -eyePos.z, eyePos.w);
The gl_Position value is in clip coordinates, which after the division by w results in NDC (normalized device coordinates). While world coordinates are typically specified in a right-handed coordinate system, with the z-axis pointing out of the screen, NDC is a left-handed coordinate system, with the z-axis pointing into the screen.
Typical projection transformations take care of flipping the z-coordinates from out-of-screen to into-screen. But if you're not using a projection transformation, you have to flip the z-coordinate yourself.
Also, you may want to double check that you really got a depth buffer. Maybe add this before glfwCreateWindow():
glfwWindowHint(GLFW_DEPTH_BITS, 24);
Based on what I could find in the GLFW documentation, this is probably the default. But it couldn't hurt to specify it explicitly.