cocos2dx ver3.3 的Sprite3DTest 例子中可以學到什麼

雖然說cocos2dx對3d的支持較unity3d來講只是一點點皮毛的功夫,但是從上手容易度來講要好很多,更適合我這樣的沒玩過3d的菜鳥。如果只是實現2.5d的一些場景,cocos2dx只要能在性能和穩定性上做得更好一點的話,想必是可以留住需要實現3d但又習慣了cocos2dx的老玩家的。


1. Sprite3DBasicTest  Sprite3D 兩種基本創建方式

(1). 直接使用一個帶有素材的obj (3dmax對象)
 Sprite3D::create("sprite3dTest/scene01.obj");  
 
(2). 使用不帶素材的對象,自己設置素材
auto sprite = Sprite3D::create("Sprite3DTest/boss1.obj");
sprite->setScale(3.f);
sprite->setTexture("Sprite3DTest/boss.png");
(3)
auto sprite = EffectSprite3D::createFromObjFileAndTexture("Sprite3DTest/boss1.obj", "Sprite3DTest/boss.png");    

2. Sprite3DHitTest 拖拽

(1) 點擊 在onTouchBegan 中設置透明度  target->setOpacity(100);
放手在 onTouchEnded中還原透明度 target->setOpacity(255);
(2)  移動 onTouchMoved
target->setPosition(target->getPosition() + touch->getDelta());

(3) addEventListenerWithSceneGraphPriority  更具sprite的z order決定丟用先後


3. Sprite3DEffectTest 一些shader 的運用例子

將具體實現封裝到了Effect3DOutline中


4.加載3dmax導出的文件,使用fbx-conv.exe轉化

std::string fileName = "Sprite3DTest/orc.c3b";

auto sprite = EffectSprite3D::create(fileName);


5. Sprite3DWithSkinOutlineTest  shader特效在c3b的運用


6. Animate3DTest 動畫的播放和切換   小烏龜的demo

(1) 同一個c3b既可以創建sprite也可以創建action
    std::string fileName ="Sprite3DTest/tortoise.c3b";
    auto sprite = Sprite3D::create(fileName);
    sprite->setScale(0.1f);
    auto s =Director::getInstance()->getWinSize();
    sprite->setPosition(Vec2(s.width *4.f / 5.f, s.height /2.f));
    addChild(sprite);
    _sprite = sprite;
    auto animation = Animation3D::create(fileName);

(2) animation 可以通過 時間來分拆,這個時間是在3Dmax中定義的
    if (animation)
    {   //2個動畫的時間不同,這些在3Dmax中定義
        auto animate = Animate3D::create(animation, 0.f,1.933f);
        _swim = RepeatForever::create(animate);
        sprite->runAction(_swim);
        _swim->retain();
        _hurt = Animate3D::create(animation,1.933f, 2.8f);
        _hurt->retain();
        _state = State::SWIMMING;
    }

(3)烏龜游到盡頭 調用 reachEndCallBack
通過reverse獲得相反的action
    auto inverse = (MoveTo*)_moveAction->reverse();
    沿y軸180度轉向
    auto rot = RotateBy::create(1.f, Vec3(0.f, 180.f, 0.f));

(4)在onTouchesEnded中實現播放烏龜的 hurt動作   ,但是這裏沒法實現hurt動作的結束回調,所以採用_hurt->getDuration() 
來獲得其結束時間,並且做一個renewCallBack來回到_swim 動作
auto delay = DelayTime::create(_hurt->getDuration() - Animate3D::getTransitionTime());
auto seq = Sequence::create(delay, CallFunc::create(CC_CALLBACK_0(Animate3DTest::renewCallBack, this)), nullptr);

疑問?  Animate3D::getTransitionTime() 用來幹嘛

爲啥會用void Animate3DTest::update(float dt) 來維護一箇中間狀態 HURT_TO_SWIMMING 和SWIMMING_TO_HURT


7. AttachmentTest  裝武器

獲取某個骨骼,Bip001 R Hand是在3Dmax定義的
auto sp = Sprite3D::create("Sprite3DTest/axe.c3b");
sprite->getAttachNode("Bip001 R Hand")->addChild(sp);

點擊後去掉附加節點

_sprite->removeAllAttachNode();


8. Sprite3DReskinTest  皮膚換裝, 動態更換材質(mesh)

(1)字號字體
TTFConfig ttfConfig("fonts/arial.ttf", 20);
auto label1 = Label::createWithTTF(ttfConfig,"Hair");

應該是在3dm中定義好了mesh的名稱?
_girlPants[0]= "Girl_LowerBody01";
_girlPants[1]= "Girl_LowerBody02";
_girlUpperBody[0] = "Girl_UpperBody01";
_girlUpperBody[1] = "Girl_UpperBody02";
_girlShoes[0]  = "Girl_Shoes01";
_girlShoes[1]  = "Girl_Shoes02";
_girlHair[0]= "Girl_Hair01";
_girlHair[1]= "Girl_Hair02";

(2) 初始化的時候隱藏備選的部分,點擊切換的時候再 交換顯示
auto girlPants = sprite->getMeshByName(_girlPants[1]);
if(girlPants)
{
    girlPants->setVisible(false);

}


