Quick-cocos(3.2) 将对象(包括子对象)变灰的方法

先上效果图:

借鉴了[Cocos2d-x 让精灵图像变灰的方法]

但这个方法在Quick-Cocos3.2下不能完美实现变灰效果-变灰了的对象的位置会跳到屏幕右上角。

百思不得其解,搜一下有没有人发现这个问题,果然有:

[关于Sprite的setShaderProgram后坐标改变的问题]

发现4楼的仁兄的回复有亮点:

[如何在Cocos2d-x 3.0中使用opengl shader?]

点进去一看,内容是这样的:

“坐标变化的解决了,将附件gray.vsh 中的CC_MVPMatrix 改为 CC_PMatrix 即可 ”

我估计应该是位置转换的矩阵问题吧,gray.vsh是什么下面会说到。

经过分析,发现原因在addGray方法([Cocos2d-x 让精灵图像变灰的方法])的27行:

pProgram->initWithVertexShaderByteArray(ccPositionTextureColor_vert, pszFragSource);

ccPositionTextureColor_vert是什么呢?它存放在cocos/renderer下,名为ccShader_PositionTextureColor.vert。它的作用是……以在下的理解,是一个shader方法(ccShader),关于位置、材质与颜色的(PositionTextureColor)且是针对顶点的(.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;
}
);

咦,发现有一个熟悉的面孔-“CC_MVPMatrix”。其实上面说到的gray.vsh的内容就是ccShader_PositionTextureColor.vert大括号括住的部分。那我将ccShader_PositionTextureColor.vert的CC_MVPMatrix改为CC_PMatrix是否就能解决灰化后对象的位置问题呢?答案是否定的,这样改会影响其他对象(例如文本)的定位。

那我再定义一个GLchar传到pProgram->initWithVertexShaderByteArray的第一个参数不就得咯?

const GLchar* pszVertSource = 
	"attribute vec4 a_position; \n 	attribute vec2 a_texCoord; \n 	attribute vec4 a_color; \n 	\n#ifdef GL_ES\n \n 	varying lowp vec4 v_fragmentColor; \n 	varying mediump vec2 v_texCoord; \n 	\n#else\n \n 	varying vec4 v_fragmentColor; \n 	varying vec2 v_texCoord; \n 	\n#endif\n \n 	void main() \n 	{ \n 		gl_Position = CC_PMatrix * a_position; \n 		v_fragmentColor = a_color; \n 		v_texCoord = a_texCoord; \n 	}";
  
pProgram->initWithVertexShaderByteArray(pszVertSource, pszFragSource);

经实践证实是可行的。其实有个更简单的方法,就是:

pProgram->initWithVertexShaderByteArray(ccPositionTextureColor_noMVP_vert, pszFragSource);

原来cocos/renderer下有个文件叫ccShader_PositionTextureColor_noMVP.vert。



最后附上实现灰化功能的全部代码。

C++部分,将此方法导出给lua用:

void setGray(Node *node)
{
  USING_NS_CC;
  do
  {
  	const GLchar* pszFragSource =
			"#ifdef GL_ES \n 			precision mediump float; \n 			#endif \n 			uniform sampler2D u_texture; \n 			varying vec2 v_texCoord; \n 			varying vec4 v_fragmentColor; \n 			void main(void) \n 			{ \n 			// Convert to greyscale using NTSC weightings \n 			vec4 col = texture2D(u_texture, v_texCoord); \n 			float grey = dot(col.rgb, vec3(0.299, 0.587, 0.114)); \n 			gl_FragColor = vec4(grey, grey, grey, col.a); \n 			}";
      
  	GLProgram* pProgram = new GLProgram();
  	pProgram->initWithByteArrays(ccPositionTextureColor_noMVP_vert, pszFragSource);
  	node->setGLProgram();
  	CHECK_GL_ERROR_DEBUG();
  }while(0);

}

lua部分:

