1
votes

I am attempting to create a simple GUI in OpenGL. I have created a picture so I can refer to it and make the explanation simpler:

texture map

When I apply a texture of a button (32x32) onto a quad polygon with the size of 120x20 (i.e. not a rectangle as the texture), ML and MR get stretched into very thick lines and it makes the button look unsightly. I know that by creating a new quad polygon for each of the segments (TL, TM, TR, etc.) and applying a part of the texture to each of them, I can avoid the distortion as shown in the picture:

Distorted texture

Question #1: Can I somehow apply parts of a source texture on exact position of a quad polygon? Could I take the TL/ML/BL part of the texture and apply it with vertical stretching on the left-most side of the quad polygon, then take TM/MM/BM and apply them with horizontal stretching right next to the previous part, etc.? Is it even possible and would it be faster, since I'd only need 4 vertices?

  • To rephrase, could I stretch only parts of a texture? Stretch some parts vertically and some parts horizontally and then apply this multi-stretched texture to a polygon?

Question #2: If it's not possible, how would I go about reducing the number of vertices needed? Creating 9x4vert quads needs 36 vertices, but if I made them share all the vertices that can be shared, I could reduce this number to 16?

The answer:

I have been working very long, drawing all the indices and coordinates by hand and putting it together on paper, so I hope this will be useful to someone. I hope it is correct, although it works fine for me. It is in C#, but translating it to C++ is trivial.

Edit: I've been working on it a whole lot longer and this is the final vertex/index array for a 3x3 plane.

    public Vector3[] VertexData = new[]
                                    {
                                        new Vector3(-1.0f, -1.0f, 0.0f),
                                        new Vector3(-0.33f, -1.0f, 0.0f),
                                        new Vector3(0.33f, -1.0f, 0.0f),
                                        new Vector3(1.0f, -1.0f, 0.0f),

                                        new Vector3(-1.0f, -0.33f, 0.0f),
                                        new Vector3(-0.33f, -0.33f, 0.0f),
                                        new Vector3(0.33f, -0.33f, 0.0f),
                                        new Vector3(1.0f, -0.33f, 0.0f),

                                        new Vector3(-1.0f, 0.33f, 0.0f),
                                        new Vector3(-0.33f, 0.33f, 0.0f),
                                        new Vector3(0.33f, 0.33f, 0.0f),
                                        new Vector3(1.0f, 0.33f, 0.0f),

                                        new Vector3(-1.0f, 1.0f, 0.0f),
                                        new Vector3(-0.33f, 1.0f, 0.0f),
                                        new Vector3(0.33f, 1.0f, 0.0f),
                                        new Vector3(1.0f, 1.0f, 0.0f)
                                    };

    public Vector3[] NormalData = new[]
                                   {
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),

                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),

                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),

                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f),
                                       new Vector3(0f, 0f, 1f)
                                   };

    public Vector2[] TextureData = new[]
                                   {
                                       new Vector2(0.0f, 1.0f),
                                       new Vector2(0.33f, 1.0f),
                                       new Vector2(0.66f, 1.0f), 
                                       new Vector2(1.0f, 1.0f), 

                                       new Vector2(0.0f, 0.66f),
                                       new Vector2(0.33f, 0.66f),
                                       new Vector2(0.66f, 0.66f), 
                                       new Vector2(1.0f, 0.66f), 

                                       new Vector2(0.0f, 0.33f), 
                                       new Vector2(0.33f, 0.33f), 
                                       new Vector2(0.66f, 0.33f), 
                                       new Vector2(1.0f, 0.33f), 

                                       new Vector2(0.0f, 0.0f), 
                                       new Vector2(0.33f, 0.0f), 
                                       new Vector2(0.66f, 0.0f), 
                                       new Vector2(1.0f, 0.0f) 
                                   };

    public UInt32[] IndicesData = new UInt32[54]
                                      {
                                          0, 1, 5,
                                          0, 4, 5,
                                          1, 2, 6,
                                          1, 5, 6,
                                          2, 3, 7,
                                          2, 6, 7,

                                          4, 5, 9,
                                          4, 8, 9,
                                          5, 6, 10,
                                          5, 9, 10,
                                          6, 7, 11,
                                          6, 10, 11,

                                          8, 9, 13,
                                          8, 12, 13,
                                          9, 10, 14,
                                          9, 13, 14,
                                          10, 11, 15,
                                          10, 14, 15
                                      };
3

3 Answers

2
votes

I know that by creating a new quad polygon for each of the segments (TL, TM, TR, etc.) and applying a part of the texture to each of them, I can avoid the distortion as shown in the picture

And that's exactly what you should to.

Question #2: If it's not possible, how would I go about reducing the number of vertices needed?

You can of course, and you should share the vertices where the edges meet, as your texture mapping is continous there and only the 1st derivative changes, which is completely in order.

1
votes

I haven't heard anything about stretching parts of a texture. In your case not only the ML and MR are being stretched, MM is stretched too. It is just not that visible as MM is one colour.

About your problem... can you partition the polygon of the button to 9 quads, like in the picture you posted? Then you can slice the texture and apply the different parts of it on the different quads. That's all I can think of at the moment.

About question #2 - you should look at vertex and index buffers, I believe. Basically, the vertex buffer is a buffer of all the unique vertices, and the index buffer holds the indices of the vertices from the vertex buffer in the order, in which they appear when you assemble triangles from them. In the index buffer an index can appear more than once (that is the purpose of this buffer - so you don't have the same vertices more than once).

0
votes

Instead of drawing the OpenGL polygon with four points each with texture coordinates

please try to make it with more points so you can control which part of the texture will be stretched. referring to your image you can make 9 rectangles in OpenGL to avoid the stretching of the margins.