OpenGLES demo - 9. 矩阵变换

原创文章,转载请注明链接 http://blog.csdn.net/hoytgm/article/details/37670893

上一章的Pipe Line中,我们讲了坐标变换,就是将开发者输入的点进行世界(model)、视点(view)和投影(perspective)变换之后,全部转化到一个截锥体(Frustum)中,然后做下一步工作。我们可以在Vertex Shader中将model、view和perspective变换做到一个4x4的矩阵中,这就是mvp矩阵,也就是我们这章要讲的矩阵变换。这部分有一些矩阵的算法,如果想明白里面的计算方式,可能需要知道一些线性代数的知识。不过不知道也没关系,知道怎么用这些函数就可以啦~~


我们先说说图形学中的点吧,一个点通常由(x, y, z, w)四个元素构成。三维空间中的位置是由x, y, z组成,为什么这里还有一个w元素呢?其实,w是一个其次坐标。我们上一章说过在裁剪和剔除环节,裁掉大部分点,而剩下的这些点,有一个共同的特性,就是 -w<x<w, -w<y<w, -w<z<w。在x,y,z进行矩阵变换之后,会把Frustum中的所有的点都进行归一化,那就是把x, y, z除以w。前面的公式除以w之后,我们就得到了-1<(x/w)<1, -1<(y/w)<1, -1<(z/w)<1。看,在(-1, 1)之间就是一个归一化的矩阵咯。


我们再说说矩阵吧,图形学用到的矩阵是一个4x4的矩阵,就是



其中,一个单位矩阵是指左对角线上的元素全为1,其他元素全为0的矩阵


我们用一个单位矩阵去乘以我们的一个点坐标(x, y, z, w),就可以得到如下结果


这样可以看出,其实一个单位矩阵对一个点坐标位置并没有任何影响。


我们在代码中定义一个三维向量和一个4x4的矩阵结构体,为了方便移植到Android上面,我们这里都用c语言完成

typedef struct _gmVector3
{
    float x;
    float y;
    float z;
}
gmVector3;
typedef struct _gmMatrix4
{
    float m[16];
}
gmMatrix4;

然后我们写一个函数,讲其中的三个元素改变值
void gmMatrixTranslate(gmMatrix4* out, float x, float y, float z)
{
    if (out == NULL)
    {
        return;
    }
    
	out->m[ 0]=1.0f;	out->m[ 4]=0.0f;	out->m[ 8]=0.0f;	out->m[12]=x;
	out->m[ 1]=0.0f;	out->m[ 5]=1.0f;	out->m[ 9]=0.0f;	out->m[13]=y;
	out->m[ 2]=0.0f;	out->m[ 6]=0.0f;	out->m[10]=1.0f;	out->m[14]=z;
	out->m[ 3]=0.0f;	out->m[ 7]=0.0f;	out->m[11]=0.0f;	out->m[15]=1.0f;
}

在单位矩阵的基础上将m12, m13和m14分别赋予了x, y, z,用这样一个矩阵再来乘以我们的一个点(x, y, z, w)有什么结果?



看,原来的点坐标上面分别加上了一个偏移,这就是这个矩阵的作用,做了一个Translate。


再写一个函数看看

void gmMatrixScale(gmMatrix4* out, float x, float y, float z)
{
    if (out == NULL)
    {
        return;
    }
    
    out->m[ 0]=x;		out->m[ 4]=0.0f;	out->m[ 8]=0.0f;	out->m[12]=0.0f;
    out->m[ 1]=0.0f;	out->m[ 5]=y;		out->m[ 9]=0.0f;	out->m[13]=0.0f;
    out->m[ 2]=0.0f;	out->m[ 6]=0.0f;	out->m[10]=z;		out->m[14]=0.0f;
    out->m[ 3]=0.0f;	out->m[ 7]=0.0f;	out->m[11]=0.0f;	out->m[15]=1.0f;
}
我们讲对角线上的值改变了,那他的作用呢?


原来的点各乘以了一个值,相当于做了放大或缩小,这就是Scale。


有了放大缩小和偏移,我们还可以做旋转。不过旋转稍稍复杂点,因为要考虑绕哪一个轴旋转。我们可以写一个绕Y轴旋转的函数

void gmMatrixRotateY(gmMatrix4* out, float y)
{
    if (out == NULL)
    {
        return;
    }
    
	float fcos, fsin;
    
    fcos = cos(y);
    fsin = sin(y);
    
    out->m[ 0]=fcos;		out->m[ 4]=0.0f;	out->m[ 8]=-fsin;		out->m[12]=0.0f;
    out->m[ 1]=0.0f;		out->m[ 5]=1.0f;	out->m[ 9]=0.0f;		out->m[13]=0.0f;
    out->m[ 2]=fsin;		out->m[ 6]=0.0f;	out->m[10]=fcos;		out->m[14]=0.0f;
    out->m[ 3]=0.0f;		out->m[ 7]=0.0f;	out->m[11]=0.0f;		out->m[15]=1.0f;
}
这个矩阵的效果???一会我们就看看。


我们这里写了一些函数和结构体,更多详细的代码大家可以去我的资源页下载,我也会在最后贴出代码地址哈~~~

讲了这么多,回到代码中去吧。要用这个矩阵,首先需要修改一下之前的Vertex Shader程序

"precision mediump float;\n"
"attribute vec4 aPosition;\n"
"uniform mat4 uMvp;\n"
"void main() {\n"
"    gl_Position = uMvp*aPosition;\n"
"}\n";
这里多用了一个uniform叫做uMvp,mat4表明这是一个4x4的矩阵。

同样,需要得到这个uniform的地址

uLocMvp = glGetUniformLocation(program, "uMvp");


对这个uniform赋值需要用到glUniformMatrix4fv,这就是传一个矩阵到shader里面。


再定义一个4x4的矩阵并初始化它

gmMatrix4 mvp;
InitgmMatrix4(&mvp);

然后,运行程序,画一个红色的三角形,它的坐标为

    float firsttriangle[] =
    {
        -0.8f, -0.8f, 0.0f, 1.0f,
        0.8f, -0.8f, 0.0f, 1.0f,
        0.0f, 0.5f, 0.0f, 1.0f,
    };
得到的结果


和以前没什么区别吧??


我们加一段代码,做一个Translate,看看结果

gmMatrixTranslate(&mvp, 0.5, 0.0, 0.0);

哈哈,向右边偏移了一点吧?因为我们刚才传的参数是(0.5, 0, 0),也就是y和z不变,x右移一点,很符合结果


改成Scale试试呢?

gmMatrixScale(&mvp, 0.5, 0.5, 0.5);

变小了吧?因为参数是0.5,相当于乘以0.5就是1/2,原来的一半了。


又改成Rotate绕Y轴呢?

    static float angle = 0.0f;
    gmMatrixRotateY(&mvp, angle);
    angle += 0.1f;

开始旋转啦!!!我们的三角形终于开始动起来咯


好咯,矩阵变换就先讲这么多,这一章的代码很重要,欢迎大家去地址 http://download.csdn.net/detail/hoytgm/7623267 下载。

注:本文参考了PVR SDK

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值