Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 5 of 5

Thread: Shader Storage Block: read data from vertex shader in fragment shader

  1. #1
    Newbie Newbie
    Join Date
    Aug 2017
    Posts
    2

    Shader Storage Block: read data from vertex shader in fragment shader

    Hi all!

    Both my fragment and vertex shaders contain the following two guys:

    Code glsl:
    struct Light {
      mat4 view;
      mat4 proj;
      vec4 fragPos;
    };
     
    layout (std430, binding = 0) buffer Lights {
      Light lights[];
    };

    My problem is that that last field, fragPos, is computed by the vertex shader like this, but the fragment shader does not see the changes made by the vertex shader in fragPos (or any changes at all):

    Code glsl:
    aLight.fragPos = bias * aLight.proj * aLight.view * vec4(vs_frag_pos, 1.0);

    ... where aLight is lights[i] in a loop. As you can imagine I'm computing the position of the vertex in the coordinate systems of each light present to be used in shadow mapping. Any idea what's wrong here? Am I doing a fundamentally wrong thing?

    Here is how I initialize my storage:

    Code cpp:
    struct LightData {
      glm::mat4 view;
      glm::mat4 proj;
      glm::vec4 fragPos;
    };
     
    glGenBuffers(1, &BBO);
    glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, BBO);
     
    glNamedBufferStorage(BBO, lights.size() * sizeof(LightData), NULL, GL_DYNAMIC_STORAGE_BIT);
     
    // lights is a vector of a wrapper class for LightData.
    for (unsigned int i = 0; i < lights.size(); i++) {
      glNamedBufferSubData(BBO, i * sizeof(LightData), sizeof(LightData), &(lights[i]->data));
    }
    It may be worth noting that if I move fragPos to a fixed-size array out variable in the vertex shader out fragPos[2], leave the results there and then add the fragment shader counterpart in fragPos[2] and use that for the rest of my stuff then things are OK. So what I want to know more about here is why my fragment shader does not see the numbers crunched down by the vertex shader.

    Can any of you guy shed some light (heh) on this? Thanks!!
    Last edited by Dark Photon; 08-02-2017 at 07:32 AM.

  2. #2
    Member Regular Contributor
    Join Date
    Jul 2012
    Posts
    420
    Quote Originally Posted by gatperdut View Post
    fragPos, is computed by the vertex shader like this, but the fragment shader does not see the changes made by the vertex shader in fragPos (or any changes at all)
    I personally don't know. But the fact that a shader output is not seen from the next shader stage input makes me believe there's something wrong with the interfaces.
    See these links for more information:

    https://www.khronos.org/opengl/wiki/...e_Block_(GLSL)
    https://www.khronos.org/opengl/wiki/...rface_matching

  3. #3
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,411
    This approach can't work, for two reasons.

    First, if you have M vertices and N lights, you need MN positions. You can't get away with storing the light-space positions for the "current" vertex because there isn't a current vertex. The vertex shader is executed for multiple vertices concurrently, and it's effectively random as to which invocation's fragPos value will end up being stored.

    Second, the light-space position computed for each vertex needs to be interpolated across the primitive to provide a light-space position for each fragment.

    If you want to perform shadow mapping for multiple lights concurrently, you need a vertex shader output which is an array of light-space positions, with one element per light. If you have many lights, you're going to run into an implementation-dependent limitation on the maximum number of vertex shader outputs.

  4. #4
    Newbie Newbie
    Join Date
    Aug 2017
    Posts
    2
    Quote Originally Posted by GClements View Post
    If you want to perform shadow mapping for multiple lights concurrently, you need a vertex shader output which is an array of light-space positions, with one element per light. If you have many lights, you're going to run into an implementation-dependent limitation on the maximum number of vertex shader outputs.
    Hey, thanks for your answer. Your suggested solution sounds a lot like what I'm trying to do.

    When a vertex (whatever its order) is processed it receives a shader storage block which effectively holds an array with all N light structures present in the scene. Each one of these light-data structures has a fragPos field (uninitialized and ignored by my c++ code) which the vertex shader is supposed to fill, once per light, by iterating over this lights array, computing the light-space coordinates (with the help of that particular's light proj and view matrices) and leaving that mat4 in the corresponding light's fragPos field. So after one iteration of the vertex shader has run, it has effectively computed the vertex light-space position N times, one per light. Given M vertices, that's MxN as you suggested.

    Maybe I'm talking nonsense? If that's the case sorry! I'm just thinking that perhaps I'm running into a synchronization problem?

    Edit - Also, as stated, if I move my light-space computations to the fragment shader, effectively running them for every fragment, things are OK. Not very efficient, though, hence my attempt at performing them in the vertex shaders so they are interpolated.
    Edit2 - Someone mentioned I may be running into a situation where memoryBarriers are needed. I'll read the spec for them and see if I can come up with something.
    Last edited by gatperdut; 08-03-2017 at 06:33 AM.

  5. #5
    Senior Member OpenGL Guru
    Join Date
    Jun 2013
    Posts
    2,411
    Quote Originally Posted by gatperdut View Post
    When a vertex (whatever its order) is processed it receives a shader storage block
    There appears to be only one shader storage block for all vertices.

    Vertices aren't processed sequentially, they're processed in parallel (well, groups of vertices are processed in parallel). And if a single vertex is used several times in a single draw call, the vertex shader may only be invoked once; the results will be cached and re-used for subsequent primitives.

    Performing MN transformations doesn't help when you only have space to store N results (i.e. the per-light positions for a single vertex).

    As it stands, when the fragment shader is invoked, lights[i].fragPos contains the position of a random vertex relative to a specific light. The vertex won't necessarily be one of the vertices of the primitive containing the fragment being rendered. For two lights i and j, lights[i].fragPos and lights[j].fragPos might not even refer to the same vertex.

    And the position will be that of a vertex, not that of the fragment. I.e. it won't be interpolated; only output variables are interpolated, not buffer variables.

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •