OpenGL lines not colored - c++
I'm working in OpenGL, with VBOs, and I have a set of three lines (along the X, Y and Z axes - think Czech hedgehog). The lines are grey by default, but I want them bright red so I can see them better. Unfortunately, though I added color information as vertex data, the lines still appear grey. I'm probably missing something basic, but I can't see it. Here is how I create the VBO:
//Position data
sf::Vector3<float> Top = sf::Vector3<float>(0.0, 1.0, 0.0);
sf::Vector3<float> Front = sf::Vector3<float>(0.0, 0.0, -1.0);
sf::Vector3<float> Right = sf::Vector3<float>(1.0, 0.0, 0.0);
sf::Vector3<float> Back = sf::Vector3<float>(0.0, 0.0, 1.0);
sf::Vector3<float> Left = sf::Vector3<float>(-1.0, 0.0, 0.0);
sf::Vector3<float> Bottom = sf::Vector3<float>(0.0, -1.0, 0.0);
//Color data
//Just to be clear, I also tried with 255.0, although I'm rather certain OpenGL
//does its colors on a 0-1 scale.
sf::Vector3<float> Color = sf::Vector3<float>(1.0, 0.0, 0.0);
//Create vector
std::vector<float> LineArray;
//Top
LineArray.push_back(Top.x);
LineArray.push_back(Top.y);
LineArray.push_back(Top.z);
LineArray.push_back(Color.x);
LineArray.push_back(Color.y);
LineArray.push_back(Color.z);
//Bottom
LineArray.push_back(Bottom.x);
LineArray.push_back(Bottom.y);
LineArray.push_back(Bottom.z);
LineArray.push_back(Color.x);
LineArray.push_back(Color.y);
LineArray.push_back(Color.z);
//Front
LineArray.push_back(Front.x);
LineArray.push_back(Front.y);
LineArray.push_back(Front.z);
LineArray.push_back(Color.x);
LineArray.push_back(Color.y);
LineArray.push_back(Color.z);
//Back
LineArray.push_back(Back.x);
LineArray.push_back(Back.y);
LineArray.push_back(Back.z);
LineArray.push_back(Color.x);
LineArray.push_back(Color.y);
LineArray.push_back(Color.z);
//Right
LineArray.push_back(Right.x);
LineArray.push_back(Right.y);
LineArray.push_back(Right.z);
LineArray.push_back(Color.x);
LineArray.push_back(Color.y);
LineArray.push_back(Color.z);
//Left
LineArray.push_back(Left.x);
LineArray.push_back(Left.y);
LineArray.push_back(Left.z);
LineArray.push_back(Color.x);
LineArray.push_back(Color.y);
LineArray.push_back(Color.z);
//Create buffer
glGenBuffers(1, &m_Buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffer);
int SizeInBytes = LineArray.size() * 6 * sizeof(float);
glBufferData(GL_ARRAY_BUFFER, SizeInBytes, NULL, GL_STATIC_DRAW);
//Upload buffer data
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * LineArray.size(), &LineArray[0]);
And this is how I display it every tick:
glPushMatrix();
//Translate
glTranslatef(m_Position.x, m_Position.y, m_Position.z);
//Rotate
glMultMatrixf(m_RotationMatrix);
//Bind buffers for vertex and color arrays
glBindBuffer(GL_ARRAY_BUFFER, m_Buffer);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, 6 * sizeof(float), 0);
glEnableClientState(GL_COLOR_ARRAY);
glColorPointer(3, GL_FLOAT, 6 * sizeof(float), (void*)12);
//Draw
glDrawArrays(GL_LINES, 0, 36);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
//Unbind the buffers
glBindBuffer(GL_ARRAY_BUFFER, 0);
glPopMatrix();
I've never used GL_COLOR_ARRAY before, but I based the code off of successful use of GL_NORMAL_ARRAY. Can someone point out what's wrong?
EDIT: On the offchance that I'm setting up my basic OpenGL parameters wrong (lighting in particular), here are those:
m_AmbientLight = {0.5f, 0.5f, 0.5f, 1.0f};
m_DiffuseLight = {1.0f, 1.0f, 1.0f, 1.0f};
m_LightPos = {8.0f, -16.0f, 8.0f, 0.0f};
//Smooth Shading
glShadeModel(GL_SMOOTH);
// Set color and depth clear value
glClearDepth(1.f);
//Color here is in RGB, converted to a 0-1 scale.
glClearColor(0.3f, 0.3f, 0.3f, 1.f);
// Enable Z-buffer read and write
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
///
///LIGHTING
///
//Set up lighting.
//This activates the ambient light.
glLightfv(GL_LIGHT0, GL_AMBIENT, m_AmbientLight);
//This activates the diffuse light.
glLightfv(GL_LIGHT1, GL_DIFFUSE, m_DiffuseLight);
//This sets the position of the diffuse light.
glLightfv(GL_LIGHT1, GL_POSITION, m_LightPos);
//This enables the light.
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
//Enables all lighting...?
glEnable(GL_LIGHTING);
glEnable(GL_COLOR_MATERIAL);
//glEnable(GL_NORMALIZE);
// Setup a perspective projection
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(60.f, 1.33f, 0.1f, 512.f);
EDIT 2: Having established that glColor3f() also doesn't have any effect, I wonder if my shaders are the problem:
Vert shader:
void main()
{
vec3 normal, lightDir;
vec4 diffuse;
float NdotL;
normal = normalize(gl_NormalMatrix * gl_Normal);
lightDir = normalize(vec3(gl_LightSource[0].position));
NdotL = max(dot(normal, lightDir), 0.0);
diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse;
gl_FrontColor = NdotL * diffuse;
gl_Position = ftransform();
}
Frag shader:
void main()
{
gl_FragColor = gl_Color;
}
Not 100% positive, but I don't believe you should have GL_COLOR_MATERIAL enabled while you draw the lines. Try disabling that.
edit (copied from comment):
Your shader doesn't make sense to me. You should just be passing in a color, and then passing that color straight to the fragment shader. Why are you using a lighting shader to draw lines? You should create a different shader that doesn't use any of that materials stuff. Enabling/disabling lighting has no effect unless you're using fixed function pipeline. I think you're mixing up fixed function commands with your shaders and getting confused.
Sounds to me like you've got lighting enabled while drawing the lines, hence the color of the vertex data being overridden by the color of the illumination calculation. Add a glDisable(GL_LIGHTING) right before the glDrawArrays.
Related
How to create two shapes using OpenGL and shaders
I am trying to create a cylinder and plane to put underneath cylinder. Before I created a new vertex buffer object for the plane, the cylinder was rendering just fine. But for some reason, neither the cylinder or the plane are rendering when I run the program. I have created an EBO for the cylinder, but I am still getting a black window. I don't know if I need to create an EBO for each shape and a VAO for each shape or if there is something wrong with my draw function. Can someone point out what may be the problem? Here is my code: #include <GL\glew.h> #include <GLFW\glfw3.h> #include <iostream> // GLM library #include <glm/glm.hpp> #include <glm/gtc/matrix_transform.hpp> #include <glm/gtc/type_ptr.hpp> using namespace std; int width, height; const double PI = 3.14159; const float toRadians = PI / 180.0f; // Draw Primitive(s) void draw() { GLenum mode = GL_TRIANGLES; GLsizei indices = 60; glDrawElements(mode, indices, GL_UNSIGNED_BYTE, nullptr); } // Create and Compile Shaders static GLuint CompileShader(const string& source, GLuint shaderType) { // Create Shader Object GLuint shaderID = glCreateShader(shaderType); const char* src = source.c_str(); // Attach source code to Shader object glShaderSource(shaderID, 1, &src, nullptr); // Compile Shader glCompileShader(shaderID); // Return ID of Compiled shader return shaderID; } // Create Program Object static GLuint CreateShaderProgram(const string& vertexShader, const string& fragmentShader) { // Compile vertex shader GLuint vertexShaderComp = CompileShader(vertexShader, GL_VERTEX_SHADER); // Compile fragment shader GLuint fragmentShaderComp = CompileShader(fragmentShader, GL_FRAGMENT_SHADER); // Create program object GLuint shaderProgram = glCreateProgram(); // Attch vertex and fragment shaders to program object glAttachShader(shaderProgram, vertexShaderComp); glAttachShader(shaderProgram, fragmentShaderComp); // Link shaders to create executable glLinkProgram(shaderProgram); // Delete compiled vertex and fragment shaders glDeleteShader(vertexShaderComp); glDeleteShader(fragmentShaderComp); // Return Shader Program return shaderProgram; } int main(void) { width = 640; height = 480; GLFWwindow* window; // Initialize the library if (!glfwInit()) return -1; // Create a windowed mode window and its OpenGL context window = glfwCreateWindow(width, height, "Main Window", NULL, NULL); if (!window) { glfwTerminate(); return -1; } // Make the window's context current glfwMakeContextCurrent(window); // Initialize GLEW if (glewInit() != GLEW_OK) cout << "Error!" << endl; GLfloat cylinderVertices[] = { // Base of the cylinder // Triangle One // Color 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, // Vertex 0 red cos(0 * toRadians), sin(0 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 1 green cos(60 * toRadians), sin(60 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 2 blue // Part of Triangle Two cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 3 purple // Part of Triangle Three cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 4 greem // Part of Triangle Four cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 5 blue // Part of Triangle Five cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 6 purple // Part of Triangle Six cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 7 green // Sides of the cylinder // Part of Triangle Seven cos(0 * toRadians), sin(0 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 8 red // Part of Triangle Eight cos(60 * toRadians), sin(60 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 9 green // Part of Triangle Nine cos(120 * toRadians), sin(120 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 10 blue // Part of Triangle Ten cos(180 * toRadians), sin(180 * toRadians), 2.0, 1.0, 0.0, 1.0, // Vertex 11 purple // Part of Triangle Eleven cos(240 * toRadians), sin(240 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 12 red // Part of Triangle Twelve cos(300 * toRadians), sin(300 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 13 green }; // Define element indices GLubyte cylinderIndices[] = { // Bottom base 0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,7, // Sides 1,2,8, 2,9,8, 2,3,9, 3,10,9, 3,4,10, 4,11,10, 5,11,4, 5,12,11, 5,6,12, 6,13,12, 6,1,13, 1,8,13 }; GLfloat planeVertices[] = { // positon attributes (x,y,z) 0.0f, 0.0f, 0.0f, // vert 14 0.0f, 1.0f, 0.0f, // red 0.0f, 0.866f, 0.0f, // vert 15 0.0f, 1.0f, 0.0f, // green 1.0f, 0.0f, 0.0f, // vert 16 0.0f, 1.0f, 0.0f, // blue 1.0f, 0.866f, 0.0f, // vert 17 1.0f, 0.0f, 1.0f // purple }; // Define element indices GLubyte planeIndices[] = { 14,16,15, 16,17,15 }; // Enable Depth Buffer glEnable(GL_DEPTH_TEST); // Wireframe mode // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); GLuint cylinderVBO, planeVBO, EBO, VAO; glGenBuffers(1, &cylinderVBO); // Create VBO and returns ID glGenBuffers(1, &planeVBO); glGenBuffers(1, &EBO); // Create EBO glGenVertexArrays(1, &VAO); // Create VAO glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); // Select VBO and activate buffer glBindBuffer(GL_ARRAY_BUFFER, planeVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO); // Select EBO glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); // Load vertex attributes glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Load indices attributes // Specify attributes location and layout to GPU glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // Color attribute location and layout glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); glBindVertexArray(0); // Vertex shader source code string vertexShaderSource = "#version 330 core\n" "layout(location = 0) in vec4 vPosition;" "layout(location = 1) in vec4 aColor;" "out vec4 oColor;" "uniform mat4 model;" "uniform mat4 view;" "uniform mat4 projection;" "void main()\n" "{\n" "gl_Position = projection * view * model * vPosition;" "oColor = aColor;" "}\n"; // Fragment shader source code string fragmentShaderSource = "#version 330 core\n" "in vec4 oColor;" "out vec4 fragColor;" "void main()\n" "{\n" "fragColor = oColor;" "}\n"; // Creating Shader Program GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource); while (!glfwWindowShouldClose(window)) { // Resize window and graphics simultaneously glfwGetFramebufferSize(window, &width, &height); glViewport(0, 0, width, height); // Render here glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Use Shader Program exe and select VAO before drawing glUseProgram(shaderProgram); // Call Shader per-frame when updating attributes // Declare identity matrix glm::mat4 modelMatrix(1.0f); glm::mat4 viewMatrix(1.0f); glm::mat4 projectionMatrix(1.0f); // Initialize transforms modelMatrix = glm::scale(modelMatrix, glm::vec3(0.5f, 0.5f, 0.5f)); // I increased the third argument from -3.0f to -6.0f to make the object smaller // Moved the cup to the right by increasing the x coordinate viewMatrix = glm::translate(viewMatrix, glm::vec3(0.5f, 0.0f, -6.0f)); // I changed up somme of the arguments, so the object would tilt right instead of toward me viewMatrix = glm::rotate(viewMatrix, 45.0f * toRadians, glm::vec3(-0.5f, 1.0f, 1.5f)); projectionMatrix = glm::perspective(45.0f * toRadians, (GLfloat)width / (GLfloat)height, 0.1f, 100.0f); // Select uniform shader and variable GLuint modelLoc = glGetUniformLocation(shaderProgram, "model"); GLuint viewLoc = glGetUniformLocation(shaderProgram, "view"); GLuint projectionLoc = glGetUniformLocation(shaderProgram, "projection"); // Pass transform to Shader glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(viewMatrix)); glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projectionMatrix)); glBindVertexArray(VAO); // User-defined VAO must be called before draw for (GLuint i = 0; i < 4; i++) { glm::mat4 modelMatrix(1.0f); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(modelMatrix)); // Draw primitive(s) draw(); } // Unbind Shader exe and VOA after drawing per frame glBindVertexArray(0); // In case different VAO will be used after glUseProgram(0); // In case different shader will be used after glBindVertexArray(VAO); // Swap front and back buffers glfwSwapBuffers(window); // Poll for and process events glfwPollEvents(); } glfwTerminate(); return 0; }
Ok, so there is a bit of a structural problem with your plane & cylinder buffer layouts (ind indexing). Vertex Buffers First, let's start with the vertex data and associated buffers (we'll worry about indexing later). You have 2 choices for how to send the data to the GPU. Seperate vertex buffers for each shape. i.e. specify a cylinderVBO (with all cylinder vertices) and a planeVBO (with all plane vertices). Combine both sets of vertices into a single vertex buffer. If you are specifying the buffers separately, then setup EACH buffer in turn. // do the cylinder buffer first! glGenBuffers(1, &cylinderVBO); glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(cylinderVertices), cylinderVertices, GL_STATIC_DRAW); // Load vertex attributes // NOW do the plane buffer! glGenBuffers(1, &planeVBO); glBindBuffer(GL_ARRAY_BUFFER, planeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, GL_STATIC_DRAW); // Load vertex attributes If you want to combine the buffers into one big blob, then generate one big array: GLfloat allVertices[] = { // ------------- cylinderVertices[] // Base of the cylinder // Triangle One // Color 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, // Vertex 0 red cos(0 * toRadians), sin(0 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 1 green cos(60 * toRadians), sin(60 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 2 blue // Part of Triangle Two cos(120 * toRadians), sin(120 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 3 purple // Part of Triangle Three cos(180 * toRadians), sin(180 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 4 greem // Part of Triangle Four cos(240 * toRadians), sin(240 * toRadians), 0.0, 0.0, 0.0, 1.0, // Vertex 5 blue // Part of Triangle Five cos(300 * toRadians), sin(300 * toRadians), 0.0, 1.0, 0.0, 1.0, // Vertex 6 purple // Part of Triangle Six cos(360 * toRadians), sin(360 * toRadians), 0.0, 0.0, 1.0, 0.0, // Vertex 7 green // Sides of the cylinder // Part of Triangle Seven cos(0 * toRadians), sin(0 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 8 red // Part of Triangle Eight cos(60 * toRadians), sin(60 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 9 green // Part of Triangle Nine cos(120 * toRadians), sin(120 * toRadians), 2.0, 0.0, 0.0, 1.0, // Vertex 10 blue // Part of Triangle Ten cos(180 * toRadians), sin(180 * toRadians), 2.0, 1.0, 0.0, 1.0, // Vertex 11 purple // Part of Triangle Eleven cos(240 * toRadians), sin(240 * toRadians), 2.0, 1.0, 0.0, 0.0, // Vertex 12 red // Part of Triangle Twelve cos(300 * toRadians), sin(300 * toRadians), 2.0, 0.0, 1.0, 0.0, // Vertex 13 green // ------------- planeVertices[] // positon attributes (x,y,z) 0.0f, 0.0f, 0.0f, // vert 14 0.0f, 1.0f, 0.0f, // red 0.0f, 0.866f, 0.0f, // vert 15 0.0f, 1.0f, 0.0f, // green 1.0f, 0.0f, 0.0f, // vert 16 0.0f, 1.0f, 0.0f, // blue 1.0f, 0.866f, 0.0f, // vert 17 1.0f, 0.0f, 1.0f // purple }; // Now generate a vertex buffer with all vertex data in one buffer GLuint allVerticesVBO; glGenBuffers(1, & allVerticesVBO); glBindBuffer(GL_ARRAY_BUFFER, allVerticesVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(allVertices), allVertices, GL_STATIC_DRAW); // Load vertex attributes Index Buffers Now, depending on how you set the vertex buffers up previously, you will have to do one (but not both!) of the following. If you have separated your vertex buffers (one for cylinder, one for the plane), then you will need separate index buffers as well. // we need two index buffers, one for the plane, one for the cylinder GLuint cylinderIBO, planeIBO; //-------------------- // cylinder //-------------------- // Define element indices GLubyte cylinderIndices[] = { // Bottom base 0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,7, // Sides 1,2,8, 2,9,8, 2,3,9, 3,10,9, 3,4,10, 4,11,10, 5,11,4, 5,12,11, 5,6,12, 6,13,12, 6,1,13, 1,8,13 }; glGenBuffers(1, &cylinderIBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cylinderIndices), cylinderIndices, GL_STATIC_DRAW); // Load indices attributes //-------------------- // plane //-------------------- GLubyte planeIndices[] = { 0,2,1, //< NOTE: These must start at ZERO in this case! 2,3,1 }; glGenBuffers(1, &planeIBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(planeIndices), planeIndices, GL_STATIC_DRAW); // Load indices attributes If however you wish to combine both shapes into a single buffer, then instead do this: // we need one index buffer! GLuint allIndicesIBO; // Define element indices GLubyte allIndices[] = { //-------------------- // cylinder //-------------------- // Bottom base 0,1,2, 0,2,3, 0,3,4, 0,4,5, 0,5,6, 0,6,7, // Sides 1,2,8, 2,9,8, 2,3,9, 3,10,9, 3,4,10, 4,11,10, 5,11,4, 5,12,11, 5,6,12, 6,13,12, 6,1,13, 1,8,13, //-------------------- // plane //-------------------- 14,16,15, //< NOTE: these now start at 14! 16,17,15 }; glGenBuffers(1, &allIndicesIBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, allIndicesIBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(allIndices), allIndices, GL_STATIC_DRAW); // Load indices attributes Vertex Buffer Objects If you have set up separate buffers for each shape, then you have two choices in how you set up the VAOs. 1.1 Create two VAO's, one for each shape. GLuint cylinderVAO, planeVAO; // generate a bind new VAO for the cylinder glGenVertexArrays(1, & cylinderVAO); glBindVertexArray(cylinderVAO); // specify which buffers the current VAO should use glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO); // Specify attributes location and layout to GPU glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // Color attribute location and layout glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); // generate a bind new VAO for the plane glGenVertexArrays(1, &planeVAO); glBindVertexArray(planeVAO); // specify which buffers the current VAO should use glBindBuffer(GL_ARRAY_BUFFER, planeVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO); // Specify attributes location and layout to GPU glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // Color attribute location and layout glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); To render the data like this, you'll need 2 draw calls, one for each shape. glBindVertexArray(cylinderVAO); glDrawElements(mode, 54, GL_UNSIGNED_BYTE, nullptr); glBindVertexArray(planeVAO); glDrawElements(mode, 6, GL_UNSIGNED_BYTE, nullptr); 1.2 Setup 1 VAO, but rebind the vertex & index buffers on the fly. GLuint sharedVAO; // generate a bind new VAO for the cylinder glGenVertexArrays(1, & sharedVAO); glBindVertexArray(sharedVAO); // Specify attributes location and layout to GPU glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // Color attribute location and layout glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); To render the data like this, you'll need 2 draw calls, one for each shape. // specify the shared vertex format glBindVertexArray(sharedVAO); // specify data sources for cylinder, and render glBindBuffer(GL_ARRAY_BUFFER, cylinderVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cylinderIBO); glDrawElements(mode, 54, GL_UNSIGNED_BYTE, nullptr); // specify data sources for plane, and render glBindBuffer(GL_ARRAY_BUFFER, planeVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, planeIBO); glDrawElements(mode, 6, GL_UNSIGNED_BYTE, nullptr); If however you have specified all of the data in a single vertex buffer, and a single index buffer, then instead you can do: GLuint sharedVAO; // generate a bind new VAO for the cylinder glGenVertexArrays(1, & sharedVAO); glBindVertexArray(sharedVAO); // specify data sources for the VAO glBindBuffer(GL_ARRAY_BUFFER, allVerticesVBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, allIndicesIBO); // Specify attributes location and layout to GPU glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)0); glEnableVertexAttribArray(0); // Color attribute location and layout glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); To render the data like this, you'll need 1 draw call. // render both shapes in one draw call glBindVertexArray(sharedVAO); glDrawElements(mode, 60, GL_UNSIGNED_BYTE, nullptr); And that's it.
OpenGL Lighting Not Shading
I'm attempting too add basic lighting to my scene. So far even without GLSL. It appears that my lighting doesn't work. And what I mean by that is everything has no shade at all (everything is lit up). I know the picture isn't the best, but thats partly because of the texture is shaded in the image. Here is my init code: glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Clear to black with full alpha glEnable(GL_DEPTH_TEST); // Enable depth testing glDepthFunc(GL_LEQUAL); // Specify depth testing function glClearDepth(1.0); // Clear the full extent of the depth buffer (default) glEnable(GL_CULL_FACE); // Enable face culling glCullFace(GL_BACK); // Cull back faces of polygons glFrontFace(GL_CCW); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glShadeModel(GL_SMOOTH); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glColorMaterial ( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); glEnable ( GL_COLOR_MATERIAL ); GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 0.2f }; GLfloat diffuseLight[] = { 0.8f, 0.8f, 0.8, 1.0f }; GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat position[] = {0, 100.0f, 0, 1.0f }; glLightModelfv(GL_AMBIENT, ambientLight); glLightModelfv(GL_DIFFUSE, ambientLight); glLightModelfv(GL_SPECULAR, specularLight); glLightModelfv(GL_POSITION, position); glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); glLightfv(GL_LIGHT0, GL_POSITION, position); Draw code: glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glEnable(GL_NORMALIZE); //For loop of the lights... glLightfv(GL_LIGHT0+m_lights.at(i)->id, GL_POSITION, glm_to_array(m_lights.at(i)->position)); glEnable(GL_LIGHT0+m_lights.at(i)->id); //Draw geometry here... And yes, I am retrieving the normals from the mesh file and inserting the glNormal3f of every face. (GL_TRIANGLES) And even the plane the model sits on never gets affected even if I completely change the normal to random values. Plane Example: if(m_shader_programme){ glUseProgram(m_shader_programme); } if(m_texture_id){ glBindTexture(GL_TEXTURE_2D, m_texture_id); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); } glBegin(GL_TRIANGLES); glNormal3f(0.0f, 1.0f, 0.0f); glTexCoord2f(0.0f, m_sizey/10); glVertex3f(m_sizex, m_height, m_sizey); glTexCoord2f(m_sizex/10, m_sizey/10); glVertex3f(m_sizex, m_height, -m_sizey); glTexCoord2f(m_sizex/10, 0.0f); glVertex3f(-m_sizex, m_height, -m_sizey); glNormal3f(0.0f, 1.0f, 0.0f); glTexCoord2f(m_sizex/10, 0.0f); glVertex3f(-m_sizex, m_height, -m_sizey); glTexCoord2f(0.0f, 0.0f); glVertex3f(-m_sizex, m_height, m_sizey); glTexCoord2f(0.0f, m_sizey/10); glVertex3f(m_sizex, m_height, m_sizey); glEnd(); if(m_shader_programme){ glUseProgram(0); } if(m_texture_id){ glBindTexture(GL_TEXTURE_2D, 0); } GLSL Fragment Shader: #version 120 uniform sampler2D tex; void main() { vec4 color = texture2D(tex,gl_TexCoord[0].st); gl_FragColor = color; } Vertex Shader: #version 120 void main() { vec3 normal, lightDir; vec4 diffuse, ambient, globalAmbient; float NdotL; gl_TexCoord[0] = gl_TextureMatrix[0] * gl_MultiTexCoord0; normal = normalize(gl_NormalMatrix * gl_Normal); lightDir = normalize(vec3(gl_LightSource[0].position)); NdotL = max(dot(normal, lightDir), 0.0); diffuse = gl_FrontMaterial.diffuse * gl_LightSource[0].diffuse; /* Compute the ambient and globalAmbient terms */ ambient = gl_FrontMaterial.ambient * gl_LightSource[0].ambient; globalAmbient = gl_LightModel.ambient * gl_FrontMaterial.ambient; gl_FrontColor = NdotL * diffuse + globalAmbient + ambient; gl_Position = ftransform(); } System Specs OS X (Yosemite) 10.10.13 (64bit) Renderer: NVIDIA GeForce GTX 780M OpenGL Engine OpenGL version supported 2.1 NVIDIA-10.2.7 310.41.25f01 Just encase anyone is wondering why I'm not using OpenGL 3.x is because GL 3.x doesn't appear to play nice on my machine.
Your fragment shader: vec4 color = texture2D(tex,gl_TexCoord[0].st); gl_FragColor = color; Simply discards all the computations you did in the vertex shader and samples the texture color. You need to multiply the texture sample by the interpolated color value: vec4 color = texture2D(tex, gl_TexCoord[0].st) * gl_Color; ^~~~~~ gl_FragColor = color;
Lighting not appearing in OpenGL
I've been trying to implement lighting for my OpenGL project, but so far I haven't been able to get any lighting effects. I know that many things could go wrong, so I've tried hardcoding my normals (and using only a few triangles), but still I don't get anything. In my scene, I have a few objects laying down along the "ground" at 0,0,0, hoping to see light coming down from above on them. They have a very basic texture on them which would easily show if they were lit up or not. I initialize my scene like this: glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glShadeModel(GL_SMOOTH); glEnable(GL_COLOR_MATERIAL); glTranslatef(0,0,0); GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 0.2f }; GLfloat diffuseLight[] = { 0.8f, 0.8f, 0.8, 1.0f }; GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat position[] = {0, 100.0f, 0, 1.0f }; glLightModelfv(GL_AMBIENT, ambientLight); glLightModelfv(GL_DIFFUSE, ambientLight); glLightModelfv(GL_SPECULAR, specularLight); glLightModelfv(GL_POSITION, position); glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight); glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight); glLightfv(GL_LIGHT0, GL_POSITION, position); glColorMaterial( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE ); GLfloat shine [] = {50}; GLfloat diffuse[] = {1.0f, 0.f, 0.f, 1.0f}; GLfloat spec[] = {1.0f, 0.f, 0.f, 1.0f}; glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE,diffuse); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR,spec); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS,shine); And when I go to render: glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, tiles[x]->image.width(), tiles[x]->image.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tiles[x]->image.bits()); glNormal3d(0,1,0); //Will eventually calculate glDrawArrays(GL_TRIANGLES, 0, 3); glDrawArrays(GL_TRIANGLES, 3, 3); "Tiles" is just a class of mine that holds an image and corresponding vectors for my objects. The "vertices" that are called is just a list of vectors (so each object has 6 vectors = 2 triangles. My fragment shader: uniform sampler2D texture; in vec4 gl_Color; in vec2 varyingTextureCoordinate; out vec4 fragColor; void main(void) { fragColor = texture2D(texture, varyingTextureCoordinate); } And my vertex shader: uniform mat4 mvpMatrix; in vec4 vertex; in vec2 textureCoordinate; out vec2 varyingTextureCoordinate; void main(void) { varyingTextureCoordinate = textureCoordinate; gl_Position = mvpMatrix * vertex; } Is my lack of lighting due to a conflict with the texture? No matter how I change that normal, I don't get any lighting.
I think you're trying to combine pre-programmable shader opengl and shader open gl here. I recommend learning how to implement lighting by utilizing as much shader code as possible BennyBox has a great youtube series on OpenGL covering shaders and engine design Here is his git repo and the java version.
Sending two textures to GLSL shader
When sending two textures to my GLSL shader only one actually arrives. What is strange is the first texture I bind is used for both textures slots in my shader. This leads me to believe the way I am passing my textures in OpenGL is wrong. However, I am unable to track down the problem. Here is the code where I configure the textures for use in my shader. glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fbo2); glPushAttrib(GL_VIEWPORT_BIT | GL_ENABLE_BIT); glClearColor(1.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Get uniforms GLuint pass_3O = glGetUniformLocation(blend_shader, "org"); GLuint pass_3B = glGetUniformLocation(blend_shader, "blur"); // Activate shaders glUseProgram(blend_shader); // Bind first texture glActiveTexture(GL_TEXTURE0 ); glBindTexture(GL_TEXTURE_2D, init_texture); // Bind the second texture glActiveTexture(GL_TEXTURE1 ); glBindTexture(GL_TEXTURE_2D, third_texture); // Assign index to 2d images glUniform1i(pass_3O, 0); glUniform1f(pass_3B, 1); The code above is passing in two textures. The first is a 2D image of the first rendering pass of the 3D scene. The third is that same texture with x2 levels of blur added. This final stage is to blend them together for a poor mans bloom. Here is the code where I am drawing both textures to the quad. // Draw to quad glBegin(GL_QUADS); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 0.0f); glMultiTexCoord2f(GL_TEXTURE1, 0.0f, 0.0f); glVertex3f(-w_width/2.0, -w_height/2.0, 0.5f); glMultiTexCoord2f(GL_TEXTURE0, 0.0f, 1.0f); glMultiTexCoord2f(GL_TEXTURE1, 0.0f, 1.0f); glVertex3f(-w_width/2.0, w_height/2.0, 0.5f); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 1.0f); glMultiTexCoord2f(GL_TEXTURE1, 1.0f, 1.0f); glVertex3f(w_width/2.0, w_height/2.0, 0.5f); glMultiTexCoord2f(GL_TEXTURE0, 1.0f, 0.0f); glMultiTexCoord2f(GL_TEXTURE1, 1.0f, 0.0f); glVertex3f(w_width/2.0, -w_height/2.0, 0.5f); glEnd(); glFlush(); glPopAttrib(); // Unbind textures glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, 0); // Disable blend shader glUseProgram(0); glBindFramebufferEXT(GL_FRAMEBUFFER_EXT,0); And here is the shader I am using to render the final image. Vert #version 120 void main() { gl_TexCoord[0] = gl_MultiTexCoord0; gl_TexCoord[1] = gl_MultiTexCoord1; gl_Position = ftransform(); } Frag #version 120 uniform sampler2D org; uniform sampler2D blur; void main() { vec4 orig_clr = texture2D( org, gl_TexCoord[0].st); vec4 blur_clr = texture2D( blur, gl_TexCoord[1].st ); //gl_FragColor = orig_clr; gl_FragColor = blur_clr; } If I switch between the last two lines in the fragment shader I get the same exact results. The only way to change which texture gets render is to change the order in which I bind them. For example, the following would finally pass me the blurred image. Once again, only getting one of the two images. glActiveTexture(GL_TEXTURE0 ); glBindTexture(GL_TEXTURE_2D, third_texture); glActiveTexture(GL_TEXTURE1 ); glBindTexture(GL_TEXTURE_2D, init_texture); Any thoughts on what I am overlooking?
Look at this code: glUniform1i(pass_3O, 0); glUniform1f(pass_3B, 1); you have some small typo here, it should be glUniform1*i* instead of Uniform1*f* in the second call. The type must match that of the shader variable, so this call should just result in some error, leaving the uniform initialized at 0, which completely explains your results.
Can I use fixed glEnable(GL_LIGHTING) alongside fragment/vertex shaders?
I have browsed many online articles and adding lighting seems very straight forward but I'm not able to get a result. I'm using OpenGL 3.0 and I use a vertex and fragment shaders for my animating model. Btw, I'm new to OpenGL. Disregarding the lighting I have everything working fine with the 3D char running around the environment. glEnable(GL_DEPTH_TEST); glClearColor(0.0f, 0.0f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); *snip* glEnable(GL_LIGHTING); glEnable (GL_LIGHT0); float ambientLight0[] = { 0.2f, 0.2f, 0.2f, 1.0f }; float diffuseLight0[] = { 0.8f, 0.8f, 0.8f, 1.0f }; float specularLight0[] = { 0.5f, 0.5f, 0.5f, 1.0f }; float position0[] = { -2.5f, 1.0f, -1.0f, 1.0f }; glLightfv(GL_LIGHT0, GL_AMBIENT, ambientLight0); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuseLight0); glLightfv(GL_LIGHT0, GL_SPECULAR, specularLight0); glLightfv(GL_LIGHT0, GL_POSITION, position0); //glEnable(GL_COLOR_MATERIAL); //float mcolor[] = { 1.0f, 0.0f, 0.0f, 1.0f }; //glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mcolor); m_Beast.onRender(); Here's how m_Beast.onRender() looks: glPushMatrix(); Vector3 pos = getPosition(); glTranslatef(pos.x, pos.y, pos.z); glBindTexture(GL_TEXTURE_2D, m_beastTextureID); static float modelviewMatrix[16]; static float projectionMatrix[16]; glGetFloatv(GL_MODELVIEW_MATRIX, modelviewMatrix); glGetFloatv(GL_PROJECTION_MATRIX, projectionMatrix); m_shaderProgram->bindShader(); m_shaderProgram->sendUniform4x4("modelview_matrix", modelviewMatrix); m_shaderProgram->sendUniform4x4("projection_matrix", projectionMatrix); m_shaderProgram->sendUniformTexture("texture0", 0); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); glVertexAttribPointer((GLint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, m_texCoordBuffer); glVertexAttribPointer((GLint)1, 2, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLES, 0, m_interpolatedFrame.vertices.size()); glDisableVertexAttribArray(1); glDisableVertexAttribArray(0); glPopMatrix(); I just want a quick way to get some directional lighting on my model. I'm really not interesting in writing a lighting shader at this point.
As soon as you use vertex shaders, you must implement the lighting calculations yourself. In older OpenGL one could still use the fixed function vertex pipeline and program only the fragment stage. But with OpenGL-3 and onwards you're required to do it all. However you shouldn't feel too bad about this. In the end you'll write less, because the huge plethora of function calls required to configure fixed function, can be replaced by much shorter and concise shader code.