首页 > 解决方案 > 在 OpenGL 中计算立方体上的 UV 映射纹理图集

问题描述

我一直在用 C 语言对一个用 OpenGL 构建的 MineCraft 应用程序进行逆向工程。如果您不知道,游戏涉及立方体的生成,立方体的 UV 贴图纹理,然后将它们放置在您(通常)添加的世界中,并删除以构建和销毁(以及更多)。

游戏功能齐全。有用。一切都呈现。所有功能都正常。但是我遇到了很多麻烦(几天),从纹理图集重建立方体上的 UV 映射。具体问题是我不明白这个系统是如何使用 UV 映射将纹理映射到立方体上的。我已经对这篇文章中提到的函数进行了逆向工程、重构和手动计算,但从我读过的所有资源来看,我还不够。如果有人足够亲切地帮助我了解我理解错误的内容,和/或这个函数是如何做它正在做的事情,我会非常高兴。这是最后一部分,是我从里到外理解的应用程序的其余部分。现在就是这个了。

一个函数被用来创建顶点缓冲区数据、法线数据和纹理数据,以便在构建立方体后下推 GL 管道。

我正在逆向工程的函数中的顶点数据是不言自明的,因为它只是使用笛卡尔坐标系。正常的数据,也很简单。但是紫外线数据,我已经在这上面旋转了三天。我被卡住的一个原因是所有的 UV 贴图教程要么涉及在正方形的所有 6 个面上使用的单个正方形纹理,要么涉及未散开的立方体纹理。这个 Minecraft 不使用其中任何一个。它使用 3x1 矩形地图。底部,中间,顶部。中间用作所有侧面(左,右,前,后),顶部和底部是独立的。

另一个原因是当我完成数学运算时(我一遍又一遍地检查我的计算),我无法得出与程序相同的答案。程序运行良好,可以正常工作。所以我知道我错过了一些东西。

我已经在我的白板上绘制了 UV 坐标,研究/阅读了许多来源的 UV 映射(我将在下面引用),我只是无法弄清楚这个公式是如何工作的。主要原因是不存在的文档和相对模糊的命名约定,人们用于创建这些功能。但是,尽管如此,我已经接近完成所有事情了。这是我需要了解的最后一块,以便整个拼图到位。

根据我对其工作原理的理解,使用 UV 纹理映射,UV 或 ST 坐标映射与笛卡尔坐标相同,只是它们来自 [0..1]。但是从我所看到的这个应用程序中的算法(有效)来看,我一定遗漏了一些东西。

我看它的方式,或者至少我在多个地方读过的内容是,无论你的顶点在哪里,无论你想渲染它们,无论你希望纹理的左下角在哪里,你都可以放置它你会认为你的左下顶点在哪里。纹理的右上角,右上角的顶点。等等。当我对其中的一些进行数学计算时,当我用正确的 [0..1] 坐标代替 <x,y,z> 向量时,有 4 / 6 的方程得到了平移。

仅供参考,纹理图集从左到右有 16 个“行”或纹理。但每个立方体由 3 个纹理方块组成。没有“左”、“右”或“后”,因为“前”纹理用于每一侧。意思是,左 = 前 = 后 = 左......最终,顶部,中间 x 4,底部。每个纹理块0.0625又宽又0.0625高。一共是16个。

这是使用的实际纹理图集。 16 个纹理,在 0..1 归一化坐标中,它们每个是 0.0625 个坐标。

当函数开始时,它减去以1w开始纹理坐标0,而不是1。然后它运行,为每个点设置坐标,进入下一个内存空间并为其分配以下坐标。它一遍又一遍地这样做,*vector_data因为指向*vector*normal_data指向*normal。这一切都很直观。

但是来到*texture_data指向“*纹理”的地方,对我来说就是地狱和手篮。

我使用值(0, 0, 0)作为初始(x, y, z)值 ,w = 1n = 0.5所有面孔 ,int left, int right, int top, int bottom, int front, int back = 1, 1, 1, 1, 1, 1来尝试剖析它,因为在我下面引用的资源中找不到明确的信息,至少这可以帮助我解决这个问题,我可以理解.

只是为了让您知道我已经尝试了所有我认为可以的方法,我还将向您提供我在此应用程序中运行的数据,这些数据与我的方程式不匹配。

有问题的功能。

