通过重新排列其四个角来旋转和翻转正方形(纹理四边形)

Rotate and flip square (texture quad) by reordering its four corners

我有一个正方形,它的四个角从左上角开始按逆时针方向排列。所以我基本上有一个坐标数组
[TL, BL, BR, TR]
它用于二维纹理坐标,但这对问题影响不大。
我想应用 90° 旋转并水平和垂直翻转到这些坐标。我想通过指定一个 "transform" 来做到这一点,该 "transform" 保存向右或向左 90° 旋转的次数和 h/v 翻转的标志。然后我想使用该变换将坐标复制到一个新位置,并根据变换以新顺序排列。所以 rot_0/xflip_0/yflip_1 会导致
[TR, BR, TL, BL]
(我通常将翻转定义为沿命名轴的反射,但这只是术语。)

如何在不在长列表中写下所有情况的情况下创建相应的坐标顺序?我对可以指定的 90° 旋转(3/4/无限)的数量很灵活,我也可以使用多个不同的变换给出相同的结果,或者选择器只包含覆盖所有的最小规格可能的转换。

达到所有最终状态所需的最小转换是什么? two/one方向的旋转和单轴翻转是否足够?

看起来像

Math.abs(invert*3 - ((coord + rot) % 4)));

可以做到这一点。
我们有四个角和四个可以放置它们的槽。这给出了一个基本的 4 组!排列。然而,该组中有 2/3 的纹理角顺序不正确。唯一的acceptable订单是四次旋转的原始CCW订单和四次旋转的反向CW订单。这意味着我们需要四次旋转和一次沿向上向量的翻转来实现所有变换。
要计算旋转,只需 shift/rotate 数组本身就足够了。所以目标数组中的每个条目都变成 coord+rot 并且为了保持循环可以使用模 4。
要沿向上向量翻转,我们必须反转顺序,这可以通过 3 坐标来完成。如果我们想使用 0/1 反转参数,我们需要处理负值,因此需要 abs() 方法。
问:有没有不同的方法来处理这个问题?不需要条件求值的公式?

我不想每次更新纹理坐标时都评估 abs() 条件,我不想将转换后的纹理坐标存储在 GPU 以外的任何地方。所以我实际上最终用所有 8 个转换填充了一个简短的 table。使用循环变得非常难看

for (int invert = 0; invert < 2; invert++)
    for (int shift = 0; shift < 4; shift++) {
        System.out.println("");
        for (int coord = 0; coord < 4; coord++) {
            System.out.print(Math.abs(invert*3 - ((coord + shift) % 4)));
        }
        System.out.println("");
    }

所以我简单地用 8 个转换手动初始化了一个数组。

char texTransform[8 * 4] = {    0, 1, 2, 3,
                                1, 2, 3, 0,
                                2, 3, 0, 1,
                                3, 0, 1, 2,
                                3, 2, 1, 0,
                                2, 1, 0, 3,
                                1, 0, 3, 2,
                                0, 3, 2, 1
                        };

并根据旋转和翻转参数计算特定变换的查找。

public static int textureTransform(int rot, int flip){
    int tf = rot % 4 + (flip % 2) * 4;
    return ( tf >= 0 ) ? tf : 0;
}

然后复制纹理坐标只需要根据变换索引参数查找角顺序。 (在我的例子中是 JNI 代码)

void nativeCopyFrameCoords(JNIEnv *env, jclass cl, jobject src, jint srcOffset, jobject dst,  jint dstOffset, jint tf)
  {
           float* pSrc = (float*) (*env)->GetDirectBufferAddress( env, src );
           float* pDst = (float*) (*env)->GetDirectBufferAddress( env, dst );

           char* selector = texTransform+tf*4;

           pDst[dstOffset +0] = pSrc[srcOffset + selector[0]*2];
           pDst[dstOffset +1] = pSrc[srcOffset + selector[0]*2 +1];

           pDst[dstOffset +2] = pSrc[srcOffset + selector[1]*2];
           pDst[dstOffset +3] = pSrc[srcOffset + selector[1]*2 +1];

           pDst[dstOffset +4] = pSrc[srcOffset + selector[2]*2];
           pDst[dstOffset +5] = pSrc[srcOffset + selector[2]*2 +1];

           pDst[dstOffset +6] = pSrc[srcOffset + selector[3]*2];
           pDst[dstOffset +7] = pSrc[srcOffset + selector[3]*2 +1];
  }

(如果不需要转换,则应调用 memcopy 而不是一个一个地设置值。memcpy( &pDst[dstOffset], &pSrc[srcOffset], sizeof(float) * 8 );