9.Sprite3DWithOBBPerfromanceTest 包圍盒與3D模型碰撞的實現

1.  decltype 用來獲取auto的type 並且作爲聲明非常適用

auto obbSize = _obb.size();

for(decltype(obbSize) i = 0; i < obbSize; i++)

2.  ray 來將觸摸點轉換到3d場景中,判斷是否點擊到。

Ray ray;

calculateRayByLocationInView(&ray,location);


那麼ray的射出方向會沿着camera的正中心發射嗎?

3.畫3d的邊框
 #include "DrawNode3D.h"
DrawNode3D*               _drawDebug;
首先要畫一個sprite的外框,比如得到他得obb


_drawDebug->clear();
Mat4 mat = _sprite->getNodeToWorldTransform();
mat.getRightVector(&_obbt._xAxis);
_obbt._xAxis.normalize();
mat.getUpVector(&_obbt._yAxis);
_obbt._yAxis.normalize();
mat.getForwardVector(&_obbt._zAxis);
_obbt._zAxis.normalize();
_obbt._center = _sprite->getPosition3D();
Vec3 corners[8] = {};
_obbt.getCorners(corners);


然後獲得corners,調用drawCube()函數
_drawDebug->drawCube(corners, Color4F(0,1,1,1));


4. obb可以不依賴sprite獨立得存在
void Sprite3DWithOBBPerfromanceTest::addNewOBBWithCoords(Vec2 p)
{
    Vec3 extents = Vec3(10, 10, 10);
    AABB aabb(-extents, extents);
    auto obb = OBB(aabb);
    obb._center = Vec3(p.x,p.y,0);
    _obb.push_back(obb);
}


5. 對碰撞的判斷其實只很簡單的一句話
_obbt.intersects(_obb[i])


10.Sprite3DMirrorTest 3D模型的鏡像

    sprite->setScaleX(-5);  在素材上轉換

    sprite->setCullFace(GL_FRONT);   在mesh上轉換


11. Camera3DTestDemo

Camera3DTest.cpp

camera 可以被添加到任何地方,如果一個sprite or layer想要被camera觀察到,
必須要包含其flag(效果也會作用到其child)
auto sprite = Sprite::create("myFile.png");
sprite->setCameraMask(CameraFlag::USER1);
auto camera = Camera::createPerspective(60, winSize.width/winSize.height, 1, 1000);
camera->setCameraFlag(CameraFlag::USER1);
scene->addChild(camera);


(1) 縮放,在點擊label的時候設置標誌位_bZoomOut _bZoomIn 

Vec3 lookDir = _camera->getPosition3D() - _sprite3D->getPosition3D();
Vec3 cameraPos = _camera->getPosition3D();
if(lookDir.length() <= 300)
{
cameraPos += lookDir.getNormalized();
_camera->setPosition3D(cameraPos);
}
重新設置camera的位置即可


(2) 左右旋轉 實際上就是沿着y軸左右旋轉
Vec3  rotation3D= _camera->getRotation3D();
rotation3D.y+= 1;
_camera->setRotation3D(rotation3D);


(3) 視角切換

_cameraType來記錄當前camera類型
enum class CameraType
{
    FreeCamera=0,
    FirstCamera=1,
    ThirdCamera=2,
};

[第一人稱] 實際上就是把相機放在了 角色頭上
Vec3 newFaceDir;
_sprite3D->getWorldToNodeTransform().getForwardVector(&newFaceDir);
newFaceDir.normalize();
_camera->setPosition3D(Vec3(0,35,0) + _sprite3D->getPosition3D());
_camera->lookAt(_sprite3D->getPosition3D() + newFaceDir*50, Vec3(0, 1, 0));


[第三人稱]
_camera->setPosition3D(Vec3(0, 130, 130) + _sprite3D->getPosition3D());
_camera->lookAt(_sprite3D->getPosition3D(), Vec3(0,1,0));

(4)讓camera 隨着角色移動

每一幀都需要更新camera的狀態
void Camera3DTestDemo::updateCamera(float fDelta)
-> move3D(fDelta);

先計算出角色需要移動多少:

①得到朝向目標的單位向量
Vec3 newFaceDir = _targetPos - curPos;
newFaceDir.y = 0.0f;
newFaceDir.normalize();

② 獲得實際移動向量
Vec3 offset = newFaceDir * 25.0f * elapsedTime;

③ camera隨之移動即可
Vec3 cameraPos= _camera->getPosition3D();
cameraPos.x+=offset.x;
cameraPos.z+=offset.z;
_camera->setPosition3D(cameraPos);


常用總結:
1. 3d 緯度的朝向設置  
sprite->setRotation3D(Vec3(0,180,0));

2. sprite->setEffect() 添加特效

3.sprite->getAttachNode("Bip001 R Hand") 獲取某個骨骼

4. sprite->getMeshByName(_girlPants[1]); 獲取材質

5. Vec2 getNormalized() const;  

Vec3 Vec3::getNormalized() const;

獲取向量的標準化形式. 若爲零向量,返回(0,0)
也可以理解爲獲取一個向量的單位向量



參考 Cocos2d-x 3.3 的3D開發功能介紹  http://cn.cocos2d-x.org/tutorial/show?id=1582

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章