Reputation: 11
I'm working on a render to texture component of a graphics engine. Took me a couple hours to implement it on DX and it works as expected, I've spent a few days on the OpenGL implementation but it refuses to work.
When rendering the depth buffer to a texture I get somewhat expected results, but the image is fully of strange artifacts (color targets work fine). I've played around with various depth and stencil bit configurations, different methods of binding but I'm getting no where.
I'll post what my results are and what relevant code I have that has resulted in the "closest" to correct results.
The scene is a large number of cannons, a camera position in front of the cannons with a plane in front of the camera. The plane's texture is the rendered result of the a second camera which spins around the the cannons. I expect the plane to be mostly red with some darker red areas where objects are close to the second camera.
Here is the result I get in DX (which is what I expect): [1]: https://i.sstatic.net/ecJfw.png "Good Result"
And here is the result I get from GL: [2]: https://i.sstatic.net/udoc8.png "Odd Result"
I have no idea where the black parts are coming from. Through a bit of shader debugging I can tell that the unrendered areas remain 1.0 (depth clear value) and non black areas are close to 1.0 but never reach it (as I would expect). The black areas are... random.
Code I use to create the texture is:
glGenTextures(1, &textureID);
dim = GL_TEXTURE_2D;
wth = width;
hgt = height;
iFormat = _glTranslateFormat(fmt, format, type);
glBindTexture(dim, textureID);
glTexStorage2D(dim, 1, iFormat, width, height);
_glTranslateFormat translates the native formats into GL formats, this returns GL_DEPTH_COMPONENT16 atm. I've tried other formats, they give even stranger results. 32 and 32F allow the values sampled to be well outside the range of 0 and 1 (like higher than 1000000000), stencil based cause a variety of issues as well (even when I change code to take the stencil into account).
Code I use to bind it to the frame buffer is:
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, d->_exposeTexture()->_exposeAPI(), 0);
_exposeAPI returns the texture's ID. This happens each time the code requires the depth buffer to be bound to a different frame buffer (framebuffer will be bound before hand).
I've tried various methods of binding a render target to a frame buffer and what not, but the issue never seems to go away. Any help would be greatly appreciated. For now I'll have to abandon the OpenGL components of the engine and work with DX until I find a fix for this issue.
EDIT: As requested I've added the shader responsible for sampling from the texture, the stuff at the end of the file is just debugging code I've played with. The depth texture is coming in as the diffuse texture.
#version 430
struct Light
{
vec4 diffuse;
vec4 specular;
vec4 attenuation;
vec3 spot;
uint nID;
uint type;
};
layout (std140, binding = 9) uniform singleLight
{
Light light;
};
struct BasicFSInput
{
vec4 position;
vec3 normal;
vec2 uv;
vec4 fragPos;
vec3 toLight;
};
layout(binding = 1) uniform sampler2D diff1;
layout(binding = 2) uniform sampler2D amb1;
layout(binding = 3) uniform sampler2D spec1;
layout (location = 0) in BasicFSInput fin;
layout (location = 0) out vec4 color;
layout(std140, binding = 10) uniform material
{
float specular;
float shininess;
};
void BasicFragmentShader()
{
vec4 dTexel = texture(diff1, fin.uv).rgba;
vec4 aTexel = texture(amb1, fin.uv).rgba;
vec4 sTexel = texture(spec1,fin.uv).rgba;
vec3 lightDir = normalize(fin.toLight);
vec3 n = normalize(fin.normal);
float NdotL = max(dot(n, lightDir),0.0);
vec4 col = NdotL * light.diffuse;
vec4 ambContrib = aTexel;
vec4 diffContrib = dTexel * col;
vec3 refl = 2.0 * NdotL * n + lightDir;
float NdotR = max(dot(normalize(refl), normalize(-fin.fragPos.xyz)),0.0);
float specContrib = sTexel * specular * pow(NdotR, shininess);
color = ambContrib + diffContrib + specContrib;/*
if(dTexel.r < -1.0)
color.r = 1.0f;
if(dTexel.r > 1.0)
color.b = 1.0f;
if(dTexel.r == 1.0f)
color.g = 1.0f;*/
//color.r = dTexel.r;
/*if(dTexel.r < 0.5f)
color.b = 1.0f;
if(dTexel.r > 0.5f)
color.r = 1.0f;*/
/*if(dTexel.r < -10000000.0f)
color.g = 1.0f;*/
//color.a = 1.0f;
}
Upvotes: 1
Views: 1619
Reputation: 3089
Don't abandon OpenGL that fast :)
Are you sure you want to render the depth buffer to a texture and not the colour buffer to a texture ?
Perhaps below might help (apologies if you knew this already). (It's taken from OpenGL Superbible 6th Edition.)
Setup framebuffer
glGenFramebuffers(1, &fbo);
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
//texture for the colour buffer
glGenTextures(1, &colourTexture);
glBindTexture(GL_TEXTURE_2D, colourTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, width, height);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//texture for the depth buffer
glGenTextures(1, &depthTexture);
glBindTexture(GL_TEXTURE_2D, depthTexture);
glTexStorage2D(GL_TEXTURE_2D, 1, GL_DEPTH_COMPONENT32F, width, hwight);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, colourTexture, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, depthTexture, 0);
const GLenum drawBuffers[] = { GL_COLOR_ATTACHMENT0 };
glDrawBuffers(1, drawBuffers);
Then before calling glDrawArrays / Elements bind to the framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, fbo);
Later, when you want to render the texture to the screen bind the texture
glBindTexture(GL_TEXTURE_2D, colourTexture);
Inside the fragment when rendering the texture a sampler is required.
#version 430 core
uniform sampler2D tex;
in VS_OUT
{
vec2 texcoord;
} fs_in;
out vec4 color;
void main(void)
{
color = texture(tex, fs_in.texcoord);
}
Upvotes: 1