--不进行灰化的对象特有的方法
DisplayUtil.LIST_DONT_GRAY = {
	"getSprite", 	--ProgressTimer
	"setString", 	--Label
}

--判断能否灰化
function DisplayUtil.canGray(node)
	for i,v in ipairs(DisplayUtil.LIST_DONT_GRAY) do
		if node[v] then
			return false
		end
	end
	return true
end

--灰化对象
function DisplayUtil.setGray(node, v)
	if type(node) ~= "userdata" then
		printError("node must be a userdata")
		return
	end
	if v == nil then
		v = true
	end
	if not node.__isGray__ then
		node.__isGray__ = false
	end
	if v == node.__isGray__ then
		return
	end
	if v then
		if DisplayUtil.canGray(node) then
    	--调用C++的setGray方法
			setGray(tolua.cast(node, "cocos2d::Node"))
			--
			-- local glProgram = node:getGLProgram()
			-- node:setGLProgram(glProgram)
			-- node:getGLProgram():bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
			-- node:getGLProgram():bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
			-- node:getGLProgram():bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_TEX_COORDS)

			--不知道为什么下面2行一定要写
			node:getGLProgram():link()
			node:getGLProgram():updateUniforms()
		end
		--children
		local children = node:getChildren()
		if children and table.nums(children) > 0 then
			--遍历子对象设置
			for i,v in ipairs(children) do
				if DisplayUtil.canGray(v) then
					DisplayUtil.setGray(v)
				end
			end
		end
	else
		DisplayUtil.removeGray(node)
	end
	node.__isGray__ = v
end

--取消灰化
function DisplayUtil.removeGray(node)
	if type(node) ~= "userdata" then
		printError("node must be a userdata")
		return
	end
	if not node.__isGray__ then
		return
	end
	if DisplayUtil.canGray(node) then
		local glProgram = cc.GLProgramCache:getInstance():getGLProgram(
			"ShaderPositionTextureColor_noMVP")
		node:setGLProgram(glProgram)
		-- glProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_POSITION, cc.VERTEX_ATTRIB_POSITION)
		-- glProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_COLOR, cc.VERTEX_ATTRIB_COLOR)
		-- glProgram:bindAttribLocation(cc.ATTRIBUTE_NAME_TEX_COORD, cc.VERTEX_ATTRIB_TEX_COORDS)

		--不知道为什么下面2行不能写,写了会出问题
		-- glProgram:link()
		-- glProgram:updateUniforms()
	end
	--children
	local children = node:getChildren()
	if children and table.nums(children) > 0 then
		--遍历子对象设置
		for i,v in ipairs(children) do
			if DisplayUtil.canGray(v) then
				DisplayUtil.removeGray(v)
			end
		end
	end
	node.__isGray__ = false
end

怎么使用不用我多说了吧。

时间: 2024-09-29 16:08:40

Quick-cocos(3.2) 将对象(包括子对象)变灰的方法的相关文章

quick cocos 或者 Cocos2dx 项目下的Android.mk文件的学习

android.mk文件的作用:编译需要的cpp文件,生成.so动态库,供android端调用. 先上一个android.mk文件: 第一次创建项目,在Android平台编译时,都需要通过android.mk文件编译整个cocos2dx的库(第一次编译我们需要等待很长的时间.....). 首先知道$(call import-module,dir_name)的作用,然后顺着lib/proj.android目录继续找对应目录下的android.mk文件 类似于递归一样,把所有目录下的android.

Qt那点事儿(三) 论父对象与子对象的关系

第三回 父与子 70后的道友都应该看过这么一部片子叫做<<父子情深>>.讲述的是一个小男孩患了绝症,父亲为了满足他的愿望,让已关门的游乐园为他们父子俩重新开放.在游乐园尽情地玩耍后,最后小孩子在父亲的怀中安详地闭上了眼睛.缓缓转动的摩天轮,配着淡淡忧伤的曲调,这一刻哥泪流满面.谁说世上只有妈妈好,父爱也顶半边天.此时台下的众多男道友热泪盈眶,不约而同地起立鼓掌.史上最大的冤屈,终于得以昭雪. 但是人世间这种真挚的父爱也存在于Qt中吗? 对此,从小缺乏父爱的张无忌小友给出了自己的答案

