• Advertisement
Sign in to follow this  

OpenGL 3D FBO I/O

This topic is 2471 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've been at this for hours and IMO my code looks pretty clear-cut. Nevertheless, I'm obviously missing something because two things are happening that I'm unable to explain:

1) first off, I'm trying to blur my shadowmap cascades (I'm using four)
2) my source is a four-layer float 32 GL_TEXTURE_2D_ARRAY RGB target (call it texVSM), which is updated properly in the VSM projective phase
3) Peculiarity 1: for some reason my VSM FBO requires me to bind the target array (texVSM) to a texture (input) although no texture look-ups are being done inside the shader (it just calculates the moments and stores them in the active slice); if I don't bind the texture, the depth buffer is updated, but the color attachment (texVSM) is not. As usual, I'm selecting my output slice by calling:

glFramebufferTextureLayerEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + iIndex, iHandle, 0, iLayerIndex);

I'm relatively sure you don't need to bind a texture for it to work as an FBO attachment.

4) rendering shadows as-is at this point works nicely (save for the first peculiarity)
5) my second FBO expects texVSM as its input at TU 0 and writes to another 3D texture attachment (call it texBlurVSM) (I've also given it a go by binding the output target as its primary input)
6) Peculiarity 2: nothing is ever written to texBlurVSM, even if I set the shader to output a constant color. This is very weird, because the code is pretty much identical to that of the first FBO, except for the fact that it's a post-processing effect and just draws a single quad. In other words, I'm unable to copy anything from one 3D texture to another through an FBO proxy. I've disable depth testing and masking for the blur FBO and it makes no difference

At this point I'm rather out of ideas as to what to even try or change. So far I have something like 6 FBO's in use and they all work just fine save for the blur one.

Here's a stitched-together mock-up of the code I'm using for both FBOs (these calls are pseudocode for actual OpenGL calls):


fbo = CreateFBO();
fbo->AddDepthBuffer();
fbo->AddAttachement(new Texture);
fbo->AddInputs(...); //basically adds all texture handles to the FBO's internal list for automated binding


fbo->Enable(); //updates attachments and calls glBindTexture() for all inputs (texture targets and TU's are automatically taken care of)
for(i to numCascades)
{
fbo->ActivateLayer(i); //calls glFramebufferTextureLayerEXT() as above for all attached output targets
ClearDepthAndColor();
//RenderShadowCasters() for the projective phase
//Draw a quad over the viewport for the blur phase
}
fbo->Disable();


Any thoughts?

Share this post


Link to post
Share on other sites
Advertisement
I think you might need a call to glDrawBuffer or glDrawBuffers, if you want to render to something other than GL_COLOR_ATTACHMENT0.

Incidentally, from what I remember of rendering to a 3d / array texture layer, the call to glFramebufferTextureLayer attaches one layer of the texture to the attachment point. So if you're only rendering to one layer at a time, you might as well use GL_COLOR_ATTACHMENT0 for all of them, instead of GL_COLOR_ATTACHMENT0 + i. (If I'm not misunderstanding what you're doing with iIndex / iLayerIndex here).

On the other hand, if you want to render to several layers at once, you should attach them all to separate attachment points once, then output multiple values from the shader (using gl_FragData or different out locations). I'm not sure what your AddAttachment(new Texture) call does -> if this is the whole 3D texture, it's not necessary, you just need to attach the individual layers. (Binding the whole 3D texture is instead used with gl_Layer in a geometry shader to render to each layer.)

Share this post


Link to post
Share on other sites
Could you try and explain what's happening and why you think there's anything wrong. If you're trying to validate your results using gDebugger you would find that it simply doesn't work when it comes to layered FBOs.

Also FBO's are very VERY picky when it comes to which calls you're using and I've personally experienced different behaviors using the EXT, ARB and core calls. So try to translate the pseudocode into actual ogl calls so we have a chance to see which you're using.

Also if you're trying to render to several layeres at once do as __sprite also said - Pick a layer using a geometry shader as that's the only way atm. If you try to do that you need to bind the layered texture to the FBO using the glFramebufferTexture() call NOT the layered one as that only binds a single slice.

Share this post


Link to post
Share on other sites
Cheers for the answers!

Ugh, work never helps to reply faster; but I finally have the time to post the full code (the iterator iIndex for the attachment number is from a generic piece of code that binds any number of added attachments - it's not specific to this example). The GL code that is called is (note that I'm actually checking each and every GL FBO call for errors and doing rather strict compatibility and format/error checking, which I have removed for clarity):


