OpenGLES demo - 11. 透视投影变换

本文详细介绍了在OpenGLES中如何实现透视投影变换,以达到近大远小的视觉效果。通过创建立方体模型,设置颜色属性并更新Shader,作者展示了观察矩阵和投影矩阵的构建过程。最终,通过矩阵相乘实现了透视效果,使得立方体呈现出立体感。附带源代码链接。
摘要由CSDN通过智能技术生成

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

这章介绍一下透视投影变换,一个物体经过了透视投影变换之后,就会有近大远小的效果,这很符合我们日常观察的结果。

在这之前,我们需要创建一个立体的模型,这样才有透视投影的效果,像之前只画一个三角形或者正方形是不行的。立方体的顶点和Index数组如下

    glGenBuffers(2, buffers);
    
    glBindBuffer(GL_ARRAY_BUFFER, buffers[VERTEX]);
    float cube[] =
    {
        -0.5f,      -0.5f,      -0.5f,      1.0f,   1.0f, 1.0f, 1.0f,
        0.5f,       -0.5f,      -0.5f,      1.0f,   1.0f, 0.0f, 0.0f,
        -0.5f,      0.5f,       -0.5f,      1.0f,   0.0f, 1.0f, 0.0f,
        0.5f,       0.5f,       -0.5f,      1.0f,   0.0f, 0.0f, 1.0f,
        
        -0.5f,      -0.5f,      0.5f,       1.0f,   1.0f, 1.0f, 0.0f,
        0.5f,       -0.5f,      0.5f,       1.0f,   1.0f, 0.0f, 1.0f,
        -0.5f,      0.5f,       0.5f,       1.0f,   0.0f, 1.0f, 1.0f,
        0.5f,       0.5f,       0.5f,       1.0f,   0.5f, 0.5f, 1.0f,
    };
    glBufferData(GL_ARRAY_BUFFER, sizeof(cube), cube, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffers[INDEX]);
    static unsigned short indices[] =
    {
        /* 0 */
        0, 1, 2, 1, 2, 3,
        0, 4, 2, 6, 4, 2,
        0, 1, 4, 1, 5, 4,
        1, 3, 5, 3, 5, 7,
        2, 3, 6, 3, 6, 7,
        4, 5, 6, 5, 6, 7,
    };
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);


为了便于区分每个面,我们给每个顶点加了一个颜色的属性,所以,Shader也需要做相应的变化来应用新加的颜色属性

char* vssource =
"precision mediump float;\n"
"attribute vec4 aPosition;\n"
"attribute vec3 aColor;\n"
"uniform mat4 uMvp;\n"
"varying vec3 vColor;\n"
"void main() {\n"
"    gl_Position = uMvp*aPosition;\n"
"    vColor = aColor;\n"
"}\n";

char* fssource =
"precision mediump float;\n"
"varying vec3 vColor;\n"
"void main() {\n"
"    gl_FragColor = vec4(vColor, 1.0);\n"
"}\n";

因为多了一个属性,所以需要再程序里面去得到Shader中的句柄,并启用它

    aLocColor = glGetAttribLocation(program, "aColor");
    glEnableVertexAttribArray(aLocColor);


而且在设置顶点的属性的时候,我们需要注意glVertexAttribPointer函数中的两个参数,Stride和offset,也就是最后两个参数。因为在之前只有一个顶点位置的属性,所以Stride为0,而现在一个Vertex Buffer里面同时有了顶点和颜色两个属性,所以需要指定Stride为多大。一个Stride就是指一组顶点加颜色占用了多少Byte,程序中一组顶点有4个float,一组颜色有3个float,所以这里的Stride就是sizeof(float)*7。而最后一个参数,在没有用Vertex Buffer的时候,是顶点数组的指针,如果我们用了Vertex Buffer,最后一个参数就是Offset,它是指当前属性在一个Stride中需要偏移多少个Byte。一组顶点和颜色的Stride中,顶点是起始,所以offset为0,而颜色是在顶点结束后才开始,所以Offset是sizeof(float)*4。

    glVertexAttribPointer(aLocPos, 4, GL_FLOAT, 0, sizeof(float)*7, 0);
    glVertexAttribPointer(aLocColor, 3, GL_FLOAT, 0, sizeof(float)*7, (GLvoid*)(sizeof(float)*4));


运行程序


现在只得到了一个有颜色矩形。为什么???因为我们现在还没有用透视投影变换,所以还处于一个正投影的世界中,这样的话,远近是看不出来的,这时候需要构造两个矩阵,第一个矩阵是决定了我们在哪里观察物体,像眼睛的位置,向上的方向是什么,观看点在哪里,这个就是观察矩阵(View)。在这里,把眼睛的位置放到(0, 0, -2),就是相当于退后2个单位,而观察点在(0, 0, 0),就是一直观看坐标中心。

    gmMatrix4 view, proj;
    
    gmVector3 eye = {0.0f, 0.0f, -2.0f};
    gmVector3 at = {0.0f, 0.0f, 0.0f};
    gmVector3 up = {0.0f, 1.0f, 0.0f};
    
    gmMatrixLookAtLH(&view, &eye, &at, &up);


第二个矩阵决定了我们的视野大小,高宽比,最近能看到哪里,最远能看到哪里等属性,也就是投影矩阵(project)

    gmMatrixPerspectiveFovLH(&proj, 3.1415f / 2, (float)_viewWidth / (float)_viewHeight, 1.0f, 1000.0f);


这两个矩阵的构造函数在之前的代码里面已经添加上去了,但是没有使用过。大家会注意到两个函数后面都有LH的字样,这个是指Left Hand,也就是左手坐标系。关于怎么区分左手或右手坐标系,这个可以查一下,需要指明的是,OpenGL和OpenGLES中,都是使用左手坐标系,而在Direct3D中却使用的是右手坐标系。


计算出两个矩阵后,将他们相乘,就是我们要的mvp了

    gmMatrixMultiply(&mvp, &view, &proj);

再运行程序


好像除了比刚才小一点之外,没有什么变化呀,改改eye的位置,把y往上面移动两个单位,再运行一下

    gmVector3 eye = {0.0f, 2.0f, -2.0f};


有点感觉了吧?再把x往右移两个单位看看

    gmVector3 eye = {2.0f, 2.0f, -2.0f};


怎么样,像一个立方体了吧???我们再加一段旋转的代码,这是之前做过的

    gmMatrix4 model, view, proj;
    
    static float angle = 0.0f;
    gmMatrixRotateY(&model, angle);
    angle += 0.1f;

现在我们有了三个矩阵,注意一下相乘的顺序,既然是mvp,那么相乘的顺序就是model * view * project

    gmMatrixMultiply(&mvp, &model, &view);
    gmMatrixMultiply(&mvp, &mvp, &proj);

再来看看结果,非常漂亮~~~~



代码地址http://download.csdn.net/detail/hoytgm/7654435


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值