make_cube(float *vector, float *normal, float *texture, int left, int right, int top, int bottom, int front, int back,
          float x, float y, float z, float n, int w) {
    float *vector_data = vector;
    float *normal_data = normal;
    float *texture_data = texture;
    float s = 1.0f / 16; // 0.0625f
    float a = 0;
    float b = 1.0f / 16; // 0.0625
//    float b = s; // 0.0625
    float du, dv;
    float ou, ov;
    w--;
    ou = (w % 16) * s; // w % 16 * 0.0625 width offset... the position of the texture times the width percentage of textures texture_pos * (1 / 16)
    ov = (w / 16 * 3) * s; // height offset

    // 108 data points, or 36 (3D) vector_data for the cube
    // 108 data points, or 36 (3D) normal_data for the cube
    // 72 data points, or  36 (2D) texture_data for the cube
    if (left) {
        du = ou; dv = ov + s;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x - n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(vector_data++) = x - n; *(vector_data++) = y + n; *(vector_data++) = z - n;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z + n;
        *(vector_data++) = x - n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(normal_data++) = -1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = -1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = -1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = -1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = -1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = -1; *(normal_data++) = 0; *(normal_data++) = 0;

        // hint: z appears to be interchanged with y in pattern
        //   and x's pattern doesn't matter.
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
    }
    if (right) {
        du = ou; dv = ov + s;
        *(vector_data++) = x + n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(vector_data++) = x + n; *(vector_data++) = y - n; *(vector_data++) = z + n;
        *(vector_data++) = x + n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(normal_data++) = 1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = 1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = 1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = 1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = 1; *(normal_data++) = 0; *(normal_data++) = 0;
        *(normal_data++) = 1; *(normal_data++) = 0; *(normal_data++) = 0;

        // hint: z appears to be interchanged with y in pattern
        //   and x's pattern doesn't matter.
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
    }
    if (top) {
        du = ou; dv = ov + s + s;
        *(vector_data++) = x - n; *(vector_data++) = y + n; *(vector_data++) = z - n;
        *(vector_data++) = x - n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(vector_data++) = x - n; *(vector_data++) = y + n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z - n;
        *(normal_data++) = 0; *(normal_data++) = 1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = 1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = 1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = 1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = 1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = 1; *(normal_data++) = 0;

        // hint: the pattern seems to be with x and z, (not y) because it remains the same
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
    }
    if (bottom) {
        du = ou; dv = ov + 0;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y - n; *(vector_data++) = z + n;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y - n; *(vector_data++) = z + n;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z + n;
        *(normal_data++) = 0; *(normal_data++) = -1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = -1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = -1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = -1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = -1; *(normal_data++) = 0;
        *(normal_data++) = 0; *(normal_data++) = -1; *(normal_data++) = 0;

        // hint: the pattern seems to fit with x, z and negate y
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
    }
    if (front) {
        du = ou; dv = ov + s;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z + n;
        *(vector_data++) = x + n; *(vector_data++) = y - n; *(vector_data++) = z + n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z + n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(vector_data++) = x - n; *(vector_data++) = y + n; *(vector_data++) = z + n;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = -1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = -1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = -1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = -1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = -1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = -1;

        // hint: u seems to link with x, and v with y (but the opposite)
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
    }
    if (back) {
        du = ou; dv = ov + s;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x - n; *(vector_data++) = y - n; *(vector_data++) = z - n;
        *(vector_data++) = x - n; *(vector_data++) = y + n; *(vector_data++) = z - n;
        *(vector_data++) = x + n; *(vector_data++) = y + n; *(vector_data++) = z - n;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = 1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = 1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = 1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = 1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = 1;
        *(normal_data++) = 0; *(normal_data++) = 0; *(normal_data++) = 1;

        // hint: the texture u seems to link with x, and v with y
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;


        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = b + du; *(texture_data++) = a + dv;
        *(texture_data++) = a + du; *(texture_data++) = b + dv;
        *(texture_data++) = b + du; *(texture_data++) = b + dv;
    }
}

当我left从程序本身得到 的结果时,这就是我得到的顶点:

x = 0.500000, y = 0.500000, z = 0.500000
x = 0.500000, y = 1.500000, z = 1.500000
x = 0.500000, y = 1.500000, z = 0.500000
x = 0.500000, y = 0.500000, z = 0.500000
x = 0.500000, y = 0.500000, z = 1.500000
x = 0.500000, y = 1.500000, z = 1.500000

和纹理数据...(请记住,因为left立方体,是第二个向上(v = 0.0625)和x起始位置是u = 0),所以UV中的原点是0, 0.0625

x = 0.000000, y = 0.062500
x = 0.062500, y = 0.125000
x = 0.000000, y = 0.125000
x = 0.000000, y = 0.062500
x = 0.062500, y = 0.062500
x = 0.062500, y = 0.125000

但是我手动计算,当我将坐标应用到 UV 贴图定位时,我实际上得到了......我这样做的方式是每次我得到一个

x = 0.000000, y = 0.062500
x = 0.062500, y = 0.125000
x = 0.062500, y = 0.062500
x = 0.000000, y = 0.062500
x = 0.000000, y = 0.125000
x = 0.062500, y = 0.125000

我不认为我得到了几乎正确的值是偶然的。立方体也没有相同的渲染纹理。其中一些是颠倒的,使纹理看起来有机地连接到另一个。以下是围绕立方体逆时针旋转时的 4 个侧面的一些屏幕截图。

