在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的更多相关文章

  1. [cocos2dx]2.2到3.1(3.0)升级帮助

    摘要: cocos2dx 是一款优秀的多平台,专为2D游戏设计的引擎. 在活跃的开源社区的推进下, 越发稳定和强大. 2.x -> 3.x的更新幅度很大, 性能的提升和功能的丰富也非常明显. 但 ...

  2. cocos2dx spine之二 :spine变色

    cocos2dx版本为3.10 1.具体原理和代码可以参考博文<利用shader改变图片色相Hue>,下面的代码根据该博文进行整理优化. 基本原理就是将RGB值转换为HSL值后加上输入的H ...

  3. cocos2dx shader实现灰度图android后台切换回来导致图像偏移的问题

    转自:http://www.tuicool.com/articles/U3URRrI 项目中经常会遇到将一张图像处理成灰色的需求,为了节省资源,一般不会让美术再做一套同样的灰度图,通常会通过代码处理让 ...

  4. 通过cocos2d-x的CCGLProgram和CCShaderCache的实现来分析OpenGL ES中的Shader编程

    在OpenGL ES中,Shader是着色器,包括两种:顶点着色器(Vertex Shader)和片元着色器(Fragment Shader).每个program对象有且仅有一个Vertex Shad ...

  5. Cocos2d-x shader学习1: 灰度shader

    灰度shader 最近在学习shader,就把cocos2d-x 3.x版本中的很简单也很常用的灰度shader拿出来学习一下. #ifdef GL_ES precision mediump floa ...

  6. cocos2dx - shader实现任意动画的残影效果

    本节主要讲利用cocos2dx机制实现opengl es shader脚本的绘制 这里先看下最终效果:                      这里分别实现了灰度效果及残影的效果. 一.绘制基类 这 ...

  7. 基于Cocos2d-x学习OpenGL ES 2.0系列——OpenGL ES渲染之Shader准备(7)

    Cocos2d-x底层图形绘制是使用OpenGL ES协议的.OpenGL ES是什么呢? OpenGL ES(OpenGl for Embedded System)是OpenGL三维图形API的子集 ...

  8. cocos2dx调用浏览器打开网址

    安卓端cocos2dx/platform/android路径下CCApplication.h: virtual void openURL(const char* pszUrl); CCApplicat ...

  9. 使用“Cocos引擎”创建的cpp工程如何在VS中调试Cocos2d-x源码

    前段时间Cocos2d-x更新了一个Cocos引擎,这是一个集合源码,IDE,Studio这一家老小的整合包,我们可以使用这个Cocos引擎来创建我们的项目. 在Cocos2d-x被整合到Cocos引 ...

随机推荐

  1. 升级mojave后的小问题解决

    首先是xcode没了,我到苹果软件市场上重新下载了一个,可以了. 然后是virtualbox无法打开了,现实版本不兼容,我到官网重新下载了一个最新的6.0.然后就可以正常打开了,并且是无感升级,原来的 ...

  2. python 插入数据获取id

    python 插入数据获取id 学习了:https://blog.csdn.net/qq_37788558/article/details/78151972 commit之前获取 cursor.las ...

  3. (LeetCode 21)Merge Two Sorted Lists

    Merge two sorted linked lists and return it as a new list. The new list should be made by splicing t ...

  4. 支持各种控件上/下拉刷新的android-pulltorefresh

    android- pulltorefresh 一个强大的拉动刷新开源项目,支持各种控件下拉刷新,如ListView.ViewPager.WevView. ExpandableListView.Grid ...

  5. Smack 结合 Openfire服务器,建立IM通信,发送聊天消息

    在文章开始,请你了解和熟悉openfire方面的相关知识,这样对你理解下面代码以及下面代码的用途有很好的了解.同时,你可能需要安装一个简单的CS聊天工具,来测试你的代码是否成功的在openfire服务 ...

  6. linux查询文件中某几行

    查询文件中某几行: sudo cat /etc/tinyproxy.conf | head -n | tail -n + [一]从第3000行开始,显示1000行.即显示3000~3999行 cat ...

  7. Java多线程系列目录(共43篇)(转)

    Java多线程系列目录(共43篇) http://www.cnblogs.com/skywang12345/p/java_threads_category.html

  8. Web应用中的普通java程序获取资源文件

  9. python一键电影搜索与下载

    代码地址如下:http://www.demodashi.com/demo/14313.html python一键电影搜索与下载 概述 使用python搜索并爬取豆瓣电影信息,包括评分,主演,导演,类型 ...

  10. HDUOJ----Ignatius and the Princess III

    Ignatius and the Princess III Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K ...