I am using OpenGL for the first time with GLFW, GLEW, and GLM. I've been more or less following a tutorial but also diverted in order to focus on the aspects I'm interested in at the moment.
Currently, I'm trying to draw pixels to a texture and then display that on the screen as a fullscreen quad. However, the texture is always displaying as black and I'm unsure where I went wrong.
Initializing the texture here (as well as the fullscreen quad):
int InitializeRenderTarget(GameManager* gameManager)
{
// Vertex Array Object
GLuint vertexArrayID;
glGenVertexArrays(1, &vertexArrayID);
glBindVertexArray(vertexArrayID);
programID = LoadShaders("Source/Graphics/SimpleVertexShader.vert", "Source/Graphics/RenderTextureFragmentShader.frag");
// The texture we're going to render to
glGenTextures(1, &renderedTexture);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB,
gameManager->GRID_SIZE, gameManager->GRID_SIZE,
0, GL_RGB, GL_UNSIGNED_BYTE, 0);
glGenerateMipmap(GL_TEXTURE_2D);
// The fullscreen quad's FBO
static const GLfloat g_quad_vertex_buffer_data[] = {
-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, //0.0f, 1.0f,
-1.0f, 1.0f, 0.0f, //0.0f, 1.0f,
1.0f, -1.0f, 0.0f, //1.0f, 0.0f,
1.0f, 1.0f, 0.0f, //1.0f, 1.0f
};
glGenBuffers(1, &quad_vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_quad_vertex_buffer_data), g_quad_vertex_buffer_data, GL_STATIC_DRAW);
texID = glGetUniformLocation(programID, "renderedTexture");
glEnable(GL_TEXTURE_2D);
return 0;
}
Drawing onto the texture here:
void RenderToTexture(GameManager* gameManager)
{
glBindTexture(GL_TEXTURE_2D, renderedTexture);
float* particleColors = gameManager->getParticleColors();
glTexSubImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
gameManager->GRID_SIZE, gameManager->GRID_SIZE,
0, GL_RGB, GL_FLOAT, (GLvoid*)particleColors);
glGenerateMipmap(GL_TEXTURE_2D);
// Poor filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
}
Drawing to screen here:
void RenderToScreen()
{
// Render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Render on the whole framebuffer, complete from the lower left corner to the upper right
glViewport(100, 100, screenWidth-200, screenHeight-200);
// Clear the screen
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, renderedTexture);
// Set our "renderedTexture" sampler to use Texture Unit 0
glUniform1i(texID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, quad_vertexbuffer);
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
);
// Draw the triangles !
glDrawArrays(GL_TRIANGLES, 0, 6); // 2*3 indices starting at 0 -> 2 triangles
glDisableVertexAttribArray(0);
// Swap buffers
glfwSwapBuffers(window);
glfwPollEvents();
}
The main loop:
int main(void)
{
if (InitializeWindow() != 0) {
fprintf(stderr, "Failed to open GLFW window.\n");
getchar();
glfwTerminate();
return -1;
}
GameManager* gameManager = gameManager->getInstance();
if (InitializeRenderTarget(gameManager) != 0) {
fprintf(stderr, "Failed to initialize render target.\n");
getchar();
glfwTerminate();
return -1;
}
do {
gameManager->Update();
RenderToTexture(gameManager);
RenderToScreen();
} // Check if the ESC key was pressed or the window was closed
while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS &&
glfwWindowShouldClose(window) == 0);
CleanUp();
return 0;
}
Vertex shader:
#version 460 core
// Input vertex data, different for all executions of this shader.
layout(location = 0) in vec3 vertexPosition_modelspace;
// Output data ; will be interpolated for each fragment.
out vec2 UV;
void main(){
gl_Position = vec4(vertexPosition_modelspace, 1);
UV = (vertexPosition_modelspace.xy+vec2(1,1))/2.0;
}
and finally fragment shader:
#version 460 core
in vec2 UV;
out vec4 color;
uniform sampler2D renderedTexture;
void main(){
color = texture(renderedTexture, UV);
//color = vec4(UV.x, UV.y, 0, 1);
}
I'm fairly certain that I am drawing the quad to the screen correctly as I used the commented out line in the fragment shader to make a nice colorful gradient effect.
However, I might not be binding the texture correctly.
I confirmed that the particleColors array does contain float values correctly. I've tried setting all the reds to 1.0f, and all the values to 1.0f, as well as all values to 255.0f (just in case).
I tried adding lines like:
glEnable(GL_TEXTURE_2D);
glGenerateMipmap(GL_TEXTURE_2D);
// Poor filtering
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
based on some other posts I saw but I have yet to see any visible effect.
I also tried changing how the vertex and fragment shader were calculating and using the UVs but that only made things worse as the gradient effect wouldn't even appear at that point.
Hopefully you can figure out what I've missed. Thank you for any help.
You're using glTexSubImage2D completely wrong. The 2nd and 3rd arguments are the offsets and the 4th and 5th arguments are the size:
glTexSubImage2D(GL_TEXTURE_2D, 0, GL_RGBA, gameManager->GRID_SIZE, gameManager->GRID_SIZE, 0, GL_RGB, GL_FLOAT, (GLvoid*)particleColors);
glTexSubImage2D(
GL_TEXTURE_2D, 0,
0, 0, gameManager->GRID_SIZE, gameManager->GRID_SIZE,
GL_RGB, GL_FLOAT, (GLvoid*)particleColors);
glEnable(GL_TEXTURE_2D); only has meaning when using the fixed function pipeline and no shader program.
I have figured it out. The correction by Rabbid76, was a big first step.
Afterwards I played some with my pixel array, and after making it smaller found that I did have a small line of pixels at the bottom of my texture. More poking around and I found I had actually filled my pixel data wrong. Fixing my logic in error in my loop filled the texture properly.
Related
Recently I've found the following link about simulating fluids on the GPU. I decided to try to implement it using OpenGL but I got stuck on how to apply successive shaders.
For example, I'd need to apply the advection shader, take its output and apply it into the difuse shader (from the link: "The operator is defined as the composition of operators for advection, diffusion, force application, and projection") but I can't figure out how. I've re-read learn opengl framebuffers tutorial but I'm still lost.
Right now I'm trying to do the following, to test communication between shaders:
1- load texture;
2- apply kernel 1 (inverse shader);
3- apply kernel 2 (advect shader);
Step 1 is done only once, while steps 2 and 3 are done while the windows is open.
Here is the shader code:
/////////////////////////////
// read image - shader.frag
/////////////////////////////
#version 330 core
out vec4 FragColor;
in vec2 uv;
uniform sampler2D texture1;
void main()
{
FragColor = texture(texture1, uv);
}
/////////////////////////////
// color inversion shader
/////////////////////////////
#version 330 core
out vec4 FragColor;
in vec2 uv;
const float offset = 1.0 / 300.0;
void main()
{
FragColor = vec4(vec3(1.0 - texture(screenTexture, uv)), 1.0);
}
/////////////////////////////
// advect shader
/////////////////////////////
#version 330 core
out vec4 FragColor;
in vec2 uv;
uniform float dt;
uniform float sigma_x_inv;
uniform sampler2D u;
uniform sampler2D x;
void main()
{
// change texture2D to texture
vec2 pos = uv - dt * sigma_x_inv * texture(u, uv).xy;
FragColor = texture(x, pos);
}
/////////////////////////////
// vertex shader
/////////////////////////////
#version 330 core
layout (location = 0) in vec3 aPos;
out vec2 uv;
void main()
{
gl_Position = vec4(aPos, 1.0);
uv = aPos.xy;
}
Here is part of my code, mostly taken from here (learn opengl). The screen is just black. If I use one framebuffer(like shown in learn opengl) I can pass data to one shader just fine - I managed to see the inversion and advection shaders working in isolation - but when I add a new frame buffer the screen just goes black. I've also tried using one framebuffer for the two shaders but it didn't work.
Also, how could I pass two textures to one shader? The advection shader, for example, needs to textures, representing two different vector fields. Bellow is my code.
#include "include/glad/glad.h"
#include <GLFW/glfw3.h>
#include "include/shader.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include "include/stb_image.h"
#include <glm/glm.hpp>
#include <chrono>
#include <iostream>
void framebuffer_size_callback(GLFWwindow* window, int width, int height);
void processInput(GLFWwindow *window);
unsigned int loadTexture(char const * path);
// settings
const unsigned int SCR_WIDTH = 800;
const unsigned int SCR_HEIGHT = 600;
unsigned int s_width = SCR_WIDTH;
unsigned int s_height = SCR_HEIGHT;
float sigma_x_inv = 1.0f / SCR_WIDTH;
const float dt = 1/60;
int main()
{
// glfw: initialize and configure
// ------------------------------
glfwInit();
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
#ifdef __APPLE__
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
#endif
// glfw window creation
// --------------------
GLFWwindow* window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "LearnOpenGL", NULL, NULL);
if (window == NULL)
{
std::cout << "Failed to create GLFW window" << std::endl;
glfwTerminate();
return -1;
}
glfwMakeContextCurrent(window);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
// glad: load all OpenGL function pointers
// ---------------------------------------
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress))
{
std::cout << "Failed to initialize GLAD" << std::endl;
return -1;
}
// build and compile our shader program
// ------------------------------------
Shader shader("shaders/shader.vert", "shaders/shader.frag");
Shader advectShader("shaders/shader.vert", "shaders/advect.frag");
Shader inversionShader("shaders/shader.vert", "shaders/inversion.frag");
Shader boundaryShader("shaders/shader.vert", "shaders/boundary.frag");
Shader divergenceShader("shaders/shader.vert", "shaders/divergence.frag");
Shader gradientShader("shaders/shader.vert", "shaders/gradient.frag");
// set up vertex data (and buffer(s)) and configure vertex attributes
// ------------------------------------------------------------------
float planeVertices[] = { // vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
float quadVertices[] =
{
// vertex attributes for a quad that fills the entire screen in Normalized Device Coordinates.
// positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
// plane VAO
unsigned int planeVAO, planeVBO;
glGenVertexArrays(1, &planeVAO);
glGenBuffers(1, &planeVBO);
glBindVertexArray(planeVAO);
glBindBuffer(GL_ARRAY_BUFFER, planeVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), &planeVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
// screen quad VAO
unsigned int quadVAO, quadVBO;
glGenVertexArrays(1, &quadVAO);
glGenBuffers(1, &quadVBO);
glBindVertexArray(quadVAO);
glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), &quadVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void*)(2 * sizeof(float)));
// load and create a texture
// -------------------------
unsigned int texture1, texture2;
// texture 1
// ---------
stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis.
unsigned int blackTexture = loadTexture("textures/black.png");
unsigned int awesomeTexture = loadTexture("textures/awesomeface.png");
shader.use();
shader.setInt("texture1", 0);
// framebuffer configuration
// -------------------------
unsigned int framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// create a color attachment texture
unsigned int textureColorbuffer;
glGenTextures(1, &textureColorbuffer);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_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, textureColorbuffer, 0);
// framebuffer configuration
// -------------------------
unsigned int framebuffer2;
glGenFramebuffers(1, &framebuffer2);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
// create a color attachment texture
unsigned int textureColorbuffer2;
glGenTextures(1, &textureColorbuffer2);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer2);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, SCR_WIDTH, SCR_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, textureColorbuffer2, 0);
// create a renderbuffer object for depth and
// stencil attachment (we won't be sampling these)
unsigned int rbo;
glGenRenderbuffers(1, &rbo);
glBindRenderbuffer(GL_RENDERBUFFER, rbo);
// use a single renderbuffer object for both a depth AND stencil buffer.
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, SCR_WIDTH, SCR_HEIGHT);
// now actually attach it
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
// now that we actually created the framebuffer and added all
// attachments we want to check if it is actually complete now
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "ERROR::FRAMEBUFFER:: Framebuffer is not complete!" << std::endl;
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// tell opengl for each sampler to which texture
// unit it belongs to (only has to be done once)
// -------------------------------------------------------------------------------------------
// advectShader.use(); // don't forget to activate/use the shader before setting uniforms!
// // either set it manually like so:
// advectShader.setInt("u", 0);
// // or set it via the texture class
// advectShader.setInt("x", 1);
divergenceShader.use();
divergenceShader.setFloat("sigma_x_inv", sigma_x_inv);
boundaryShader.use();
boundaryShader.setFloat("scale", 1.0f);
shader.use();
// Program start time
auto start = std::chrono::system_clock::now();
// render
// ------
// bind to framebuffer and draw scene as we normally would to color texture
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glEnable(GL_DEPTH_TEST); // enable depth testing (is disabled for rendering screen-space quad)
glClearColor(0.3f, 0.3f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
shader.use();
glBindVertexArray(planeVAO);
glBindTexture(GL_TEXTURE_2D, awesomeTexture);
glDrawArrays(GL_TRIANGLES, 0, 6);
// render loop
// -----------
while (!glfwWindowShouldClose(window))
{
// input
// -----
processInput(window);
// ----
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer2);
glDisable(GL_DEPTH_TEST);
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
inversionShader.use();
glBindVertexArray(planeVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer2);
glDrawArrays(GL_TRIANGLES, 0, 6);
// test boy
// -----------------------------
// now bind back to default framebuffer and draw a quad plane
// with the attached framebuffer color texture
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDisable(GL_DEPTH_TEST);
// glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
// glClear(GL_COLOR_BUFFER_BIT);
// density step
// -----------------------------
// boundaryShader.use();
// boundaryShader.setFloat("scale", 1.0f);
// boundaryShader.setVec2("offset", 0.5, 0.5);
// pass current time to shader
advectShader.use();
auto now = std::chrono::system_clock::now();
std::chrono::duration<float> diff = now - start;
advectShader.setFloat("dt", diff.count());
advectShader.setFloat("sigma_x_inv", 1000 * 1 / s_width);
glBindVertexArray(quadVAO);
glBindTexture(GL_TEXTURE_2D, textureColorbuffer);
glDrawArrays(GL_TRIANGLES, 0, 6);
// needs to check how to get shader
// velocity step
// -----------------------------
// glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
// -------------------------------------------------------------------------------
glfwSwapBuffers(window);
glfwPollEvents();
}
// optional: de-allocate all resources once they've outlived their purpose:
// ------------------------------------------------------------------------
glDeleteVertexArrays(1, &planeVAO);
glDeleteVertexArrays(1, &quadVAO);
glDeleteBuffers(1, &planeVBO);
glDeleteBuffers(1, &quadVBO);
glDeleteFramebuffers(1, &framebuffer);
// glfw: terminate, clearing all previously allocated GLFW resources.
// ------------------------------------------------------------------
glfwTerminate();
return 0;
}
// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly
// ---------------------------------------------------------------------------------------------------------
void processInput(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 framebuffer_size_callback(GLFWwindow* window, int width, int height)
{
s_width = width;
s_height = height;
// make sure the viewport matches the new window dimensions; note that width and
// height will be significantly larger than specified on retina displays.
glViewport(0, 0, width, height);
}
// utility function for loading a 2D texture from file
// ---------------------------------------------------
unsigned int loadTexture(char const * path)
{
unsigned int textureID;
glGenTextures(1, &textureID);
int width, height, nrComponents;
unsigned char *data = stbi_load(path, &width, &height, &nrComponents, 0);
if (data)
{
GLenum format;
if (nrComponents == 1)
format = GL_RED;
else if (nrComponents == 3)
format = GL_RGB;
else if (nrComponents == 4)
format = GL_RGBA;
glBindTexture(GL_TEXTURE_2D, textureID);
glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, format, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Texture failed to load at path: " << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
I'm trying to work on a texture mapping 2D to a triangle. But currently, I can only get a triangle that has a gradient colour without any texture on it. Which means, my texture function in glsl always return vec4(1,1,1,1) and my textCoords is working. How should I fix it? Any suggestions would be helpful to try!
By the way, have been working on this for 3 days.
in texture class:
constructor:
Texture::Texture(const std::string& fileName){
int width, height, numComponents;
//float* imageData = stbi_loadf(fileName.c_str(), &width, &height, &numComponents, 4);
unsigned char* imageData = stbi_load(fileName.c_str(), &width, &height, &numComponents, 4);
if(imageData == NULL){
cerr << "Texture loading failed for "<<fileName<< endl;
}
glGenTextures(1, &m_texture);
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
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_RGBA8,width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
stbi_image_free(imageData);
}
Texture binding function:
void Texture::Bind(){
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_texture);
}
In my main.cpp:
m_shader.generateProgramObject();
m_shader.attachVertexShader( getAssetFilePath("VertexShader.vs").c_str() );
m_shader.attachFragmentShader( getAssetFilePath("FragmentShader.fs").c_str() );
m_shader.link();
// texture created here
texture = Texture("Assets/bricks.jpg");
// enable vertex attribute indices
glGenVertexArrays(1, &m_vao_triangle);
glBindVertexArray(m_vao_triangle);
// Enable the attribute index location for "position" when rendering.
GLint positionAttribLocation = m_shader.getAttribLocation( "position" );
glEnableVertexAttribArray(positionAttribLocation);
GLint textCoordLocation = m_shader.getAttribLocation( "atextCoord" );
glEnableVertexAttribArray(textCoordLocation);
// Restore defaults
glBindVertexArray(0);
CHECK_GL_ERRORS;
uploade triangle data to buffer
vec3 triangleVertices[] = {
// Construct equalaterial triangle
vec3(0.0f, 0.0f, 0.0f),
vec3(0.25f, 1.0f, 0.0),
vec3(0.5f, 0.0f, 0.0f)
};
vec2 textCoords[] = {
vec2(1.0f, 0.0f),
vec2(0.25f, 1.0f),
vec2(0.5f, 0.0f)};
// Generate a vertex buffer object to hold the triangle's vertex data.
glGenBuffers(1, &m_vbo_triangle);
//-- Upload triangle vertex data to the vertex buffer:
glBindBuffer(GL_ARRAY_BUFFER, m_vbo_triangle);
glBufferData(GL_ARRAY_BUFFER, sizeof(triangleVertices), triangleVertices,
GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, 0);
CHECK_GL_ERRORS;
//====generate buffer for holding texture coordinates====
glGenBuffers(1, &m_uv_triangle);
glBindBuffer(GL_ARRAY_BUFFER, m_uv_triangle);
glBufferData(GL_ARRAY_BUFFER, sizeof(textCoords), textCoords,
GL_STATIC_DRAW);
// Unbind the target GL_ARRAY_BUFFER, now that we are finished using it.
glBindBuffer(GL_ARRAY_BUFFER, 0);
CHECK_GL_ERRORS;
map buffer data to shader
glBindVertexArray(m_vao_triangle);
glBindBuffer(GL_ARRAY_BUFFER, m_vbo_triangle);
GLint positionAttribLocation = m_shader.getAttribLocation( "position" );
glVertexAttribPointer(positionAttribLocation, 3, GL_FLOAT, GL_FALSE, 0, nullptr);
glBindBuffer(GL_ARRAY_BUFFER, m_uv_triangle);
GLint textCoordLocation = m_shader.getAttribLocation( "atextCoord" );
glVertexAttribPointer(textCoordLocation,2, GL_FLOAT, GL_FALSE, 0, nullptr);
//-- Unbind target, and restore default values:
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
CHECK_GL_ERRORS;
upload uniform to shader
m_shader.enable();
...
GLint uniformLocation_diffuse = m_shader.getUniformLocation("diffuse");
glUniform1i(uniformLocation_diffuse, 0);
CHECK_GL_ERRORS;
m_shader.disable();
CHECK_GL_ERRORS;
And in my draw function:
glBindVertexArray(m_vao_triangle);
// below I tried, but didn't work
// glClear(GL_STENCIL_BUFFER_BIT);
// glEnable(GL_BLEND);
// glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
// glEnable(GL_DEPTH_TEST);
texture.Bind();
// do these below:
// glActiveTexture(GL_TEXTURE0);
// glBindTexture(GL_TEXTURE_2D, texture.m_texture);
m_shader.enable();
glDrawArrays(GL_TRIANGLES, 0, 3);
m_shader.disable();
// Restore defaults
glBindVertexArray(0);
CHECK_GL_ERRORS;
Here I will also attach my shaders
vertex shader:
#version 330
in vec3 position;
in vec2 atextCoord;
uniform mat4 transform;
out vec2 textCoord;
void main() {
gl_Position = transform * vec4(position, 1.0);
textCoord = atextCoord;
}
And my fragment shader:
#version 330
uniform sampler2D diffuse;
out vec4 fragColor;
in vec2 textCoord;
void main() {
fragColor = vec4(texture(diffuse, textCoord).rgb,1.0) * vec4(textCoord,0.0,1.0);
// texture(...) shows vec4(1,1,1,1)
// radiant colour can only prove my textCoord is working
// fragColor = texture(diffuse, textCoord); <- only shows a default texture
}
here is the running result
Here is the texture image
I found one way to make it work.
I copy every lines in Texture constructor and paste it to draw(), instead calling texture.Bind().
Looks like I make a texture just before it's ready to draw a geometry and this way is working.
But I still have to know why it happens like that. For coding style, I still have to put my code in Texture class. Would you mind to provide a solution that what happened before?
it looks like this right now
I want to use a 1d texture (color ramp) to texture a simple triangle.
My fragment shader looks like this:
#version 420
uniform sampler1D colorRamp;
in float height;
out vec4 FragColor;
void main()
{
FragColor = texture(colorRamp, height).rgba;
}
My vertex shader looks like this:
#version 420
layout(location = 0) in vec3 position;
out float height;
void main()
{
height = (position.y + 0.75f) / (2 * 0.75f);
gl_Position = vec4( position, 1.0);
}
When drawing the triangle I proceed this way (I removed error checking form code for better readability):
glUseProgram(program_);
GLuint samplerLocation = glGetUniformLocation(program_, name.toCString());
glUniform1i(samplerLocation, currentTextureUnit_);
glActiveTexture( GL_TEXTURE0 + currentTextureUnit_ );
glBindTexture(GL_TEXTURE_1D, textureId);
Unfortunately my triangle is only black. Any ideas how to solve this issue?
I am pretty sure that the assigned texture is filled with proper data since I read it back with glGetTexImage and checked it. Do I need to call other functions to bind and activited the texture? I have almost the same code for 2d textures which is working.
When I change the shader code this way:
#version 420
uniform sampler1D colorRamp;
in float height;
out vec4 FragColor;
void main()
{
FragColor = vec4(height, height, height, 1.0); // change!
}
I get this output:
I prepared some demo source code that reproduces the error. The source can be found here.
It generates the following output:
The 1d texture is created this way - with only red pixels:
static GLuint Create1DTexture()
{
GLuint textureId_;
// generate the specified number of texture objects
glGenTextures(1, &textureId_);
assert(glGetError() == GL_NO_ERROR);
// bind texture
glBindTexture(GL_TEXTURE_1D, textureId_);
assert(glGetError() == GL_NO_ERROR);
// tells OpenGL how the data that is going to be uploaded is aligned
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
assert(glGetError() == GL_NO_ERROR);
float data[] =
{
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f
};
glTexImage1D(
GL_TEXTURE_1D, // Specifies the target texture. Must be GL_TEXTURE_1D or GL_PROXY_TEXTURE_1D.
0, // Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image.
GL_RGBA32F,
3*sizeof(float)*4,
0, // border: This value must be 0.
GL_RGBA,
GL_FLOAT,
data
);
assert(glGetError() == GL_NO_ERROR);
// texture sampling/filtering operation.
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT);
assert(glGetError() == GL_NO_ERROR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT);
assert(glGetError() == GL_NO_ERROR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
assert(glGetError() == GL_NO_ERROR);
glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
assert(glGetError() == GL_NO_ERROR);
glBindTexture(GL_TEXTURE_1D, 0);
assert(glGetError() == GL_NO_ERROR);
return textureId_;
}
Texture binding is done this way:
GLuint samplerLocation = glGetUniformLocation(rc.ToonHandle, "ColorRamp");
glUniform1i(samplerLocation, 0);
glActiveTexture(GL_TEXTURE0 + 0);
glBindTexture(GL_TEXTURE_1D, rc.texure1d);
Found the bug:
glTexImage1D(
GL_TEXTURE_1D, // Specifies the target texture. Must be GL_TEXTURE_1D or GL_PROXY_TEXTURE_1D.
0, // Specifies the level-of-detail number. Level 0 is the base image level. Level n is the nth mipmap reduction image.
GL_RGBA32F,
3/*3*sizeof(float)*4*/, // bug fix!!!!
0, // border: This value must be 0.
GL_RGBA,
GL_FLOAT,
data
);
I am trying to implement the stencil_texturing extension of OpenGL as a proof of concept. My video card supports up to GL 4.3 so stencil_texturing is available to me. If more clarification is necessary here is the spec provided: http://www.opengl.org/registry/specs/ARB/stencil_texturing.txt.
So the goal of my test is to render my color buffer to a texture in frame 0, then the depth buffer in frame 1 and finally the stencil buffer in frame 2. The easy part is done and I have my color and depth buffer textures rendered fine. My issue lies with the stencil buffer and I believe the issue is coming from either my lack of understanding stencil buffers (which could very well be the case) or is my misuse of stencil_texturing. I tried to find some info online but there is very little available.
To give you an idea of what I am rendering here are my current frame captures:
Color buffer, Depth buffer, Stencil buffer
So my vision for the stencil buffer is to just stencil out the middle triangle, so everything in the middle triangle has a value of 1 and every part of the texture has a value of 0. I am not sure how this will come up when rendering but I imagine the areas with a stencil value of 1 will be different than those with 0.
Here is my code below. It is just a test class that I throw into a framework I made for them. I believe the only thing not definied is GLERR() which basically calls glGetError() to make sure everything is correct.
typedef struct
{
GLuint program;
GLuint vshader;
GLuint fshader;
} StencilTexturingState;
class TestStencilTexturing : public TestInfo
{
public:
TestStencilTexturing(TestConfig& config, int argc, char** argv)
:width(config.windowWidth), height(config.windowHeight)
{
state = (StencilTexturingState*) malloc(sizeof(StencilTexturingState));
}
~TestStencilTexturing()
{
destroyTestStencilTexturing();
}
void loadFBOShaders()
{
const char* vshader = "assets/stencil_texturing/fbo_vert.vs";
const char* fshader = "assets/stencil_texturing/fbo_frag.fs";
state->vshader = LoadShader(vshader, GL_VERTEX_SHADER);
GLERR();
state->fshader = LoadShader(fshader, GL_FRAGMENT_SHADER);
GLERR();
state->program = Link(state->vshader, state->fshader, 1, "inPosition");
GLERR();
glUseProgram(state->program);
}
void loadTextureShaders()
{
const char* vshader = "assets/stencil_texturing/tex_vert.vs";
const char* fshader = "assets/stencil_texturing/tex_frag.fs";
state->vshader = LoadShader(vshader, GL_VERTEX_SHADER);
GLERR();
state->fshader = LoadShader(fshader, GL_FRAGMENT_SHADER);
GLERR();
state->program = Link(state->vshader, state->fshader, 1, "inPosition");
GLERR();
glUseProgram(state->program);
}
void destroyTestStencilTexturing()
{
glUseProgram(0);
glDeleteShader(state->vshader);
glDeleteShader(state->fshader);
glDeleteProgram(state->program);
free(state);
}
void RenderToTexture(GLuint renderedTexture, int frame)
{
GLint posId, colId;
GLuint fboId, depth_stencil_rb;
const float vertexFBOPositions[] =
{
-0.7f, -0.7f, 0.5f, 1.0f,
0.7f, -0.7f, 0.5f, 1.0f,
0.6f, 0.7f, 0.5f, 1.0f,
};
const float vertexFBOColors[] =
{
1.0f, 1.0f, 0.0f, 1.0f,
1.0f, 1.0f, 1.0f, 1.0f,
1.0f, 0.0f, 0.0f, 1.0f,
};
// Load shaders for the FBO
loadFBOShaders();
// Setup the FBO
glGenFramebuffers(1, &fboId);
glBindFramebuffer(GL_FRAMEBUFFER, fboId);
glViewport(0, 0, width, height);
// Set up renderbuffer for depth_stencil formats.
glGenRenderbuffers(1, &depth_stencil_rb);
glBindRenderbuffer(GL_RENDERBUFFER, depth_stencil_rb);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, depth_stencil_rb);
// Depending on the frame bind the 2D texture differently.
// Frame 0 - Color, Frame 1 - Depth, Frame 2 - Stencil
glBindTexture(GL_TEXTURE_2D, renderedTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
// Create our RGBA texture to render our color buffer into.
if (frame == 0)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderedTexture, 0);
}
// Create our Depth24_Stencil8 texture to render our depth buffer into.
if (frame == 1)
{
glEnable(GL_DEPTH_TEST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, renderedTexture, 0);
}
// Create our Depth24_Stencil8 texture and change depth_stencil_texture mode
// to render our stencil buffer into.
if (frame == 2)
{
glEnable(GL_DEPTH_TEST | GL_STENCIL_TEST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, width, height, 0, GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, renderedTexture, 0);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_STENCIL_TEXTURE_MODE, GL_STENCIL_INDEX);
}
GLERR();
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE)
{
printf("There is an error with the Framebuffer, fix it!\n");
}
GLERR();
// Give the values of the position and color of our triangle to the shaders.
posId = glGetAttribLocation(state->program, "position");
colId = glGetAttribLocation(state->program, "color");
GLERR();
glVertexAttribPointer(posId, 4, GL_FLOAT, 0, 0, vertexFBOPositions);
glEnableVertexAttribArray(posId);
glVertexAttribPointer(colId, 4, GL_FLOAT, 0, 0, vertexFBOColors);
glEnableVertexAttribArray(colId);
// Clear the depth buffer back to 1.0f to draw our RGB stripes far back.
glClearDepth(1.0f);
glClear(GL_DEPTH_BUFFER_BIT);
if (frame == 2)
{
glStencilFunc(GL_NEVER, 1, 0xFF); // never pass stencil test
glStencilOp(GL_REPLACE, GL_KEEP, GL_KEEP); // replace stencil buffer values to ref=1
glStencilMask(0xFF); // stencil buffer free to write
glClear(GL_STENCIL_BUFFER_BIT); // first clear stencil buffer by writing default stencil value (0) to all of stencil buffer.
glDrawArrays(GL_TRIANGLES, 0, 3); // at stencil shape pixel locations in stencil buffer replace stencil buffer values to ref = 1
// no more modifying of stencil buffer on stencil and depth pass.
glStencilMask(0x00);
// can also be achieved by glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
// stencil test: only pass stencil test at stencilValue == 1 (Assuming depth test would pass.) and write actual content to depth and color buffer only at stencil shape locations.
glStencilFunc(GL_EQUAL, 1, 0xFF);
}
// Use the Scissors to clear the FBO with a RGB stripped pattern.
glEnable(GL_SCISSOR_TEST);
glScissor(width * 0/3, 0, width * 1/3, height);
glClearColor(0.54321f, 0.0f, 0.0f, 0.54321f); // Red
glClear(GL_COLOR_BUFFER_BIT);
glScissor(width * 1/3, 0, width * 2/3, height);
glClearColor(0.0f, 0.65432f, 0.0f, 0.65432f); // Green
glClear(GL_COLOR_BUFFER_BIT);
glScissor(width * 2/3, 0, width * 3/3, height);
glClearColor(0.0f, 0.0f, 0.98765f, 0.98765f); // Blue
glClear(GL_COLOR_BUFFER_BIT);
glDisable(GL_SCISSOR_TEST);
GLERR();
glDrawArrays(GL_TRIANGLES, 0, 3);
glDisable(GL_DEPTH_TEST);
GLERR();
// Remove FBO and shaders and return to original viewport.
glUseProgram(0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glDeleteShader(state->vshader);
glDeleteShader(state->fshader);
glDeleteProgram(state->program);
glDeleteFramebuffers(1, &fboId);
glViewport(0, 0, width, height);
GLERR();
}
void drawFrameTestStencilTexturing(int frame)
{
GLint posLoc, texLoc;
GLuint renderedTexture;
const GLubyte indxBuf[] = {0, 1, 2, 1, 3, 2};
const float positions[] =
{
-0.8f, -0.8f,
-0.8f, 0.8f,
0.8f, -0.8f,
0.8f, 0.8f,
};
const float texCoords[] =
{
0.0f, 0.0f,
0.0f, 1.0f,
1.0f, 0.0f,
1.0f, 1.0f
};
// Allocate and initialize the texture that will be rendered to, and then
// textured onto a quad on the default framebuffer.
glGenTextures(1, &renderedTexture);
// Render to the texture using FBO.
RenderToTexture(renderedTexture, frame);
// Create and load shaders to draw the texture.
loadTextureShaders();
// Draw texture to the window.
glClearColor(0.25f, 0.25f, 0.25f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
posLoc = glGetAttribLocation(state->program, "position");
texLoc = glGetAttribLocation(state->program, "a_texCoords");
glVertexAttribPointer(posLoc, 2, GL_FLOAT, 0, 0, positions);
glEnableVertexAttribArray(posLoc);
glVertexAttribPointer(texLoc, 2, GL_FLOAT, 0, 0, texCoords);
glEnableVertexAttribArray(texLoc);
// Draw our generated texture onto a quad.
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, indxBuf);
glFlush();
glDeleteTextures(1, &renderedTexture);
GLERR();
}
void renderTest(int frame)
{
drawFrameTestStencilTexturing(frame);
}
private:
StencilTexturingState* state;
const int height, width;
};
RUN_TEST(StencilTexturing, "stencil_texturing", 2);
The line
glEnable(GL_DEPTH_TEST | GL_STENCIL_TEST);
is not going to work, the GL enable enums are NOT bit values, but just enums, so you might enable something else, or just get some GL_INVALID_ENUM error, but you don't enable the stencil test here.
I want to do volume rendering using programmable pipeline (using glsl) and no fixed pipelines. I implement it with 2 passes with 2 shader programs, exitPointProg and rayCastProg. the first pass is to get the exit points (i.e. the back face) of a cube bounding box which will be used as a texture in the next pass which doing the raycasting. the idea to do the raycasting volume rendering comes from here. I think I have done the most of the things right cause I have implemented this with fixed pipeline combined with the programmable pipeline. the things that confused me is that I achieved the result with the very first frame, and with a flash the display on the screen turn totally white (I set the glClearColor(1.0f, 1.0f, 1.0f, 1.0f). I think there maybe some wrong with the switch of the shader programs or the FBO. here is what I do in the render() function.
1st pass, render to a fbo with exitPoints texture bound to it to get the exit points of cube bounding box, using shader program exitPointProg.
2ed pass, mapped the exitPoints texture (bound to GL_TEXTURE1) into the shader program rayCastProg as a uniform sampler2D variable which will used in the shader.
here is the setupFBO and render and two subroutines:
the setupFBO() function:
void SimpleRayCasting::setupFBO()
{
GLuint textureHandles[1];
glGenTextures(1, textureHandles);
entryPoints = textureHandles[0];
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, exitPoints);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexImage2D(GL_TEXTURE_2D, 0,GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, NULL);
GLuint depthRenderBuffer;
glGenRenderbuffers(1, &depthRenderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, depthRenderBuffer);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT, width, height);
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
exitPoints, 0/* level */);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER,
depthRenderBuffer);
checkFramebufferState(__FILE__, __LINE__);
GLenum drawbufs[] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, drawbufs);
glBindFramebuffer(GL_FRAMEBUFFER,0);
}
the render() function:
void SimpleRayCasting::render()
{
getExitPoints();
GLUtils::checkForOpenGLError(__FILE__,__LINE__);
rayCasting();
GLUtils::checkForOpenGLError(__FILE__,__LINE__);
}
the getExitPoints() function:
void SimpleRayCasting::getExitPoints()
{
// render to the texture
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
// checkFramebufferState(__FILE__, __LINE__);
glClearColor(0.2f, 0.2f, 0.2f, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
exitPointsProg.use();
// note that the model will recalculated.
model = mat4(1.0f);
model *= glm::rotate(angle , vec3(0.0f,1.0f,0.0f));
model *= glm::rotate(90.0f, vec3(1.0f, 0.0f, 0.0f));
model *= glm::translate(vec3(-0.5f, -0.5f, -0.5f));
view = glm::lookAt(vec3(0.0f,0.0f,2.0f), vec3(0.0f,0.0f,0.0f), vec3(0.0f,1.0f,0.0f));
projection = mat4(1.0f);
projection = glm::perspective(60.0f, (float)width/(float)height,0.01f, 400.0f);
setMatrices(exitPointsProg);
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
drawBoundBox();
glDisable(GL_CULL_FACE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
the rayCasting function:
void SimpleRayCasting::rayCasting()
{
// Directly render to the screen
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glEnable(GL_DEPTH_TEST);
glViewport(0, 0, width, height);
glClearColor(1.0f, 1.0f, 1.0f, 1.0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
rayCastProg.use();
model = mat4(1.0f);
model *= glm::rotate(angle, vec3(0.0f,1.0f,0.0f));
model *= glm::rotate(90.0f, vec3(1.0f, 0.0f, 0.0f));
model *= glm::translate(vec3(-0.5f, -0.5f, -0.5f));
view = glm::lookAt(vec3(0.0f,0.0f,2.0f), vec3(0.0f,0.0f,0.0f), vec3(0.0f,1.0f,0.0f));
projection = mat4(1.0f);
projection = glm::perspective(60.0f, (float)width/(float)height,0.01f, 400.0f);
setMatrices(rayCastProg);
rayCastProg.setUniform("StepSize", stepSize);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, exitPoints);
rayCastProg.setUniform("ExitPoints", 1);
glActiveTexture(GL_TEXTURE4);
glBindTexture(GL_TEXTURE_3D, volume_to);
rayCastProg.setUniform("VolumeTex", 4);
glActiveTexture(GL_TEXTURE5);
glBindTexture(GL_TEXTURE_1D, transferFunc_to);
rayCastProg.setUniform("TransferFunc", 5);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
drawBoundBox();
glDisable(GL_CULL_FACE);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
I am using a class inherited from QGLWidget in Qt. As I have mentioned early, I got the right result with just the 1st frame and quickly it flash away and turn totally white. I don't know what's wrong with this, is there something wrong with the switch of the shader program or the FBO thing? I have been working on this a long time and can't figure it out, any help will be appreciated!
edit to ask
is there any demo or tutorial demonstrate how to use multiple glsl shader programs with FBO?