I'm fairly new to OpenGL and have run into a problem that I can't seem to crack. I'm trying to add a simple 2D texture to a triangle, the texture seems to be loading fine but it's getting displayed grainy and in black and white.
texture
result
Here's my related code:
main.cxx
#include <iostream>
#include "display.h"
#include "shader.h"
#include "texture.h"
#include "mesh.h"
#include <glm/glm.hpp>
#include <GLFW/glfw3.h>
int main()
{
Display display(800, 600, "project2");
Vertex vertices[] = {
Vertex(glm::vec3(-0.5f, -0.5f, 0.0f), glm::vec2(0.0f, 0.0f)),
Vertex(glm::vec3(0.5f, -0.5f, 0.0f), glm::vec2(1.0f, 0.0f)),
Vertex(glm::vec3(0.0f, 0.5f, 0.0f), glm::vec2(0.5f, 1.0f)),
};
Mesh mesh(vertices, sizeof(vertices)/sizeof(vertices[0]));
Shader shader("./shaders/shader");
Texture texture("./textures/container.jpg");
while (!display.IsClosed())
{
display.ProcessInput();
display.Clear(0.0f, 0.15f, 0.3f, 1.0f);
texture.Bind(0);
shader.Bind();
mesh.Draw();
display.Update();
}
return 0;
}
texture.cxx
#include "texture.h"
Texture::Texture(const std::string &filePath)
{
int width, height, numComponents;
unsigned char* imageData = stbi_load(filePath.c_str(), &width, &height, &numComponents, 4);
if (!imageData) {
std::cerr << "Failed to load texture: " << filePath << std::endl;
return;
}
stbi_set_flip_vertically_on_load(true);
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);
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_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData);
glGenerateMipmap(GL_TEXTURE_2D);
stbi_image_free(imageData);
}
Texture::~Texture()
{
glDeleteTextures(1, &texture);
}
void Texture::Bind(unsigned int unit)
{
glActiveTexture(GL_TEXTURE0 + unit);
glBindTexture(GL_TEXTURE_2D, texture);
}
fragment shader
#version 330 core
out vec4 FragColor;
uniform sampler2D diffuse;
in vec2 texCoord0;
void main() {
FragColor = texture(diffuse, texCoord0);
}
vertex shader
#version 330 core
layout (location=0) in vec3 position;
layout (location=1) in vec2 texCoord;
out vec2 texCoord0;
void main() {
gl_Position = vec4(position, 1.0);
texCoord0 = texCoord;
}
I had textures working before in another project and my code looks almost identical, if anyone could help me out that would be much appreciated.
When a RGB image with 3 color channels is loaded to a texture object, then GL_UNPACK_ALIGNMENT has to be set to 1:
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB,
GL_UNSIGNED_BYTE, imageData);
GL_UNPACK_ALIGNMENT specifies the alignment requirements for the start of each pixel row in memory. By default GL_UNPACK_ALIGNMENT is set to 4.
This means the start of each line of the image is assumed to be aligned to an address which is a multiple of 4. Since the image data are tightly packed and each pixel has a size of 3 bytes, the alignment has to be changed.
To proper read the image the last parameter of stbi_load has to be 0 (since the jpg format provides 3 color channesl) or 3 (to force 3 color channels):
unsigned char* imageData = stbi_load(filePath.c_str(),
&width, &height, &numComponents, 0);
stbi_load can be forced to generate an image with 4 color channels, by explicitly pass 4 to the last parameter:
See stb_image.h:
Basic usage (see HDR discussion below for HDR usage):
int x,y,n;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
// ... process data if not NULL ...
// ... x = width, y = height, n = # 8-bit components per pixel ...
// ... replace '0' with '1'..'4' to force that many components per pixel
// ... but 'n' will always be the number that it would have been if you said 0
stbi_image_free(data)
In this case the format parameter has to be changed from GL_RGB to GL_RGBA when loading the image:
unsigned char* imageData = stbi_load(filePath.c_str(),
&width, &height, &numComponents, 0);
// [...]
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGBA,
GL_UNSIGNED_BYTE, imageData);
Related
I'm trying to make a skybox that can change with a button.
My solution for this is to bind my skyboxes and load my textures in the following way:
//SkyBox
GLuint skyboxVBO, skyboxVAO;
glGenVertexArrays(1, &skyboxVAO);
glGenBuffers(1, &skyboxVBO);
glBindVertexArray(skyboxVAO);
glBindBuffer(GL_ARRAY_BUFFER, skyboxVBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(skyboxVertices), &skyboxVertices, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid *)0);
// Load textures
vector<const GLchar*> facesN;
facesN.push_back("SkyBox/night/right.tga");
facesN.push_back("SkyBox/night/left.tga");
facesN.push_back("SkyBox/night/top.tga");
facesN.push_back("SkyBox/night/bottom.tga");
facesN.push_back("SkyBox/night/back.tga");
facesN.push_back("SkyBox/night/front.tga");
GLuint cubemapTextureN = TextureLoading::LoadCubemap(facesN);
vector<const GLchar*> faces;
faces.push_back("SkyBox/day/right.tga");
faces.push_back("SkyBox/day/left.tga");
faces.push_back("SkyBox/day/top.tga");
faces.push_back("SkyBox/day/bottom.tga");
faces.push_back("SkyBox/day/back.tga");
faces.push_back("SkyBox/day/front.tga");
GLuint cubemapTexture = TextureLoading::LoadCubemap(faces);
Then, in the program loop I draw the skybox with the following:
// Draw skybox as last
glDepthFunc(GL_LEQUAL); // Change depth function so depth test passes when values are equal to depth buffer's content
SkyBoxshader.Use();
view = glm::mat4(glm::mat3(camera.GetViewMatrix())); // Remove any translation component of the view matrix
glUniformMatrix4fv(glGetUniformLocation(SkyBoxshader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(SkyBoxshader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
// skybox cube
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE1);
if (daytime == 1.0f) {
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture);
}
else {
glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTextureN);
}
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS); // Set depth function back to default
In theory, whenever I press the button that changes the value of daytime, the skybox should change its textures to cubemapTextureN and, with another press of the button, change back to cubemapTexture. Instead, it just draws the texture that was loaded last, cubemapTexture in this case.
I already tested daytime and it does change, so it's not that.
Also, I tried loading cubemapTextureN after cubemapTexture and by doing so cubemapTextureN gets drawn instead, but still no change. I'm assuming somehow while loading the second textures, the first ones get updated, which shouldn't happen since they have different names, unless i'm understanding it wrong.
Easy solution would be to just make models of the entire skyboxes and work with that, but if possible I want to see if I can use this solution.
Edit:
These are the Shaders for the skybox.
Fragment shader:
#version 330 core
in vec3 TexCoords;
out vec4 color;
uniform samplerCube skybox;
void main()
{
color = texture(skybox, TexCoords);
}
Vertex shader:
#version 330 core
layout (location = 0) in vec3 position;
out vec3 TexCoords;
uniform mat4 projection;
uniform mat4 view;
void main()
{
vec4 pos = projection * view * vec4(position, 1.0);
gl_Position = pos.xyww;
TexCoords = position;
}
And their use:
Shader SkyBoxshader("Shaders/SkyBox.vs", "Shaders/SkyBox.frag");
Also, if this is usefull, this is the header with the definition of TextureLoading, which contains LoadCubemap
#pragma once
// GLEW
#include <GL/glew.h>
// Other Libs
#include "stb_image.h"
// Other includes
#include "Model.h"
#include <vector>
class TextureLoading
{
public:
static GLuint LoadTexture(GLchar *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);
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_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
stbi_image_free(data);
}
else
{
std::cout << "Failed to load texture" << path << std::endl;
stbi_image_free(data);
}
return textureID;
}
static GLuint LoadCubemap(vector<const GLchar * > faces)
{
GLuint textureID;
glGenTextures(1, &textureID);
int width, height, nrChannels;
for (unsigned int i = 0; i < faces.size(); i++)
{
unsigned char *data = stbi_load(faces[i], &width, &height, &nrChannels, 0);
if (data)
{
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
stbi_image_free(data);
}
else
{
std::cout << "Cubemap texture failed to load at path: " << faces[i] << std::endl;
stbi_image_free(data);
}
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
return textureID;
}
};
I am a bloody newbie to OpenGL and it still looks sometimes like black magic to me. I just want to load and display an texture for testing purposes and I do not want to use the tutorial libraries to really understand what happens. But I just get a black screen and I cannot find the reason for it.
My c++ source code
int main(){
new cpp_logger();
GLint program_rgb_;
Mat img = imread("plane.jpg");
std::string file_path = "plane.jpg";
// Set viewport window size and clear color bit.
glClearColor(0, 0, 0, 0);
glClear(GL_COLOR_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
//set viewport
glViewport(0, 0, img.size().width, img.size().height);
// Create a Vertex Buffer Object and copy the vertex data to it
GLuint vbo;
glGenBuffers(1, &vbo);
GLfloat vertices[] = {-1, 1, -1, -1, 1, 1, 1, -1,
0, 0, 0, 1, 1, 0, 1, 1};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
//create program and shader
program_rgb_ = glCreateProgram();
const char* vertexShader = read_shader("vertex.glsl"); //simple method to read the shader files
const char* fragmentShader = read_shader("fragment.glsl");
CreateShader(program_rgb_, GL_VERTEX_SHADER, vertexShader); //simple method to link and compile shader programs
CreateShader(program_rgb_, GL_FRAGMENT_SHADER, fragmentShader);
glLinkProgram(program_rgb_);
glUseProgram(program_rgb_);
//use fast 4-byte alignment (default anyway) if possible because using OpenCV
glPixelStorei(GL_UNPACK_ALIGNMENT, (img.step & 3) ? 1 : 4);
//set length of one complete row in data (doesn't need to equal image.cols)
glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, img.step/img.elemSize());
flip(img, img, 0);
// Load texture
GLuint tex;
glGenTextures(1, &tex);
glBindTexture(GL_TEXTURE_2D, tex);
//set 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);
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_RGB, img.cols, img.rows, 0, GL_RGBA, GL_UNSIGNED_BYTE, img.data);
glUniform1i(glGetUniformLocation(program_rgb_,"tex"), 0);
uint8_t* result = new uint8_t[img.cols * img.rows * 4];
while(true){
GLint pos_location = glGetAttribLocation(program_rgb_, "a_position");
GLint tc_location = glGetAttribLocation(program_rgb_, "a_texCoord");
// Specify the layout of the vertex data
glEnableVertexAttribArray(pos_location);
glVertexAttribPointer(pos_location, 2, GL_FLOAT, GL_FALSE, 0, 0);
//specify color data
glEnableVertexAttribArray(tc_location);
glVertexAttribPointer(tc_location, 2, GL_FLOAT, GL_FALSE, 0, static_cast<float*>(0) + 8);
// Draw a rectangle from the 2 triangles using 6 indices
glDrawArrays(GL_TRIANGLES, 0, 8);
glReadPixels(0, 0, img.rows, img.cols, GL_BGRA_EXT, GL_UNSIGNED_BYTE, (void*)result);
auto result_ = cv::Mat(img.rows, img.cols, CV_8UC4, result);
imshow("img", result_);
if(waitKey(1) >= 0) break;
}
destroyAllWindows();
return EXIT_SUCCESS;
}
My fragment shader
#version 150 core
precision mediump float;
in vec2 texCoord;
uniform sampler2D tex;
void main()
{
gl_FragColor = texture2D(tex, texCoord);
}
my vertex shader
#version 150 core
out vec2 texCoord;
attribute vec2 a_texCoord;
attribute vec4 a_position;
void main()
{
texCoord = a_texCoord;
gl_Position = a_position;
}
Thank you a lot for your help!
EDIT
Sorry for the missunderstanding. I meant: I do not want to use the libraries like SOIL and SFML and I want to go an alternative way to fully understand what actually happens.
I'm trying to implement a skybox and then use the cube map for the skybox to make a reflective sphere in my scene using some code I found editing to fit my project. The skybox shows but the image is almost corrupted looking, there is a basic outline of the mountains but no colour as you can see in the image.
http://i.imgur.com/kJT4aCV.jpg
I've been trying to make sure active texture and my shaders are correct but I just can't figure it out.
Vertex and fragment shader
#version 330 core
layout (location = 0) in vec3 position;
out vec3 TexCoords;
uniform mat4 projection;
uniform mat4 view;
void main()
{
vec4 pos = projection * view * vec4(position, 1.0);
gl_Position = pos.xyww;
TexCoords = position;
}
#version 330 core
in vec3 TexCoords;
out vec4 color;
uniform samplerCube skybox;
void main()
{
color = texture(skybox, TexCoords);
}
Load cubemap
GLuint loadCubemap(std::vector<const GLchar*> faces)
{
GLuint textureID;
glGenTextures(1, &textureID);
int width, height, numComponents;
unsigned char* image;
glBindTexture(GL_TEXTURE_CUBE_MAP, textureID);
for (GLuint i = 0; i < faces.size(); i++)
{
image = stbi_load(faces[i], &width, &height, &numComponents, 4);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image);
stbi_image_free(image);
}
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
glBindTexture(GL_TEXTURE_CUBE_MAP, 0);
return textureID;
}
Drawing skybox
glDepthFunc(GL_LEQUAL);
skyShader.Bind();
skyShader.Update(transform, camera);
view = glm::mat4(glm::mat3(camera.GetViewProjection()));
glUniformMatrix4fv(glGetUniformLocation(skyShader.getProg(), "view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(glGetUniformLocation(skyShader.getProg(), "projection"), 1, GL_FALSE, glm::value_ptr(projection));
glBindVertexArray(skyboxVAO);
glActiveTexture(GL_TEXTURE0);
glUniform1i(glGetUniformLocation(skyShader.getProg(), "skybox"), 0);
glBindTexture(GL_TEXTURE_CUBE_MAP, skyboxTexture);
glDrawArrays(GL_TRIANGLES, 0, 36);
glBindVertexArray(0);
glDepthFunc(GL_LESS);
Let me know if any other parts would be useful to see
The texture was read in, and fed to OpenGL with inconsistent number of components per pixel
image = stbi_load(faces[i], &width, &height, &numComponents, 4); read in the image with 4 components
But when you fed it to OpenGL, glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); you fed it as a texture with 3 components per pixel, causing every 4 bytes to be interpreted as red when it should've been something else
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 seeing a strange issue with a multi pass, multi RT ping-pong render
I am using 3 shaders and an FBO, I get no errors at any stage. I am using opengl 4, so I am not using glBegin/glEnd, I use my own matrices for transformation and i am using vertex buffers for rendering
The general idea of this test is to render 3 different colours to three separate fbo attachments (I realise that it is not efficient rendering the vbo twice in the first pass but this is just to help me understand a problem in some other source) I then bind a separate set of textures to the fbo and use the first set as the samplers. The final pass is to blend the results into the back buffer
What is odd is that the output is both quads appear red, when the first should be red and the second green (as these values come from the second shader).
If i change the function SamplePix in the second shader to always take from the second sampler both appear green, and if lookups up from the third then all appears yellow, but it seems to only read from one.
For now I can't seem to explain why I can read from each sampler ok but the loop doesn't seem to lookup correctly (in shader 2)
Also if I switch to rendering the texture sampled in shader 2 i see a black quad in the second pass (image 2)
Hopefully someone can throw some light on the problem. (I have also tried adding a sync fence object after the first pass but this didn't make a difference)
Texture Sample:
// initial setup of shaders and vertex buffers ommitted for now (in separate source files)
// fbo setup like so
const int DepthLayers = 3;
bool InitFBO()
{
// width and height 768pixels
for (int j=0; j<DepthLayers; j++)
{
const int idx = j + (DepthLayers*i);
glGenTextures(1, &g_FBOManager.m_fboTex[ idx ]);
glBindTexture(GL_TEXTURE_2D, g_FBOManager.m_fboTex[ idx ]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//no mipmaps
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, g_XMLSettings->WWidth(), g_XMLSettings->WHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
//depth
glGenTextures(1, &g_FBOManager.m_fboDepthTex[ idx ]);
glBindTexture(GL_TEXTURE_2D, g_FBOManager.m_fboDepthTex[ idx ]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
//no mipmaps
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_DEPTH_TEXTURE_MODE, GL_INTENSITY);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE/* GL_COMPARE_R_TO_TEXTURE*/);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexImage2D( GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT32, g_XMLSettings->WWidth(), g_XMLSettings->WHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glBindTexture(GL_TEXTURE_2D, g_FBOManager.m_fboDepthTex[idx]);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, g_FBOManager.m_fboDepthTex[idx], 0);
glBindTexture(GL_TEXTURE_2D, g_FBOManager.m_fboTex[idx]);
// attach a texture to FBO color attachment point
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, g_FBOManager.m_fboTex[idx], 0);
// check FBO status
pglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, g_FBOManager.FboId(i) );
if(!CheckFramebufferStatus())
{
return false;
}
}
BindFrameBuffer(-1); // unbind fbo
if (GLGETERROR("1", fileBuf, lineBuf)) ; // check for glErrors
return true; // all ok
}
// code to init second set of textures before the render loop
const int w = g_XMLSettings->WWidth(); //res: 768 square
const int h = g_XMLSettings->WHeight();
glGenTextures(bufCount, &ttex[0]);
for (int i=0; i<bufCount; ++i)
{
glBindTexture(GL_TEXTURE_2D, ttex[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
}
const int bufCount = 3;
void EnableTexture1()
{
glActiveTextureARB(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, g_BackTexture);
glUniform1iARB(g_pPassAShader->m_clr_idx, 0);
}
void RenderLoop()
{
GLenum buffers[] = { GL_COLOR_ATTACHMENT0_EXT, GL_COLOR_ATTACHMENT1_EXT, GL_COLOR_ATTACHMENT2_EXT };
glColor4f(0.0f, 0.0f, 0.0f, 0.0f);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
glUseProgramObjectARB(g_pPassAShader->m_glContext);
EnableTexture1();
//... code omitted to set transform matrix and supply to shader
if (!BindFrameBuffer(0))
assert(0);
const GLuint DTex = g_FBOManager.GetDepthTexture(0);
glBindTexture(GL_TEXTURE_2D, DTex);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT,GL_TEXTURE_2D, DTex, 0);
for (UINT i=0; i<bufCount; ++i)
{
glBindTexture(GL_TEXTURE_2D, g_FBOManager.GetTexture(i));
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, g_FBOManager.GetTexture(i), 0);
if (!CheckFramebufferStatus())
assert(0);
}
glDrawBuffers(bufCount,buffers);
// this is very important! if we don't clear it won't get written to
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glDisable(GL_BLEND);
EnableTexture1();
RenderVertexCache(0);
//... code omitted to set transform matrix and supply to shader
// render the second quad to other FBO tex
RenderVertexCache(0);
DisableShader(0);
BindFrameBuffer(-1); // unbinds fbo
//pass 2
if (!BindFrameBuffer(0))
assert(0);
// bind other set of textures to the fbo
for (UINT i=0; i<bufCount; ++i)
{
glBindTexture(GL_TEXTURE_2D,ttex[i]);
pglFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + i, GL_TEXTURE_2D, ttex[i], 0);
if (!CheckFramebufferStatus())
assert(0);
}
glDrawBuffers(bufCount,buffers);
// this is very important! if we don't clear it won't get written to
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
// bind our set from prev pass to the samplers as input
glUseProgramObjectARB(g_pPassBShader->m_glContext);
for (UINT i=0; i<bufCount; ++i)
{
glActiveTextureARB(GL_TEXTURE0+i);
glBindTexture(GL_TEXTURE_2D,g_FBOManager.GetTexture(i));
glUniform1iARB(g_pPassBShader->m_intex_idx[i], i);
}
VertexBufferManager2::RenderUsingOrthoEx(g_pPassBShader); // renders a full screen quad
DisableShader(0);
BindFrameBuffer(-1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// pass 3
glUseProgramObjectARB(g_pPassCShader->m_glContext);
for (UINT i=0; i<bufCount; ++i)
{
glActiveTextureARB(GL_TEXTURE0+i);
glBindTexture(GL_TEXTURE_2D, ttex[i]);
glUniform1iARB(g_pPassCShader->m_intex_idx[i], i);
}
VertexBufferManager2::RenderUsingOrthoEx(g_pPassCShader);
if (GLGETERROR("at1", fileBuf, lineBuf)) ; // reports any glErrors
}
// the three shaders (fragment shaders only)
// vertex shaders transfer uv's and transform vertices (version set to 410 in all)
// shader for pass1
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#version 410
uniform sampler2D g_ClrMap;
in vec2 g_InterpUV; // supplied by vshader
out vec4 g_FBOLayers[ 3 ];
void main(void)
{
vec4 tex = texture(g_ClrMap, g_InterpUV); // if we set fbo from texture only first texture renders
g_FBOLayers[0] = vec4(1,0,0,.5);
g_FBOLayers[1] = vec4(0,1,0,1);
g_FBOLayers[2] = vec4(1,1,0,1);
}
// shader pass 2
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#version 410
uniform sampler2D g_inLayers0;
uniform sampler2D g_inLayers1;
uniform sampler2D g_inLayers2;
in vec2 g_InterpUV ;
out vec4 g_FBOLayers[ 3 ];
vec2 fTextureSize;
vec4 SamplePix(in int buf, in vec2 tCoords, in float lod)
{
if (buf==1)
return textureLod(g_inLayers1, tCoords, lod);
else if (buf==2)
return textureLod(g_inLayers2, tCoords, lod);
return textureLod(g_inLayers0, tCoords, lod);
}
void main(void)
{
ivec2 iCoords = ivec2(int(gl_FragCoord.x),int(gl_FragCoord.y));
ivec2 iTextureSize = textureSize(g_inLayers0,0);
fTextureSize = vec2(float(iTextureSize.x), float(iTextureSize.y));
vec2 coords = vec2(gl_FragCoord.x/iTextureSize.x,gl_FragCoord.y/iTextureSize.y);
for(int i=0; i<3; ++i)
{
g_FBOLayers[i] = vec4(0.,0.,0.,0.);
}
int j = 0;
for(; j < 2; ++j)
{
g_FBOLayers[j] = SamplePix(j,coords,0);
}
}
// shader pass 3
//--------------------------------------------------------------------------------------------
//--------------------------------------------------------------------------------------------
#version 410
uniform sampler2D g_inLayers0;
uniform sampler2D g_inLayers1;
uniform sampler2D g_inLayers2;
in vec2 g_InterpUV ;
out vec4 g_PixColour;
vec4 tFetch(in int buf, in ivec2 tCoords, in int lod)
{
if (buf==1)
return texelFetch(g_inLayers1, tCoords, lod);
if (buf==2)
return texelFetch(g_inLayers2, tCoords, lod);
return texelFetch(g_inLayers0, tCoords, lod);
}
void main(void)
{
ivec2 iCoords = ivec2(int(gl_FragCoord.x),int(gl_FragCoord.y));
ivec2 iTextureSize = textureSize(g_inLayers0,0);
vec2 coords = vec2(gl_FragCoord.x/iTextureSize.x,gl_FragCoord.y/iTextureSize.y);
vec4 colour = vec4(0.,0.,0.,0.);
int i = 0;
for(; i <2; ++i) // 3rd texture omitted for now
{
vec4 texel = tFetch(i,iCoords,0);
if(texel.a + colour.a <= 1.0)
{
colour.rgb += (texel.rgb*texel.a);
colour.a += texel.a;
}
else
{
texel.a -= (texel.a + colour.a) - 1.0;
colour.rgb += (texel.rgb*texel.a);
colour.a += texel.a;
break;
}
}
g_PixColour = colour;
}