Cocos2d-x之3D

举报
yd_221104950 发表于 2020/12/03 01:15:36 2020/12/03
【摘要】 Cocos2d-x是一个二维(2D)游戏引擎。但在Cocos2d-x版本3开始,3D特性被加了进来并进行了改进。3D游戏市场非常巨大, Cocos2d-x正在添加3D开发所需的所有功能 。 3D技术 Mesh(网格): 顶点,用于构造要渲染的形状和纹理。Model( 模型 ): 可以渲染的对象 ,它是风格的集合。在Cocos2d-x中就是Sprite3D对象。Tex...

Cocos2d-x是一个二维(2D)游戏引擎。但在Cocos2d-x版本3开始,3D特性被加了进来并进行了改进。3D游戏市场非常巨大, Cocos2d-x正在添加3D开发所需的所有功能 。

3D技术

  • Mesh(网格): 顶点,用于构造要渲染的形状和纹理。
  • Model( 模型 ): 可以渲染的对象 ,它是风格的集合。在Cocos2d-x中就是Sprite3D对象。
  • Texture( 纹理 ):三维模型的所有曲面和顶点都可以映射到纹理。大多数情况, 每个模型有多个纹理 , 在纹理图集中展开。
  • Camera(照相机): 因为三维世界不是平面的,你需要设置一个相机来观察它。 使用不同的相机参数可以得到不同的场景。
  • Light(灯光): 应用灯光使场景看起来逼真。 为了使一个物体看起来真实,颜色应该根据光线变化。 当你面对光明时,它是光明的,相反的是黑暗的。 照亮物体意味着根据光线计算物体的颜色。

Sprite3D对象

就像2D游戏,3D游戏也有Sprite对象。Sprite对象是任何游戏的核心基础。Sprite3D和Sprite唯一不同的是Sprite3D对象有3个轴,可以定位在x、y和z轴上。 Sprite3D在很多方面都像普通的Sprite一样工作。 加载并展示Sprite3D对象:

auto sprite = Sprite3D::create("boss.c3b"); //c3b file, created with the FBX-converter
sprite->setScale(5.f); //sets the object scale in float
sprite->setPosition(Vec2(200,200)); //sets sprite position
scene->addChild(sprite,1); //adds sprite to scene, z-index: 1

  
 
  • 1
  • 2
  • 3
  • 4

.c3b3D文件可以用FBX-converter工具来创建

现在,让我们来循环旋转模型。为此,我们将创建一个操作并运行它:

//rotate around the X axis
auto rotation = RotateBy::create(15, Vec3(0, 360, 0));
//our sprite object runs the action
sprite->runAction(RepeatForever::create(rotation));

  
 
  • 1
  • 2
  • 3
  • 4

要在Sprite或Sprite3D上设置定位点,请使用:

sprite->setAnchorPoint(Point(0.0f,0.0f));

  
 
  • 1

将三维模型附加到Sprite3D对象

请记住,三维模型是网格的集合。可以将三维模型附加到其他三维模型以创建丰富的效果。如添加武器到主角上,为了做到这一点,你需要找到武器将被添加的附着点。可以调用getAttachNode(attachment_point_name)函数来找到。 然后我们用addChild()将新模型作为子模型添加到附件点 。

auto sp = Sprite3D::create("axe.c3b");
sprite->getAttachNode("Bip001 R Hand")->addChild(sp);

  
 
  • 1
  • 2

交换三维模型

当做3D开发时,你可能要对你的模型做些动态改变 。这种改变可能是换装、 视觉线索 、通知用户关于模型的状态变化。 如果三维模型由网格组成,则可以使用getMeshByIndex()getMeshByName()访问网格数据。 . 使用这些功能,可以实现像用武器或衣服交换角色一样的效果。

auto sprite = Sprite3D::create("ReskinGirl.c3b");

// display the first coat
auto girlTop0 = sprite->getMeshByName("Girl_UpperBody01");
girlTop0->setVisible(true);

auto girlTop1 = sprite->getMeshByName("Girl_UpperBody02");
girlTop1->setVisible(false);

// swap to the second coat
girlTop0->setVisible(false);
girlTop1->setVisible(true);


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

Animation动画

创建Animate3D对象,使用动画。

// the animation is contained in the .c3b file
auto animation = Animation3D::create("orc.c3b");

// creates the Action with Animation object
auto animate = Animate3D::create(animation);

// runs the animation
sprite->runAction(RepeatForever::create(animate));

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

多动画
同时运行多个动画。

auto animation = Animation3D::create(fileName);

auto runAnimate = Animate3D::create(animation, 0, 2);
sprite->runAction(runAnimate);

auto attackAnimate = Animate3D::create(animation, 3, 5);
sprite->runAction(attackAnimate);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面这个例子有两个动画。第一个立刻执行,持续2秒,第二个在3秒后执行,持续5秒。

