(转载)Cocos2dx-OpenGL ES2.0教程:初识MVP(3)
在上一篇文章中,我在介绍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 |
varying vec4 v_fragmentColor; |
此时,我们需要在程序里面给这个u_color传值。它的基本做法与attribute的传值是一样的。
首先,我们需要获得这个uniform在shader里面的位置。
1 |
GLuint uColorLocation = glGetUniformLocation(glProgram->getProgram(), "u_color"); |
然后,我们可以通过glUniformXXX函数给这个uniform赋值:
1 |
float uColor[] = {1.0, 0.0, 0.0, 1.0};
|
此时,我们就在c++代码和shader程序之间传递数据啦。编译并运行,我们会得到一个半红不红的三角形:
triangle
初识CC_MVPMatrix
CC_MVPMatrix是一个mat4类型的uniform,在shader代码被编译之前,它由cocos2d-x框架插入进来的。
1 |
bool GLProgram::compileShader(GLuint * shader, GLenum type, const GLchar* source) |
从上面的代码,我们可以看到, 这里除了插入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 |
Director::getInstance()->pushMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); |
然后在onDraw函数返回前加入下列代码:
1 |
Director::getInstance()->popMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); |
这里,我们通过调用pushMatrix把当前矩阵压栈,这个操作会把原来栈顶上的元素拷贝一份并压入栈,这样我们后续对于此矩阵的操作可以通过调用popMatrix来撤销影响。此处,我们把ModelView和Projection矩阵都重置成了单位矩阵。而我们通过调用下列代码可以更新CC_MVPMatrix:
1 |
glProgram->setUniformsForBuiltins(); |
此时,如果我们运行程序,会得到一个黑屏(什么也显示不了)。
设备空间(normalized device space)
为了解决上述问题,我们只需要把对象的顶点数据修改为:
1 |
float vertercies[] = { -1,-1, //第一个点的坐标
|
为什么要这样呢?因为任何一个顶点乘以一个单位矩阵,它的值是不变的。而normalized device space空间的取值范围是-1~+1,如下图所示:
clippingspace
所以,如果我们要想显示同之前一模一样的三角形,就必须修改这个顶点数据,让它的取值范围落在Clipping Space以内。这也是我们在其它许多书本上面看到的规范的三角形的范例。
(转载)Cocos2dx-OpenGL ES2.0教程:初识MVP(3)的更多相关文章
- Cocos2d-x中使用OpenGL ES2.0编写shader
这几天在看子龙山人的关于OpenGL的文章,先依葫芦画瓢,能看到些东西,才能慢慢深入了解,当入门文章不错,但是其中遇到的一些问题,折腾了一些时间,为了方便和我一样的小白们,在这篇文章中进行写补充. O ...
- OpenGL ES2.0 入门经典例子
原文链接地址:http://www.raywenderlich.com/3664/opengl-es-2-0-for-iphone-tutorial 免责申明(必读!):本博客提供的所有教程的翻译原稿 ...
- iOS开发——图形编程OC篇&OpenGL ES2.0编程步骤
OpenGL ES2.0编程步骤 OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL 三维图形 API 的子集,针对手机.PDA和游戏主机等嵌入式设备而设 ...
- Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤
原文地址: Eclipse中通过Android模拟器调用OpenGL ES2.0函数操作步骤 - 网络资源是无限的 - 博客频道 - CSDN.NET http://blog.csdn.net/fen ...
- OpenGL ES2.0入门详解
引自:http://blog.csdn.net/wangyuchun_799/article/details/7736928 1.决定你要支持的OpenGL ES的版本.目前,OpenGL ES包含 ...
- OPENGL ES2.0如何不使用glActiveTexture而显示多个图片
https://www.oschina.net/question/253717_72107 用opengl es 2.0显示多个图片的话,我只会一种方式,先将图片生成纹理,然后用下面的方式渲染 // ...
- Android +NDK+eclipse+opengl ES2.0 开启深度測试
參考:https://www.opengl.org/discussion_boards/showthread.php/172736-OpenGL-ES-Depth-Buffer-Problem 环境: ...
- OpenGL ES2.0 基本编程
1. EGL OpenGL ES命令须要一个rendering context和一个drawing surface. Rendering Context: 保存当前的OpenGL ES状态. Draw ...
- (转载)Cocos2dx-OpenGL ES 2.0教程:你的第一个三角形(1)
前言 在本系列教程中,我会以当下最流行的2D引擎Cocos2D-X为基础,介绍OpenGL ES 2.0的一些基本用法.本系列教程的宗旨是OpenGL扫盲,让大家在使用Cocos2D-X过程中,知其然 ...
随机推荐
- LeetCode 268
Missing Number Given an array containing n distinct numbers taken from 0, 1, 2, ..., n, find the one ...
- 用bash命令得到Windows一个目录下的所有文件并且把结果输入到一个文件
方式一: 只用如下一条语句就可以了: tree/f>index.txt 放入一个文件中命名为"****.bat" 双击就会在该目录下生成一个index.txt文件,在这个文件 ...
- [改善Java代码]避开基本类型数组转换列表陷阱
开发中经常用到Arrays和Collections这两个工具类. 在数组和列表之间进行切换.非常方便.但是也会遇到一些问题. 看代码: import java.util.Arrays; import ...
- [改善Java代码]不要主动进行垃圾回收
建议51: 不要主动进行垃圾回收 很久很久以前,在Java 1.1的年代里,我们经常会看到System.gc这样的调用—主动对垃圾进行回收.不过,在Java知识深入人心后,这样的代码就逐渐销声匿迹了— ...
- 关于JDK中的设计模式
结构型模式: 适配器模式: 用来把一个接口转化成另一个接口. java.util.Arrays#asList() javax.swing.JTable(TableModel) java.io.Inpu ...
- KMP模版
#include<iostream> #include<cstdio> #include<cstring> using namespace std; ]; void ...
- 快速启动软件之 Rolan ,你真的会用?
2015.2.14 很高兴 Rolan 这个软件至今还在更新,并且愈发完善,UI 的设计和功能上的改进都给了我不小的震撼. 如今的 Rolan ,可以对比一下 2014 年的图,变化真的很大有木有: ...
- HTML5与CSS3基础教程第八版学习笔记11~15章
第十一章,用CSS进行布局 开始布局注意事项 1.内容与显示分离 2.布局方法:固定宽度和响应式布局 固定宽度,整个页面和每一栏都有基于像素的宽度 响应式布局也称为流式页面,使用百分数定义宽度 3.浏 ...
- Spring 数据源配置三:多数据源
在上一节中,我们讲述了多数据的情况: 1. 数据源不同(数据库厂商不同, 业务范围不同, 业务数据不同) 2. SQL mapper 文件不同, 3. mybatis + 数据方言不同 即最为简单的多 ...
- android图片切换ImageSwichter的动画切换效果
activity_main.xml 控件的线性布局 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/an ...