zoukankan      html  css  js  c++  java
  • 【脚下生根】之深度探索安卓OpenGL投影矩阵

    世界变化真快,前段时间windows开发技术热还在如火如荼,web技术就开始来势汹汹,正当web呈现欣欣向荣之际,安卓小机器人,咬过一口的苹果,winPhone开发平台又如闪电般划破了混沌的web世界。

    相信很多开发者都在疑问,为什么世界不是围着我转?而是我在围着世界转。我的答案是,少林寺的和尚学打架,首先要学会站桩。要练功,先占三年桩。少林寺的和尚打架从来不围着别人转,而是别人围着他转。

    世界的原理都是相通的,开发者一样,要做到脚下生根。

    最近几天在看OpenGL的投影矩阵,自己也实现了一个投影矩阵:

    【1 0 0 0】

    【0 1 0 0】

    【0 0 1 1/d]

    [0 0 0 0]

    其中d代表的是近平面的距离也就是near。

    做任何事情,必须带着疑问去学习,这是我的原则,不然就不要学,尽信书不如无书,是懂非懂不如不懂。我的疑问是为什么OpenGL的投影矩阵那么复杂,我想复杂必然有其复杂的道理。经过一番研究,其根本原因是为了将实景体映射到一个立方体,范围是【-1,1】的边长为2的立方体。而不是直接变换到屏幕上。这就是OpenGL的想法。因此,像我那样直接转换到屏幕上就不对了。x,y经过这个变换后到-1,1. 而z的变换则必须满足线性变换的规则。这个推导的过程并不复杂。原理是,x,y按照线性比例进行压缩。z轴则进行一次线性变换以满足线性矩阵的要求。这些推导很简单,就不说了。

    接下来要讲的东西更加出人意外,因为既然研究UI的底层实现,不能仅仅限于OpenGL。于是我又追根究底地剖解了一下Skia库。Skia库在3D上可以说在OpenGL面前就是小菜一碟。但是它在2D图形处理上,可以说OpenGL就是小菜一碟。因此互为补充。当然我研究的是Skia也增加了一些在2D图形进行3D特效的东东。其中有一些矩阵变换。刚好印证了我的矩阵是多么的正确。具体参照SkCamera.cpp这个文件。具体里面的那些数学矩阵运算怎么怎么进行的就不说了。根本原理就是我上面提到的那个投影矩阵。

    这些东西很简单。不是吗?

    具体OpenGL是怎么算的,稍微有点线性代数知识的人,高等代数等都可以看懂,下面是这个链接。

    http://hi.baidu.com/dych_cnu/item/a7b78ba58a86e0208819d30f

    Java代码  收藏代码
    1. void SkCamera3D::patchToMatrix(const SkPatch3D& quilt, SkMatrix* matrix) const {  
    2.     if (fNeedToUpdate) {  
    3.         this->doUpdate();  
    4.         fNeedToUpdate = false;  
    5.     }  
    6.   
    7.     const SkScalar* mapPtr = (const SkScalar*)(const void*)&fOrientation;  
    8.     const SkScalar* patchPtr;  
    9.     SkPoint3D       diff;  
    10.     SkScalar        dot;  
    11.   
    12.     diff.fX = quilt.fOrigin.fX - fLocation.fX;  
    13.     diff.fY = quilt.fOrigin.fY - fLocation.fY;  
    14.     diff.fZ = quilt.fOrigin.fZ - fLocation.fZ;  
    15.   
    16.     dot = SkUnit3D::Dot(*(const SkUnit3D*)(const void*)&diff,  
    17.                         *(const SkUnit3D*)(((const SkScalar*)(const void*)&fOrientation) + 6));  
    18.   
    19.     //  patchPtr的结构为{U,V,ORIGIN}其中U,V 代表列向量  
    20.     // ORIGIN 是坐标原点  
    21.       
    22.     patchPtr = (const SkScalar*)&quilt;  
    23.       
    24.     /* 
    25.      其中matrix表示一个3x3的矩阵 
    26.     第一行代表U的系数,第二行是V的系数,第三行是diff 的系数 
    27.     matrix 的每一列代表的是一个坐标轴。 
    28.     */  
    29.     //第一列  
    30.     matrix->set(SkMatrix::kMScaleX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));  
    31.     matrix->set(SkMatrix::kMSkewY,  SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));  
    32.     matrix->set(SkMatrix::kMPersp0, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot));  
    33.   
    34.     //第二列  
    35.     patchPtr += 3;  
    36.     matrix->set(SkMatrix::kMSkewX,  SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));  
    37.     matrix->set(SkMatrix::kMScaleY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));   
    38.     matrix->set(SkMatrix::kMPersp1, SkScalarDotDiv(3, patchPtr, 1, mapPtr+6, 1, dot));  
    39.   
    40.     //第三列  
    41.     patchPtr = (const SkScalar*)(const void*)&diff;  
    42.     matrix->set(SkMatrix::kMTransX, SkScalarDotDiv(3, patchPtr, 1, mapPtr, 1, dot));  
    43.     matrix->set(SkMatrix::kMTransY, SkScalarDotDiv(3, patchPtr, 1, mapPtr+3, 1, dot));  
    44.     matrix->set(SkMatrix::kMPersp2, SK_UnitScalar1);  
    45.       
    46. }  
  • 相关阅读:
    服务器编程入门(12) 守护进程
    Effective C++(10) 重载赋值操作符时,返回该对象的引用(retrun *this)
    C++ Primer(6) 模板和泛型编程(上)
    Effective C++(9) 构造函数调用virtual函数会发生什么
    Android开发(7)数据库和Content Provider
    Effective C++(7) 为多态基类声明virtual析构函数 or Not
    Effective C++(6) 如何拒绝编译器的自动生成函数
    Effective C++(4) 确定对象被使用前已先被初始化
    Effective C++(5) 了解C++默默地编写并调用哪些函数
    Effective C++(1-2) 编译器替换预处理器
  • 原文地址:https://www.cnblogs.com/xiaochao1234/p/4186668.html
Copyright © 2011-2022 走看看