//accepts an already propely created texture ref; additional error and compatibility checking is done here
void FBO:AddAttachment(TEXHANDLE tex)
{
output.push_back(tex);
int iIndex = output.size() - 1;

if(GetNumLayers(tex) > 1)
glFramebufferTexture3DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + iIndex, GL_TEXTURE_3D, GetHandle(tex), 0, 0)
else
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + iIndex, GL_TEXTURE_2D, GetHandle(tex), 0)
}

void FBO:AddInput(TEXHANDLE tex)
{
input.push_back(tex);
}

void FBO::Enable()
{
//set up the target list for glDrawBuffers(); the output[] array contains refs to actual target handles
UINT mrt[GD_FBO_MAX_TARGETS];

UINT iNumActiveTargets = 0;

for(UINT i = 0; i < GD_MAX_TEXTURE_UNITS; i++)
{
if(output)
{ mrt = GL_COLOR_ATTACHMENT0_EXT + i; iNumActiveTargets = i + 1; }
else
mrt = NULL;
}

glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, iHandle);

glDrawBuffers(iNumActiveTargets, mrt);

for(i to numinputs)
glBindTexture(GetTarget(input), GetHandle(intput);
}

void FBO::ActivatLayer(int iLayerIndex)
{
glFramebufferTextureLayerEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, iHandle, 0, iLayerIndex);
for(iIndex all attachmetns)
glFramebufferTextureLayerEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + iIndex, iHandle, 0, iLayerIndex);
}


I hope there are no mistakes in the above code as I had to copy these bits together from all over the place (my code is structured in an object-oriented manner on multiple levels). I'm not including my texture generation code, which is used to actually create all the targets as it's an all-around piece of code and contains some hacks (nevertheless, I use it all over the place and it works just fine, both for 2D and 3D targets). If there's any other code I can include, please let me know; I'm guessing that, if anything, the above bit should be to blame, though.

>> (Binding the whole 3D texture is instead used with gl_Layer in a geometry shader to render to each layer.)

My Cascaded VSM store depth code uses the above method of output layer selection and works just fine; why would I need to use a geometry shader here?

Also, I'm only rendering to a single slice at once (the calling code structure in the OP loops through each layer and does the magic individually on each one)!

Or am I misunderstanding the whole thing?

Thanks for the input!

Share this post


Link to post
Share on other sites
If you are rendering to 1 slice at a time, then
glDrawBuffers(iNumActiveTargets, mrt);

probably needs to be
mrt = GL_COLOR_ATTACHMENT0_EXT;
glDrawBuffers(1, mrt);

Share this post


Link to post
Share on other sites
Your ActivateLayer function looks incomplete / wrong, you might want to check you've copied it here correctly. (You're attaching a layer of some texture as a depth attachment, then iterating something and attaching that same layer as color outputs... even if that's allowed in the specs (which seems unlikely) it doesn't make any sense).

Your enable function also appears to be adding a draw buffer for every attachment, but you say you only want to render to one attachment. I'm not sure what the specs say happens if you only output to one drawbuffer having specified several, but it may be undefined (at least for the buffers you don't output to).

(I'm not sure that putting inputs in the fbo class really makes sense from a conceptual viewpoint of what a framebuffer object actually is either?)

In the end, you appear to want to render to one output attachment at a time. That output just happens to be a layer of a 3D texture. So you want something like this:

[font="Lucida Console"][size="1"]// At startup:
Create your fbo.
Attach the depth buffer (assuming this stays constant, if not, do so at render time).

// At render time:
For each layer of 3D texture
* Attach one layer of 3D texture to COLOR_ATTACHMENT0 (using glFramebufferTextureLayer).
* Render to that layer (just output gl_FragColor).
[/font]
OR something like this:

[font="Lucida Console"][size="1"]// At startup:
Create your fbo.
Attach depth buffer (assuming it's constant...)
Attach 3D texture to GL_COLOR_ATTACHMENT0 (using glFramebufferTexture).

// At render time:
Render once (use a geometry shader to output vertices once for each layer, using gl_Layer to specify which. Fragment shader outputs to gl_FragColor.)
[/font]
On the other hand, if you really wanted to render to multiple attachments, your code would look something like this:

[font="Lucida Console"][size="1"]// At startup:
Create fbo.
Attach depth buffer.
Attach one layer of 3D texture to each attachment point (using glFramebufferTextureLayer).

// At render time:
Render once (Fragment shader outputs a value to each attachment using gl_FragData[n]).[/font]

Share this post


Link to post
Share on other sites
V-Man - my code automatically degenerates to rendering to just one attachment if there is just one color target attached :). Generally working with 2 or more attachements made me write an FBO class that automatically takes care of any number of attached targets.

__sprite:

You're absolutely right - I made a mistake when copying the code. The layer activation code should be (with some more elaboration):


void FBO::ActivatLayer(int iLayerIndex)
{
//activate the desired layer for the depth buffer (assumed to be 3D)
glFramebufferTextureLayerEXT(GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, iDepthHandle, 0, iLayerIndex);
//loop through all color attachments (assumed to be 3D and have the same number of layers as the depth buffer) and activate the desired layer
for(iIndex in all attachments)
glFramebufferTextureLayerEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + iIndex, output[iIndex], 0, iLayerIndex);
}