Animation speed动画速度
向前的动画速度是一个正整数,负速度则是相反的方向。

Animation blending动画混合
当使用多个动画时, 在每个动画之间自动应用混合。混合的目的是在效果之间创建平滑过渡。 给定两个动画A和B,动画A的最后几帧和动画B的前几帧重叠以使动画中的更改看起来自然。 默认的过渡时间是0.1秒。可以使用Animate3D::setTransitionTime修改过渡时间。
Cocos2d-x只支持关键帧之间的线性插值。 这将填充曲线中的间隙以确保路径平滑。如果在模型制作中使用其他插值方法,我们的内置工具fbx-conv将生成额外的关键帧以进行补偿。

Camera照相机

3D世界不是平的,我们需要使用照相机观察它。因此Camera对象在3D开发中是非常重要的。Camera对象继承Node,因此支持大多数相同的动作对象。有两类Camera对象: perspective camera (透视照相机)和orthographic camera(正交相机)。

  • 透视照相机用于观看具有近到远效果的对象 。透视照相机的效果:在近处的物体会比较大,在远处的物体会比较小。
  • 正交摄影机可以将其理解为将三维世界转换为二维表示。使用正交摄影机可以看到,无论对象距摄影机对象有多远,它们的大小都是相同的。游戏中的小地图通常使用正交摄影机渲染。另一个例子是自上而下的视图,可能是在地牢风格的游戏中。

每一个Scene自动地创建一个默认的camera, 基于Director对象的投影特性 。如果你要更多的camera,可以用如下代码创建:

auto s = Director::getInstance()->getWinSize();
auto camera = Camera::createPerspective(60, (GLfloat)s.width/s.height, 1, 1000);

// set parameters for camera
camera->setPosition3D(Vec3(0, 100, 100));
camera->lookAt(Vec3(0, 0, 0), Vec3(0, 1, 0));

addChild(camera); //add camera to the scene

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

创建正交照相机
默认的Camera是透视照相机,如果要创建正交照相机,可以用如下代码来创建:

Camera::createOrthographic();

  
 
  • 1

如:

auto s = Director::getInstance()->getWinSize();
auto camera = Camera::createOrthographic(s.width, s.height, 1, 1000);

  
 
  • 1
  • 2

从相机中隐藏对象
有时,我们并不想在照相机里显示所有对象。从一个照相机里隐藏一个对象其实也很简单,通过在Node(节点)上调用setCameraMask(CameraFlag)和在Camera上调用setCameraFlag(CameraFlag)即可:

//Camera
camera->setCameraFlag(CameraFlag::USER1);

//Node
node->setCameraMask(CameraFlag::USER1);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5

Cubemap Texture立方纹理

立方体贴图纹理是六个单独的正方形纹理的集合,这些纹理放置在虚拟立方体的面上。它们通常用于在对象上显示无限远的反射,类似于“天空盒”在背景中显示遥远景物的方式。展开的立方体映射的外观 :
在这里插入图片描述
Cocos2d-x创建立方纹理的方法:

// create a textureCube object with six texture assets
auto textureCube = TextureCube::create("skybox/left.jpg",  "skybox/right.jpg", "skybox/top.jpg", "skybox/bottom.jpg", "skybox/front.jpg", "skybox/back.jpg");

// set cube map texture parameters
Texture2D::TexParams tRepeatParams;
tRepeatParams.magFilter = GL_NEAREST;
tRepeatParams.minFilter = GL_NEAREST;
tRepeatParams.wrapS = GL_MIRRORED_REPEAT;
tRepeatParams.wrapT = GL_MIRRORED_REPEAT;
textureCube->setTexParameters(tRepeatParams);

// create and set our custom shader
auto shader = GLProgram::createWithFilenames("cube_map.vert", "cube_map.frag");
auto _state = GLProgramState::create(shader);

// bind cube map texture to uniform
state->setUniformTexture("u_cubeTex", textureCube);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

Skybox

Skybox是你整个场景的包装,它显示了你的几何之外的世界。你可以用一个天空盒来模拟无限的天空、山脉和其他现象。 创建Skybox:

// create a Skybox object
auto box = Skybox::create();

// set textureCube for Skybox
box->setTexture(_textureCube);

// attached to scene
_scene->addChild(box);

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

Light光线

光线对于营造游戏的气氛和氛围非常重要。目前支持4种照明技术。

  • Ambient Light(环绕光): AmbientLight对象将均匀地为场景中的所有对象应用灯光。效果就像办公室里的照明。灯光在头顶,当你看到办公室周围的物体时,你会看到它们在同一个灯光下。
auto light = AmbientLight::create (Color3B::RED);
addChild(light);

  
 
  • 1
  • 2
  • Directional Light(平行光、定向光): 平行光通常用于模拟光源,如阳光。当使用方向光时,请记住它的密度是相同的,不管你和它的关系是什么。当你直视太阳时,它是一种强烈的光,即使你朝任何方向移动几步 。
