在上一篇文章中,我在介绍vertex shader的时候挖了一个坑:CC_MVPMatrix。它其实是一个uniform,每一个cocos2d-x预定义的shader都包含有这个uniform,
但是如果你在shader里面不使用这个变量的话,OpenGL底层会把它优化掉。

但是,CC_MVPMatrix是在什么时候设置进来的呢?我在shader里面明明没有看到它,它从哪儿来的?别急,请继续往下读。

初识Uniform

在回答上面几个问题之前,让我们先来介绍一下什么是uniform。简单来说,uniform是shader里面的一种变量,它是由外部程序设置进来的,它不像vertex的attribute,每个顶点都有一份数据。除非你显式地调用glUniformXXX函数来修改这个uniform的值,否则它的值恒定不变。接下来,让我们修改myFragmentShader.frag,给它添加一个新的uniform数据:

1
2
3
4
5
6
varying vec4 v_fragmentColor;
uniform vec4 u_color;
void main()
{    gl_FragColor = v_fragmentColor * u_color;
}

此时,我们需要在程序里面给这个u_color传值。它的基本做法与attribute的传值是一样的。

首先,我们需要获得这个uniform在shader里面的位置。

1
GLuint uColorLocation = glGetUniformLocation(glProgram->getProgram(), "u_color");

然后,我们可以通过glUniformXXX函数给这个uniform赋值:

1
2
float uColor[] = {1.0, 0.0, 0.0, 1.0};
glUniform4fv(uColorLocation,1, uColor);

此时,我们就在c++代码和shader程序之间传递数据啦。编译并运行,我们会得到一个半红不红的三角形:

triangle

初识CC_MVPMatrix

CC_MVPMatrix是一个mat4类型的uniform,在shader代码被编译之前,它由cocos2d-x框架插入进来的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
bool GLProgram::compileShader(GLuint * shader, GLenum type, const GLchar* source)
{    //部分代码省略
    const GLchar *sources[] = {        "uniform mat4 CC_PMatrix;\n"
        "uniform mat4 CC_MVMatrix;\n"
        "uniform mat4 CC_MVPMatrix;\n"
        "uniform vec4 CC_Time;\n"
        "uniform vec4 CC_SinTime;\n"
        "uniform vec4 CC_CosTime;\n"
        "uniform vec4 CC_Random01;\n"
        "uniform sampler2D CC_Texture0;\n"
        "uniform sampler2D CC_Texture1;\n"
        "uniform sampler2D CC_Texture2;\n"
        "uniform sampler2D CC_Texture3;\n"
        "//CC INCLUDES END\n\n",
        source,
    };
    *shader = glCreateShader(type);
    glShaderSource( *shader, sizeof(sources)/sizeof( *sources), sources, nullptr);
    glCompileShader( *shader);
    //下面的代码省略了...
}

从上面的代码,我们可以看到, 这里除了插入CC_MVPMatrix以外,还插入了其它一些uniform。只要你在后面的main函数里面不使用这些变量,最终shader program里面是看不到它们的。(被优化掉了)

CC_MVPMatrix的作用

CC_MVPMatrix本质上是一个变换矩阵,用来把一个世界坐标系中的点转换到Clipping space。当然,如果学过OpenGL的人都知道,3D物体从建模到最终显示到屏幕上面要经历以下几个阶段:

  • 对象空间(Object Space)
  • 世界空间(World Space)
  • 照相机空间(Camera Space/Eye Space)
  • 裁剪空间(Clipping Space)
  • 设备空间(normalized device space)
  • 视口空间(Viewport)

从对象空间到世界空间的变换通常叫做Model-To-World变换,从世界空间到照相机空间的变换叫做World-To-View变换,而从照相机空间到裁剪空间的变换叫做View-To-Projection。合起来,就是我们常常提到的MVP变换。这里面每一个变换都是乘以一个矩阵,3个矩阵相乘最后还是一个矩阵,也就是cocos2d-x里面的CC_MVPMatrix啦。当然,实际开发过程中,我们往往会把MV变换放到一起,一般做法如下:

1
gl_Position = P * MV * ObjectPosition;

具体这些变换是怎么计算的,另外每一个计算的几何意义是什么。本系列教程暂不讨论,感兴趣的读者可以去看看我在本系列教程第一篇的最后推荐的一些资源。

修改CC_MVPMatrix

我们怎么样修改CC_MVPMatrix呢?前面介绍过uniform变量的修改方法在这里是适用的,我们可以先通过glGetUniformLocation来获取这个uniform的入口,然后调用glUniformMatrix4fv来给它传值就行了。

但是,等等。我该怎么计算这个矩阵的值呢?有两个函数glLookAt和glPerspective可以做这些事,具体的用法 ,大家可以参考CCDirector.cpp里面的代码。我就不在此处展开讨论了,另外强烈推荐大家运行此网页中的一个演示程序,用来加深于这两个函数的理解。

在cocos2d-x里面,我们可以通过修改矩阵栈里面的ModelView和Projection栈顶元素,从而修改ModelView和Projection矩阵,最终达到修改CC_MVPMatrix的目的。

首先,让我们在onDraw函数的最开头加入下列代码:

1
2
3
4
Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
   Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
   Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
   Director::getInstance()->loadIdentityMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

然后在onDraw函数返回前加入下列代码:

1
2
Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
  Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);

这里,我们通过调用pushMatrix把当前矩阵压栈,这个操作会把原来栈顶上的元素拷贝一份并压入栈,这样我们后续对于此矩阵的操作可以通过调用popMatrix来撤销影响。此处,我们把ModelView和Projection矩阵都重置成了单位矩阵。而我们通过调用下列代码可以更新CC_MVPMatrix:

