Sampler 2D Alpha Value Stays at 1 - glsl

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.

Related

Why is this OpenGL code using texelFetch not working?

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.)

opengl + emscripten textures not getting displayed

i am tring to display textures using opengles + emscripten, but all i am getting are black triangles.
output image
my vertex shader:
attribute vec3 position;
attribute vec4 color;
attribute vec3 normal;
attribute vec2 uv;
varying vec4 v_color;
varying vec3 v_normal;
varying vec2 v_uv;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
highp mat4 transpose(in highp mat4 inMatrix) {
highp vec4 i0 = inMatrix[0];
highp vec4 i1 = inMatrix[1];
highp vec4 i2 = inMatrix[2];
highp vec4 i3 = inMatrix[3];
highp mat4 outMatrix = mat4(
vec4(i0.x, i1.x, i2.x, i3.x),
vec4(i0.y, i1.y, i2.y, i3.y),
vec4(i0.z, i1.z, i2.z, i3.z),
vec4(i0.w, i1.w, i2.w, i3.w)
);
return outMatrix;
}
void main()
{
v_color = color;
v_normal = normal;
v_uv = uv;
gl_Position = projection * view * transpose(model) * vec4(position.xyz, 1.0);
}
fragment shader:
precision mediump float;
varying vec4 v_color;
varying vec3 v_normal;
varying vec2 v_uv;
uniform sampler2D tex;
void main()
{
// gl_FragColor = v_color;
gl_FragColor = texture2D(tex, v_uv.xy);
}
texture create function:
void IG::Texture::create(unsigned char* image,
uint32_t width,
uint32_t height,
uint32_t channels)
{
if(image == nullptr)
{
std::cout<<"Texture creation failed! invalid image data.."<<std::endl;
return;
}
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glGenTextures(1, &ID);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, ID);
// set the texture wrapping parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, attribs.uv_mode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, attribs.uv_mode);
// set texture filtering parameters
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, attribs.min_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, attribs.mag_filter);
glTexImage2D(GL_TEXTURE_2D,
attribs.mip_level,
GL_RGB,
width,
height,
attribs.border,
GL_RGB,
GL_UNSIGNED_BYTE,
image);
// glGenerateMipmap(GL_TEXTURE_2D);
}
here attribs is a struct with values:
uv_mode(GL_REPEAT),
min_filter(GL_LINEAR_MIPMAP_LINEAR),
mag_filter(GL_LINEAR),
mip_level(0),
border(0)
i have verified that the image is valid using stb_image.
inside the draw loop all triangles are iterated and drawn using this call:
void Renderer::draw_objects(){
for(auto& v : gl_objects){
auto &shape = v.second;
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, shape.tex.ID);
shader->set_mat4("model", shape.transform);
glBindVertexArray(shape.VAO);
glUniform1i(shape.tex.samplerLoc, 0);
glDrawArrays(GL_TRIANGLES, 0, 3);
}
}
i am taking references from these links learopengl emscripten opengles examples
i am unable to debug what i am doing wrong here. what could be the issue here?
Your problem come from the missing mipmaps, it try to render a specific mipmaps that is not created, resulting in black pixels.
A proper call to glGenerateMipmap after glTexImage2D would solve the issue.
If you don't generate mipmaps mipmaps (with glGenerateMipmap) you must use one of the non mipmap minifying functions (GL_NEAREST or GL_LINEAR). If you use a mipmap minification function, the texture would be "Mipmap Incomplete".
Eiter use min_filter(GL_LINEAR) or call glGenerateMipmap(GL_TEXTURE_2D);.

When using texture arrays, why do I not have to bind the sampler to the shader?

