cocos2dx 3.x ccPositionTextureColor_vert与ccPositionTextureColor_noMVP_vert
在cocos2dx 2.x中,如果我们要对sprite更换片段shader,写成:
myProgram->initWithByteArrays(ccPositionTextureColor_vert, myFragSource);
但是到3.x中,上面做法会导致显示出来的sprite坐标不对。
于是看3.x代码,发现在3.x中,Sprite的默认shader不再是kCCShader_PositionTextureColor(即
GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR),而是改成了GLProgram::SHADER_NAME_POSITION_TEXTURE_COLOR_NO_MVP(见Sprite::initWithTexture(...)函数实现)。
因此应该用:
myProgram->initWithByteArrays(ccPositionTextureColor_noMVP_vert, myFragSource);
显示就正常了。
对比一下ccPositionTextureColor_vert和ccPositionTextureColor_noMVP_vert的代码:
const char* ccPositionTextureColor_vert = STRINGIFY(
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
\n#ifdef GL_ES\n
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
\n#else\n
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
\n#endif\n
void main()
{
gl_Position = CC_MVPMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
);
const char* ccPositionTextureColor_noMVP_vert = STRINGIFY(
attribute vec4 a_position;
attribute vec2 a_texCoord;
attribute vec4 a_color;
\n#ifdef GL_ES\n
varying lowp vec4 v_fragmentColor;
varying mediump vec2 v_texCoord;
\n#else\n
varying vec4 v_fragmentColor;
varying vec2 v_texCoord;
\n#endif\n
void main()
{
gl_Position = CC_PMatrix * a_position;
v_fragmentColor = a_color;
v_texCoord = a_texCoord;
}
);
可见唯一区别就是顶点坐标a_position乘的矩阵不同,ccPositionTextureColor_vert中乘的是CC_MVPMatrix,ccPositionTextureColor_noMVP_vert中乘的是CC_PMatrix。
于是就明白了:
在2.x的立即模式中,传入shader的顶点坐标为局部坐标,所以需要在shader中乘以MVP矩阵来求屏幕坐标。
在3.x的command模式中,传入shader的顶点坐标已预先转化成了世界坐标(即已乘过MV矩阵),所以在shader中就只乘P矩阵即可。
于是引出两个问题:
问题1,为什么command模式下,sprite要预先转化成世界坐标?
因为如果所有顶点都转化到了相同的空间(比如世界空间),那么它们的变换矩阵M就同一了(可以作为一个uniform变量),于是这些顶点可以一次性提交,从而减少了draw call数量。这也正是command机制的目的所在。不过需要注意的是,3.x中也并非所有的节点都使用了noMVP的形式,因为并不是所有渲染对象都如sprite这样顶点数很少适合展平做batch -- 假设有几个MV矩阵不同的顶点数很多的mesh,如果也像处理sprite一样进行展平一次性提交,虽然draw call数量下来了,可是cpu做顶点变换的开销却会大幅增加,其结果很可能反而不如多用几个draw call,但把顶点变换转移到gpu(shader)中去做效率高。所以在对一个节点更换shader的时候,要注意看一下其默认shader是有MVP还是noMVP。
问题2,sprite预先转化成世界坐标的代码在哪?
在void Renderer::visitRenderQueue(const RenderQueue& queue)中的if ( RenderCommand::Type::QUAD_COMMAND == commandType )分支中有一句fillQuads(cmd)。fillQuads(...)的实现如下:
void Renderer::fillQuads(const QuadCommand *cmd)
{
memcpy(_quadVerts + _numberQuads * 4, cmd->getQuads(), sizeof(V3F_C4B_T2F_Quad) * cmd->getQuadCount());
const Mat4& modelView = cmd->getModelView();
for(ssize_t i=0; i< cmd->getQuadCount() * 4; ++i)
{
V3F_C4B_T2F *q = &_quadVerts[i + _numberQuads * 4];
Vec3 *vec1 = (Vec3*)&q->vertices;
modelView.transformPoint(vec1);
}
_numberQuads += cmd->getQuadCount();
}
其中的for循环就是在对quads顶点数组中的每个坐标乘以MV矩阵。
cocos2dx 3.x ccPositionTextureColor_vert与ccPositionTextureColor_noMVP_vert的更多相关文章
- [cocos2dx]2.2到3.1(3.0)升级帮助
摘要: cocos2dx 是一款优秀的多平台,专为2D游戏设计的引擎. 在活跃的开源社区的推进下, 越发稳定和强大. 2.x -> 3.x的更新幅度很大, 性能的提升和功能的丰富也非常明显. 但 ...
- cocos2dx spine之二 :spine变色
cocos2dx版本为3.10 1.具体原理和代码可以参考博文<利用shader改变图片色相Hue>,下面的代码根据该博文进行整理优化. 基本原理就是将RGB值转换为HSL值后加上输入的H ...
- cocos2dx shader实现灰度图android后台切换回来导致图像偏移的问题
转自:http://www.tuicool.com/articles/U3URRrI 项目中经常会遇到将一张图像处理成灰色的需求,为了节省资源,一般不会让美术再做一套同样的灰度图,通常会通过代码处理让 ...
- 通过cocos2d-x的CCGLProgram和CCShaderCache的实现来分析OpenGL ES中的Shader编程
在OpenGL ES中,Shader是着色器,包括两种:顶点着色器(Vertex Shader)和片元着色器(Fragment Shader).每个program对象有且仅有一个Vertex Shad ...
- Cocos2d-x shader学习1: 灰度shader
灰度shader 最近在学习shader,就把cocos2d-x 3.x版本中的很简单也很常用的灰度shader拿出来学习一下. #ifdef GL_ES precision mediump floa ...
- cocos2dx - shader实现任意动画的残影效果
本节主要讲利用cocos2dx机制实现opengl es shader脚本的绘制 这里先看下最终效果: 这里分别实现了灰度效果及残影的效果. 一.绘制基类 这 ...
- 基于Cocos2d-x学习OpenGL ES 2.0系列——OpenGL ES渲染之Shader准备(7)
Cocos2d-x底层图形绘制是使用OpenGL ES协议的.OpenGL ES是什么呢? OpenGL ES(OpenGl for Embedded System)是OpenGL三维图形API的子集 ...
- cocos2dx调用浏览器打开网址
安卓端cocos2dx/platform/android路径下CCApplication.h: virtual void openURL(const char* pszUrl); CCApplicat ...
- 使用“Cocos引擎”创建的cpp工程如何在VS中调试Cocos2d-x源码
前段时间Cocos2d-x更新了一个Cocos引擎,这是一个集合源码,IDE,Studio这一家老小的整合包,我们可以使用这个Cocos引擎来创建我们的项目. 在Cocos2d-x被整合到Cocos引 ...
随机推荐
- 老三星手机i9001刷机记录
家里的老的三星i9001,准备给我妈用,打算刷机,但又实在头疼那些复杂的刷机技术,昨天研究了一下,用比较简单的方法完成刷机,记录如下: 用卡刷比较简单,线刷不考虑 进入恢复模式的方法:1.电源+音量加 ...
- 红米NOTE应用闪退(包括系统设置等各种界面)问题解决经历
关机状态下同时按减音量按钮和开机按钮,进入一个菜单,选择recovery(减音量键是移动,加音量键是确定),当出现一个倒地的机器人的时候,稍待片刻按开机键会出现双清以及刷机菜单.wipe data/f ...
- [Javascript] Closure Cove, Common mistake
They’ve got a problem with their existing code, which tries to use a closure. Check it out: function ...
- Android Studio中安装Genymotion模拟器
Genymotion的安装: Genymotion无疑是目前最快最好用的模拟器.官网下载地址:https://www.genymotion.com/ 进到官网却找不到免费下载地址了,都需要money, ...
- C# 64位系统调用32位DLL异常解决办法(异常来自HRESULT :0x8007007E)
解决办法如下 1.在IDE中将目标平台设置成x86(VS是在项目的属性->生成->目标平台) 2.如果DLL中调用了其他的DLL,需要将其他的DLL一同编译 3.有时DLL生成时会依赖于I ...
- Java实现根据输入的日期以及天数,获取此日期之后的天数的工作日
public static void main(String[] args) { List<String> list = new ArrayList<String>();//节 ...
- MySQL的各种SHOW
. SHOW语法 13.5.4.1. SHOW CHARACTER SET语法 13.5.4.2. SHOW COLLATION语法 13.5.4.3. SHOW COLUMNS语法 13.5.4.4 ...
- 使用fiddler来抓包
使用fiddler来抓包 Sniffer,wireshark,WinNetCap.WinSock Expert,SpyNet 都是当前流行的抓包工具 需要先做一些简单的准备工作: 一台带有无线网卡的P ...
- Tomcat跨二级域配置
内容转自:http://blog.csdn.net/luka2008/article/details/38385703/,请直接看原文,不过这篇“原文”也是转的... 1,Tomcat下 代码: im ...
- windows登陆密码破解方法之一
网上的一些人让别人进入命令提示符安全模式,我比较奇怪如果没有密码怎么进去?能进去干嘛还要进去? 本笨方法的原理主要是利用登陆界面的一些程序入口,把它当成后门来使用,比如win7登陆界面上除了输密码的地 ...