OpenGL-一次将所有数据传递到着色器时遇到麻烦

I'm trying to display textures on quads (2 triangles) using opengl 3.3

Drawing a texture on a quad works great; however when I have ONE textures (sprite atlas) but using 2 quads(objects) to display different parts of the atlas. When in draw loop, they end up switching back and fourth(one disappears than appears again, etc) at their individual translated locations.

The way I'm drawing this is not the standard DrawElements for each quad(or object) but I package all quads, uv, translations, etc send them up to the shader as one big chunk (as "in" variables): Vertex shader:

 #version 330 core

// Input vertex data, different for all executions of this shader.
in vec3 vertexPosition_modelspace;
in vec3 vertexColor;
in vec2 vertexUV;
in vec3 translation;
in vec4 rotation;
in vec3 scale;
// Output data ; will be interpolated for each fragment.
out vec2 UV;
// Output data ; will be interpolated for each fragment.
out vec3 fragmentColor;
// Values that stay constant for the whole mesh.
uniform mat4 MVP;

...

void main(){


    mat4 Model = mat4(1.0);

    mat4 t = translationMatrix(translation);
    mat4 s = scaleMatrix(scale);
    mat4 r = rotationMatrix(vec3(rotation), rotation[3]);

    Model *= t * r * s;


    gl_Position = MVP * Model * vec4 (vertexPosition_modelspace,1); //* MVP;

    // The color of each vertex will be interpolated
    // to produce the color of each fragment
    fragmentColor = vertexColor;

    // UV of the vertex. No special space for this one.
    UV = vertexUV;

}

Is the vertex shader working as I think it would with a large chunk of data - that it draws each segment passed up as uniform individually because it does not seem like it? Is my train of thought correct on this?

For completeness this is my fragment shader:

#version 330 core

// Interpolated values from the vertex shaders
in vec3 fragmentColor;

// Interpolated values from the vertex shaders
in vec2 UV;

// Ouput data
out vec4 color;

// Values that stay constant for the whole mesh.
uniform sampler2D myTextureSampler;

void main()
{

    // Output color = color of the texture at the specified UV
    color = texture2D( myTextureSampler, UV ).rgba;

}

A request for more information was made so I will put how i bind this data up to the vertex shader. The following code is just one I use for my translations. I have more for color, rotation, scale, uv, etc:

gl.BindBuffer(gl.ARRAY_BUFFER, tvbo)
gl.BufferData(gl.ARRAY_BUFFER, len(data.Translations)*4, gl.Ptr(data.Translations), gl.DYNAMIC_DRAW)
tAttrib := uint32(gl.GetAttribLocation(program, gl.Str("translation\x00")))
gl.EnableVertexAttribArray(tAttrib)
gl.VertexAttribPointer(tAttrib, 3, gl.FLOAT, false, 0, nil)

...

gl.DrawElements(gl.TRIANGLES, int32(len(elements)), gl.UNSIGNED_INT, nil)

Since I needed more input on this matter, I linked this page to reddit and someone was able to help me with one response! Anyways the reddit link is here:

https://www.reddit.com/r/opengl/comments/3gyvlt/opengl_passing_all_scene_data_into_shader_each/

The issue of seeing two individual textures/quads after passing all vertices as one data structure over to vertex shader was because my element indices were off. I needed to determine the correct index of each set of vertices for my 2 triangle(quad) objects. Simply had to do something like this:

        vertexInfo.Elements = append(vertexInfo.Elements, uint32(idx*4), uint32(idx*4+1), uint32(idx*4+2), uint32(idx*4), uint32(idx*4+2), uint32(idx*4+3))

You have just single sampler2D

  • which means you have just single texture at your disposal
  • regardless on how many of them you bind.
  • If you really need to pass the data as single block
  • then you should add sampler per each texture you got
  • not sure how many objects/textures you have
  • but you are limited by gfx hw limit on texture units with this way of data passing
  • also you need to add another value to your data telling which primitive use which texture unit
  • and inside fragment then select the right texture sampler ...

You should add stuff like this:

// vertex
in int usedtexture;
out int txr;

void main()
 {
 txr=usedtexture;
 }

// fragment
uniform sampler2D myTextureSampler0;
uniform sampler2D myTextureSampler1;
uniform sampler2D myTextureSampler2;
uniform sampler2D myTextureSampler3;
in vec2 UV;
in int txr;
out vec4 color;
void main
 {
      if (txr==0) color = texture2D( myTextureSampler0, UV ).rgba;
 else if (txr==1) color = texture2D( myTextureSampler1, UV ).rgba;
 else if (txr==2) color = texture2D( myTextureSampler2, UV ).rgba;
 else if (txr==3) color = texture2D( myTextureSampler3, UV ).rgba;
 else color=vec4(0.0,0.0,0.0,0.0);
 }

This way of passing is not good for these reasons:

  • number of used textures is limited to HW texture units limit
  • if your rendering would need additional textures like normal/shininess/light maps
  • then you need more then 1 texture per object type and your limit is suddenly divided by 2,3,4...
  • You need if/switch statements inside fragment which can slow things down considerably
  • Yes you can do it brunch less but then you would need to access all textures all the time increasing heat stress on gfx without reason...

This kind of passing is suitable for

  • all textures inside single image (as you mentioned texture atlas)
  • which can be faster this way and reasonable for scenes with small number of object types (or materials) but large object count...