Why is this OpenGL code using texelFetch not working? - c++

I've written this code to render a 2d map of square tiles:
#define TILE_NUM_INDICES 6
inline static u32 GetRandomIntBetween(u32 min, u32 max) {
return (u32)rand() % (max - min + 1) + min;
}
static void GetRandomTileMap(u32* map, u32 size) {
for (int i = 0; i < size; i++) {
u32 r = GetRandomIntBetween(0, 23);
map[i] = r;
}
}
NewRenderer::NewRenderer(const NewRendererInitialisationInfo& info)
:m_tileShader("shaders\\TilemapVert2.glsl", "shaders\\TilemapFrag2.glsl"),
m_worldMapSize(info.tilemapSizeX, info.tilemapSizeY),
m_tilemapChunkSize(info.chunkSizeX, info.chunkSizeY),
m_windowWidth(info.windowWidth),
m_windowHeight(info.windowHeight)
{
using namespace std;
const u32 mapsize = info.tilemapSizeX * info.tilemapSizeY;
m_worldTextureBytes = make_unique<u32[]>(mapsize);
GetRandomTileMap(m_worldTextureBytes.get(), mapsize);
glGenTextures(1, &m_worldTextureHandle);
glBindTexture(GL_TEXTURE_2D, m_worldTextureHandle);
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_NEAREST); // GL_NEAREST is the better filtering option for this game
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, info.tilemapSizeX, info.tilemapSizeY, 0, GL_RED, GL_UNSIGNED_INT, m_worldTextureBytes.get());
glGenerateMipmap(GL_TEXTURE_2D);
glGenVertexArrays(1, &m_vao);
}
void NewRenderer::DrawChunk(
const glm::ivec2& chunkWorldMapOffset,
const glm::vec2& pos,
const glm::vec2& scale,
float rotation,
ArrayTexture2DHandle texArray,
const Camera2D& cam
) const
{
m_tileShader.use();
glm::mat4 model = glm::mat4(1.0f);
model = glm::translate(model, glm::vec3(pos, 0.0f));
model = glm::rotate(model, glm::radians(rotation), glm::vec3(0.0f, 0.0f, 1.0f));
model = glm::scale(model, glm::vec3(scale, 1.0f));
m_tileShader.setMat4("vpMatrix", cam.GetProjectionMatrix(m_windowWidth, m_windowHeight));
m_tileShader.setMat4("modelMatrix", model);
m_tileShader.SetIVec2("chunkOffset", chunkWorldMapOffset);
m_tileShader.SetIVec2("chunkSize", m_tilemapChunkSize);
m_tileShader.setInt("masterTileTexture", 0);
m_tileShader.setInt("atlasSampler", 1);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_worldTextureHandle);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D_ARRAY, texArray);
glBindVertexArray(m_vao);
glDrawArrays(GL_TRIANGLES, 0, m_tilemapChunkSize.x * m_tilemapChunkSize.y * TILE_NUM_INDICES);
}
(Vertex shader)
#version 440 core
/*
cpp setup:
create a big index buffer
*/
layout (location = 0) in vec2 pos;
layout (location = 1) in vec2 uv;
out vec3 TexCoords;
uniform mat4 vpMatrix;
uniform mat4 modelMatrix;
uniform ivec2 chunkOffset;
uniform ivec2 chunkSize;
uniform sampler2D masterTileTexture;
#define TILE_NUM_VERTS 4
#define NUM_TILE_INDICES 6
void main()
{
// vertices and indices that make up two triangles (a quad)
// ie one tile in the map
vec4 vertices[TILE_NUM_VERTS] = vec4[TILE_NUM_VERTS](
vec4(0.5f, 0.5f, 1.0f, 1.0f),
vec4(0.5f, -0.5f, 1.0f, 0.0f),
vec4(-0.5f, -0.5f, 0.0f, 0.0f),
vec4(-0.5f, 0.5f, 0.0f, 1.0f)
);
int indices[NUM_TILE_INDICES] = int[NUM_TILE_INDICES](
0, 1, 3, // first triangle
1, 2, 3 // second triangle
);
// cycle through indicies
int index = indices[int(gl_VertexID % NUM_TILE_INDICES)];
// get base vertex
vec4 baseVertex = vertices[index];
// which tile in the map is being drawn?
int whichTile = gl_VertexID / NUM_TILE_INDICES;
// transfrom into x y coords of tile in the chunk
ivec2 tilexy = ivec2(int(whichTile / chunkSize.y), int(whichTile % chunkSize.y));
// translate base vertex by tilexy
baseVertex.xy += vec2(tilexy);
// set the z coord of the tex coords passed based on what tile is here
// in the master tile map.
// based on shader output all steps up to here are successful, a grid is drawn.
// The problem is the texelFetch is not working, it's always the same tile drawn.
TexCoords = vec3(
baseVertex.zw,
// changing this to different hard coded values does change what tile is drawn as expectd so sampler2DArray is setup correctly
float(texelFetch(masterTileTexture, tilexy + chunkOffset, 0).r));
gl_Position = vpMatrix * modelMatrix * vec4(baseVertex.xy, 0.0, 1.0);
}
(Frag shader)
#version 440 core
uniform sampler2DArray atlasSampler;
in vec3 TexCoords;
out vec4 FragColor;
void main()
{
FragColor = texture(atlasSampler, TexCoords);
}
The idea is that it will be used to draw chunks of a large texture, each pixel of which represents a tile. The basic premise seems to work, a grid of tiles is drawn, however the texelFetch line in the vertex shader does not seem to be working, or the texture containing the tile indices is not set up properly as it is only ever the tile with index 0 that is drawn.
To test it I've tried to make a texture which contains random values for the tile index texture, debugging the code I can see that random values are inserted into the texture buffer.
I've used texelFetch before in a shader and it's worked and as far as I can tell I am using it right.
Can anyone spot what is wrong with my code?

glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, info.tilemapSizeX, info.tilemapSizeY, 0, GL_RED, GL_UNSIGNED_INT, m_worldTextureBytes.get());
This creates a texture in a normalized fixed-point format. When you read it in the shader (through texelFetch) the value is always going to be between 0 and 1, thus sampling the 0th layer from the array texture.
OpenGL 4.4 supports integer texture formats, which is what you should use here. Replace the first GL_RED with GL_R8UI, GL_16UI or GL_R32UI, whichever is more appropriate, and the second GL_RED with GL_RED_INTEGER. E.g.:
glTexImage2D(GL_TEXTURE_2D, 0, GL_R32UI, //<---
info.tilemapSizeX, info.tilemapSizeY, 0, GL_RED_INTEGER, //<---
GL_UNSIGNED_INT, m_worldTextureBytes.get());
Additionally you have to change the sampler2D in the shader to a matching integer sampler type. For the above internal format, the matching sampler would be usampler2D:
uniform usampler2D masterTileTexture;
EDIT: Also you have to set the MAG filter to GL_NEAREST, since it's the only one that's supported:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
(MIN filter could also be GL_NEAREST_MIPMAP_NEAREST.)

Related

SSAO | Edges of the screen darken when close to a surface

I am having a problem with my SSAO implementation. Whenever I get close to a surface the edges of the screen appear to darken and this causes a large performance drop.
It has come to my knowledge that the darkening might be happening on the noise texture. But I have tried changing the positions texture to GL_REPEAT, GL_CLAMP_TO_EDGE and it still doesnt reduce the problem.
Any ideas? Here is the code..
gPosition Setup
// The attachment is added in as follows
new FboAttachment(width, height, GL_RGB16F, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0, false, true)
// attachment is created like this
// This function will create an fbo attachment
inline void Create()
{
// Generate a texture and sets its data and information
glGenTextures(1, &_texture); // Generate the colour texture
glBindTexture(GL_TEXTURE_2D, _texture); // Bind the texture map
glTexImage2D(GL_TEXTURE_2D, 0, _internal_format, _width, _height, 0, _format, _type, 0); // Store the texture data to a buffer
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // Set the linear filter for min
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, _mipmapping == true ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR); // Set the linear filter for mag
/*
* If border clamping is enabled then set the border colour (mainly used for shadow mapping to remove peter panning)
*/
if (_border_clamping)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
GLfloat border[4] = { 1,0,0,0 };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border);
}
/*
* If mipmapping enabled then generate mipmaps for this FBO texture.
*/
if (_mipmapping)
{
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); // set the minimum texture mip level
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 4); // set the maximum texture mip level
glGenerateMipmap(GL_TEXTURE_2D); // generate a mipmap for the shadowmap
}
// Send this generated texture to the framebufferobject
glFramebufferTexture2D(GL_FRAMEBUFFER, _attachment, GL_TEXTURE_2D, _texture, 0); // Assign the texture to the frame buffer as an attachment
// Check for any problems with the frame buffer object
if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
std::cout << "Error : FBO Could not be created!" << std::endl;
}
SSAO Setup
// Initialise the post effect
inline void Create(std::vector<GLuint> shader_programs, size_t width, size_t height, GLuint sample_res)
{
_shader_programs = shader_programs; // Assign shader pointers
_sample_res = sample_res; // Assign sample resolution value
_rect = new Rect((double)width, (double)height, 1.0f, true);
// Create two frame buffers, one for ssao colour and another for ssao blur
_fbos.push_back(new Fbo(width, height, { new FboAttachment(width, height, GL_RED, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0) }, false));
_fbos.push_back(new Fbo(width, height, { new FboAttachment(width, height, GL_RED, GL_RGB, GL_FLOAT, GL_COLOR_ATTACHMENT0) }, false));
//////////////////////////////////////////////////////////////////////////////////////////////////////////
std::uniform_real_distribution<GLfloat> rand_floats(0.0f, 1.0f); // Generate random floats between 0.0 and 1.0
std::default_random_engine rand_generator; // A generator for randomising floats
// Create temp iterator var
for (unsigned int i = 0; i < 64; ++i) // Iterate through each sample...
{
glm::vec3 sample(rand_floats(rand_generator) * 2.0f - 1.0f,
rand_floats(rand_generator) * 2.0f - 1.0f,
rand_floats(rand_generator)); // the third parameter was wrong on this line
sample = glm::normalize(sample); // Normalise the sample
sample *= rand_floats(rand_generator); // Seed the randomisation
float scale = (float)i / 64.0f; // Get pixel position in NDC about the resolution size
scale = Math::lerpf(0.1f, 1.0f, scale * scale); // Interpolate the scale
sample *= scale; // Scale the s and t values
_ssao_kernals.push_back(sample); // Assign sample to the kernal array
_u_samples.push_back(glGetUniformLocation(shader_programs[0], ("samples[" + std::to_string(i) + "]").c_str())); // Get each sample uniform location
}
// generate noise texture
for (unsigned int i = 0; i < 16; i++)
{
glm::vec3 noise(rand_floats(rand_generator) * 2.0 - 1.0, rand_floats(rand_generator) * 2.0 - 1.0, 0.0f); // rotate around z-axis (in tangent space)
ssaoNoise.push_back(noise);
}
glGenTextures(1, &noiseTexture);
glBindTexture(GL_TEXTURE_2D, noiseTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB32F, 4, 4, 0, GL_RGB, GL_FLOAT, &ssaoNoise[0]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glUseProgram(_shader_programs[0]); // Use the first shader pass
glUniform1i(glGetUniformLocation(shader_programs[0], "gPosition"), 0); // The positions texture in the gbuffer
glUniform1i(glGetUniformLocation(shader_programs[0], "gNormal"), 1); // The normals texture in the gbuffer
glUniform1i(glGetUniformLocation(shader_programs[0], "texNoise"), 2); // The albedospec texture in the gbuffer
_u_projection = glGetUniformLocation(shader_programs[0], "proj"); // Get projection uniform
glUseProgram(_shader_programs[1]); // Use the second shader pass
glUniform1i(glGetUniformLocation(shader_programs[1], "ssaoInput"), 0); // the positions texture in the gbuffer
}
SSAO Binding
inline virtual void Render()
{
_fbos[0]->Bind(); // bind ssao texture
glClear(GL_COLOR_BUFFER_BIT); // clear colour data on the screen
glUseProgram(_shader_programs[0]); // Use the first shader pass
for (unsigned int i = 0; i < SSAO_SAMPLE_RESOLUTION; ++i) // For each ssao sample...
glUniform3fv(_u_samples[i], 1, glm::value_ptr(_ssao_kernals[i])); // Assign kernal uniform data
glUniformMatrix4fv(_u_projection, 1, GL_FALSE, glm::value_ptr(Content::_map->GetCamera()->GetProjectionMatrix())); // Assign camera projection uniform data
glActiveTexture(GL_TEXTURE0); // Set active texture to index 0
glBindTexture(GL_TEXTURE_2D, _g_buffer_data->GetAttachments()[0]->_texture); // Bind positions
glActiveTexture(GL_TEXTURE1); // Set active texture to index 1
glBindTexture(GL_TEXTURE_2D, _g_buffer_data->GetAttachments()[1]->_texture); // Bind normals
glActiveTexture(GL_TEXTURE2); // Set active texture to index 2
glBindTexture(GL_TEXTURE_2D, noiseTexture); // Bind the noise texture
_screen_rect->Render(1); // Render to screen rectangle
_fbos[0]->Unbind();
// Blur ssao texture
_fbos[1]->Bind();
glClear(GL_COLOR_BUFFER_BIT);
glUseProgram(_shader_programs[1]); // Use the second shader pass
glActiveTexture(GL_TEXTURE0); // Bind active texture to index 0
glBindTexture(GL_TEXTURE_2D, _fbos[0]->GetAttachments()[0]->_texture); // Bind the final colour
_screen_rect->Render(1); // Render to screen rectangle
_fbos[1]->Unbind();
}
SSAO Fragment Shader
#version 330 core
out float FragColor;
in vec2 _texcoord;
uniform sampler2D gPosition;
uniform sampler2D gNormal;
uniform sampler2D texNoise;
uniform vec3 samples[64];
int kernelSize = 64;
float radius = 0.5;
float bias = 0.025;
const vec2 noiseScale = vec2(1920.0 / 4.0, 1080.0 / 4.0);
uniform mat4 proj;
void main()
{
vec3 fragPos = texture(gPosition, _texcoord).xyz;
vec3 normal = normalize(texture(gNormal, _texcoord).rgb);
vec3 randomVec = normalize(texture(texNoise, _texcoord * noiseScale).xyz);
vec3 tangent = normalize(randomVec - normal * dot(randomVec, normal));
vec3 bitangent = cross(normal, tangent);
mat3 TBN = mat3(tangent, bitangent, normal);
float occlusion = 0.0;
for(int i = 0; i < kernelSize; ++i)
{
// get sample position
vec3 sample = TBN * samples[i]; // from tangent to view-space
sample = fragPos + sample * radius;
// project sample position (to sample texture) (to get position on screen/texture)
vec4 offset = vec4(sample, 1.0);
offset = proj * offset; // from view to clip-space
offset.xyz /= offset.w; // perspective divide
offset.xyz = offset.xyz * 0.5 + 0.5; // transform to range 0.0 - 1.0
// get sample depth
float sampleDepth = texture(gPosition, offset.xy).z; // get depth value of kernel sample
// range check & accumulate
float rangeCheck = smoothstep(0.0, 1.0, radius / abs(fragPos.z - sampleDepth));
occlusion += (sampleDepth >= sample.z + bias ? 1.0 : 0.0) * rangeCheck;
}
occlusion = 1.0 - (occlusion / kernelSize);
FragColor = pow(occlusion, 5.0);
}
What could be the reason of this problem?
Problem Fixed
GL_CLAMP_TO_EDGE fixed it

passing a float array as a 3D Texture to GLSL fragment shader

I'm trying to implement ray casting based volume rendering and therefore I'd need to pass a float Array to the fragment shader as a Texture (Sampler3D).
I've got a volume datastructure containing all the voxels. Each voxel contains a density value. So for processing I stored the values into a float Array.
//initialize glew, initialize glfw, create window, etc.
float* density;
density = new float[volume->size()];
for (int i = 0; i < volume->size(); i++){
density[i] = volume->voxel(i).getValue();
}
Then I tried creating and binding the textures.
glGenTextures(1, &textureHandle);
glBindTexture(GL_TEXTURE_3D, textureHandle);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R, GL_REPEAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE, volume->width(),
volume->height(), volume->depth(), 0, GL_LUMINANCE, GL_FLOAT, density);
In my render loop I try to load the Texture to the uniform Sampler3D.
glClearColor(0.4f, 0.2f, 0.3f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glActiveTexture(GL_TEXTURE0);
GLint gSampler = glGetUniformLocation(shader->shaderProgram, "volume");
glUniform1i(gSampler, 0);
cube->draw();
So the basic idea is to calculate the current position and direction for ray casting in the Vertex Shader.
in vec3 position;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
uniform vec4 cameraPos;
out vec3 pos;
out vec3 dir;
void main(){
gl_Position = projection * view * model * vec4(position, 1.0);
pos = position;
dir = pos - (inverse(model) * cameraPos).xyz;
}
That seems to work well, so far so good. The fragment shader looks like this. I take some samples along the ray and the one with the largest density value will be taken as a color for red, green and blue.
#version 330 core
in vec3 pos;
in vec3 dir;
uniform sampler3D volume;
out vec4 color;
const float stepSize = 0.008;
const float iterations = 1000;
void main(){
vec3 rayDir = normalize(dir);
vec3 rayPos = pos;
float src;
float dst = 0;
float density = 0;
for(int i = 0; i < iterations; i++){
src = texture(volume, rayPos).r;
if(src > density){
density = src;
}
rayPos += rayDir * stepSize;
//check whether rays are within bounds. if not -> break.
}
color = vec4(density, density, density, 1.0f);
}
Now I've tried inserting some small debug assertions.
if(src != 0){
rayPos = vec3(1.0f);
break;
}
But src seems to be 0 at every iteration of every pixel. Which gets me to the conclusion that the Sampler isn't correctly set. Debugging the C++ code I get the correct values for the density array right before I pass it to the shader, so I guess there must be some opengl function missing. Thanks in advance!
glTexImage3D(GL_TEXTURE_3D, 0, GL_LUMINANCE, volume->width(), volume->height(), volume->depth(), 0, GL_LUMINANCE, GL_FLOAT, density);
Unless this density is on the range [0, 1], then this is almost certainly not doing what you intend.
GL_LUMINANCE, when used as an internal format (the third parameter to glTexImage3D, means that each pixel in OpenGL's texture data will contain a single normal integer value. So if you want a floating-point value, you're kinda out of luck.
The proper way to do this is to explicitly declare the type and pixel size of the data. Luminance was removed from the core OpenGL profile back in 3.1, so the way to do that today is to use GL_R32F as your internal format. That declares that each pixel contains one value, and that value is a 32-bit float.
If you really need to broadcast the value across the RGB channels, you can use texture swizzling to accomplish that. You can set a swizzle mask to broadcast the red component to any other channel you like.
glActiveTexture(GL_TEXTURE0);
GLint gSampler = glGetUniformLocation(shader->shaderProgram, "volume");
glUniform1i(gSampler, 0);
I've heard that binding the texture is also a good idea. You know, if you actually want to read from it ;)

Shadow Map: whole mesh is in shadow, there is no light where it should be according to depth map

First time trying to implement shadow map using openGL ang glsl shader language.
I think the first pass where I render to a texture is correct but when I compare the depth values it seems to shadow everything.
https://www.dropbox.com/s/myxenx9y41yz2fc/Screenshot%202014-12-09%2012.18.53.png?dl=0
My perspective projection matrix looks like this:
FOV = 90
Aspect = According to the programs window size. (I also tried to put different values here)
Near = 2;
Far= 10000;
Function to initialize the frame buffer
void OpenGLWin::initDepthMap()
{
//Framebuffer
m_glFunctions->glGenFramebuffers(1, &m_frameBuffer);
m_glFunctions->glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);
//////////////////////////////////////////////////////////////////////////
//Texture to render scene to
m_glFunctions->glGenTextures(1, &m_renderToTexture);
//Bind created texture to make it current
m_glFunctions->glBindTexture(GL_TEXTURE_2D, m_renderToTexture);
//Creates an empty texture of specified size.
//m_glFunctions->glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 1024, 768, 0, GL_RGB, GL_UNSIGNED_BYTE, 0);
m_glFunctions->glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, 0);
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
m_glFunctions->glDrawBuffer(GL_NONE);
m_glFunctions->glReadBuffer(GL_NONE);
// Always check that our framebuffer is ok
if (m_glFunctions->glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE){
qDebug() << "FrameBuffer not OK";
return;
}
m_glFunctions->glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Draw function for each mesh. Model matrix is passed as argument from a Transform class draw function
void Mesh::draw(const Matrix4x4& projection, const Matrix4x4& view, const Matrix4x4& model)
{
//Shadow map pass 1
if (m_shadowMapFirstpass){
//Pass 1 Shaders
m_glFunctions->glUseProgram(m_depthRTTShaderProgram);
//Light view matrix
m_depthMVP = projection*view*model;
//Get the location of the uniform name mvp
GLuint depthMVPLocation = m_glFunctions->glGetUniformLocation(m_depthRTTShaderProgram, "depthMVP");
m_glFunctions->glUniformMatrix4fv(depthMVPLocation, 1, GL_TRUE, &m_depthMVP[0][0]);
m_shadowMapFirstpass = false;
}
//Shadow map pass 2
else if(m_shadowMapFirstpass == false){
//Pass 2 Shader
m_glFunctions->glUseProgram(m_shaderProgram);
//Gets the model matrix which is then multiplied with view and projection to form the mvp matrix
Matrix4x4 mvp = projection * view * model;
//Get the location of the uniform name mvp
GLuint mvpLocation = m_glFunctions->glGetUniformLocation(m_shaderProgram, "mvp");
//Send the mvp matrix to the vertex shader
m_glFunctions->glUniformMatrix4fv(mvpLocation, 1, GL_TRUE, &mvp[0][0]);
Matrix4x4 depthBiasMVP = m_depthMVP;// biasMatrix*m_depthMVP;
GLuint depthBiasMVPLocation = m_glFunctions->glGetUniformLocation(m_shaderProgram, "depthBiasMVP");
m_glFunctions->glUniformMatrix4fv(depthBiasMVPLocation, 1, GL_TRUE, &depthBiasMVP[0][0]);
m_shadowMapFirstpass = true;
}
//Bind this mesh VAO
m_glFunctions->glBindVertexArray(m_vao);
//Draw the triangles using the index buffer(EBO)
glDrawElements(GL_TRIANGLES, m_indices.size(), GL_UNSIGNED_INT, 0);
//Unbind the VAO
m_glFunctions->glBindVertexArray(0);
/////////////////////////////////////////////////////////////////////////////////////////////////////
//Calls the childrens' update
if (!m_children.empty())
{
for (int i = 0; i < m_children.size(); i++)
{
if (m_children[i] != NULL)
{
m_children[i]->draw(frustumCheck, projection, view, bvScaleFactor, model);
}
}
}
}
My render loop
void OpenGLWin::paintGL()
{
// m_glFunctions->glBindFramebuffer(GL_FRAMEBUFFER, m_frameBuffer);
m_glFunctions->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, m_frameBuffer);
glViewport(0, 0, 1024, 1024);
// Clear the buffer with the current clearing color
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Light View Matrix
Matrix4x4 lightView;
lightView.lookAt(Vector3(0, 0, 0), Vector3(0, 0, -1), Vector3(0, 1, 0));
//Draw scene to Texture
m_root->draw(m_projection, lightView);
///////////////////////////////////////////////////////////////////
//Draw to real scene
m_glFunctions->glBindFramebuffer(GL_FRAMEBUFFER, 0);
// m_glFunctions->glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Bind Pass 2 shader
m_glFunctions->glUseProgram(m_shadowMapShaderProgram->getShaderProgramID());
GLuint shadowMapLocation = m_glFunctions->glGetUniformLocation(m_shadowMapShaderProgram->getShaderProgramID(), "shadowMap");
//Shadow Texture
m_glFunctions->glActiveTexture(GL_TEXTURE0);
m_glFunctions->glBindTexture(GL_TEXTURE_2D, m_renderToTexture);
m_glFunctions->glUniform1i(shadowMapLocation, 0);
//Updates matrices and view matrix for player camera
m_root->update(m_view);
//Render scene to main frame buffer
m_root->draw(m_projection, m_view);
}
Pass 1 Vertex Shader
#version 330 core
//Passthrough vertex shader
uniform mat4 depthMVP;
//Vertex received from the program
layout(location = 0) in vec3 vertexPosition_modelspace;
void main(void)
{
//Output position of vertex in clip space
gl_Position = depthMVP * vec4(vertexPosition_modelspace, 1);
}
Pass 1 Fragment Shader
#version 330 core
//Render to texture
// Ouput data
layout(location = 0) out float depthValue;
void main(void)
{
depthValue = gl_FragCoord.z;
}
Pass 2 Vertex Shader
#version 330 core
layout(location = 0) in vec3 vertexPosition_modelspace;
out vec4 ShadowCoord;
// Values that stay constant for the whole mesh.
uniform mat4 mvp;
uniform mat4 depthBiasMVP;
void main(){
// Output position of the vertex, in clip space : MVP * position
gl_Position = mvp * vec4(vertexPosition_modelspace,1);
ShadowCoord = depthBiasMVP * vec4(vertexPosition_modelspace,1);
}
Pass 2 Fragment Shader
#version 330 core
in vec4 ShadowCoord;
// Ouput data
layout(location = 0) out vec3 color;
// Values that stay constant for the whole mesh.
uniform sampler2D shadowMap;
void main(){
float visibility=1.0;
vec3 ProjCoords = ShadowCoord.xyz / ShadowCoord.w;
vec2 UVCoords;
UVCoords.x = 0.5 * ProjCoords.x + 0.5;
UVCoords.y = 0.5 * ProjCoords.y + 0.5;
float z = 0.5 * ProjCoords.z + 0.5;
float Depth = texture(shadowMap, UVCoords).z;//or x
if (Depth < (z + 0.00001)){
visibility = 0.1;
}
color = visibility*vec3(1,0,0);
}
Disable texture comparison for one thing. That's only valid when used with sampler2DShadow and you clearly are not using that in your code because your texture coordinates are 2D.
This means replacing the following code:
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE);
With this instead:
m_glFunctions->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
Likewise, using GL_LINEAR filtering on a non-sampler2DShadow texture is a bad idea. That is going to average the 4 nearest depth values and give you a single depth back. But that's not the proper way to anti-alias shadows; you actually want to average the result of 4 depth tests instead of doing a single test on the average of 4 depths.

Sampler 2D Alpha Value Stays at 1

I create a texture for use in a 2D sampler as a displacement map for a mesh of tessellated terrain. Using the passed in vertex coordinates, I have a smooth interpolated value of the patch corners for subsequent vertices. When using the height value derived from the sampler, all I receive is a flat plane. When I multiply that value by a hundred, the height of the plane increases by around a hundred leading me to believe the alpha value is constantly one.
Here is the GLSL evaluation shader and the texture setup.
#version 430
layout(triangles, equal_spacing, ccw) in;
uniform mat4 camera;
uniform mat4 model;
uniform sampler2D terrain;
//uniform float lod_factor;
uniform float size;
in vec4 WorldPos_ES_in[];
in vec2 TexCoord_ES_in[];
in vec3 Normal_ES_in[];
out vec4 WorldPos_FS_in;
out vec2 TexCoord_FS_in;
out vec3 Normal_FS_in;
vec3 interpolate3D(vec3, vec3, vec3);
vec2 interpolate2D(vec2, vec2, vec2);
void main()
{
// Interpolate the attributes of the output vertex using the barycentric coordinates
TexCoord_FS_in = interpolate2D(TexCoord_ES_in[0], TexCoord_ES_in[1], TexCoord_ES_in[2]);
Normal_FS_in = interpolate3D(Normal_ES_in[0], Normal_ES_in[1], Normal_ES_in[2]);
Normal_FS_in = normalize(Normal_FS_in);
WorldPos_FS_in = vec4(interpolate3D(WorldPos_ES_in[0].xyz, WorldPos_ES_in[1].xyz, WorldPos_ES_in[2].xyz),1);
vec2 position=WorldPos_FS_in.xz;
float Displacement = texture(terrain, position/size).a;
//gl_Position = camera*model * WorldPos_FS_in;
gl_Position = camera*model * vec4(WorldPos_FS_in.x, Displacement,WorldPos_FS_in.z, 1.0);
}
vec2 interpolate2D(vec2 v0, vec2 v1, vec2 v2)
{
return vec2(gl_TessCoord.x) * v0 + vec2(gl_TessCoord.y) * v1 + vec2(gl_TessCoord.z) * v2;
}
vec3 interpolate3D(vec3 v0, vec3 v1, vec3 v2)
{
return vec3(gl_TessCoord.x) * v0 + vec3(gl_TessCoord.y) * v1 + vec3(gl_TessCoord.z) * v2;
}
and
glActiveTexture(GL_TEXTURE1);
GLuint tex2 = createTerrainMap();
glBindTexture(GL_TEXTURE_2D, tex2);
shader->setUniform("terrain", 1);
static GLuint createTerrainMap(){
GLuint texName;
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
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_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, size+1, size+1, 0, GL_RGBA, GL_FLOAT, terrainM);
return texName;
}
terrainM is declared as
GLfloat terrain[size+1][size+1][4];
As mentioned, using the vertex coordinates yields the correct result but defeats the purpose of the displacement map. In addition, I use another texture from a file as GL_TEXTURE1 which is TexCoord_ES_in and it is for the fragment shader and correctly applied. Any ideas to what is causing the flat plane instead of a displaced value?
Since the TEC does not provide data about the position of the triangle outside of the barycentric coordinates inside of it. Using the interpolated data for the triangle is useless. In my situation where the world coordinates is from 0 to an arbitrary amount, another set of UV coordinates is needed to find the correct height.

