文档章节

Cocos2dx-OpenGL ES2.0教程:初识MVP(3)

乐逍遥jun
 乐逍遥jun
发布于 2016/02/22 21:38
字数 1458
阅读 54
收藏 1

上一篇文章中,我在介绍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数据:

123456
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赋值:

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

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

triangletriangle

初识CC_MVPMatrix

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

1234567891011121314151617181920212223
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函数的最开头加入下列代码:

1234
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函数返回前加入下列代码:

12
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)

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

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

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

clippingspaceclippingspace

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

本文转载自:

乐逍遥jun
粉丝 6
博文 79
码字总数 39510
作品 0
东城
技术主管
私信 提问
零基础使用cocos2dx-lua和skynet全栈式开发网游三(客户端配置)

客户端配置 一、扯几个概念 问题:cocos2dx引擎到底如何运作的? 在解答这个问题前,需要了解几个概念。 1.颜色 在自然界中,存在一种场,叫电磁场。电荷粒子运动状态变化时,就会释放电磁波...

量子出击
2018/06/21
0
0
cocos2dx- call to OpenGL ES API with no current context(logged once per thread)

Android APP 在红米2(Android 5.1系统)上进行全屏应用切换的时候,会出现卡屏,不会闪退并且出现频繁.在红米note和moto x1(Android 4.4系统)中偶尔出现. 其他手机上暂时还未出现全屏切换...

GLancelot
2015/08/14
2.1K
3
Xcode6编译Cocos2d-x3.1.1 link错误

Xcode6编译Cocos2d-x3.1.1 link错误 原来苹果公司打算自己整一套OPenGL的东西,所有,有些东西需要根据IOS平台来加入它的东西。这个问题的解决方案如下: 在工程目录下cocos/platform/CCImag...

Nov_Eleven
2015/01/19
1K
2
blender导出的骨骼动画加载在webgl后变形

@李勇2 你好,想跟你请教个问题: 我看到您写的《cocos2dx blender 骨骼动画实现》里面讲到了骨骼的变换和opengl中不同。我在做的时候,也发现代码加载动画和我在blender中设置的动画不同,但...

蚊子蚊子
2014/05/25
1K
1
Cocos2d-x2.0 -- 从点,线,面学起

[Cocos2d-x相关教程来源于红孩儿的游戏编程之路 CSDN博客地址:http://blog.csdn.net/honghaier] 红孩儿Cocos2d-X学习园地QQ群:249941957 加群写:Cocos2d-x 本章为我的Cocos2d-x教程一书初...

长平狐
2013/03/19
164
0

没有更多内容

加载失败,请刷新页面

加载更多

3_数组

3_数组

行者终成事
今天
7
0
经典系统设计面试题解析:如何设计TinyURL(二)

原文链接:https://www.educative.io/courses/grokking-the-system-design-interview/m2ygV4E81AR 编者注:本文以一道经典的系统设计面试题:《如何设计TinyURL》的参考答案和解析为例,帮助...

APEMESH
今天
7
0
使用logstash同步MySQL数据到ES

概述   在生成业务常有将MySQL数据同步到ES的需求,如果需要很高的定制化,往往需要开发同步程序用于处理数据。但没有特殊业务需求,官方提供的logstash就很有优势了。   在使用logstas...

zxiaofan666
今天
10
0
X-MSG-IM-分布式信令跟踪能力

经过一周多的鏖战, X-MSG-IM的分布式信令跟踪能力已基本具备, 特点是: 实时. 只有要RX/TX就会实时产生信令跟踪事件, 先入kafka, 再入influxdb待查. 同时提供实时sub/pub接口. 完备. 可以完整...

dev5
今天
7
0
OpenJDK之CyclicBarrier

OpenJDK8,本人看的是openJDK。以前就看过,只是经常忘记,所以记录下 图1 CyclicBarrier是Doug Lea在JDK1.5中引入的,作用就不详细描述了,主要有如下俩个方法使用: await()方法,如果当前线...

克虏伯
今天
8
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部