I am creating an array of textures using GL_TEXTURE_2D_ARRAY in my code:
// Load all images ito opengl
unsigned int width, height;
std::vector<unsigned char> textures;
int num = 0;
for ( auto each : image_list )
{
// Load PNG
std::vector<unsigned char> buffer, this_texture;
lodepng::load_file(buffer, each.string().c_str());
auto lode_error = lodepng::decode(this_texture, width, height, buffer);
if (lode_error)
{
LOG_ERROR("lodepng has reported this error: " + std::string(lodepng_error_text(lode_error)));
return false;
}
m_indexes.insert(std::make_pair(each.filename().string(), num));
textures.insert(textures.end(), this_texture.begin(), this_texture.end());
num++;
}
// Active texture
glActiveTexture(GL_TEXTURE0);
// Generate texture
glGenTextures(1, &m_texture_id);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_id);
// Send pixels
glTexImage3D(GL_TEXTURE_2D_ARRAY,
0,
GL_RGBA,
width, height,
image_list.size(),
0,
GL_RGBA,
GL_UNSIGNED_BYTE,
textures.data());
// Set options
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
Here are the shaders I am using:
Vertex Shader
#version 430 core
/* layouts */
layout (location = 0) in vec3 in_vertex;
layout (location = 1) in vec2 in_uv;
layout (location = 2) in vec4 in_tint;
layout (location = 3) in mat4 in_model;
layout (location = 7) in vec3 in_scale;
layout (location = 8) in float in_textured_index;
/* uniforms */
uniform mat4 ortho;
uniform mat4 view;
/* outputs */
out vec4 tint;
out vec2 uv;
out float textured_index;
void main()
{
mat4 mvp = ortho * view * in_model;
gl_Position = mvp * vec4(in_vertex * in_scale, 1.0);
tint = in_tint;
uv = in_uv;
textured_index = in_textured_index;
}
Fragment Shader
#version 430 core
/* inputs from vertex shader */
in vec4 tint;
in vec2 uv;
in float textured_index;
/* output to GPU */
out vec4 fragment;
/* texture sampler */
uniform sampler2DArray sampler_unit;
void main()
{
fragment = texture(sampler_unit, vec3(uv.xy, textured_index)).rgba;
fragment = fragment * tint;
}
Code to bind the texture array:
void ArrayTextures::attach()
{
if (glIsTexture(m_texture_id)){
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D_ARRAY, m_texture_id);
}
}
What I have noticed, is that I do not have to attach the texture unit or the texture id to my shader, as long as the texture is bound with above function. It just works. I would like to understand why. In OpenGL 3.X, you have to bind the sampler to your shader before you can use it. Is there any automatism behind the scenes, that I am not aware of? Since I have a 5700XT, may this be an AMD specific oddity? What is the correct way here, so I can be sure it also works on NVIDIA?
This has nothing to do with the sampler type. The binding between the texture object and the texture sampler is the texture unit. The texture object must be bound to a texture unit, and the texture unit number must be set to the texture sampler uniform.
In GLSL almost everything is initialized with 0 respectively 0.0 by default. Therefore the default Binding point is 0. If the texture is bound to the texture unit 0 (GL_Texture0), it is not necessary to set the texture sampler uniform as it is 0 by default.

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 ;)

Incorrect texture coordinate calculated for shadow map

I am having problems getting the correct texture coordinate to sample my shadow map. Looking at my code, the problem appears to be from incorrect matrices. This is the fragment shader for the rendering pass where I do shadows:
in vec2 st;
uniform sampler2D colorTexture;
uniform sampler2D normalTexture;
uniform sampler2D depthTexture;
uniform sampler2D shadowmapTexture;
uniform mat4 invProj;
uniform mat4 lightProj;
uniform vec3 lightPosition;
out vec3 color;
void main () {
vec3 clipSpaceCoords;
clipSpaceCoords.xy = st.xy * 2.0 - 1.0;
clipSpaceCoords.z = texture(depthTexture, st).x * 2.0 - 1.0;
vec4 position = invProj * vec4(clipSpaceCoords,1.0);
position.xyz /= position.w;
//At this point, position.xyz seems to be what it should be, the world space coordinates of the pixel. I know this because it works for lighting calculations.
vec4 lightSpace = lightProj * vec4(position.xyz,1.0);
//This line above is where I think things go wrong.
lightSpace.xyz /= lightSpace.w;
lightSpace.xyz = lightSpace.xyz * 0.5 + 0.5;
float lightDepth = texture(shadowmapTexture, lightSpace.xy).x;
//Right here lightDepth seems to be incorrect. The only explanation I can think of for this is if there is a problem in the above calculations leading to lightSpace.xy.
float shadowFactor = 1.0;
if(lightSpace.z > lightDepth+0.0005) {
shadowFactor = 0.2;
}
color = vec3(lightDepth);
}
I have removed all the code irrelevant to shadowing from this shader (Lighting, etc). This is the code I use to render the final pass:
glCullFace(GL_BACK);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
postShader->UseShader();
postShader->SetUniform1I("colorTexture", 0);
postShader->SetUniform1I("normalTexture", 1);
postShader->SetUniform1I("depthTexture", 2);
postShader->SetUniform1I("shadowmapTexture", 3);
//glm::vec3 cp = camera->GetPosition();
postShader->SetUniform4FV("invProj", glm::inverse(camera->GetCombinedProjectionView()));
postShader->SetUniform4FV("lightProj", lights[0].camera->GetCombinedProjectionView());
//Again, if I had to guess, these two lines above would be part of the problem.
postShader->SetUniform3F("lightPosition", lights[0].x, lights[0].y, lights[0].z);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, frameBuffer->GetColor());
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, frameBuffer->GetNormals());
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, frameBuffer->GetDepth());
glActiveTexture(GL_TEXTURE3);
glBindTexture(GL_TEXTURE_2D, lights[0].shadowmap->GetDepth());
this->BindPPQuad();
glDrawArrays(GL_TRIANGLES, 0, 6);
In case it is relevant to my problem, here is how I generate the depth framebuffer attachments for the depth and shadow maps:
void FrameBuffer::Init(int textureWidth, int textureHeight) {
glGenFramebuffers(1, &fbo);
glGenTextures(1, &depth);
glBindTexture(GL_TEXTURE_2D, depth);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, textureWidth, textureHeight, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Where is the problem in my math or my code, and what can I do to fix it?
After some experimentation, I have found that my problem does not lie in my matrices, but in my clamping. It seems that I get strange values when I use GL_CLAMP or GL_CLAMP_TO_EDGE, but I get almost correct values when I use GL_CLAMP_TO_BORDER. There are more problems, but they do not seem to be matrix related as I thought.