正面剩下 左后 右后退 _ 正确的

有谁知道这是如何工作的?有人可以指出我的方向吗?我觉得我一直在看这个太久了,我无法透过树木看到森林。我需要了解这些 UV 坐标是如何映射到这个立方体的每个特定侧面的。

如果其他人有兴趣,这里是顶点和纹理数据的其余输出(分别在同一代码块中)。

正确的

x = 1.500000, y = 0.500000, z = 0.500000
x = 1.500000, y = 1.500000, z = 1.500000
x = 1.500000, y = 0.500000, z = 1.500000
x = 1.500000, y = 0.500000, z = 0.500000
x = 1.500000, y = 1.500000, z = 0.500000
x = 1.500000, y = 1.500000, z = 1.500000

x = 0.062500, y = 0.062500
x = 0.000000, y = 0.125000
x = 0.000000, y = 0.062500
x = 0.062500, y = 0.062500
x = 0.062500, y = 0.125000
x = 0.000000, y = 0.125000

最佳

x = 0.500000, y = 1.500000, z = 0.500000
x = 0.500000, y = 1.500000, z = 1.500000
x = 1.500000, y = 1.500000, z = 1.500000
x = 0.500000, y = 1.500000, z = 0.500000
x = 1.500000, y = 1.500000, z = 1.500000
x = 1.500000, y = 1.500000, z = 0.500000


x = 0.000000, y = 0.187500
x = 0.000000, y = 0.125000
x = 0.062500, y = 0.125000
x = 0.000000, y = 0.187500
x = 0.062500, y = 0.125000
x = 0.062500, y = 0.187500

底部

x = 0.500000, y = 0.500000, z = 0.500000
x = 1.500000, y = 0.500000, z = 0.500000
x = 1.500000, y = 0.500000, z = 1.500000
x = 0.500000, y = 0.500000, z = 0.500000
x = 1.500000, y = 0.500000, z = 1.500000
x = 0.500000, y = 0.500000, z = 1.500000


x = 0.000000, y = 0.000000
x = 0.062500, y = 0.000000
x = 0.062500, y = 0.062500
x = 0.000000, y = 0.000000
x = 0.062500, y = 0.062500
x = 0.000000, y = 0.062500

正面

x = 0.500000, y = 0.500000, z = 1.500000
x = 1.500000, y = 0.500000, z = 1.500000
x = 1.500000, y = 1.500000, z = 1.500000
x = 0.500000, y = 0.500000, z = 1.500000
x = 1.500000, y = 1.500000, z = 1.500000
x = 0.500000, y = 1.500000, z = 1.500000


x = 0.062500, y = 0.062500
x = 0.000000, y = 0.062500
x = 0.000000, y = 0.125000
x = 0.062500, y = 0.062500
x = 0.000000, y = 0.125000
x = 0.062500, y = 0.125000

后退

x = 0.500000, y = 0.500000, z = 0.500000
x = 1.500000, y = 1.500000, z = 0.500000
x = 1.500000, y = 0.500000, z = 0.500000
x = 0.500000, y = 0.500000, z = 0.500000
x = 0.500000, y = 1.500000, z = 0.500000
x = 1.500000, y = 1.500000, z = 0.500000


x = 0.000000, y = 0.062500
x = 0.062500, y = 0.125000
x = 0.062500, y = 0.062500
x = 0.000000, y = 0.062500
x = 0.000000, y = 0.125000
x = 0.062500, y = 0.125000

如果有人能弄清楚这一点,我将不胜感激。只是为了让我的心平静下来。我被称为杰克沙沙猎犬——无法放手。

我很想看看我缺少的简单的东西!如果你已经走了这么远,谢谢!

以下是我用来解决这个问题的一些参考资料。

http://www.opengl-tutorial.org/beginners-tutorials/tutorial-5-a-textured-cube/ https://gamedev.stackexchange.com/questions/152991/how-can-i-calculate-normals-使用-a-vertex-and-index-buffer https://gamedev.stackexchange.com/questions/172352/finding-texture-coordinates-for-plane https://gamedev.net/forums/topic/626790-uv- mapping-where-do-the-uv-coordinates-correspond-to-on-a-square-texture/4951976/ https://github.com/Hopson97/MineCraft-One-Week-Challenge/blob/master/Source/纹理/TextureAtlas.cpp https://en.wikipedia.org/wiki/UV_mapping https://gamedev.stackexchange.com/questions/25057/help-a-2d-image-onto-a-3d-cube OpenGL 4 -三角带立方体的 UV 坐标 https://conceptartempire.com/uv-mapping-unwrapping/ Dave Astle 的《开始 OpenGL 游戏编程》第 151 - 158 页(纹理映射)

标签: copenglverticesuv-mapping

解决方案


推荐阅读