Which assumes the FBO has any number of color attachments and a single depth attachment, all of which have the same number of layers. The reason I'm not just activating attachment 0 is because I'm looping through all color targets and activating them to their rightful attachments at the requested layer. Again, this degenerates to what V-Man wrote if there is only one attachment. The same applies to Enable() - the code assumes the FBO can have up to GD_MAX_TEXTURE_UNITS attachments, but only enables those that have actual targets attached to them. Unless I'm blind to boot, I'm pretty sure there are no logic problems with this code.

What is especially annoying is the fact that OpenGL is generating zero errors (as mentioned in the OP, I'm actually checking each and every FBO call for errors and none are generated - I've removed the checks for clarity from the posted code). Is there any way I can check if my GTX 260M is even supposed to support this? I mean, maybe the drivers are silently letting the code slip, but there's no actual hardware support.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
  • Advertisement
  • Popular Tags

  • Advertisement
  • Popular Now

  • Similar Content

    • By reenigne
      For those that don't know me. I am the individual who's two videos are listed here under setup for https://wiki.libsdl.org/Tutorials
      I also run grhmedia.com where I host the projects and code for the tutorials I have online.
      Recently, I received a notice from youtube they will be implementing their new policy in protecting video content as of which I won't be monetized till I meat there required number of viewers and views each month.

      Frankly, I'm pretty sick of youtube. I put up a video and someone else learns from it and puts up another video and because of the way youtube does their placement they end up with more views.
      Even guys that clearly post false information such as one individual who said GLEW 2.0 was broken because he didn't know how to compile it. He in short didn't know how to modify the script he used because he didn't understand make files and how the requirements of the compiler and library changes needed some different flags.

      At the end of the month when they implement this I will take down the content and host on my own server purely and it will be a paid system and or patreon. 

      I get my videos may be a bit dry, I generally figure people are there to learn how to do something and I rather not waste their time. 
      I used to also help people for free even those coming from the other videos. That won't be the case any more. I used to just take anyone emails and work with them my email is posted on the site.

      I don't expect to get the required number of subscribers in that time or increased views. Even if I did well it wouldn't take care of each reoccurring month.
      I figure this is simpler and I don't plan on putting some sort of exorbitant fee for a monthly subscription or the like.
      I was thinking on the lines of a few dollars 1,2, and 3 and the larger subscription gets you assistance with the content in the tutorials if needed that month.
      Maybe another fee if it is related but not directly in the content. 
      The fees would serve to cut down on the number of people who ask for help and maybe encourage some of the people to actually pay attention to what is said rather than do their own thing. That actually turns out to be 90% of the issues. I spent 6 hours helping one individual last week I must have asked him 20 times did you do exactly like I said in the video even pointed directly to the section. When he finally sent me a copy of the what he entered I knew then and there he had not. I circled it and I pointed out that wasn't what I said to do in the video. I didn't tell him what was wrong and how I knew that way he would go back and actually follow what it said to do. He then reported it worked. Yea, no kidding following directions works. But hey isn't alone and well its part of the learning process.

      So the point of this isn't to be a gripe session. I'm just looking for a bit of feed back. Do you think the fees are unreasonable?
      Should I keep the youtube channel and do just the fees with patreon or do you think locking the content to my site and require a subscription is an idea.

      I'm just looking at the fact it is unrealistic to think youtube/google will actually get stuff right or that youtube viewers will actually bother to start looking for more accurate videos. 
    • By Balma Alparisi
      i got error 1282 in my code.
      sf::ContextSettings settings; settings.majorVersion = 4; settings.minorVersion = 5; settings.attributeFlags = settings.Core; sf::Window window; window.create(sf::VideoMode(1600, 900), "Texture Unit Rectangle", sf::Style::Close, settings); window.setActive(true); window.setVerticalSyncEnabled(true); glewInit(); GLuint shaderProgram = createShaderProgram("FX/Rectangle.vss", "FX/Rectangle.fss"); float vertex[] = { -0.5f,0.5f,0.0f, 0.0f,0.0f, -0.5f,-0.5f,0.0f, 0.0f,1.0f, 0.5f,0.5f,0.0f, 1.0f,0.0f, 0.5,-0.5f,0.0f, 1.0f,1.0f, }; GLuint indices[] = { 0,1,2, 1,2,3, }; GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(vertex), vertex, GL_STATIC_DRAW); GLuint ebo; glGenBuffers(1, &ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices,GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, false, sizeof(float) * 5, (void*)0); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, false, sizeof(float) * 5, (void*)(sizeof(float) * 3)); glEnableVertexAttribArray(1); GLuint texture[2]; glGenTextures(2, texture); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture[0]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); sf::Image* imageOne = new sf::Image; bool isImageOneLoaded = imageOne->loadFromFile("Texture/container.jpg"); if (isImageOneLoaded) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageOne->getSize().x, imageOne->getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageOne->getPixelsPtr()); glGenerateMipmap(GL_TEXTURE_2D); } delete imageOne; glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture[1]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); sf::Image* imageTwo = new sf::Image; bool isImageTwoLoaded = imageTwo->loadFromFile("Texture/awesomeface.png"); if (isImageTwoLoaded) { glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageTwo->getSize().x, imageTwo->getSize().y, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageTwo->getPixelsPtr()); glGenerateMipmap(GL_TEXTURE_2D); } delete imageTwo; glUniform1i(glGetUniformLocation(shaderProgram, "inTextureOne"), 0); glUniform1i(glGetUniformLocation(shaderProgram, "inTextureTwo"), 1); GLenum error = glGetError(); std::cout << error << std::endl; sf::Event event; bool isRunning = true; while (isRunning) { while (window.pollEvent(event)) { if (event.type == event.Closed) { isRunning = false; } } glClear(GL_COLOR_BUFFER_BIT); if (isImageOneLoaded && isImageTwoLoaded) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture[0]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, texture[1]); glUseProgram(shaderProgram); } glBindVertexArray(vao); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, nullptr); glBindVertexArray(0); window.display(); } glDeleteVertexArrays(1, &vao); glDeleteBuffers(1, &vbo); glDeleteBuffers(1, &ebo); glDeleteProgram(shaderProgram); glDeleteTextures(2,texture); return 0; } and this is the vertex shader
      #version 450 core layout(location=0) in vec3 inPos; layout(location=1) in vec2 inTexCoord; out vec2 TexCoord; void main() { gl_Position=vec4(inPos,1.0); TexCoord=inTexCoord; } and the fragment shader
      #version 450 core in vec2 TexCoord; uniform sampler2D inTextureOne; uniform sampler2D inTextureTwo; out vec4 FragmentColor; void main() { FragmentColor=mix(texture(inTextureOne,TexCoord),texture(inTextureTwo,TexCoord),0.2); } I was expecting awesomeface.png on top of container.jpg

    • By khawk
      We've just released all of the source code for the NeHe OpenGL lessons on our Github page at https://github.com/gamedev-net/nehe-opengl. code - 43 total platforms, configurations, and languages are included.
      Now operated by GameDev.net, NeHe is located at http://nehe.gamedev.net where it has been a valuable resource for developers wanting to learn OpenGL and graphics programming.

      View full story
    • By TheChubu
      The Khronos™ Group, an open consortium of leading hardware and software companies, announces from the SIGGRAPH 2017 Conference the immediate public availability of the OpenGL® 4.6 specification. OpenGL 4.6 integrates the functionality of numerous ARB and EXT extensions created by Khronos members AMD, Intel, and NVIDIA into core, including the capability to ingest SPIR-V™ shaders.
      SPIR-V is a Khronos-defined standard intermediate language for parallel compute and graphics, which enables content creators to simplify their shader authoring and management pipelines while providing significant source shading language flexibility. OpenGL 4.6 adds support for ingesting SPIR-V shaders to the core specification, guaranteeing that SPIR-V shaders will be widely supported by OpenGL implementations.
      OpenGL 4.6 adds the functionality of these ARB extensions to OpenGL’s core specification:
      GL_ARB_gl_spirv and GL_ARB_spirv_extensions to standardize SPIR-V support for OpenGL GL_ARB_indirect_parameters and GL_ARB_shader_draw_parameters for reducing the CPU overhead associated with rendering batches of geometry GL_ARB_pipeline_statistics_query and GL_ARB_transform_feedback_overflow_querystandardize OpenGL support for features available in Direct3D GL_ARB_texture_filter_anisotropic (based on GL_EXT_texture_filter_anisotropic) brings previously IP encumbered functionality into OpenGL to improve the visual quality of textured scenes GL_ARB_polygon_offset_clamp (based on GL_EXT_polygon_offset_clamp) suppresses a common visual artifact known as a “light leak” associated with rendering shadows GL_ARB_shader_atomic_counter_ops and GL_ARB_shader_group_vote add shader intrinsics supported by all desktop vendors to improve functionality and performance GL_KHR_no_error reduces driver overhead by allowing the application to indicate that it expects error-free operation so errors need not be generated In addition to the above features being added to OpenGL 4.6, the following are being released as extensions:
      GL_KHR_parallel_shader_compile allows applications to launch multiple shader compile threads to improve shader compile throughput WGL_ARB_create_context_no_error and GXL_ARB_create_context_no_error allow no error contexts to be created with WGL or GLX that support the GL_KHR_no_error extension “I’m proud to announce OpenGL 4.6 as the most feature-rich version of OpenGL yet. We've brought together the most popular, widely-supported extensions into a new core specification to give OpenGL developers and end users an improved baseline feature set. This includes resolving previous intellectual property roadblocks to bringing anisotropic texture filtering and polygon offset clamping into the core specification to enable widespread implementation and usage,” said Piers Daniell, chair of the OpenGL Working Group at Khronos. “The OpenGL working group will continue to respond to market needs and work with GPU vendors to ensure OpenGL remains a viable and evolving graphics API for all its customers and users across many vital industries.“
      The OpenGL 4.6 specification can be found at https://khronos.org/registry/OpenGL/index_gl.php. The GLSL to SPIR-V compiler glslang has been updated with GLSL 4.60 support, and can be found at https://github.com/KhronosGroup/glslang.
      Sophisticated graphics applications will also benefit from a set of newly released extensions for both OpenGL and OpenGL ES to enable interoperability with Vulkan and Direct3D. These extensions are named:
      GL_EXT_memory_object GL_EXT_memory_object_fd GL_EXT_memory_object_win32 GL_EXT_semaphore GL_EXT_semaphore_fd GL_EXT_semaphore_win32 GL_EXT_win32_keyed_mutex They can be found at: https://khronos.org/registry/OpenGL/index_gl.php
      Industry Support for OpenGL 4.6
      “With OpenGL 4.6 our customers have an improved set of core features available on our full range of OpenGL 4.x capable GPUs. These features provide improved rendering quality, performance and functionality. As the graphics industry’s most popular API, we fully support OpenGL and will continue to work closely with the Khronos Group on the development of new OpenGL specifications and extensions for our customers. NVIDIA has released beta OpenGL 4.6 drivers today at https://developer.nvidia.com/opengl-driver so developers can use these new features right away,” said Bob Pette, vice president, Professional Graphics at NVIDIA.
      "OpenGL 4.6 will be the first OpenGL release where conformant open source implementations based on the Mesa project will be deliverable in a reasonable timeframe after release. The open sourcing of the OpenGL conformance test suite and ongoing work between Khronos and X.org will also allow for non-vendor led open source implementations to achieve conformance in the near future," said David Airlie, senior principal engineer at Red Hat, and developer on Mesa/X.org projects.

      View full story
    • By _OskaR
      Hi,
      I have an OpenGL application but without possibility to wite own shaders.
      I need to perform small VS modification - is possible to do it in an alternative way? Do we have apps or driver modifictions which will catch the shader sent to GPU and override it?
  • Advertisement