1
glProgram->setUniformsForBuiltins();

此时,如果我们运行程序,会得到一个黑屏(什么也显示不了)。

设备空间(normalized device space)

为了解决上述问题,我们只需要把对象的顶点数据修改为:

1
2
3
float vertercies[] = { -1,-1,   //第一个点的坐标
        1, -1,   //第二个点的坐标
        0, 1};  //第三个点的坐标

为什么要这样呢?因为任何一个顶点乘以一个单位矩阵,它的值是不变的。而normalized device space空间的取值范围是-1~+1,如下图所示:

clippingspace

所以,如果我们要想显示同之前一模一样的三角形,就必须修改这个顶点数据,让它的取值范围落在Clipping Space以内。这也是我们在其它许多书本上面看到的规范的三角形的范例。

转载于:https://www.cnblogs.com/lexiaoyao-jun/p/5208238.html

(转载)Cocos2dx-OpenGL ES2.0教程:初识MVP(3)相关推荐

  1. iOS OpenGL ES2.0教程   Lesson03 旋转

    iOS OpenGL ES2.0教程    Lesson03  旋转 注:可供翻译的课程只有前两课.从这节课起,我试着根据我对OpenGL ES的理解写接下去的课程,希望能和大家一起学习. 在上节课中 ...

  2. 初识 OpenGL ES2.0

    原文链接:Android OpenGLES2.0(一)--了解OpenGLES2.0 OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API ...

  3. OpenGL ES2.0 – Iphone开发指引

    原文链接地址:http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial 免责申明(必读!):本博客提供的所有教程的翻译原稿 ...

  4. Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤

    1.  先按照http://blog.csdn.net/fengbingchun/article/details/10439281中操作搭建好基本的Android开发环境: 2.  打开Eclipse ...

  5. OpenGL ES的性能范围(OpenGL ES2.0官方文档)

    http://blog.csdn.net/mengtnt/article/details/7773304 OpenGL ES 1.1和OpengGL ES2.0的规范中,都定义了每种实现必须支持的最低 ...

  6. opengl es2.0 渲染文字

    在OpenGL 家族中是没有提供直接渲染文字的接口,所以我们要在opengl中显示文字,就需要借助于其他的三方库或者自己解析绘制文字,然后使用opengl中的绘制接口去渲染出文字 这里我使用的free ...

  7. opengl es2.0 使用字符偏移图渲染文字

    在OpenGL 家族中是没有提供直接渲染文字的接口,所以我们要在opengl中显示文字,就需要借助于其他的三方库或者自己解析绘制文字,然后使用opengl中的绘制接口去渲染出文字 这里我使用的free ...

  8. Android 基于OpenGL ES2.0 的CircleProgressBar

    之前想在播放器上加一个那种卡顿的转转提示: 类似: https://github.com/lsjwzh/MaterialLoadingProgressBar 这种效果的 由于当时没想到怎么在openg ...

  9. android双指滑动方向,OpenGL ES2.0实现手指滑动平移、双指缩放Android

    主要是实现了手指在屏幕上滑动实现平移,两个手指进行缩放.主要是这部分矩阵还挺麻烦的. 效果图如下所示: 核心部分代码如下 触控事件处理: @SuppressLint("ClickableVi ...

最新文章

  1. linux 安装软件出现/tmp 磁盘不足时 解决方案
  2. Transformer在深度推荐系统中的应用及2019最新进展
  3. CodeForces - 1422E Minlexes(dp+字符串)
  4. windows phone 8 使用页面传对象的方式 实现页面间的多值传递
  5. c++ map 获取key列表_好未来Golang源码系列一:Map实现原理分析
  6. SpringBoot视频教程
  7. 编程迷宫_跟我学编程第十期——迷宫游戏
  8. 年轻时听到别人金钱至上的话语
  9. 丁胖胖眼中的WINDOWS操作系统(一)
  10. web安全day44:进阶,使用Nmap+Wireshark理解端口扫描
  11. conda:Could not find a version that satisfies the requirement XXX
  12. 数据库基础知识和SQL语言
  13. 计算机老丢失运行库,为什么电脑缺失运行库,电脑环境缺失运行库怎么办
  14. mysql 支持嵌套查询吗_【转】MySql 嵌套查询
  15. html弹窗确认取消公告代码,javascript实现确定和取消提示框效果
  16. 【JAVA问题解决方案】01.EasyExcel导出数据超过Excel单表上限解决方案
  17. 2020年中国半导体划片机行业现状分析,国产替代+需求扩张,行业前景广阔「图」
  18. js 模块defin化讲解
  19. 波场java-tron3.6 fullnode节点广播交易前的流程分析
  20. saturn pcb toolkit相关功能界面介绍

热门文章

  1. GetSpecialPath 获取应用程序当前目录
  2. 区块链溯源系统架构---区块链工作笔记002
  3. C++_基础部分_C++文件操作_文件的写入操作---C++语言工作笔记076
  4. C++_类和对象_C++运算符重载_递增运算符重载_重载++运算符_前置++_后置++重载---C++语言工作笔记057
  5. 嵌入式工作笔记0005---嵌入式发展和组成
  6. 人脸识别FAR值重新认识
  7. caffe 使用小技巧
  8. 可以用来做ppt的网页效果
  9. 杭电1422 重温世界杯
  10. android开发之AsyncTask的用法