1

我正在尝试在 OpenGL 中创建一个简单的 GUI。我创建了一张图片,因此我可以参考它并使解释更简单:

纹理贴图

当我将按钮 (32x32) 的纹理应用到大小为 120x20 的四边形(即不是矩形作为纹理)上时,MLMR被拉伸成非常粗的线条,这使得按钮看起来难看。我知道,通过为每个线段( TLTMTR等)创建一个新的四边形并将部分纹理应用到每个线段,我可以避免如图所示的失真:

扭曲的纹理

问题 #1:我能否以某种方式将源纹理的一部分应用于四边形的确切位置?我可以取纹理的TL/ML/BL部分并在四边形的最左侧应用垂直拉伸,然后取TM/MM/BM并在前一部分旁边应用水平拉伸, ETC。?因为我只需要4个顶点,它甚至可能而且会更快吗?

  • 换句话说,我可以只拉伸纹理的一部分吗?垂直拉伸一些部分,水平拉伸一些部分,然后将此多拉伸纹理应用于多边形?

问题#2:如果不可能,我将如何减少所需的顶点数量?创建 9x4vert 四边形需要 36 个顶点,但如果我让它们共享所有可以共享的顶点,我可以将这个数字减少到 16 个吗?

答案:

我一直在工作很长时间,手工绘制所有索引和坐标并将其放在纸上,所以我希望这对某人有用。我希望它是正确的,尽管它对我来说很好。它在 C# 中,但将其转换为 C++ 是微不足道的。

编辑:我一直在研究它,这是 3x3 平面的最终顶点/索引数组。

    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
                                      };
4

3 回答 3

2

我知道,通过为每个线段(TL、TM、TR 等)创建一个新的四边形并将部分纹理应用到每个线段,我可以避免如图所示的失真

这正是你应该做的。

问题#2:如果不可能,我将如何减少所需的顶点数量?

你当然可以,而且你应该共享边缘相交的顶点,因为你的纹理映射在那里是连续的,只有一阶导数会发生变化,这是完全有序的。

于 2012-08-09T13:24:07.360 回答
1

我还没有听说过任何关于拉伸纹理部分的事情。在您的情况下,不仅MLMR被拉伸,MM也被拉伸。它只是不那么明显,因为MM是一种颜色。

关于您的问题...您可以将按钮的多边形划分为 9 个四边形,就像您发布的图片中一样?然后您可以对纹理进行切片并将其不同部分应用到不同的四边形上。这就是我目前能想到的。

关于问题 #2 - 我相信您应该查看顶点和索引缓冲区。基本上,顶点缓冲区是所有唯一顶点的缓冲区,索引缓冲区按顺序保存顶点缓冲区中顶点的索引,当您从它们组装三角形时它们出现的顺序。在索引缓冲区中,一个索引可以出现多次(这就是这个缓冲区的目的——所以你不能多次拥有相同的顶点)。

于 2012-08-09T13:13:07.100 回答
0

而不是用四个点绘制 OpenGL 多边形,每个点都有纹理坐标

请尝试用更多的点来制作它,以便您可以控制纹理的哪一部分将被拉伸。参考您的图像,您可以在 OpenGL 中制作 9 个矩形,以避免拉伸边距。

于 2012-08-09T13:25:57.010 回答