Textures appear pure black, unless I pass an invalid value to texture uniform location

My program has been working perfectly so far, but it turns out that I've been lucky. I began doing some cleanup of the shader, because it was full of experimental stuff, and I had the following line at the end of the fragment shader:
gl_FragColor = final_color * (texture2D(tex, gl_TexCoord[0].st)*1.0 + texture2D(tex2, gl_TexCoord[0].st)*1.0);
I attempted to clean it up and I had the following declared at the top:
uniform sampler2D tex, tex2;
Changing these lines to:
gl_FragColor = final_color * texture2D(tex, gl_TexCoord[0].st;
and
uniform sampler2D tex;
actually broke the program (black screen), even though I am doing
GLuint tex_loc = glGetUniformLocation(shader_prog_id_, "tex");
glUniform1i(tex_loc, texture_id_);
in my main code. I'm sure it's a texture issue and not a glsl compiler error, because I can add 1.0 to the output and end up with a white silhouette of my mesh.
The strangeness begins when I change the lines in my shader to:
gl_FragColor = final_color * texture2D(tex2, gl_TexCoord[0].st;
and
uniform sampler2D tex2;
but still retrieve the location for tex. The program works as it always has, even though inspecting the value of tex_loc in the debugger indicates an error. I'm not happy doing this, and now that I'm trying to load multiple textures, it will cause bigger headaches down the line.
I'm using VBOs, in interleaved format, to render the geometry. I'm passing in the vertex position, normal and texcoord this way.
There are other questions with the "black texture" issue, but they're using immediate mode calls and setting the wrong texture state. I tried changing the texture unit before supplying the arrays, with no success.
Here is as much relevant code as possible from the main program:
void MeshWidget::draw() {
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, 0.0f, -4.0f + zoom_factor_);
glRotatef(rotX, 1.0f, 0.0f, 0.0f);
glRotatef(rotY, 0.0f, 1.0f, 0.0f);
glRotatef(rotZ, 0.0f, 0.0f, 1.0f);
// Auto centre mesh based on vertex bounds.
glTranslatef(-x_mid_, -y_mid_, -z_mid_);
glDrawElements(GL_TRIANGLES, mesh_.num_indices, GL_UNSIGNED_SHORT, BUFFER_OFFSET(0)); //The starting point of the IBO
}
void MeshWidget::openMesh(const string& filename) {
if (mesh_filename_ != filename) {
clearMeshData(mesh_);
glDeleteBuffersARB(1, &VertexVBOID);
glDeleteBuffersARB(1, &IndexVBOID);
ReadMsh(mesh_, filename);
// Create buffer objects here.
glGenBuffersARB(1, &VertexVBOID);
glBindBufferARB(GL_ARRAY_BUFFER, VertexVBOID);
glBufferDataARB(GL_ARRAY_BUFFER, sizeof(VertexAttributes)*mesh_.num_vertices, &mesh_.vertices[0], GL_STATIC_DRAW);
glGenBuffersARB(1, &IndexVBOID);
glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint16_t)*mesh_.num_indices, &mesh_.indices[0], GL_STATIC_DRAW);
glBindBuffer(GL_ARRAY_BUFFER, VertexVBOID);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(VertexAttributes), BUFFER_OFFSET(0)); //The starting point of the VBO, for the vertices
glEnableClientState(GL_NORMAL_ARRAY);
glNormalPointer(GL_FLOAT, sizeof(VertexAttributes), BUFFER_OFFSET(12)); //The starting point of normals, 12 bytes away
glClientActiveTexture(GL_TEXTURE0);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glTexCoordPointer(2, GL_FLOAT, sizeof(VertexAttributes), BUFFER_OFFSET(24)); //The starting point of texcoords, 24 bytes away
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexVBOID);
if (startup_done_) updateGL();
}
}
void MeshWidget::openTexture(const string& filename) {
size_t dot = filename.find_last_of('.');
string ext(filename, dot, filename.size()); // 3rd parameter should be length of new string, but is internally clipped to end.
glActiveTexture(GL_TEXTURE0);
glClientActiveTexture(GL_TEXTURE0);
glDeleteTextures(1, &texture_id_);
glGenTextures(1, &texture_id_);
glBindTexture(GL_TEXTURE_2D, texture_id_);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
if (ext == ".dds") {
if (GLEE_EXT_texture_compression_s3tc) {
texture_id_ = SOIL_load_OGL_texture(filename.c_str(), SOIL_LOAD_AUTO, texture_id_, SOIL_FLAG_DDS_LOAD_DIRECT);
// SOIL takes care of calling glTexParams, glTexImage2D, etc.
yflip_texture_ = true;
} else {
//std::cout << "S3TC not supported on this graphics hardware." << std::endl;
// TODO: Error message in status bar?
}
} else {
QImage tex(filename.c_str());
tex = QGLWidget::convertToGLFormat(tex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
yflip_texture_ = false;
}
updateUniforms();
if (startup_done_) updateGL();
}
void MeshWidget::updateUniforms() {
GLuint texture_flip_uniform = glGetUniformLocation(shader_prog_id_, "yflip");
glUniform1f(texture_flip_uniform, float(yflip_texture_ * 1.0f));
GLuint tex_loc = glGetUniformLocation(shader_prog_id_, "tex");
glUniform1i(tex_loc, texture_id_);
}
And my shaders (there's still some junk in here because I was experimenting, but nothing that affects the output):
varying vec3 normal, lightDir, eyeVec;
uniform float yflip;
void main()
{
normal = gl_NormalMatrix * gl_Normal;
vec3 vVertex = vec3(gl_ModelViewMatrix * gl_Vertex);
lightDir = vec3(gl_LightSource[0].position.xyz - vVertex);
eyeVec = -vVertex;
gl_TexCoord[0].x = gl_MultiTexCoord0.x;
gl_TexCoord[1].x = gl_MultiTexCoord1.x;
if (yflip == 1.0) {
gl_TexCoord[0].y = 1 - gl_MultiTexCoord0.y;
gl_TexCoord[1].y = 1 - gl_MultiTexCoord1.y;
} else {
gl_TexCoord[0].y = gl_MultiTexCoord0.y;
gl_TexCoord[1].y = gl_MultiTexCoord1.y;
}
gl_Position = ftransform();
}
fragment shader:
varying vec3 normal, lightDir, eyeVec;
uniform sampler2D tex2;
void main (void)
{
vec4 texel = texture2D(tex2, gl_TexCoord[0].st);
vec4 final_color =
(gl_FrontLightModelProduct.sceneColor * gl_FrontMaterial.ambient) +
(gl_LightSource[0].ambient * gl_FrontMaterial.ambient);
vec3 N = normalize(normal);
vec3 L = normalize(lightDir);
float lambertTerm = dot(N,L);
if(lambertTerm > 0.0)
{
final_color += gl_LightSource[0].diffuse *
gl_FrontMaterial.diffuse *
lambertTerm;
vec3 E = normalize(eyeVec);
vec3 R = reflect(-L, N);
float specular = pow( max(dot(R, E), 0.0),
gl_FrontMaterial.shininess );
final_color += gl_LightSource[0].specular *
gl_FrontMaterial.specular *
specular;
}
gl_FragColor = final_color * texel;
}
glUniform1i(tex_loc, texture_id_);
The second parameter should specify ID of a texture unit(hint: glActiveTexture sets the currently active texture unit), not ID of particular texture object.