zoukankan      html  css  js  c++  java
  • openGL 坐标系的互相转换

    openGL坐标系包括旋转,平移,缩放被塞在一个矩阵里面。

    坐标系之间的转换基础是矩阵的运算。

    每个矩阵代表的坐标系,就是是原点坐标系通过旋转。平移,缩放得到的坐标系。

    当一个矩阵右乘一个向量或是还有一个矩阵,意味着把右边的变换。变成相对于左边的矩阵坐标系之上。



    假设把一个世界坐标的X转换到一个矩阵上,我们能够矩阵右乘这个坐标:

    static float multiplyMX(Matrix4* matrix, float x) {
    	return matrix->m[0] * x + matrix->m[4] + matrix->m[8] + matrix->m[12];
    }
    


    假设把一个世界坐标Y转换到一个矩阵上。我们能够矩阵右乘这个坐标:

    static float multiplyMY(Matrix4* matrix, float y) {
    	return matrix->m[1] + matrix->m[5] * y + matrix->m[9] + matrix->m[13];
    }


    假设把一个世界坐标点转换到一个矩阵上,我们能够矩阵右乘这个点:

    static void multiplyMV4(Matrix4* matrix, float x, float y, float z, float w, Out(Vector4* result)) {
    	result->v[0] = matrix->m[0] * x + matrix->m[4] * y + matrix->m[8]  * z + matrix->m[12] * w;
    	result->v[1] = matrix->m[1] * x + matrix->m[5] * y + matrix->m[9]  * z + matrix->m[13] * w;
    	result->v[2] = matrix->m[2] * x + matrix->m[6] * y + matrix->m[10] * z + matrix->m[14] * w;
    	result->v[3] = matrix->m[3] * x + matrix->m[7] * y + matrix->m[11] * z + matrix->m[15] * w;
    }
    
    
    static void multiplyMV3(Matrix4* matrix, float x, float y, float z, Out(Vector3* result)) {
    	result->v[0] = matrix->m[0] * x + matrix->m[4] * y + matrix->m[8]  * z + matrix->m[12];
    	result->v[1] = matrix->m[1] * x + matrix->m[5] * y + matrix->m[9]  * z + matrix->m[13];
    	result->v[2] = matrix->m[2] * x + matrix->m[6] * y + matrix->m[10] * z + matrix->m[14];
    }
    
    
    static void multiplyMV2(Matrix4* matrix, float x, float y, Out(Vector2* result)) {
    	result->v[0] = matrix->m[0] * x + matrix->m[4] * y + matrix->m[8] + matrix->m[12];
    	result->v[1] = matrix->m[1] * x + matrix->m[5] * y + matrix->m[9] + matrix->m[13];
    }



    
    

    假设把一个世界坐标系转换到一个矩阵上,我们矩阵右乘这个矩阵:

    static void multiplyMM(Matrix4* left, Matrix4* right, Out(Matrix4* result)) {
      result->m[0]  = left->m[0] * right->m[0]  + left->m[4] * right->m[1]  + left->m[8]  * right->m[2]  + left->m[12] * right->m[3];
      result->m[1]  = left->m[1] * right->m[0]  + left->m[5] * right->m[1]  + left->m[9]  * right->m[2]  + left->m[13] * right->m[3];
      result->m[2]  = left->m[2] * right->m[0]  + left->m[6] * right->m[1]  + left->m[10] * right->m[2]  + left->m[14] * right->m[3];
      result->m[3]  = left->m[3] * right->m[0]  + left->m[7] * right->m[1]  + left->m[11] * right->m[2]  + left->m[15] * right->m[3];
    
      result->m[4]  = left->m[0] * right->m[4]  + left->m[4] * right->m[5]  + left->m[8]  * right->m[6]  + left->m[12] * right->m[7];
      result->m[5]  = left->m[1] * right->m[4]  + left->m[5] * right->m[5]  + left->m[9]  * right->m[6]  + left->m[13] * right->m[7];
      result->m[6]  = left->m[2] * right->m[4]  + left->m[6] * right->m[5]  + left->m[10] * right->m[6]  + left->m[14] * right->m[7];
      result->m[7]  = left->m[3] * right->m[4]  + left->m[7] * right->m[5]  + left->m[11] * right->m[6]  + left->m[15] * right->m[7];
    
      result->m[8]  = left->m[0] * right->m[8]  + left->m[4] * right->m[9]  + left->m[8]  * right->m[10] + left->m[12] * right->m[11];
      result->m[9]  = left->m[1] * right->m[8]  + left->m[5] * right->m[9]  + left->m[9]  * right->m[10] + left->m[13] * right->m[11];
      result->m[10] = left->m[2] * right->m[8]  + left->m[6] * right->m[9]  + left->m[10] * right->m[10] + left->m[14] * right->m[11];
      result->m[11] = left->m[3] * right->m[8]  + left->m[7] * right->m[9]  + left->m[11] * right->m[10] + left->m[15] * right->m[11];
    
      result->m[12] = left->m[0] * right->m[12] + left->m[4] * right->m[13] + left->m[8]  * right->m[14] + left->m[12] * right->m[15];
      result->m[13] = left->m[1] * right->m[12] + left->m[5] * right->m[13] + left->m[9]  * right->m[14] + left->m[13] * right->m[15];
      result->m[14] = left->m[2] * right->m[12] + left->m[6] * right->m[13] + left->m[10] * right->m[14] + left->m[14] * right->m[15];
      result->m[15] = left->m[3] * right->m[12] + left->m[7] * right->m[13] + left->m[11] * right->m[14] + left->m[15] * right->m[15];
    }

    这就是利用矩阵, 把一个世界坐标系的坐标,转换到局部坐标系的方法。



    那么。怎样把一个局部坐标系转换到世界坐标系呢?

    这里须要得到局部坐标系相应矩阵的逆矩阵,这个矩阵包括了还原矩阵操作的变换。

    然后,把逆矩阵当做左边的矩阵,去右乘局部坐标点, 我们就能够得到局部坐标变成世界坐标后的坐标。

    static bool tryInvert(Matrix4* matrix, Out(Matrix4* result)) {
        float a0 = matrix->m[0]  * matrix->m[5]  - matrix->m[1]  * matrix->m[4];
        float a1 = matrix->m[0]  * matrix->m[6]  - matrix->m[2]  * matrix->m[4];
        float a2 = matrix->m[0]  * matrix->m[7]  - matrix->m[3]  * matrix->m[4];
        float a3 = matrix->m[1]  * matrix->m[6]  - matrix->m[2]  * matrix->m[5];
        float a4 = matrix->m[1]  * matrix->m[7]  - matrix->m[3]  * matrix->m[5];
        float a5 = matrix->m[2]  * matrix->m[7]  - matrix->m[3]  * matrix->m[6];
    
        float b0 = matrix->m[8]  * matrix->m[13] - matrix->m[9]  * matrix->m[12];
        float b1 = matrix->m[8]  * matrix->m[14] - matrix->m[10] * matrix->m[12];
        float b2 = matrix->m[8]  * matrix->m[15] - matrix->m[11] * matrix->m[12];
        float b3 = matrix->m[9]  * matrix->m[14] - matrix->m[10] * matrix->m[13];
        float b4 = matrix->m[9]  * matrix->m[15] - matrix->m[11] * matrix->m[13];
        float b5 = matrix->m[10] * matrix->m[15] - matrix->m[11] * matrix->m[14];
    
        // Calculate the determinant.
        float det = a0 * b5 - a1 * b4 + a2 * b3 + a3 * b2 - a4 * b1 + a5 * b0;
    
        // Close to zero, can't invert.
        if (fabs(det) < FLT_EPSILON) {
        	 return false;
    	}
    
        float scalar   = 1.0f / det;
    
        // Support the case where matrix == result
    
        result->m[0]   = ( matrix->m[5]  * b5 - matrix->m[6]  * b4 + matrix->m[7]  * b3) * scalar;
        result->m[1]   = (-matrix->m[1]  * b5 + matrix->m[2]  * b4 - matrix->m[3]  * b3) * scalar;
        result->m[2]   = ( matrix->m[13] * a5 - matrix->m[14] * a4 + matrix->m[15] * a3) * scalar;
        result->m[3]   = (-matrix->m[9]  * a5 + matrix->m[10] * a4 - matrix->m[11] * a3) * scalar;
    
        result->m[4]   = (-matrix->m[4]  * b5 + matrix->m[6]  * b2 - matrix->m[7]  * b1) * scalar;
        result->m[5]   = ( matrix->m[0]  * b5 - matrix->m[2]  * b2 + matrix->m[3]  * b1) * scalar;
        result->m[6]   = (-matrix->m[12] * a5 + matrix->m[14] * a2 - matrix->m[15] * a1) * scalar;
        result->m[7]   = ( matrix->m[8]  * a5 - matrix->m[10] * a2 + matrix->m[11] * a1) * scalar;
    
        result->m[8]   = ( matrix->m[4]  * b4 - matrix->m[5]  * b2 + matrix->m[7]  * b0) * scalar;
        result->m[9]   = (-matrix->m[0]  * b4 + matrix->m[1]  * b2 - matrix->m[3]  * b0) * scalar;
        result->m[10]  = ( matrix->m[12] * a4 - matrix->m[13] * a2 + matrix->m[15] * a0) * scalar;
        result->m[11]  = (-matrix->m[8]  * a4 + matrix->m[9]  * a2 - matrix->m[11] * a0) * scalar;
    
        result->m[12]  = (-matrix->m[4]  * b3 + matrix->m[5]  * b1 - matrix->m[6]  * b0) * scalar;
        result->m[13]  = ( matrix->m[0]  * b3 - matrix->m[1]  * b1 + matrix->m[2]  * b0) * scalar;
        result->m[14]  = (-matrix->m[12] * a3 + matrix->m[13] * a1 - matrix->m[14] * a0) * scalar;
        result->m[15]  = ( matrix->m[8]  * a3 - matrix->m[9]  * a1 + matrix->m[10] * a0) * scalar;
    
        return true;
    }
    是的有些矩阵是没有逆矩阵的,所以求逆矩阵的操作会失败。


    世界坐标系的意义,就是坐标是相对于原点坐标系的。

    局部坐标系的意义。就是坐标不是相对于原点坐标系。而是相对于某个详细的坐标系。

    局部坐标系是能够通过上面的方法互相转换的。


    那么怎样在局部坐标系之间互相转换呢?

    我们无法把一个局部坐标系的坐标,一次就变化成还有一个局部坐标系上。

    由于两个不同的局部坐标的坐标。都是相对于各自的坐标系。也就是參考系不同。

    但。我们能够,把一个局部坐标系,转换到世界坐标系。以后再从世界坐标系转换到还有一个局部坐标系上。



    坐标系转换的意义是什么?

    假设我们可以恰当的选取坐标系。在进行坐标计算的时候,会简化非常多运算和思考的模型。

    由于一个物体坐标的变化总是在父类坐标之内的,也就是相对于父类坐标系去变化。

    这个父类坐标系。要么世界坐标系,要么就是某个详细的坐标系。


    而我们这里讨论的坐标转换的模型是这种。

    一个坐标终于呈如今屏幕上,我们假设改动了坐标的父坐标系,通过坐标系的转化。而保持这个坐标终于呈现的位置不变。


    打一个例如

    假设一个坐标(0, 0)在世界坐标系上,终于呈现出来的就是在(0, 0)点处。

    我们如今把这个坐标,放到一个在(5, 5)处的坐标系内。这样这个坐标全部的数值都像相对于(5, 5)这个坐标系的。

    那么,(0, 0)终于呈现的就是在(5, 5)处了,而不再原来的位置。

    我们通过把这个坐标(0, 0)转换到(5, 5)的坐标系里,会得到新的坐标(-5, -5)这是相对于新坐标系的数值。

    终于(-5, -5) 会呈如今(0, 0)的位置。


    其实,在openGL绘制的时候。我们常常须要在各种不同的坐标系之间互相转换,可能是为了计算动画。可能是为了计算物理碰撞。

  • 相关阅读:
    LinkedHashMap、HashMap和TreeMap的比较使用
    RocketMQ之Namesrv
    mysql创建、删除、查看索引
    java8 JVM堆内存(heap) 新生代 老年代 元空间垃圾回收详解
    Java中GCRoots包括哪些
    单例模式双重校验锁
    内存屏障
    LockSupport的用法及原理
    HashSet,TreeSet和LinkedHashSet的区别
    Windows常用网络命令技巧汇总
  • 原文地址:https://www.cnblogs.com/gavanwanggw/p/6705909.html
Copyright © 2011-2022 走看看