auto light = DirectionLight::create(Vec3(-1.0f, -1.0f, 0.0f), Color3B::RED);
addChild(light);

  
 
  • 1
  • 2
  • Point Light点光源:点光源通常用于模拟灯泡、灯或火炬的效果。 点光源的方向是 从发光位置到点光源 。离光源近则亮,远则暗。
auto light = PointLight::create(Vec3(0.0f, 0.0f, 0.0f), Color3B::RED, 10000.0f);
addChild(light);

  
 
  • 1
  • 2
  • Spot Light聚光源:聚光源通常用于模拟手电筒。:
auto spotLight = SpotLight::create(Vec3(-1.0f, -1.0f, 0.0f), Vec3(0.0f, 0.0f, 0.0f),
Color3B::RED, 0.0, 0.5, 10000.0f) ;
addChild(spotLight);


  
 
  • 1
  • 2
  • 3
  • 4

遮光

在节点上使用照明遮罩仅对其应用特定的光源。例如,如果场景中有多个灯光,则节点只能由其中一个灯光而不是全部三个灯光照亮。可以使用setLightFlag(LightFlag)控制灯光影响哪些节点对象。需要注意的是,所有光源都是在一个过程中渲染的。由于移动平台性能问题,不建议使用多个光源。默认最大值为1。如果要打开多个光源,必须在info.plist中定义以下键:

<key> cocos2d.x.3d.max_dir_light_in_shader </key>
<integer> 1 </integer>
<key> cocos2d.x.3d.max_point_light_in_shader </key>
<integer> 1 </integer>
<key> cocos2d.x.3d.max_spot_light_in_shader </key>
<integer> 1 </integer>


  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

Terrain地形

纹理用于表示高度图。最多可以使用4种纹理来混合地形、草地、道路等的细节。

HeightMap高度图

高度图对象是地形图的核心。与普通图像不同,高度图表示顶点的高度。它决定了地形的几何形状。

DetailMap详细图

DetailMap对象是确定地形细节的纹理列表,最多可以使用四个纹理。

AlphaMap字母表

AlphaMap对象是一个图像,其数据是细节贴图的混合权重。混合结果是最终地形的外观。

LOD(Level Of Detail)政策

地形使用一种称为细节层次(Level Of Detail,LOD)的优化技术。这是一种渲染技术,当对象与摄影机的距离增加时,它可以减少对其进行渲染的垂直(或三角形)数量。用户可以通过调用Terrain::setLODDistance(float lod1, float lod2, float lod3) 方法来设置到相机的距离。
相邻的地形对象块,其LOD不同,可能会产生裂纹伪影。地形提供了两个功能来避免它们:

Terrain::CrackFixedType::SKIRT
Terrain::CrackFixedType::INCREASE_LOWER

  
 
  • 1
  • 2

Terrain::CrackFixedType::SKIRT: 将在块的每个边上生成四个类似裙子的网格。
Terrain::CrackFixedType::INCREASE_LOWER: 将动态调整每个块索引以无缝连接它们。

创建Terrain地形
以下代码片段创建一个玩家并将其放置在地形图上:

player->setScale(0.08);
player->setPositionY(terrain->getHeight(player->getPositionX(),player->getPositionZ()));

  
 
  • 1
  • 2

创建所有DetailMap对象,最多4个。我们需要将DetailMap对象传递给Terrain::DetailMap结构体:

Terrain::DetailMap r("dirt.dds");
Terrain::DetailMap g("grass.dds");
Terrain::DetailMap b("road.dds");
Terrain::DetailMap a("greenSkin.jpg");

  
 
  • 1
  • 2
  • 3
  • 4

用DetailMap对象创建TerrainData变量,并指定高度图文件路径和字母图文件路径:

Terrain::TerrainData data("chapter9/heightmap16.jpg","TerrainTest/alphamap.png", r, g, b, a);

  
 
  • 1

传递TerrainData对象给Terrain::create,最后一个参数决定LOD政策:

_terrain = Terrain::create(data, Terrain::CrackFixedType::SKIRT);

  
 
  • 1

如果你设置Terrain对象照相机遮罩(camera mask)并添加到一个节点Node或一个场景Scene。这时要当心,Terrain被添加到节点或场景后,就不能再用transform(translate,scale)。另外,如果在addChild方法之后做以上操作,可能会导致一个错误。

使用方法Terrain::getHeight(float x, float z, Vec3 * normal= nullptr)可以获得指定位置的高度。当你想把一个Sprite3D对象或任意节点放在地形图上时,这个方法特别有用。

射线地形交会试验将会计算指定位置的交点。
Terrain::CrackFixedType::SKIRT会产生四个 每一块边缘都有裙状网格 。
Terrain::CrackFixedType::INCREASE_LOWER将会动态调整每个块索引以无缝连接它们。

文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/weixin_40763897/article/details/104569284

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。