Cocos2dx-Lua 利用网格Grid实现3D的景深效果显示

目录

1、博客介绍

2、内容

(1)原理

(2)代码分析

(3)自定的Grid3D

(4)碰到的问题

(5)现成白嫖

(6)C++具体用例

(7)lua用例

3、推送

4、结语


1、博客介绍

最近有一些需求,希望能够在2D效果上,能够展现出来一些3D的透视关系,就花时间研究了一下实现思路,我们先看一看实现后的效果吧


2、内容

(1)原理

        我们可以看到在开头的示例当中,图片有一个很明显的近大远小的透视效果,用过cocos2dx的人应该知道,在cocos的action动作中有一种叫做网格(grid)动画的东西,利用网格动画,我们可以实现一些翻页抖屏的3D动画效果,既然已经可以做到翻页效果了,那理论上我应该可以让一张图片变化成任意的结构来显示出来,开头的效果就是参考网格动画做出来的。

(2)代码分析

我们首先通过研究cocos自带的一些源码,知道大概的解决思路以后,我们再开始着手改造我们自己需要的结构

相关脚本:CCNodeGrid   GridBase  Grid3D  CCActionPageTurn3D

以下是一个简单翻页的实现效果: 

	auto gridNode = NodeGrid::create();
	auto sp = Sprite::create("Hello.png");
	gridNode->addChild(sp);
	sp->setPosition(Vec2(360, 640));
	gridNode->runAction(PageTurn3D::create(5,Size(100,100)));

tips:这里博主只摘取源码内的有效内容列举,其他附带方法属性,有兴趣自己过一遍 ,以下内容要结合源码一起看才容易理解哟

NodeGrid:

NodeGrid是一个继承继承自Node 的类,其中主要信息,重写了Node的visit方法,还有一个类型为GridBase的私有变量。

重写的visit函数内,在_nodeGrid存在并活跃的时候,调用了_nodeGrid的一个方法set2DProjection,并在渲染前执行了onGridBeginDraw方法,调用完begainDraw方法后,在_nodeGrid存在并活跃的情况下,调用director的setProjection方法,重新设置了一下视口,并在之后调用了onGridEndDraw方法。

我们看begainDraw和endDraw方法内,分别又调用了_nodeGrid的beforeDraw和afterDraw方法,所以NodeGrid的功能就基本到这里了,利用重写Node的visit方法,来重新渲染最后显示在屏幕上的内容。

GridBase:

GridBase在init方法中实例了一个Texture2D,并且将这个texture设置为了gl的缓冲区,就是我们我们显示的内容会全部先绘制到这个texture上,到时候我们再去修改这个texture。

在beforeDraw和afterDraw去绘制和重新设置视口

Grid3D:

Grid3D是继承自GridBase,在一定方面对GridBase进行了补充,其中方法getOriginalVertex是用来获取对应网格的原始坐标,setVertex方法是设定对应网格的新坐标。

CCActionPageTurn3D:

在PageTurn3D的update方法内,我们可以看到调用了重新设置网格定点坐标的方法setVertex

总上所述,我们其实已经能够大概知道,一个3DAction的动画是怎么实现的

1、我们首先会建立一个承载的Node,这个Node上添加的物体并不会被直接渲染在屏幕上

2、创建一个新的texture用来接收本应该被渲染在屏幕上的顶点信息

3、将这个texture根据自定义的Size来分成一个 col * row 的网格

4、重新计算每个网格的坐标顶点信息

5、最后将计算后的样式渲染在屏幕当中

(3)自定的Grid3D

其实到这里,只要上述的内容你能明白,接下来该怎么做

1、我们需要创建一个新的GridBase3D,该类融合了GridBase和Grid3D,并且在最后视口需要用3D视口来绘制

2、新建一个NodeGrid3D类,该类基本和NodeGrid相同,不过当中的GridBase替换为了GridBase3D

3、最后我们手动去调用GridBase3D的setVertex方法就可以显示出任意你想要出现的结果

(4)碰到的问题

博主这里不会对新做的类进行细致的介绍,列举几个制作当中出现的问题

1、正常显示的话,超出屏幕外的精灵不会被渲染,当你改变网格的Z轴后,本来看不到的精灵就会出现在视野里,但是因为原先就没有渲染所以现在还是看不到

解决方案:重写一个Sprite类,继承Sprite,重写Draw方法,让精灵在任意情况下均会被渲染

2、设置3D视口的话,有一个被称为远截面和近截面的东西,就是当Z过大或者过小的时候,就不会被渲染了

解决方案:手动设置远截面的值

(5)现成白嫖

代码不贴出来了,需要的从后边跳转博主github自行下载,下载后,直接放到libcocos2d目录下,重新编译后就可以使用了

(6)C++具体用例

    这里给个上述例子的写法演示	

    //创建NodeGrid3D
	auto gridNode = NodeGrid3D::create();
	scene->addChild(gridNode);
	//创建GridBase3D  参数: Size(100,500)网格100*500   720*2048 texture的尺寸  5000远截面距离
	auto grid3D = GridBase3D::create(Size(100, 500), 720, 2048, 5000);
	gridNode->setGrid3D(grid3D);
	//创建精灵添加在NodeGrid3D上
	for (int i = 0; i < 5; i++)
	{
		auto sp = SpriteAll::create("Hello.png");
		gridNode->addChild(sp);
		sp->setPosition(Vec2(360,160+322*i));
		sp->runAction(MoveBy::create(8, Vec2(0, -1000)));
	}
	//重新设置网格的顶点信息
	for (int col = 0; col < 100; col++)
	{
		for (int row = 0; row < 500; row++)
		{
			auto vPos = grid3D->getOriginalVertex(Vec2(col, row));
			//纵坐标大于150的网格Z值被修改
			if (row > 150) {
				
				auto zValue = -(row - 150) * 5;
				grid3D->setVertex(Vec2(col, row), Vec3(vPos.x, vPos.y, zValue));
			
			}
		}
	}

(7)lua用例

以为博主用的是 Cocos2dX+Lua 所有这里添加一段绑定Lua的用例

    local gNode = cc.NodeGrid3D:create()
    local grid3D = cc.GridBase3D:create(cc.size(100,500),720,2048,5000)
    gNode:setGrid3D(grid3D)

    for i=1,100 do
        for j=1,500 do
            local v3 = grid3D:getOriginalVertex(cc.p(i,j))
            if j > 300 then
                local zValue = (300 - j) * 15;
                grid3D:setVertex(cc.p(i, j), cc.vec3(v3.x, v3.y, zValue));
            end

        end
    end

3、推送

github:https://github.com/KingSun5/Cocos2dx_3DGrid


4、结语

若是觉得博主的文章写的不错,不妨关注一下博主,点赞一下博文,另博主能力有限,若文中有出现什么错误的地方,欢迎各位评论指摘。

       QQ交流群:806091680(Chinar)

       该群为CSDN博主Chinar所创,推荐一下!我也在群里!

       本文属于原创文章,转载请著名作者出处并置顶!!!!

猜你喜欢

转载自blog.csdn.net/Mr_Sun88/article/details/111780022
今日推荐