I'm trying to enable mutlisampling and alpha-to-coverage for an FBO. Using the default framebuffer, all I have to do is call glEnable(GL_MULTISAMPLE) and glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE). However, I am unable to achieve the same effect using my own FBO.
My goal: Draw the scene to an FBO the same way it would be drawn to the default framebuffer with the above properties. From there I want to be able to use the image as a texture for future passes through a shader.
This works: Code for making an FBO without multisampling/alpha-to-coverage, 1 color attachment, 1 depth attachment:
// Generate the color attachment
glGenTextures(1,&defaultColorAttachment0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D,defaultColorAttachment0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D,0,GL_RGBA,screenWidth,screenHeight,0,GL_RGBA,GL_UNSIGNED_BYTE,NULL);
// Bind the texture to the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, defaultColorAttachment0,0);
// Generate the depth attachment
glGenRenderbuffers(1,&defaultDepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, defaultDepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenWidth, screenHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, defaultDepthBuffer);
This doesn't work. Code trying to make a multisampled FBO:
// Generate the color attachment
glGenTextures(1,&defaultColorAttachment0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, defaultColorAttachment0);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, screenWidth, screenHeight, GL_FALSE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, defaultColorAttachment0,0);
// Generate the depth attachment
glGenRenderbuffers(1,&defaultDepthBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, defaultDepthBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, screenWidth, screenHeight);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, defaultDepthBuffer);
I have tried looking through the OpenGL wiki on this, although the it's incomplete (various unfinished headings make it look unprofessional). glGetError never complains. I've tried messing around with this, but I either get a black screen or a screen full of garbage pixels.
Main Question: What things do I need to consider/change and where (FBO creation, textures, shaders) in order to get multisampling and alpha-to-coverage to work with an FBO?
You need to allocate a multisampled depth buffer for this to work correctly and give it the same number of samples as your color buffer. In other words, you should be calling glRenderbufferStorageMultisample (...) instead of glRenderbufferStorage (...).
Your FBO should be failing a completeness check the way it is allocated right now. A call to glCheckFramebufferStatus (...) ought to return GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE because your depth buffer has exactly 1 sample and your color buffer attachment has 4.
Since you are also using a multisampled texture attachment in this FBO, you should be aware of differences between sampling a single-sampled texture vs. multisampled in GLSL shaders.
Multisampled textures have a special sampler uniform type (e.g. sampler2DMS) and you have to explicitly fetch each sample in the texture by its integer (non-normalized) texel coordinate and sample index using texelFetch (...). This also means that they cannot be filtered or mip-mapped.
You probably do not want a multisampled texture in this case, you probably want to use glBlitFramebuffer (...) to do the MSAA resolve into a single-sampled FBO. If you do this instead you can read the anti-aliased results in your shaders rather than having to fetch each sample and implement the anti-aliasing yourself.
Here is a working example to go along with the accepted answer. It is a modified example of the triangle example from the LearnopenGL tutorials to draw a MSAA custom framebuffer to a quad which is then draw to the default framebuffer (the screen):
#include <iostream>
#include <glad/glad.h>
#include <GLFW/glfw3.h>
const char *vertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec3 aPos;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
"}\0";
const char *fragmentShaderSource = "#version 330 core\n"
"out vec4 FragColor;\n"
"void main()\n"
"{\n"
" FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);\n"
"}\n\0";
const char *postProcessvertexShaderSource = "#version 330 core\n"
"layout (location = 0) in vec2 position;\n"
"layout (location = 1) in vec2 inTexCoord;\n"
"out vec2 texCoord;\n"
"void main(){\n"
" texCoord = inTexCoord;\n"
" gl_Position = vec4(position.x, position.y, 0.0f, 1.0f);\n"
"}\n\0";
const char *postProcessFragmentShaderSource = "#version 330 core\n"
"out vec4 fragmentColor;\n"
"in vec2 texCoord;\n"
"//notice the sampler\n"
"uniform sampler2DMS screencapture;\n"
"uniform int viewport_width;\n"
"uniform int viewport_height;\n"
"void main(){\n"
" //texelFetch requires a vec of ints for indexing (since we're indexing pixel locations)\n"
" //texture coords is range [0, 1], we need range [0, viewport_dim].\n"
" //texture coords are essentially a percentage, so we can multiply text coords by total size \n"
" ivec2 vpCoords = ivec2(viewport_width, viewport_height);\n"
" vpCoords.x = int(vpCoords.x * texCoord.x); \n"
" vpCoords.y = int(vpCoords.y * texCoord.y);\n"
" //do a simple average since this is just a demo\n"
" vec4 sample1 = texelFetch(screencapture, vpCoords, 0);\n"
" vec4 sample2 = texelFetch(screencapture, vpCoords, 1);\n"
" vec4 sample3 = texelFetch(screencapture, vpCoords, 2);\n"
" vec4 sample4 = texelFetch(screencapture, vpCoords, 3);\n"
" fragmentColor = vec4(sample1 + sample2 + sample3 + sample4) / 4.0f;\n"
"}\n\0";
int main()
{
int width = 800;
int height = 600;
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
GLFWwindow* window = glfwCreateWindow(width, height, "OpenglContext", nullptr, nullptr);
if (!window)
{
std::cerr << "failed to create window" << std::endl;
exit(-1);
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cerr << "failed to initialize glad with processes " << std::endl;
exit(-1);
}
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
int samples = 4;
float quadVerts[] = {
-1.0, -1.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0
};
GLuint postVAO;
glGenVertexArrays(1, &postVAO);
glBindVertexArray(postVAO);
GLuint postVBO;
glGenBuffers(1, &postVBO);
glBindBuffer(GL_ARRAY_BUFFER, postVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVerts), quadVerts, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast<void*>(0));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), reinterpret_cast<void*>(2 * sizeof(float)));
glEnableVertexAttribArray(1);
glBindVertexArray(0);
GLuint msaaFB;
glGenFramebuffers(1, &msaaFB);
glBindFramebuffer(GL_FRAMEBUFFER, msaaFB); //bind both read/write to the target framebuffer
GLuint texMutiSampleColor;
glGenTextures(1, &texMutiSampleColor);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor);
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// vertex shader
unsigned int vertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
glCompileShader(vertexShader);
// check for shader compile errors
// fragment shader
unsigned int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
glCompileShader(fragmentShader);
// check for shader compile errors
// link shaders
unsigned int shaderProgram = glCreateProgram();
glAttachShader(shaderProgram, vertexShader);
glAttachShader(shaderProgram, fragmentShader);
glLinkProgram(shaderProgram);
// check for linking errors
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
//postprocess vertex shader
unsigned int postProcessVertexShader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(postProcessVertexShader, 1, &postProcessvertexShaderSource, NULL);
glCompileShader(postProcessVertexShader);
// postprocess fragment shader
unsigned int postProcessFragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(postProcessFragmentShader, 1, &postProcessFragmentShaderSource, NULL);
glCompileShader(postProcessFragmentShader);
// check for shader compile errors
// link shaders
unsigned int postProcessShaderProgram = glCreateProgram();
glAttachShader(postProcessShaderProgram, postProcessVertexShader);
glAttachShader(postProcessShaderProgram, postProcessFragmentShader);
glLinkProgram(postProcessShaderProgram);
// check for linking errors
glDeleteShader(postProcessVertexShader);
glDeleteShader(postProcessFragmentShader);
glUseProgram(postProcessShaderProgram);
glUniform1i(glGetUniformLocation(postProcessShaderProgram, "screencapture"), 0);
glUniform1i(glGetUniformLocation(postProcessShaderProgram, "viewport_width"), width);
glUniform1i(glGetUniformLocation(postProcessShaderProgram, "viewport_height"), height);
float vertices[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
0.0f, 0.5f, 0.0f
};
unsigned int VBO, VAO;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
bool use_msaa = true;
while (!glfwWindowShouldClose(window))
{
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
{
glfwSetWindowShouldClose(window, true);
}
if (glfwGetKey(window, GLFW_KEY_R) == GLFW_PRESS)
use_msaa = true;
if (glfwGetKey(window, GLFW_KEY_T) == GLFW_PRESS)
use_msaa = false;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (use_msaa) {
glBindFramebuffer(GL_FRAMEBUFFER, msaaFB);
}
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
// draw our first triangle
glUseProgram(shaderProgram);
glBindVertexArray(VAO);
glDrawArrays(GL_TRIANGLES, 0, 3);
if (use_msaa) {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glUseProgram(postProcessShaderProgram);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor);
glBindVertexArray(postVAO);
glDrawArrays(GL_TRIANGLES, 0, 6);
}
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwTerminate();
// cleanup
}
Demo:
Thankyou Matt Stone from the comment section of LearnOpenGL for the working code.
Adding to jackw11111's answer, I wanted to test this sample code in python. Enclosed is my near 1:1 translation to python of code apparently by Matt Stone in comments of LearnOpenGL. Tested on Ubuntu and MacOS.
## Not needed for python.
## #include <glad/glad.h>
# Setup might be something like:
# python3 -m venv venv_msaa
# source venv_msaa/bin/activate
# pip install PyOpenGL glfw numpy
# Note: On a MacOS hidpi screen, the results will vary.
import ctypes
import numpy as np
import glfw
from OpenGL.GL import *
VERTEX_SHADER_SOURCE = """#version 330 core
layout (location = 0) in vec3 aPos;
void main()
{
gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0);
}
"""
FRAGMENT_SHADER_SOURCE = """#version 330 core
out vec4 FragColor;
void main()
{
FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
}
"""
POSTPROCESS_VERTEX_SHADER_SOURCE = """#version 330 core
layout (location = 0) in vec2 position;
layout (location = 1) in vec2 inTexCoord;
out vec2 texCoord;
void main(){
texCoord = inTexCoord;
gl_Position = vec4(position.x, position.y, 0.0f, 1.0f);
}
"""
POSTPROCESS_FRAGMENT_SHADER_SOURCE = """#version 330 core
out vec4 fragmentColor;
in vec2 texCoord;
// notice the sampler
uniform sampler2DMS screencapture;
uniform int viewport_width;
uniform int viewport_height;
void main(){
// texelFetch requires a vec of ints for indexing (since we're indexing pixel locations)
// texture coords is range [0, 1], we need range [0, viewport_dim].
// texture coords are essentially a percentage, so we can multiply text coords by total size
ivec2 vpCoords = ivec2(viewport_width, viewport_height);
vpCoords.x = int(vpCoords.x * texCoord.x);
vpCoords.y = int(vpCoords.y * texCoord.y);
// do a simple average since this is just a demo
vec4 sample1 = texelFetch(screencapture, vpCoords, 0);
vec4 sample2 = texelFetch(screencapture, vpCoords, 1);
vec4 sample3 = texelFetch(screencapture, vpCoords, 2);
vec4 sample4 = texelFetch(screencapture, vpCoords, 3);
fragmentColor = vec4(sample1 + sample2 + sample3 + sample4) / 4.0f;
}
"""
def main():
width = 800
height = 600
glfw.init()
glfw.window_hint(glfw.CONTEXT_VERSION_MAJOR, 3)
glfw.window_hint(glfw.CONTEXT_VERSION_MINOR, 3)
glfw.window_hint(glfw.OPENGL_PROFILE, glfw.OPENGL_CORE_PROFILE)
glfw.window_hint(glfw.OPENGL_FORWARD_COMPAT, GL_TRUE)
window = glfw.create_window(width, height, "OpenglContext", None, None)
if not window:
print("failed to create window")
sys.exit(-1)
glfw.make_context_current(window);
## Not needed for python.
## if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
## {
## std::cerr << "failed to initialize glad with processes " << std::endl;
## exit(-1);
## }
glfw.set_input_mode(window, glfw.CURSOR, glfw.CURSOR_DISABLED)
samples = 4
quadVerts = np.array([
-1.0, -1.0, 0.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 1.0, 0.0,
1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0
], dtype=np.float32)
postVAO = glGenVertexArrays(1)
glBindVertexArray(postVAO)
sizeof_float = ctypes.sizeof(ctypes.c_float) # Complicated way of saying 4
postVBO = glGenBuffers(1)
glBindBuffer(GL_ARRAY_BUFFER, postVBO)
glBufferData(GL_ARRAY_BUFFER, quadVerts.nbytes, quadVerts.ctypes._as_parameter_, GL_STATIC_DRAW)
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof_float, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof_float, ctypes.c_void_p(2 * sizeof_float))
glEnableVertexAttribArray(1)
glBindVertexArray(0)
msaaFB = glGenFramebuffers(1)
glBindFramebuffer(GL_FRAMEBUFFER, msaaFB); # bind both read/write to the target framebuffer
texMutiSampleColor = glGenTextures(1)
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor)
glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, GL_RGB, width, height, GL_TRUE)
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0)
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor, 0)
glBindFramebuffer(GL_FRAMEBUFFER, 0)
# vertex shader
vertexShader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(vertexShader, VERTEX_SHADER_SOURCE)
glCompileShader(vertexShader)
# check for shader compile errors
# fragment shader
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(fragmentShader, FRAGMENT_SHADER_SOURCE)
glCompileShader(fragmentShader)
# check for shader compile errors
# link shaders
shaderProgram = glCreateProgram()
glAttachShader(shaderProgram, vertexShader)
glAttachShader(shaderProgram, fragmentShader)
glLinkProgram(shaderProgram)
# check for linking errors
glDeleteShader(vertexShader)
glDeleteShader(fragmentShader)
#postprocess vertex shader
postProcessVertexShader = glCreateShader(GL_VERTEX_SHADER)
glShaderSource(postProcessVertexShader, POSTPROCESS_VERTEX_SHADER_SOURCE)
glCompileShader(postProcessVertexShader)
# check for shader compile errors
# postprocess fragment shader
postProcessFragmentShader = glCreateShader(GL_FRAGMENT_SHADER)
glShaderSource(postProcessFragmentShader, POSTPROCESS_FRAGMENT_SHADER_SOURCE)
glCompileShader(postProcessFragmentShader)
# check for shader compile errors
# link shaders
postProcessShaderProgram = glCreateProgram()
glAttachShader(postProcessShaderProgram, postProcessVertexShader)
glAttachShader(postProcessShaderProgram, postProcessFragmentShader)
glLinkProgram(postProcessShaderProgram)
# check for linking errors
glDeleteShader(postProcessVertexShader)
glDeleteShader(postProcessFragmentShader)
glUseProgram(postProcessShaderProgram)
glUniform1i(glGetUniformLocation(postProcessShaderProgram, "screencapture"), 0)
glUniform1i(glGetUniformLocation(postProcessShaderProgram, "viewport_width"), width)
glUniform1i(glGetUniformLocation(postProcessShaderProgram, "viewport_height"), height)
vertices = np.array([
-0.5, -0.5, 0.0,
0.5, -0.5, 0.0,
0.0, 0.5, 0.0
], dtype=np.float32)
VAO = glGenVertexArrays(1)
VBO = glGenBuffers(1)
glBindVertexArray(VAO)
glBindBuffer(GL_ARRAY_BUFFER, VBO)
glBufferData(GL_ARRAY_BUFFER, vertices.nbytes, vertices.ctypes._as_parameter_, GL_STATIC_DRAW)
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof_float, ctypes.c_void_p(0))
glEnableVertexAttribArray(0)
glBindBuffer(GL_ARRAY_BUFFER, 0)
glBindVertexArray(0)
use_msaa = True
while not glfw.window_should_close(window):
if glfw.get_key(window, glfw.KEY_ESCAPE) == glfw.PRESS:
glfw.set_window_should_close(window, True)
if glfw.get_key(window, glfw.KEY_R) == glfw.PRESS:
use_msaa = True
if glfw.get_key(window, glfw.KEY_T) == glfw.PRESS:
use_msaa = False
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
if use_msaa:
glBindFramebuffer(GL_FRAMEBUFFER, msaaFB)
glClearColor(0.0, 0.0, 0.0, 1.0)
glClear(GL_COLOR_BUFFER_BIT)
# draw our first triangle
glUseProgram(shaderProgram)
glBindVertexArray(VAO)
glDrawArrays(GL_TRIANGLES, 0, 3)
glBindVertexArray(0)
if use_msaa:
glBindFramebuffer(GL_FRAMEBUFFER, 0)
glUseProgram(postProcessShaderProgram)
glActiveTexture(GL_TEXTURE0)
glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, texMutiSampleColor)
glBindVertexArray(postVAO)
glDrawArrays(GL_TRIANGLES, 0, 6)
glBindVertexArray(0)
glfw.swap_buffers(window)
glfw.poll_events()
glfw.terminate()
# cleanup
if __name__ == "__main__":
main()
Related
I've looked at other peoples implementation of it, and I'm still not sure what I'm doing wrong. My graphics drivers are up to date, and I'm getting no error messages.
I'm trying to use a GLSL compute shader to write to a texture which is then rendered onto a screen-size quad.
Here is the code for my main.cpp:
unsigned int hRes = 512;
unsigned int vRes = 512;
int main(void) {
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow* window = glfwCreateWindow(hRes, vRes, "Learn OpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
glViewport(0, 0, hRes, vRes);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
//
float vertices[] = {
// positions // Tex coords
1.f, 1.f, 0.0f, 1.f, 1.f, // top right
1.f, -1.f, 0.0f, 1.f, 0.f, // bottom right
-1.f, -1.f, 0.0f, 0.f, 0.f, // bottom left
-1.f, 1.f, 0.0f, 0.f, 1.f, // top left
};
unsigned int indices[] = {
0, 1, 3, // first triangle
1, 2, 3 // second triangle
};
unsigned int VAO;
glGenVertexArrays(1, &VAO);
glBindVertexArray(VAO);
unsigned int VBO;
glGenBuffers(1, &VBO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(0));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3));
glEnableVertexAttribArray(1);
unsigned int EBO;
glGenBuffers(1, &EBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, hRes, vRes, 0, GL_RGBA, GL_FLOAT, NULL);
glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32F);
// Vertex and fragment shaders are pretty much empty, and just pass through vertex/texture coord data
Shader vertex("doNothing.vert", GL_VERTEX_SHADER);
Shader fragment("doNothing.frag", GL_FRAGMENT_SHADER);
ShaderProgram renderProg;
renderProg.attach(vertex);
renderProg.attach(fragment);
renderProg.link();
Shader computeShader("julia.comp", GL_COMPUTE_SHADER);
ShaderProgram computeProg;
computeProg.attach(computeShader);
computeProg.link();
while (!glfwWindowShouldClose(window))
{
// Input (currently does nothing)
processInput(window);
glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
computeProg.use();
glDispatchCompute(hRes / 16, vRes / 16, 1); // For local work group size 16. Ensures entire texture is written to
glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT);
renderProg.use();
glBindTexture(GL_TEXTURE_2D, texture);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
// End drawing current frame
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &VAO);
glDeleteBuffers(1, &VBO);
glDeleteBuffers(1, &EBO);
glfwTerminate();
return 0;
}
ShaderProgram and Shader are just helper classes that wrap the OpenGL object ID.
Shader code:
doNothing.frag:
#version 460 core
out vec4 FragColor;
in vec2 TexCoord;
uniform sampler2D ourTexture;
void main()
{
FragColor = texture(ourTexture, TexCoord);
}
doNothing.vert:
#version 460 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aTexCoord;
out vec2 TexCoord;
void main()
{
gl_Position = vec4(aPos, 1.0);
TexCoord = aTexCoord;
}
julia.comp:
#version 460
layout (binding = 0, rgba32f) uniform writeonly image2D destTex;
layout (local_size_x = 16, local_size_y = 16) in;
void main() {
ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
if(storePos.x > 100){
imageStore(destTex, storePos, vec4(0., 0., 1.0, 1.0));
}else{
imageStore(destTex, storePos, vec4(1., 0., 0.0, 1.0));
}
}
I expected this code to output an image where one portion was red, and the other portion was blue.
What instead happens is that it outputs a single-colour image where the entire screen is a blend of the red and blue colours.
I have played around with the conditions inside of the julia.comp shader, and it seems that if I set the conditions such that the corners are each coloured differently, I get a blend of the corner colours (E.G. if I set the condition to storePos.x > 100 && storePos.x < 511 I get only the colour from the else block, but if I set it to storePos.x > 100 && storePos.x < 513 I get a blend of both colours.
Any help would be appreciated.
EDIT:
image of what I get:
And this is what happens if I replace vec4(0., 0., 1., 1.) with vec4(0., 1., 0., 1.) in the "if" code block:
Which is why I believe it is blending the colours somehow. (Note that the yellow colour is also fairly dim, which suggests the colours have been averaged, not added together)
EDIT: I tried setting the magnification filter to GL_NEAREST, and this results in a bright red texture across the entire screen. (No blending between the two colours)
EDIT: the post "OpenGL compute shader - strange results" does not solve my problem. That askers problem was with a particular library he was using for their matrix calculations, and I am not even using a single matrix in my answer. I have also tried other suggestions people on that post had, and none of them worked.
The offset to glVertexAttribPointer is in bytes. You pass a (void*)(3) for what should be (void*)(3*sizeof(float)):
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void*)(3*sizeof(float))); // <--- here
I have been writing a program to visualize a fractal point cloud and so far everything has been working, camera movement is using arc-ball movement centered on the origin and points are being rendered. However, I am needing to output the scene into an integrated window inside a UI so i have been trying to get frame buffers to work.
So far i have got a texture to be successfully rendered onto a quad that i am then outputting to the screen which for testing purposes is basically the same as when i was not using a fbo. My issue comes when trying to get camera movement to also display using the rendered texture. i know this is definitely possible as there are lots of examples of this but i haven't been able to get any to work with my code. I'm fairly certain my issue is with my shaders but i have scoured lots of websites, YouTube tutorials, openGL examples and found nothing that works. to the best of my knowledge i have to render the scene as normal so i have been using the same shaders that have worked for me previously for the initial rendering step but i have using my fbo instead of the default fbo
for simplicity's sake, i have just been rendering a point cube as it is faster than generating a fractal each time.
here is the main setup of the fbo, texture and rbo:
GLuint fbo;
GLuint texturebuffer;
GLuint rbo;
void initFBO(){
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glGenTextures(1, &texturebuffer);
glBindTexture(GL_TEXTURE_2D, texturebuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, WINDOW_WIDTH, WINDOW_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texturebuffer, 0);
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, WINDOW_WIDTH, WINDOW_HEIGHT);
glBindRenderbuffer(GL_RENDERBUFFER, 0); // once rbo memory allocated unbind
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
}
here is the main and the draw loop:
int main(){
if(!setup())
return -1;
// // white background
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
GLuint VertexArrayID;
glGenVertexArrays(1, &VertexArrayID);
glBindVertexArray(VertexArrayID);
// GLuint programID = LoadShaders( "new_vertex_shader", "new_fragment_shader" ); // custom shader
GLuint programID = LoadShaders("new_vertex_shader", "new_fragment_shader");
GLuint modelMatrixID = glGetUniformLocation(programID, "model");
GLuint viewMatrixID = glGetUniformLocation(programID, "view");
GLuint matrixID = glGetUniformLocation(programID, "MVP");
GLuint quad_programID = LoadShaders( "screen_vertex_shader", "screen_fragment_shader" );
GLuint textureID = glGetUniformLocation(quad_programID, "screenTexture");
// initialise mvp matrices
glm::mat4 ProjectionMatrix = perspective(radians(45.0f), 4.0f / 3.0f, 0.1f, 100.0f);
glm::mat4 ViewMatrix = translate(mat4(1.0f), vec3(0,0,-RADIUS));
glm::mat4 ModelMatrix = mat4(1.0f);
glm::mat4 MVP;
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
GLfloat cube[24] = {
0.5,0.5,0.5,
0.5,-0.5,0.5,
-0.5,0.5,0.5,
-0.5,-0.5,0.5,
0.5,0.5,-0.5,
0.5,-0.5,-0.5,
-0.5,-0.5,-0.5,
-0.5,0.5,-0.5
};
glBufferData(GL_ARRAY_BUFFER, sizeof(cube),cube, GL_STATIC_DRAW);
glfwSetMouseButtonCallback(window, mouseCallback);
// ################# main draw loop #######################
while( glfwGetKey(window, GLFW_KEY_ESCAPE ) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 ){
// render to fbo first
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
glEnable(GL_DEPTH_TEST);
glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
computeMatricesFromInputs();
ProjectionMatrix = getProjectionMatrix();
ViewMatrix = getViewMatrix();
ModelMatrix = getModelMatrix();
MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// Use our shader
glUseProgram(programID);
// Send our transformation to the currently bound shader in the "MVP" uniform
glUniformMatrix4fv(matrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(modelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(viewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
// render scene as normal
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer); // index buffer
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glPointSize(POINT_SIZE);
glDrawArrays(GL_POINTS, 0, sizeof(cube));
glDisableVertexAttribArray(0);
// bind back to default frame buffer to show on screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(quad_programID);
glEnableVertexAttribArray(0);
glBindVertexArray(quad_vertex_buffer);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
glDrawArrays(GL_POINTS, 0, sizeof(cube));
glDisableVertexAttribArray(0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
vertex shader:
#version 330 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;
uniform mat4 view;
uniform mat4 model;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = MVP * vec4(vertexPosition_modelspace,1.0);
}
fragment shader:
#version 330 core
// Output data
out vec3 color;
void main(){
// Output color = black
color = vec3(0,0,0);
}
screen quad vertex shader:
#version 330 core
layout (location = 0) in vec2 aPos;
layout (location = 1) in vec2 aTexCoords;
out vec2 TexCoords;
void main()
{
TexCoords = aTexCoords;
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
}
screen quad fragment shader:
#version 330 core
out vec4 FragColour;
in vec2 TexCoords;
uniform sampler2D screenTexture;
void main()
{
FragColour = texture(screenTexture, TexCoords);
}
sorry if this is quite a big block of code, im not entirely sure where the error would lie and im somewhat new to using openGL. many thanks in advance for anyhelp.
glEnableVertexAttribArray changes a state in the Vertex Array Object. It has to be done after binding the VAO by glBindVertexArray.
I assume that quad_vertex_buffer is a Vertex Array Object, even though the name "vertex_buffer" is misleading.
glBindVertexArray(quad_vertex_buffer);
glEnableVertexAttribArray(0);
When you draw the screen space quad (2nd pass), then you have to use a primitive type which generates a (filled) polygon (probably GL_TRIANGLES or GL_TRIANGLE_STRIP), rather than the point primitive type GL_POINTS:
glDrawArrays(GL_POINTS, 0, sizeof(cube));
glDrawArrays(GL_TRIANGLE_STRIP, 0, sizeof(cube))
I have a Mac running OS X Yosemite with GLFW 3 and OpenGL 4.1. I've got this program:
#include <glm/gtc/matrix_transform.hpp>
#include <glm/gtx/string_cast.hpp>
#include <stdio.h>
#include "myglutils.hpp"
int main() {
if (!setupGLFW()) return 1;
setupApple();
GLFWwindow* window = glfwCreateWindow(640, 480, "Perspective", 0, NULL);
if (!window) {
fprintf(stderr, "Failed to create window.\n");
glfwTerminate();
return 0;
}
glfwMakeContextCurrent(window);
if (!setupGLEW()) return 1;
glClearColor(0.2, 0.0, 0.8, 1.0);
const GLfloat vertices[] = {
-1.0, -1.0,
1.0, -1.0,
0.0, 1.0
};
const GLchar* vert_shader =
"#version 410 core\n"
"in vec2 pos;"
"uniform mat4 MVP;"
"void main() {"
" gl_Position = MVP * vec4(pos, 0.0, 1.0);"
"}";
const GLchar* frag_shader =
"#version 410 core\n"
"out vec4 color;"
"void main() {"
" color = vec4(1.0, 0.0, 0.0, 1.0);"
"}";
GLuint shader = getShader(vert_shader, frag_shader);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 6 * sizeof(GLfloat), vertices, GL_STATIC_DRAW);
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
GLuint MVPID = glGetUniformLocation(shader, "MVP");
glm::mat4 perspective = glm::perspective(45.0, 4.0 / 3.0, 0.1, 100.0);
glm::mat4 view = glm::lookAt(glm::vec3(4.0, 3.0, 3.0), glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0, 1.0, 0.0));
glm::mat4 MVP = perspective * view;
while (!glfwWindowShouldClose(window) && glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS) {
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(shader);
glUniformMatrix4fv(MVPID, 1, GL_FALSE, &MVP[0][0]);
glBindVertexArray(vao);
glDrawArrays(GL_TRIANGLES, 0, 6);
glfwSwapBuffers(window);
glfwPollEvents();
}
glDeleteVertexArrays(1, &vao);
glDeleteProgram(shader);
glfwTerminate();
return 0;
}
The functions setupGLFW(), setupApple(), and setupGLEW() aren't the problem. Neither is getShader(). I feel like my error is something silly like forgetting a simple OpenGL function call. What I'm trying to do is draw a triangle at a 3D angle.
Note: this program compiles perfectly, but only displays an empty blue screen.
There are a number of issues in this code. The main one is that you never enable the vertex attribute array. You will need to add a glEnableVertexAttribArray() call in the setup code:
glBindVertexArray(vao);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glEnableVertexAttribArray(0);
Also, the arguments to glDrawArrays() are not correct:
glDrawArrays(GL_TRIANGLES, 0, 6);
The 3rd argument is the number of vertices. Since you only have 3 vertices, it should be:
glDrawArrays(GL_TRIANGLES, 0, 3);
Also, unless this is taken care of in code you did not post, you need to make sure that the attribute location you are using matches the program. You use 0 in the code, but you can't count on the location being zero without any further action. The easiest way to fix this is to use a location layout qualifier in the shader code:
"layout(location=0) in vec2 pos;"
This will set the location to 0, matching your code.
Drawing with a regular VBO on older GLSL versions is not a problem but for whatever reason I get this result when using GLSL 3.3.
It should be drawing a 2x2 plane on each axis.
(Lighter colors are closer to the far plane, darker are closer to the near plane)
One of the major changes with 3.3 was that you have to provide uniforms with your Model View Projection matrixes as opposed to using the old provided ones.
I don't know what I'm doing wrong but I'm almost certain it's something to do with the Model View Projection data. Here is the relevant code.
Main draw method
float r = 0.0f;
void display() {
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glClear(GL_COLOR_BUFFER_BIT); // Clear the color buffer
glClear(GL_DEPTH_BUFFER_BIT); // And the depth buffer
r += 0.001f;
glUseProgram(program);
glEnable(GL_DEPTH_TEST);
GLuint uniformModel = glGetUniformLocation(program, "model");
GLuint uniformView = glGetUniformLocation(program, "view");
GLuint uniformProjection = glGetUniformLocation(program, "projection");
glm::mat4 projection = glm::perspective(70.0f, 1.0f, 0.0f, 16.0f);
glUniformMatrix4fv(uniformProjection, 1, GL_FALSE, glm::value_ptr(projection));
glm::vec3 eye = glm::vec3(sin(r*0.33)*5.0f,5,cos(r*0.33)*5.0f);
glm::vec3 center = glm::vec3(0.0f,0.0f,0.0f);
glm::vec3 up = glm::vec3(0.0f,0.0f,1.0f);
glm::mat4 view = glm::lookAt(eye, center, up);
glUniformMatrix4fv(uniformView, 1, GL_FALSE, glm::value_ptr(view));
glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f,0.0f,0.0f));
glUniformMatrix4fv(uniformModel, 1, GL_FALSE, glm::value_ptr(model));
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(
0,
3,
GL_FLOAT,
GL_FALSE,
0,
(void*)0
);
glDrawElements(GL_TRIANGLES, 18, GL_UNSIGNED_INT, indices);
glDisableVertexAttribArray(0);
glDisable(GL_DEPTH_TEST);
glUseProgram(0);
glFlush(); // Render now
}
Vertex/Indices Array & Shader
string vert
= "#version 330 core\n"
"layout(location = 0) in vec3 vertex;\n"
"uniform mat4 model;\n"
"uniform mat4 view;\n"
"uniform mat4 projection;\n"
"void main(){\n"
" gl_Position = projection * view * model * vec4(vertex,1.0f);\n"
"}";
string frag
= "#version 330 core\n"
"out vec3 color;\n"
"void main()\n"
"{\n"
" float lin = 1.0 / gl_FragCoord.w;\n"
" float depth = (lin - 0.1) / (16.0 - 0.1);\n"
" color = vec3(depth,depth,1.0f);\n"
"}";
float* data = new float[36] {
-1.0f,-1.0f,0.0f,
1.0f,-1.0f,0.0f,
1.0f,1.0f,0.0f,
-1.0f,1.0f,0.0f,
0.0f,-1.0f,-1.0f,
0.0f,1.0f,-1.0f,
0.0f,1.0f,1.0f,
0.0f,-1.0f,1.0f,
-1.0f,0.0f,-1.0f,
1.0f,0.0f,-1.0f,
1.0f,0.0f,1.0f,
-1.0f,0.0f,1.0f
};
GLuint* indices = new GLuint[18] {
0,1,2,
0,3,2,
4,5,6,
4,7,6,
8,9,10,
8,11,10
};
Init
const int winSize = 1024;
void glInit(int argc, char** argv) {
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE);
glutInitContextVersion(3,3);
//glutInitContextFlags(GLUT_CORE_PROFILE | GLUT_DEBUG);
glutInitWindowSize(winSize, winSize);
glutInitWindowPosition(25, 25);
glutCreateWindow("Loading...");
glewExperimental = GL_TRUE;
glewInit();
glViewport (0, 0, winSize, winSize);
camera.setPosition(0.0f,0.0f,4.0f);
glGenVertexArrays(1, &vba);
glBindVertexArray(vba);
program = compileShader(vert, frag);
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 3*4*3*4, data, GL_STATIC_DRAW);
glEnable(GL_DEPTH_TEST);
while(!bExit) {
string pre;
pre.assign("Test Program - ");
pre.append(std::to_string(fps));
glutSetWindowTitle(pre.c_str());
frames++;
display();
}
}
Turns out I'm an idiot and it was just a typo kind of error.
I define GLuint vbo in the init method AND on the scope of the program as well but the actual value of the vbo is only put into local variable. display() didn't have visibility of the vbo at all.
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
It's always the little things that cause ridiculous bugs. <_>
I have been staring at this code for a while now with no luck. I'm working on integrating librocket into my own project (the library isn't that important to the question) and part of that requires writing a renderer class. I've been trying to do just that but can't get the textures to display. The vertex color and position work fine.
I'm using OpenGL3.2.
I've temporarily modified the code to try to draw a single quad. The only parameter being used is the texture parameter, which is just a GLuint cast to another type.
There's a good chance that I'm missing something stupid, but I can't see it. Hopefully another set of eyes will help. Feel free to ask for more code/info.
// Called by Rocket when it wants to render geometry that it does not wish to optimise.
void SDLRenderInterface::RenderGeometry(Rocket::Core::Vertex* vertices, int num_vertices, int* indices, int num_indices, const Rocket::Core::TextureHandle texture, const Rocket::Core::Vector2f& translation)
{
GLuint program;
GLuint vertexBuffer;
GLuint indexBuffer;
GLuint vertexPosLoc = 0;
GLuint vertexColorLoc = 0;
GLuint vertexTexCoordLoc = 0;
GLuint texSamplerLoc = 0;
GLuint translationLoc = 0;
GLuint viewDimLoc = 0;
int offset = 8;
int vertexCount = 4;
float vertexData[] = {-0.5, -0.5, 1.0, 1.0, 1.0, 1.0, 0.0, 0.0,
0.5, -0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 0.0,
0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
-0.5, 0.5, 1.0, 1.0, 1.0, 1.0, 0.0, 1.0};
int indexData[] = {0,1,2,0,2,3};
int indexCount = 6;
// Populate vertex buffer
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(float)*offset*vertexCount,
vertexData, GL_STATIC_DRAW);
// Populate index buffer
glGenBuffers(1, &indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(int) * indexCount,
indexData, GL_STATIC_DRAW);
program = shaderManager->getProgram(2, "rocketTex.vert",
"rocketTex.frag");
glUseProgram(program);
// Set up the texture
texSamplerLoc = glGetUniformLocation(program, "texSampler");
vertexTexCoordLoc = glGetAttribLocation(program, "vertexTexCoord");
if(texSamplerLoc == -1)
{
std::cerr << "Error: cannot find texture location." << std::endl;
return;
}
if(vertexTexCoordLoc == -1)
{
std::cerr << "Error: cannot find texture coord location."
<< std::endl;
return;
}
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, (GLuint) texture);
glUniform1i(texSamplerLoc, 0);
// Set up the per vertex texture coords
glEnableVertexAttribArray(vertexTexCoordLoc);
glVertexAttribPointer(vertexTexCoordLoc, 2, GL_FLOAT, GL_FALSE,
offset * sizeof(float),
(void*) (sizeof(float) * 6));
// Set up uniforms
translationLoc = glGetUniformLocation(program, "translation");
viewDimLoc = glGetUniformLocation(program, "viewDimensions");
if(translationLoc == -1)
{
std::cerr << "Error: cannot find translation location."
<< std::endl;
return;
}
if(viewDimLoc == -1)
{
std::cerr << "Error: cannot find viewDim location."
<< std::endl;
return;
}
glUniform2f(translationLoc, 0,0);
glUniform2f(viewDimLoc, 1,1);
// Set up per-vertex attributes
vertexPosLoc = glGetAttribLocation(program, "vertexPosition");
vertexColorLoc = glGetAttribLocation(program, "vertexColor");
if(vertexPosLoc == -1)
{
std::cerr << "Error: cannot find vertex position location."
<< std::endl;
return;
}
if(vertexColorLoc == -1)
{
std::cerr << "Error: cannot find vertex color location."
<< std::endl;
return;
}
glEnableVertexAttribArray(vertexPosLoc);
glEnableVertexAttribArray(vertexColorLoc);
glVertexAttribPointer(vertexPosLoc, 2, GL_FLOAT, GL_FALSE,
offset * sizeof(float), 0);
glVertexAttribPointer(vertexColorLoc, 4, GL_FLOAT, GL_TRUE,
offset * sizeof(float),
(void*) (sizeof(float) * 2));
// Draw the geometry
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
glDisableVertexAttribArray(vertexPosLoc);
glDisableVertexAttribArray(vertexColorLoc);
glDisableVertexAttribArray(vertexTexCoordLoc);
glDeleteBuffers(1, &vertexBuffer);
glDeleteBuffers(1, &indexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glUseProgram(0);
}
Vertex Shader:
#version 120
uniform vec2 translation;
uniform vec2 viewDimensions;
attribute vec2 vertexPosition;
attribute vec4 vertexColor;
attribute vec2 vertexTexCoord;
varying vec2 texCoord;
varying vec4 fragColor;
void main(void)
{
vec2 ndcPos = ((vertexPosition + translation)/(viewDimensions));
texCoord = vertexTexCoord;
fragColor = vertexColor;
gl_Position = vec4(ndcPos, 0.0, 1.0);
}
Fragment Shader:
#version 120
uniform sampler2D texSampler;
varying vec2 texCoord;
varying vec4 fragColor;
void main(void)
{
vec4 objectColor = texture2D(texSampler, texCoord);
gl_FragColor = vec4((objectColor * fragColor).xyz, 1.0);
}
So, I finally figured it out. jozxyqk's advice for testing the texture coords confirmed my suspicions that the texture coordinates were off (every vertex was getting the same coordinate). The problem ended up being that I was calling glVertexAttribDivisor(attributeLoc, 1) in another part of my code and never setting it back to per vertex, so it was affecting my other shaders. Thinking about the design of OpenGL, it makes sense that this would be necessary.
Glad that's settled!