quick cocos UIListView之isItemInViewRect方法修正

功能描述:一个滚动列表,当列表可视区域上部有内容时则上部出现向上箭头提示,当列表可视区域下部有内容则下部出现向下箭头提示. 功能实现:应用cocos studio1.6制作界面,上面放置一个背景,一个滚动列表,然后程序加载解析这个界面的json文件,应用quick3.3final下的UIListView的方法isItemInViewRect进行检测第一条与最后一条是否在可视区域内. 问题:当界面加载进来,坐标设置0,0时,isItemInViewRect方法判断都没问题,但当把界面调整位置时,i

解决 堆栈 出现的父对象和子对象相关联的问题 (深拷贝)

// 解决 堆栈 出现的父对象和子对象相关联的问题 function dishesStackHandle(p, c) { var c = c || {}; for (var i in p) { if (typeof p[i] === 'object') { if (i == 'null' || i == null || p[i] == null) { c[i] = {}; } else { c[i] = (p[i].constructor === Array) ? [] : {}; } dish

获取数据库连接对象(包括线程)

/** * 负责数据库连接定义的程序类 * 该类可以负责所有操作线程的数据库连接,利用get()方法可以获得连接对象 */ public class DatabaseConnection { private static final String DBDRIVER = "oracle.jdbc.driver.OracleDriver" ; private static final String DBURL = "jdbc:oracle:thin:@localhost:1521

黑马程序员---OC---内存管理(在对象属性的- setter和- dealloc方法里面写内存管理代码)

------iOS培训.Java培训.Android培训, iOS学习型技术博客,期待与您交流------ 内存管理(在对象属性的- setter和- dealloc方法里面写内存管理代码) 内存管理范围: 任何继承自NSObject的对象:其他数据类型(int.char.double.float.struct.enum等)不需要内存管理 对象的引用计数器: 每个OC对象内部都有自己的int类型(占据4个字节)的引用计数器,表示“对象被引用的次数”. 1> 当使用alloc.new或者copy创

对象不支持ajax属性或方法

今天在做泛微流程开发的时候,遇到一件很奇怪的事情,流程流转到第二个节点,居然报错了,提示”对象不支持ajax属性和方法“,但是第一个节点测试并未报错了, /(ㄒoㄒ)/~~,然后试着把jQuery的简写“$"改成”JQuery“后,不在提示”对象不支持ajax属性和方法“错误,而是变成了“automation服务器不能创建对象”问题,看下了错误的代码 行”var xhr = window.ActiveXObject ? new ActiveXObject("Microsoft.XMLH

将插座变量(IBOutlet)关联到*.xib文件中对象 + 将对*.xib对象的操作关联到动作方法(IBAction)

将插座变量(IBOutlet)关联到*.xib文件中对象 以BNRDetailViewController.m和BNRDetailViewController.xib为例(<iOS编程>第10章例子) 1.打开BNRDetailViewController.xib,添加一个UITextField对象: 2.在辅助编辑器中打开BNRDetailViewController.m,方法是:按住Option键并点击项目导航面板中的BNRDetailViewController.m: 3.按住Contr

JS中的内置对象简介与简单的属性方法

JS中的数组: 1.数组的概念: 数组是在内存中连续存储的多个有序元素的结构,元素的顺序称为下标,通过下标查找对应元素 2.数组的声明: ①通过字面量声明var arr1 = [,,,,] JS中同一数组可以储存多种不同的数据类型(但,同一数组一般只用于存放同种数据类型) 例如var arr1 = [1,"2",true,{"name":"啦啦啦"},[1,2]]; ②通过new关键字声明:var arr2 = new Array(参数); &g