Cocos2d-x 3.x 图形学渲染系列二十五

笔者介绍:姜雪伟IT公司技术合伙人,IT高级讲师,CSDN社区专家,特邀编辑,畅销书作者,国家专利发明人;已出版书籍:《手把手教你架构3D游戏引擎》电子工业出版社和《Unity3D实战核心技术详解》电子工业出版社等。

CSDN视频网址:http://edu.csdn.net/lecturer/144

大年三十,还是忍不住,再写一篇文章吧,作为在猴年的最后一篇文章。。。。

游戏中的角色包括玩家、NPC、怪物等都具有骨骼动画,对于成熟的引擎也是需要支持骨骼动画的,骨骼动画是在模型的基础上经过max工具调试出来的,在程序中只需要提供播放骨骼动画的接口即可,掌握骨骼动画的原理对于评判一个程序员是否精通引擎的必要条件,也是一个重要的评判指标。本章重点给读者介绍Cocos2d-x的骨骼动画,虽然该引擎对骨骼动画的处理不是很成熟,但简单的骨骼动画还是可以实现的。本章会把Cocos2d-x引擎中关于动画的处理的缺点和优点都会给读者分享。

骨骼动画是通过蒙皮实现的,Cocos2d-x引擎有自己的demo实现,如果开发者掌握骨骼动画,必须自己要尝试着做一下。Cocos2d-x引擎还是有很多坑的,尤其是在播放动画方面。后面会给读者介绍到,下面就以自己做的带有骨骼动画的宇航员模型为例给读者介绍。因为c3t是json文件格式,相对读者能够看到其文件内容,更有助于读者理解。在这里只截取了骨骼动画数据展示如下所示:

"animations": [
		{
			"id": "Take 001", 
			"length":  0.666000, 
			"bones": [
				{
					"boneId": "Box002", 
					"keyframes": [
						{
							"keytime":  0.000000, 
							"rotation": [-0.707107, -0.000000,  0.000000,  0.707107], 
							"scale": [ 1.000000,  1.000000,  1.000000], 
							"translation": [ 0.000000,  36.417324, -74.842522]
						}, 
						{
							"keytime":  0.050050, 
							"rotation": [-0.696203, -0.000000,  0.000000,  0.717845]
						}, 
						{
							"keytime":  0.100100, 
							"rotation": [-0.665764, -0.000000,  0.000000,  0.746162]
						}, 
						{
							"keytime":  0.150150, 
							"rotation": [-0.617108, -0.000000,  0.000000,  0.786878]
						}, 
						{
							"keytime":  0.200200, 
							"rotation": [-0.556456, -0.000000,  0.000000,  0.830877]
						}, 
						{
							"keytime":  0.250250, 
							"rotation": [-0.486915, -0.000000,  0.000000,  0.873449]
						}, 
						{
							"keytime":  0.300300, 
							"rotation": [-0.414019, -0.000000,  0.000000,  0.910268]
						}, 
						{
							"keytime":  0.350350, 
							"rotation": [-0.342342, -0.000000,  0.000000,  0.939575]
						}, 
						{
							"keytime":  0.400400, 
							"rotation": [-0.283450, -0.000000,  0.000000,  0.958987]
						}, 
						{
							"keytime":  0.450450, 
							"rotation": [-0.241560, -0.000000,  0.000000,  0.970386]
						}, 
						{
							"keytime":  0.500501, 
							"rotation": [-0.226392, -0.000000,  0.000000,  0.974036]
						}, 
						{
							"keytime":  0.550551, 
							"rotation": [-0.240981, -0.000000,  0.000000,  0.970530]
						}, 
						{
							"keytime":  0.600601, 
							"rotation": [-0.282420, -0.000000,  0.000000,  0.959291]
						}, 
						{
							"keytime":  0.650651, 
							"rotation": [-0.341023, -0.000000,  0.000000,  0.940055]
						}, 
						{
							"keytime":  0.700701, 
							"rotation": [-0.410364, -0.000000,  0.000000,  0.911922]
						}, 
						{
							"keytime":  0.750751, 
							"rotation": [-0.485455, -0.000000,  0.000000,  0.874261]
						}, 
						{
							"keytime":  0.800801, 
							"rotation": [-0.555123, -0.000000,  0.000000,  0.831769]
						}, 
						{
							"keytime":  0.850851, 
							"rotation": [-0.616001, -0.000000,  0.000000,  0.787745]
						}, 
						{
							"keytime":  0.900901, 
							"rotation": [-0.664969, -0.000000,  0.000000,  0.746871]
						}, 
						{
							"keytime":  0.950951, 
							"rotation": [-0.695771, -0.000000,  0.000000,  0.718264]
						}, 
						{
							"keytime":  1.000000, 
							"rotation": [-0.707102, -0.000000,  0.000000,  0.707111], 
							"scale": [ 1.000000,  1.000000,  1.000000], 
							"translation": [ 0.000000,  36.417324, -74.842522]
						}
					]
				}
			]
		}
	]

在上述文件中id表示的是骨骼动画的名字,bone表示的是动作,在bone项里面包含keytime帧动画时间,rotation旋转的角度,scale缩放大小,translation表示的骨骼转换的起始位置和最终转换的位置。程序的作用就是加载读取该模型文件,程序加载模型文件,需要在程序中定义相应的结构体,定义结构体主要是用于存放模型信息对应项,Cocos2d-x引擎已定义的结构体给介绍如下:

//模型顶点属性
struct MeshVertexAttrib
{
	//描述该属性所需要的元素个数,比如描述一个Vec3的位置信息,需要x、y、z 3个变量
	GLint size;
	//元素的类型如GL_FLOAT
	GLenum type;
	//描述该属性类型的值,使用的值是GLProgram类的枚举,例如	GLProgram::VERTEX_ATTRIB_POSITION
	int  vertexAttrib;
	//存储该属性所需要的字节数,等于size * sizeof(type)
	int attribSizeBytes;
};
再介绍一下模型蒙皮数据结构体如下所示:
struct MeshData
{
	//模型的顶点索引数组
typedefstd::vector<unsignedshort> IndexArray;
	//模型的顶点数组
std::vector<float> vertex;
	//模型的顶点数量
int vertexSizeInFloat;
//子模型的索引
std::vector<IndexArray> subMeshIndices;
//子模型的名字ID
std::vector<std::string> subMeshIds; //子网格名字 (从版本3.3开始)
//模型的碰撞盒
	std::vector<AABB> subMeshAABB;
int numIndex;
//模型的顶点属性信息
	std::vector<MeshVertexAttrib> attribs;
int attribCount;
}
以c3t文件为例,先介绍模型相关文件属性:
"version": "0.7", 
	"id": "", 
	"meshes": [
		{
			"attributes": [{
					"size":   3, 
					"type": "GL_FLOAT", 
					"attribute": "VERTEX_ATTRIB_POSITION"
				}, {
					"size":   3, 
					"type": "GL_FLOAT", 
					"attribute": "VERTEX_ATTRIB_NORMAL"
				}, {
					"size":   3, 
					"type": "GL_FLOAT", 
					"attribute": "VERTEX_ATTRIB_TANGENT"
				}, {
					"size":   3, 
					"type": "GL_FLOAT", 
					"attribute": "VERTEX_ATTRIB_BINORMAL"
				}, {
					"size":   2, 
					"type": "GL_FLOAT", 
					"attribute": "VERTEX_ATTRIB_TEX_COORD"
				}],


attribs属性数组分别代表:

(1)顶点在模型坐标系下的位置信息(VERTEX_ATTRIB_POSITION)

(2)顶点的法线(VERTEX_ATTRIB_NORMAL)

(3)顶点的纹理坐标(VERTEX_ATTRIB_TEX_COOD)

(4)作用于该顶点的某骨骼,对该顶点最终位置的权重(VERTEX_ATTRIB_BLEND_WEIGHT)

(5)影响该顶点的骨骼在骨骼数组中的索引(VERTEX_ATTRIB_BLEND_INDEX)

   接下来介绍模型的蒙皮骨骼信息,引擎提供了结构体如下所示:


struct SkinData
{
//影响到模型蒙皮的骨骼名字数组,skinBone的数组
std::vector<std::string> skinBoneNames; 
//未影响到模型蒙皮的骨骼名字数组,nodeBone的数组
std::vector<std::string> nodeBoneNames; 
//从对应的skinBone坐标系到模型坐标系变换的逆变换,可实现将该骨骼影响的蒙	皮顶点从模型坐标系的坐标,转换至骨骼坐标系的坐标
std::vector<Mat4>        inverseBindPoseMatrices; 
//skinBone到其父骨骼坐标的初始矩阵
std::vector<Mat4>        skinBoneOriginMatrices; 
//nodeBone到其父骨骼坐标的初始矩阵
std::vector<Mat4>        nodeBoneOriginMatrices; 
//所有骨骼与其子骨骼索引的map,值得说明的是这个索引是对skinBoneNames	和nodeBoneNames两个数组而言的。
std::map<int, std::vector<int>> boneChild;
//根骨骼索引,同样是相对两个数组而言的
	introotBoneIndex;
}
//材质数据结构体
struct MaterialData
{
	std::map<int, std::string> texturePaths; //子网格id和纹理路径
	void resetData()
    {
		texturePaths.clear();
    }
};


骨骼动画的运动是通过矩阵之间的变换实现的,在Bone3D类中实现了骨骼矩阵的更新,函数如下所示:

void Bone3D::updateJointMatrix(Vec4* matrixPalette)
{
    {
	static Mat4 t;
	//得到需要的矩阵
	Mat4::multiply(_world, getInverseBindPose(), &t);
	//将矩阵最后一行去掉,得到4 * 3的Vec4向量数组
	 matrixPalette[0].set(t.m[0], t.m[4], t.m[8], t.m[12]);
	 matrixPalette[1].set(t.m[1], t.m[5], t.m[9], t.m[13]);
	 matrixPalette[2].set(t.m[2], t.m[6], t.m[10], t.m[14]);
    }
}

updateJointMatrix函数主要是告诉读者,模型的骨骼在运动时都是通过矩阵运算得到的,骨骼数量越多,它们消耗CPU越多,因此为了优化骨骼运算,现在的处理方式都是将运算移到GPU中计算。

下面构建渲染指令,传递矩阵数据变换到GPU中进行计算,把骨骼动画处理的Shader文件给读者展示如下:

vec4 getPosition()
{
	//对该顶点产生作用的第一块骨骼所占比重
	float blendWeight = a_blendWeight[0];
	
	int matrixIndex = int (a_blendIndex[0]) * 3;
	//对传递进来的matrixPalette矩阵乘以骨骼的权重
	vec4 matrixPalette1 = u_matrixPalette[matrixIndex] * blendWeight;
	vec4 matrixPalette2 = u_matrixPalette[matrixIndex + 1] * blendWeight;
	vec4 matrixPalette3 = u_matrixPalette[matrixIndex + 2] * blendWeight;


    	blendWeight = a_blendWeight[1];
if (blendWeight >0.0)
{
		//若还有别的骨骼对该顶点产生影响,则进行混合
        matrixIndex = int(a_blendIndex[1]) * 3;
        matrixPalette1 += u_matrixPalette[matrixIndex] * blendWeight;
        matrixPalette2 += u_matrixPalette[matrixIndex + 1] * blendWeight;
        matrixPalette3 += u_matrixPalette[matrixIndex + 2] * blendWeight;

        blendWeight = a_blendWeight[2];
	if (blendWeight >0.0)
        {
            matrixIndex = int(a_blendIndex[2]) * 3;
            matrixPalette1 += u_matrixPalette[matrixIndex] * blendWeight;
            matrixPalette2 += u_matrixPalette[matrixIndex + 1] * blendWeight;
            matrixPalette3 += u_matrixPalette[matrixIndex + 2] * blendWeight;

            blendWeight = a_blendWeight[3];
	    if (blendWeight >0.0)
            {
                matrixIndex = int(a_blendIndex[3]) * 3;
                matrixPalette1 += u_matrixPalette[matrixIndex] * blendWeight;
                matrixPalette2 += u_matrixPalette[matrixIndex + 1] * blendWeight;
                matrixPalette3 += u_matrixPalette[matrixIndex + 2] * blendWeight;
            }
        }
    }

    vec4 _skinnedPosition;
    vec4 postion = vec4(a_position, 1.0);
    //使用这个混合后的矩阵,对顶点进行变换,得到该顶点在模型坐标系下的坐标
    _skinnedPosition.x = dot(postion, matrixPalette1);
    _skinnedPosition.y = dot(postion, matrixPalette2);
    _skinnedPosition.z = dot(postion, matrixPalette3);
    _skinnedPosition.w = postion.w;

	return _skinnedPosition;
}
void main()
{
	//得到顶点在模型坐标系下的坐标
	vec4 position = getPosition();
	//使用MVP矩阵进行变换的到最终坐标
	gl_Position = CC_MVPMatrix * position;

    	TextureCoordOut = a_texCoord;
   	TextureCoordOut.y = 1.0 - TextureCoordOut.y;
}

骨骼动画在GPU中根据骨骼的权重进行矩阵运算,这样也可以保证骨骼动画与动画之间的过渡是平滑的,保证了不同的骨骼动画之间的切换是顺畅的。在美术制作模型时,要按照一定的规则制作,从而保证导出的模型可以在Cocos2d-x引擎中加载,接下来给读者介绍关于模型的制作。






  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: cocos2d-x js是一个开源的游戏开发引擎,用于开发跨平台的2D游戏,它使用JavaScript作为脚本语言。以下是对cocos2d-x js的回答。 cocos2d-x js是cocos2d-x引擎的JavaScript版本,它继承了cocos2d-x引擎强大的功能和性能,同时提供了使用JavaScript编写游戏的便利性。 cocos2d-x js通过使用JavaScript脚本语言进行游戏开发,使得开发者可以更加方便地编写游戏逻辑和动作表现。JavaScript是一种简单易用的脚本语言,对于不熟悉复杂编程语言的开发者来说,使用JavaScript进行游戏开发会更加容易上手。 cocos2d-x js提供了丰富的游戏功能和API,包括精灵动画、物理引擎、碰撞检测、场景管理等,这些功能可以帮助开发者快速构建2D游戏。同时,cocos2d-x js还提供了跨平台的支持,可以将游戏轻松移植到不同的平台上,如iOS、Android、Windows等。 除了基本的功能和API,cocos2d-x js还支持插件和扩展,开发者可以根据自己的需求进行扩展和定制,以满足游戏的特殊需求。 总结来说,cocos2d-x js是一个强大而灵活的游戏开发引擎,它提供了使用JavaScript进行游戏开发的便利性,同时具备跨平台的支持和丰富的功能和API。无论是初学者还是有经验的开发者,都可以通过cocos2d-x js来快速构建出高质量的2D游戏。 ### 回答2: Cocos2d-x是一款强大的跨平台游戏开发引擎,具有许多独特而且强大的功能。cocos2d-x js篇是Cocos2d-x引擎的JavaScript版本,它可以让开发者使用JavaScript编写游戏逻辑和界面。 使用Cocos2d-x js篇,开发者可以轻松地创建2D游戏,并在多个平台上运行,如iOS、Android、Windows和Web。这意味着开发者只需编写一次代码,就可以发布到多个平台,大大提高了开发效率。 cocos2d-x js篇提供了丰富的API和功能,使得开发复杂的游戏变得轻松。它包括图形渲染、动画系统、物理引擎、碰撞检测、音频管理等功能,开发者可以利用这些功能创建出丰富多样的游戏体验。 此外,cocos2d-x js篇还支持现代开发工具和技术,如可视化编辑器Cocos Creator,可实时调试和热更新等。开发者可以使用Cocos Creator创建游戏场景、编辑动画、创建粒子效果等。同时,Cocos2d-x js篇还集成了调试工具,方便开发者进行错误排查和优化。 总之,Cocos2d-x js篇是一个非常强大且灵活的游戏开发引擎。它提供了广泛的功能和工具,使得开发者能够快速创建高质量的2D游戏,并在多个平台上发布。无论是初学者还是有经验的开发者,都可以通过Cocos2d-x js篇轻松实现独特而丰富的游戏体验。 ### 回答3: Cocos2d-x js是一种使用Javascript编写的跨平台游戏开发框架。它是基于Cocos2d-x引擎的扩展,可以在多个平台上运行,包括iOS、Android、Windows和Mac等。 Cocos2d-x js提供了丰富的游戏开发工具和功能,可以帮助开发人员轻松创建高质量的游戏应用。它具有优秀的性能和灵活性,并且能够快速部署到各种平台上。 使用Cocos2d-x js,开发人员可以使用熟悉的Javascript语言进行游戏开发,而无需学习其他编程语言。它提供了一系列API和组件,例如精灵、动作、节点和场景等,以简化游戏的创建和管理过程。 此外,Cocos2d-x js还提供了多种功能,如物理引擎、碰撞检测、音效播放和动画效果等,可以帮助开发人员实现各种游戏特效和交互效果。 Cocos2d-x js还支持一些常用的开发模式和工具,如游戏UI编辑器、游戏调试器和性能分析器等,方便开发人员进行游戏开发和调试。 总之,Cocos2d-x js是一款功能强大、易于使用并且跨平台的游戏开发框架。无论是新手还是经验丰富的开发人员,都可以借助它来创建出令人印象深刻的游戏应用。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

海洋_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值