Cocos2d-x 3.3 的3D开发功能介绍
今天下载了Cocos2d-x 3.3,3D功能果然强大 主要有以下功能: 1. 基本的Sprite3D使用,加载静态模型和动态模型,看 Sprite3DBasicTest 2.Sprite3D对象的旋转,缩放等Action操作 3.Sprite3D中使用Shader特效,实现outLine 4.Animate3D来创建3D动画 5.动态增加3D骨骼,实现怪物添加手持武器功能 6,动态修改骨骼皮肤实现换装功能Sprite3DReskinTest 7.通过包围盒实现3D模型碰撞,Sprite3DWithOBBPerfromanceTest 8.实现水平镜像3D模型,Sprite3DMirrorTest
下面介绍一下Sprite3DTest里面的源码
#include "Sprite3DTest.h" #include "3d/CCAnimation3D.h" #include "3d/CCAnimate3D.h" #include "3d/CCAttachNode.h" #include "3d/CCRay.h" #include "3d/CCSprite3D.h" #include "renderer/CCVertexIndexBuffer.h" #include "DrawNode3D.h"
1.在Scene中添加3D模型
void Sprite3DBasicTest::addNewSpriteWithCoords(Vec2 p) { //这里的obj可以使用3dmax直接导出 // //option 1: load a obj that contain the texture in it 第一种方法是在模型文件中包含了纹理 // auto sprite = Sprite3D::create("sprite3dTest/scene01.obj"); //option 2: load obj and assign the texture 第二种方法是在模型文件中不包含纹理 auto sprite =Sprite3D::create("Sprite3DTest/boss1.obj"); sprite->setScale(3.f); sprite->setTexture("Sprite3DTest/boss.png"); //在Sprite3D中包含了一些基本的Shader特效,下面是让3D模型实现outline //sprite->setEffect(cocos2d::EFFECT_OUTLINE); //add to scene addChild( sprite ); sprite->setPosition( Vec2( p.x,p.y) ); ActionInterval* action; float random = CCRANDOM_0_1();
if( random < 0.20 ) action = ScaleBy::create(3,2); else if(random <0.40) action = RotateBy::create(3,360); else if( random <0.60) action = Blink::create(1,3); else if( random <0.8 ) action = TintBy::create(2,0,-255,-255); else action = FadeOut::create(2); auto action_back = action->reverse(); auto seq = Sequence::create( action,action_back,nullptr ); sprite->runAction( RepeatForever::create(seq) ); //以上大家看到Sprite3D起始和Sprite类似都可以实现各种Action } void Sprite3DBasicTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event* event) { for (auto touch: touches) { auto location = touch->getLocation(); //触摸屏幕添加3D模型 addNewSpriteWithCoords( location ); } } 2.透过触摸屏幕拖动模型移动
Sprite3DHitTest::Sprite3DHitTest() { auto s =Director::getInstance()->getWinSize(); auto sprite1 =Sprite3D::create("Sprite3DTest/boss1.obj");
sprite1->setScale(4.f); sprite1->setTexture("Sprite3DTest/boss.png"); sprite1->setPosition( Vec2(s.width/2,s.height/2) );
//add to scene addChild( sprite1 ); sprite1->runAction(RepeatForever::create(RotateBy::create(3,360)));
auto sprite2 =Sprite3D::create("Sprite3DTest/boss1.obj");
sprite2->setScale(4.f); sprite2->setTexture("Sprite3DTest/boss.png"); sprite2->setPosition( Vec2(s.width/2,s.height/2) ); sprite2->setAnchorPoint(Vec2(0.5,0.5));
//add to scene addChild( sprite2 ); sprite2->runAction(RepeatForever::create(RotateBy::create(3,-360)));
// Make sprite1 touchable auto listener1 =EventListenerTouchOneByOne::create(); listener1->setSwallowTouches(true);
listener1->onTouchBegan = [](Touch* touch,Event* event){ auto target = static_cast<Sprite3D*>(event->getCurrentTarget());
Rect rect = target->getBoundingBox(); if (rect.containsPoint(touch->getLocation())) { log("sprite3d began... x = %f,y = %f",touch->getLocation().x,touch->getLocation().y); target->setOpacity(100); return true; } return false; };
listener1->onTouchMoved = [](Touch* touch,Event* event){ auto target = static_cast<Sprite3D*>(event->getCurrentTarget()); target->setPosition(target->getPosition() + touch->getDelta()); };
listener1->onTouchEnded = [=](Touch* touch,Event* event){ auto target = static_cast<Sprite3D*>(event->getCurrentTarget()); log("sprite3d onTouchesEnded.. "); target->setOpacity(255); };
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1,sprite1); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(),sprite2);
} 3.在一个Sprite3D上使用Shader
Effect3D继承REF封装了Shader的处理 Effect3DOutline继承了Effect3D,封装了Outline类型的Shader EffectSprite3D继承了Sprite3D封装了对Effect3DOutline的调用
class Effect3D : publicRef { public: virtual void draw(constMat4 &transform) =0; virtual void setTarget(EffectSprite3D *sprite) =0; protected: Effect3D() : _glProgramState(nullptr) {} virtual ~Effect3D() { CC_SAFE_RELEASE(_glProgramState); } protected: GLProgramState* _glProgramState; };
class Effect3DOutline: publicEffect3D { public: static Effect3DOutline* create();
void setOutlineColor(constVec3& color);
void setOutlineWidth(float width);
virtual void draw(constMat4 &transform) override; virtual void setTarget(EffectSprite3D *sprite) override; protected:
Effect3DOutline(); virtual ~Effect3DOutline();
bool init();
Vec3 _outlineColor; float _outlineWidth; //weak reference EffectSprite3D* _sprite; #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) EventListenerCustom* _backToForegroundListener; #endif
protected: static const std::string _vertShaderFile; static const std::string _fragShaderFile; static const std::string _keyInGLProgramCache;
static const std::string _vertSkinnedShaderFile; static const std::string _fragSkinnedShaderFile; static const std::string _keySkinnedInGLProgramCache;
static GLProgram* getOrCreateProgram(bool isSkinned =false); }; class EffectSprite3D : publicSprite3D { public: static EffectSprite3D* createFromObjFileAndTexture(conststd::string& objFilePath,const std::string& textureFilePath); static EffectSprite3D* create(conststd::string& path);
void setEffect3D(Effect3D* effect); void addEffect(Effect3DOutline* effect,ssize_t order); virtual void draw(Renderer *renderer,constMat4 &transform,uint32_t flags) override; protected: EffectSprite3D(); virtual ~EffectSprite3D();
std::vector<std::tuple<ssize_t,Effect3D*,CustomCommand>> _effects; Effect3D* _defaultEffect; CustomCommand _command; };
class Sprite3DEffectTest : public Sprite3DTestDemo { public: CREATE_FUNC(Sprite3DEffectTest); Sprite3DEffectTest(); virtual std::string title()const override; virtual std::string subtitle()const override;
void addNewSpriteWithCoords(Vec2 p);
void onTouchesEnded(conststd::vector<Touch*>& touches,Event* event); };
const std::stringEffect3DOutline::_vertShaderFile ="Shaders3D/OutLine.vert"; const std::stringEffect3DOutline::_fragShaderFile ="Shaders3D/OutLine.frag"; const std::stringEffect3DOutline::_keyInGLProgramCache ="Effect3DLibrary_Outline";
const std::stringEffect3DOutline::_vertSkinnedShaderFile ="Shaders3D/SkinnedOutline.vert"; const std::stringEffect3DOutline::_fragSkinnedShaderFile ="Shaders3D/OutLine.frag"; const std::stringEffect3DOutline::_keySkinnedInGLProgramCache ="Effect3DLibrary_Outline"; GLProgram* Effect3DOutline::getOrCreateProgram(bool isSkinned/* = false */ ) { if(isSkinned) { auto program = GLProgramCache::getInstance()->getGLProgram(_keySkinnedInGLProgramCache); if(program == nullptr) { program = GLProgram::createWithFilenames(_vertSkinnedShaderFile,_fragSkinnedShaderFile); GLProgramCache::getInstance()->addGLProgram(program,_keySkinnedInGLProgramCache); } return program; } else { auto program = GLProgramCache::getInstance()->getGLProgram(_keyInGLProgramCache); if(program == nullptr) { program = GLProgram::createWithFilenames(_vertShaderFile,_fragShaderFile); GLProgramCache::getInstance()->addGLProgram(program,_keyInGLProgramCache); } return program; }
}
Effect3DOutline* Effect3DOutline::create() { Effect3DOutline* effect =new (std::nothrow)Effect3DOutline(); if(effect && effect->init()) { effect->autorelease(); return effect; } else { CC_SAFE_DELETE(effect); return nullptr; } }
bool Effect3DOutline::init() {
return true; }
Effect3DOutline::Effect3DOutline() : _outlineWidth(1.0f) ,_outlineColor(1,1,1) ,_sprite(nullptr) { #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) _backToForegroundListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED, [this](EventCustom*) { auto glProgram = _glProgramState->getGLProgram(); glProgram->reset(); glProgram->initWithFilenames(_vertShaderFile,_fragShaderFile); glProgram->link(); glProgram->updateUniforms(); } ); Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backToForegroundListener,-1); #endif }
Effect3DOutline::~Effect3DOutline() { #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundListener); #endif }
void Effect3DOutline::setOutlineColor(constVec3& color) { if(_outlineColor != color) { _outlineColor = color; if(_glProgramState) _glProgramState->setUniformVec3("OutLineColor",_outlineColor); } }
void Effect3DOutline::setOutlineWidth(float width) { if(_outlineWidth != width) { _outlineWidth = width; if(_glProgramState) _glProgramState->setUniformFloat("OutlineWidth",_outlineWidth); } }
void Effect3DOutline::setTarget(EffectSprite3D *sprite) { CCASSERT(nullptr != sprite &&nullptr != sprite->getMesh(),"Error: Setting a null pointer or a null mesh EffectSprite3D to Effect3D");
if(sprite != _sprite) { GLProgram* glprogram; if(!sprite->getMesh()->getSkin()) glprogram = GLProgram::createWithFilenames(_vertShaderFile,_fragShaderFile); else glprogram = GLProgram::createWithFilenames(_vertSkinnedShaderFile,_fragSkinnedShaderFile);
_glProgramState = GLProgramState::create(glprogram);
_glProgramState->retain(); _glProgramState->setUniformVec3("OutLineColor",_outlineColor); _glProgramState->setUniformFloat("OutlineWidth",_outlineWidth);
_sprite = sprite;
auto mesh = sprite->getMesh(); long offset = 0; for (auto i =0; i < mesh->getMeshVertexAttribCount(); i++) { auto meshvertexattrib = mesh->getMeshVertexAttribute(i);
_glProgramState->setVertexAttribPointer(s_attributeNames[meshvertexattrib.vertexAttrib], meshvertexattrib.size, meshvertexattrib.type, GL_FALSE, mesh->getVertexSizeInBytes(), (void*)offset); offset += meshvertexattrib.attribSizeBytes; }
Color4F color(_sprite->getDisplayedColor()); color.a = _sprite->getDisplayedOpacity() /255.0f; _glProgramState->setUniformVec4("u_color",Vec4(color.r,color.g,color.b,color.a)); }
}
static void MatrixPalleteCallBack(GLProgram* glProgram,Uniform* uniform,int paletteSize,const float* palette) { glUniform4fv( uniform->location,(GLsizei)paletteSize,(constfloat*)palette ); }
void Effect3DOutline::draw(constMat4 &transform) { //draw Color4F color(_sprite->getDisplayedColor()); color.a = _sprite->getDisplayedOpacity() /255.0f; _glProgramState->setUniformVec4("u_color",color.a)); if(_sprite && _sprite->getMesh()) { glEnable(GL_CULL_FACE); glCullFace(GL_FRONT); glEnable(GL_DEPTH_TEST);
auto mesh = _sprite->getMesh(); glBindBuffer(GL_ARRAY_BUFFER,mesh->getVertexBuffer());
auto skin = _sprite->getMesh()->getSkin(); if(_sprite && skin) { auto function = std::bind(MatrixPalleteCallBack,std::placeholders::_1,std::placeholders::_2, skin->getMatrixPaletteSize(),(float*)skin->getMatrixPalette()); _glProgramState->setUniformCallback("u_matrixPalette",function); }
if(_sprite) _glProgramState->apply(transform); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,mesh->getIndexBuffer()); glDrawElements(mesh->getPrimitiveType(),mesh->getIndexCount(),mesh->getIndexFormat(),0); CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1,mesh->getIndexCount());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0); glBindBuffer(GL_ARRAY_BUFFER,0); glDisable(GL_DEPTH_TEST); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); } }
void EffectSprite3D::draw(cocos2d::Renderer *renderer,constcocos2d::Mat4 &transform,uint32_t flags) { for(auto &effect : _effects) { if(std::get<0>(effect) >=0) break; CustomCommand &cc = std::get<2>(effect); cc.func = CC_CALLBACK_0(Effect3D::draw,std::get<1>(effect),transform); renderer->addCommand(&cc);
}
if(!_defaultEffect) { Sprite3D::draw(renderer,transform,flags); } else { _command.init(_globalZOrder); _command.func =CC_CALLBACK_0(Effect3D::draw,_defaultEffect,transform); renderer->addCommand(&_command); }
for(auto &effect : _effects) { if(std::get<0>(effect) <=0) continue; CustomCommand &cc = std::get<2>(effect); cc.func = CC_CALLBACK_0(Effect3D::draw,transform); renderer->addCommand(&cc);
} } //Sprite3DEffectTest中实现了对Sprite3DEffect的加载 Sprite3DEffectTest::Sprite3DEffectTest() { auto s =Director::getInstance()->getWinSize(); addNewSpriteWithCoords(Vec2(s.width/2,s.height/2) );
auto listener =EventListenerTouchAllAtOnce::create(); listener->onTouchesEnded = CC_CALLBACK_2(Sprite3DEffectTest::onTouchesEnded,this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this); }
void Sprite3DEffectTest::addNewSpriteWithCoords(Vec2 p) { //option 2: load obj and assign the texture auto sprite =EffectSprite3D::createFromObjFileAndTexture("Sprite3DTest/boss1.obj","Sprite3DTest/boss.png"); Effect3DOutline* effect =Effect3DOutline::create(); sprite->addEffect(effect,-1); effect->setOutlineColor(Vec3(1,0)); effect->setOutlineWidth(0.01f);
Effect3DOutline* effect2 =Effect3DOutline::create(); sprite->addEffect(effect2,-2); effect2->setOutlineWidth(0.02f); effect2->setOutlineColor(Vec3(1,1,0)); //sprite->setEffect3D(effect); sprite->setScale(6.f);
//add to scene addChild( sprite );
sprite->setPosition( Vec2( p.x,p.y) );
ActionInterval* action; float random = CCRANDOM_0_1();
if( random < 0.20 ) action = ScaleBy::create(3,nullptr );
sprite->runAction( RepeatForever::create(seq) ); }
void Sprite3DEffectTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event* event) { for (auto touch: touches) { auto location = touch->getLocation();
addNewSpriteWithCoords( location ); } } 4.加载包含了3D纹理和动画的C3B文件,具体转化方法为在tools下使用fbx-conv.exe将3dmax导出的文件转化为c3b
用Sprite3D来加载c3b,用Animation3D,和Animate3D来创建动画 auto animation = Animation3D::create(fileName); if (animation) { auto animate = Animate3D::create(animation); sprite->runAction(RepeatForever::create(animate)); }
void Sprite3DWithSkinTest::addNewSpriteWithCoords(Vec2 p) { std::string fileName ="Sprite3DTest/orc.c3b"; auto sprite = EffectSprite3D::create(fileName); sprite->setScale(3); sprite->setRotation3D(Vec3(0,180,0)); addChild(sprite); sprite->setPosition( Vec2( p.x,p.y) ); auto animation = Animation3D::create(fileName); if (animation) { auto animate = Animate3D::create(animation); bool inverse = (std::rand() %3 ==0);
int rand2 = std::rand(); float speed = 1.0f; if(rand2 % 3 ==1) { speed = animate->getSpeed() + CCRANDOM_0_1(); } else if(rand2 %3 ==2) { speed = animate->getSpeed() - 0.5 * CCRANDOM_0_1(); } animate->setSpeed(inverse ? -speed : speed);
sprite->runAction(RepeatForever::create(animate)); } } 5.在以上模型和动画中添加特效(方法和在静态模型上一样)
void Sprite3DWithSkinOutlineTest::addNewSpriteWithCoords(Vec2 p) { std::string fileName ="Sprite3DTest/orc.c3b"; auto sprite = EffectSprite3D::create(fileName);
Effect3DOutline* effect =Effect3DOutline::create(); effect->setOutlineColor(Vec3(1,0)); effect->setOutlineWidth(0.01f); sprite->addEffect(effect,-1);
Effect3DOutline* effect2 =Effect3DOutline::create(); effect2->setOutlineWidth(0.02f); effect2->setOutlineColor(Vec3(1,0)); sprite->addEffect(effect2,-2);
sprite->setScale(3); sprite->setRotation3D(Vec3(0,0)); addChild(sprite); sprite->setPosition( Vec2( p.x,p.y) );
auto animation = Animation3D::create(fileName); if (animation) { auto animate = Animate3D::create(animation); bool inverse = (std::rand() %3 ==0);
int rand2 = std::rand(); float speed = 1.0f; if(rand2 % 3 ==1) { speed = animate->getSpeed() + CCRANDOM_0_1(); } else if(rand2 %3 ==2) { speed = animate->getSpeed() - 0.5 * CCRANDOM_0_1(); } animate->setSpeed(inverse ? -speed : speed);
sprite->runAction(RepeatForever::create(animate)); } } 6.动画的切换 既然每个3D动画是Action就可以通过切换每个Sprite3D的Action来切换动画,下面是一个小乌龟的2个动画之间的切换
Animate3DTest::Animate3DTest() : _hurt(nullptr) ,_swim(nullptr) ,_sprite(nullptr) ,_moveAction(nullptr) ,_elapseTransTime(0.f) { //添加小乌龟 addSprite3D();
auto listener =EventListenerTouchAllAtOnce::create(); listener->onTouchesEnded = CC_CALLBACK_2(Animate3DTest::onTouchesEnded,this);
scheduleUpdate(); }
Animate3DTest::~Animate3DTest() { CC_SAFE_RELEASE(_moveAction); CC_SAFE_RELEASE(_hurt); CC_SAFE_RELEASE(_swim); }
void Animate3DTest::update(float dt) { if (_state ==State::HURT_TO_SWIMMING) { _elapseTransTime += dt;
if (_elapseTransTime >=Animate3D::getTransitionTime()) { _sprite->stopAction(_hurt); _state = State::SWIMMING; } } elseif (_state ==State::SWIMMING_TO_HURT) { _elapseTransTime += dt; if (_elapseTransTime >=Animate3D::getTransitionTime()) { _sprite->stopAction(_swim); _state = State::HURT; } } }
void Animate3DTest::addSprite3D() { 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); 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; }
_moveAction = MoveTo::create(4.f,Vec2(s.width /5.f,s.height / 2.f)); _moveAction->retain(); auto seq = Sequence::create(_moveAction,CallFunc::create(CC_CALLBACK_0(Animate3DTest::reachEndCallBack,this)),nullptr); seq->setTag(100); sprite->runAction(seq); } //当触摸小乌龟则改变动画 void Animate3DTest::reachEndCallBack() { _sprite->stopActionByTag(100); auto inverse = (MoveTo*)_moveAction->reverse(); inverse->retain(); _moveAction->release(); _moveAction = inverse; auto rot = RotateBy::create(1.f,Vec3(0.f,180.f,0.f)); auto seq = Sequence::create(rot,_moveAction,nullptr); seq->setTag(100); _sprite->runAction(seq); }
void Animate3DTest::renewCallBack() { //rerun swim action _sprite->runAction(_swim); _state =State::HURT_TO_SWIMMING; _elapseTransTime = 0.0f; }
void Animate3DTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event* event) { for (auto touch: touches) { auto location = touch->getLocation();
if (_sprite) { float len = (_sprite->getPosition() - location).length(); if (len < 40) { //hurt the tortoise 在游动状态改变为被抓住的动画 if (_state ==State::SWIMMING) { _elapseTransTime =0.0f; _state = State::SWIMMING_TO_HURT; _sprite->stopAction(_hurt); _sprite->runAction(_hurt); auto delay = DelayTime::create(_hurt->getDuration() -Animate3D::getTransitionTime()); auto seq = Sequence::create(delay,CallFunc::create(CC_CALLBACK_0(Animate3DTest::renewCallBack,nullptr); seq->setTag(101); _sprite->runAction(seq); } return; } } } } 7.动态添加武器
AttachmentTest::AttachmentTest() : _hasWeapon(false) ,_sprite(nullptr) { auto s =Director::getInstance()->getWinSize(); addNewSpriteWithCoords(Vec2(s.width/2,s.height/2) ); auto listener =EventListenerTouchAllAtOnce::create(); listener->onTouchesEnded = CC_CALLBACK_2(AttachmentTest::onTouchesEnded,this); }
void AttachmentTest::addNewSpriteWithCoords(Vec2 p) { std::string fileName ="Sprite3DTest/orc.c3b"; auto sprite = Sprite3D::create(fileName); sprite->setScale(5); sprite->setRotation3D(Vec3(0,p.y) ); //test attach 亮点在这里,获取某个骨骼,Bip001 R Hand是在3Dmax定义的 auto sp =Sprite3D::create("Sprite3DTest/axe.c3b"); sprite->getAttachNode("Bip001 R Hand")->addChild(sp);
auto animation = Animation3D::create(fileName); if (animation) { auto animate = Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate)); } _sprite = sprite; _hasWeapon = true; }
void AttachmentTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event* event) { if (_hasWeapon) { _sprite->removeAllAttachNode(); //去掉新骨骼节点 } else { auto sp = Sprite3D::create("Sprite3DTest/axe.c3b"); _sprite->getAttachNode("Bip001 R Hand")->addChild(sp); } _hasWeapon = !_hasWeapon; } 8.动态修改材质Mesh(这个demo好,美女的模型超赞)
Sprite3DReskinTest::Sprite3DReskinTest() : _sprite(nullptr) { auto s = Director::getInstance()->getWinSize(); addNewSpriteWithCoords( Vec2(s.width/2,s.height/2) );
auto listener = EventListenerTouchAllAtOnce::create(); listener->onTouchesEnded = CC_CALLBACK_2(Sprite3DReskinTest::onTouchesEnded,this); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this); TTFConfig ttfConfig("fonts/arial.ttf",20); auto label1 = Label::createWithTTF(ttfConfig,"Hair"); auto item1 = MenuItemLabel::create(label1,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchHair,this) ); auto label2 = Label::createWithTTF(ttfConfig,"Glasses"); auto item2 = MenuItemLabel::create(label2,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchGlasses,this) ); auto label3 = Label::createWithTTF(ttfConfig,"Coat"); auto item3 = MenuItemLabel::create(label3,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchCoat,this) ); auto label4 = Label::createWithTTF(ttfConfig,"Pants"); auto item4 = MenuItemLabel::create(label4,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchPants,this) ); auto label5 = Label::createWithTTF(ttfConfig,"Shoes"); auto item5 = MenuItemLabel::create(label5,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchShoes,this) ); item1->setPosition( Vec2(VisibleRect::left().x+50,VisibleRect::bottom().y+item1->getContentSize().height*4 ) ); item2->setPosition( Vec2(VisibleRect::left().x+50,VisibleRect::bottom().y+item1->getContentSize().height *5 ) ); item3->setPosition( Vec2(VisibleRect::left().x+50,VisibleRect::bottom().y+item1->getContentSize().height*6 ) ); item4->setPosition( Vec2(VisibleRect::left().x+50,VisibleRect::bottom().y+item1->getContentSize().height *7 ) ); item5->setPosition( Vec2(VisibleRect::left().x+50,VisibleRect::bottom().y+item1->getContentSize().height *8 ) ); auto pMenu1 = CCMenu::create(item1,item2,item3,item4,item5,NULL); pMenu1->setPosition(Vec2(0,0)); this->addChild(pMenu1, 10);
} void Sprite3DReskinTest::menuCallback_switchHair(Ref* sender) { _useHairId++; if(_useHairId > 1 ) { _useHairId = 0; } if(_useHairId >= 0 && _sprite) { for(int i =0; i <2; i++ ) { // 获取材质 可见3.3支持了多套材质 auto subMesh = _sprite->getMeshByName(_girlHair[i]); if(subMesh) { if(i == _useHairId ) { subMesh->setVisible(true); } else { subMesh->setVisible(false); } } } } } void Sprite3DReskinTest::menuCallback_switchGlasses(Ref* sender) { auto subMesh = _sprite->getMeshByName("Girl_Glasses01"); if(subMesh) { if(subMesh->isVisible()) { subMesh->setVisible(false); } else { subMesh->setVisible(true); } } } void Sprite3DReskinTest::menuCallback_switchCoat(Ref* sender) { _useUpBodyId++; if(_useUpBodyId > 1 ) { _useUpBodyId = 0; } if(_useUpBodyId >= 0 && _sprite) { for(int i =0; i <2; i++ ) { auto subMesh = _sprite->getMeshByName(_girlUpperBody[i]); if(subMesh) { if(i == _useUpBodyId ) { subMesh->setVisible(true); } else { subMesh->setVisible(false); } } } } } void Sprite3DReskinTest::menuCallback_switchPants(Ref* sender) { _usePantsId++; if(_usePantsId > 1 ) { _usePantsId = 0; } if(_usePantsId >= 0 && _sprite) { for(int i =0; i <2; i++ ) { auto subMesh = _sprite->getMeshByName(_girlPants[i]); if(subMesh) { if(i == _usePantsId ) { subMesh->setVisible(true); } else { subMesh->setVisible(false); } } } } } void Sprite3DReskinTest::menuCallback_switchShoes(Ref* sender) { _useShoesId++; if(_useShoesId > 1 ) { _useShoesId = 0; } if(_useShoesId >= 0 && _sprite) { for(int i =0; i <2; i++ ) { auto subMesh = _sprite->getMeshByName(_girlShoes[i]); if(subMesh) { if(i == _useShoesId ) { subMesh->setVisible(true); } else { subMesh->setVisible(false); } } } }
} std::string Sprite3DReskinTest::title() const { return"Testing Sprite3D Reskin"; } std::string Sprite3DReskinTest::subtitle() const { return ""; }
void Sprite3DReskinTest::addNewSpriteWithCoords(Vec2 p) { _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"; _usePantsId = 0; _useUpBodyId = 0; _useShoesId =0; _useHairId = 0;
std::string fileName = "Sprite3DTest/ReskinGirl.c3b"; auto sprite = Sprite3D::create(fileName); sprite->setScale(4); sprite->setRotation3D(Vec3(0,0)); auto girlPants = sprite->getMeshByName(_girlPants[1]); if(girlPants) { girlPants->setVisible(false); } auto girlShoes = sprite->getMeshByName(_girlShoes[1]); if(girlShoes) { girlShoes->setVisible(false); } auto girlHair = sprite->getMeshByName(_girlHair[1]); if(girlHair) { girlHair->setVisible(false); } auto girlUpBody = sprite->getMeshByName( _girlUpperBody[1]); if(girlUpBody) { girlUpBody->setVisible(false); } addChild(sprite); sprite->setPosition( Vec2( p.x,p.y-60) ); auto animation = Animation3D::create(fileName); if (animation) { auto animate = Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate)); } _sprite = sprite; }
9.包围盒与3D模型碰撞的实现 AABB碰撞原理参考以下网址 http://cn.cocos2d-x.org/tutorial/show?id=1572
Sprite3DWithOBBPerfromanceTest::Sprite3DWithOBBPerfromanceTest() { auto listener = EventListenerTouchAllAtOnce::create(); listener->onTouchesBegan = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesBegan,this); listener->onTouchesEnded = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesEnded,this); listener->onTouchesMoved = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesMoved,this); auto s = Director::getInstance()->getWinSize(); initDrawBox(); addNewSpriteWithCoords(Vec2(s.width/2,s.height/2)); MenuItemFont::setFontName("fonts/arial.ttf"); MenuItemFont::setFontSize(65); auto decrease = MenuItemFont::create(" - ",CC_CALLBACK_1(Sprite3DWithOBBPerfromanceTest::delOBBCallback,this)); decrease->setColor(Color3B(0,200,20)); auto increase = MenuItemFont::create(" + ",CC_CALLBACK_1(Sprite3DWithOBBPerfromanceTest::addOBBCallback,this)); increase->setColor(Color3B(0,20));
auto menu = Menu::create(decrease,increase,nullptr); menu->alignItemsHorizontally(); menu->setPosition(Vec2(s.width/2,s.height-65)); addChild(menu,1);
TTFConfig ttfCount("fonts/Marker Felt.ttf",30); _labelCubeCount = Label::createWithTTF(ttfCount,"0 cubes"); _labelCubeCount->setColor(Color3B(0,20)); _labelCubeCount->setPosition(Vec2(s.width/2,s.height-90)); addChild(_labelCubeCount); _hasCollider = false; addOBBCallback(nullptr); scheduleUpdate(); } std::string Sprite3DWithOBBPerfromanceTest::title() const { return"OBB Collison Perfromance Test"; } std::string Sprite3DWithOBBPerfromanceTest::subtitle() const { return ""; } 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); }
void Sprite3DWithOBBPerfromanceTest::onTouchesBegan(const std::vector<Touch*>& touches,Event* event) { for (auto touch: touches) { auto location = touch->getLocationInView();
if(_obb.size() > 0) { _intersetList.clear(); Ray ray; calculateRayByLocationInView(&ray,location); for(int i =0; i < _obb.size(); i++) { if(ray.intersects(_obb[i])) { _intersetList.insert(i); return; } } } } }
void Sprite3DWithOBBPerfromanceTest::onTouchesEnded(const std::vector<Touch*>& touches,Event* event) {
}
void Sprite3DWithOBBPerfromanceTest::onTouchesMoved(const std::vector<Touch*>& touches,Event* event) { for (auto touch: touches) { auto location = touch->getLocation();
for(int i =0; i < _obb.size(); i++) { if(_intersetList.find(i) != _intersetList.end()) _obb[i]._center = Vec3(location.x,location.y,0); } } }
void Sprite3DWithOBBPerfromanceTest::update(float dt) { char szText[16]; sprintf(szText,"%lu cubes",_obb.size()); _labelCubeCount->setString(szText);
if (_drawDebug) { _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); _drawDebug->drawCube(corners,Color4F(0,1)); } if(_obb.size() > 0) { _drawOBB->clear(); for(int i =0; i < _obb.size(); i++) { Vec3 corners[8] = {}; _obb[i].getCorners(corners); _drawOBB->drawCube(corners,_obbt.intersects(_obb[i])?Color4F(1,1):Color4F(0,1)); } } }
void Sprite3DWithOBBPerfromanceTest::initDrawBox() { _drawOBB = DrawNode3D::create(); addChild(_drawOBB); }
void Sprite3DWithOBBPerfromanceTest::addNewSpriteWithCoords(Vec2 p) { 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); if (animation) { auto animate = Animate3D::create(animation,1.933f); sprite->runAction(RepeatForever::create(animate)); }
_moveAction = MoveTo::create(4.f,Vec2(s.width /5.f,s.height /2.f)); _moveAction->retain(); auto seq = Sequence::create(_moveAction,CallFunc::create(CC_CALLBACK_0(Sprite3DWithOBBPerfromanceTest::reachEndCallBack,nullptr); seq->setTag(100); sprite->runAction(seq);
AABB aabb = _sprite->getAABB(); _obbt = OBB(aabb);
_drawDebug = DrawNode3D::create(); addChild(_drawDebug); }
void Sprite3DWithOBBPerfromanceTest::reachEndCallBack() { _sprite->stopActionByTag(100); auto inverse = (MoveTo*)_moveAction->reverse(); inverse->retain(); _moveAction->release(); _moveAction = inverse; auto rot = RotateBy::create(1.0f,Vec3(0.f,0.f)); auto seq = Sequence::create(rot,_moveAction,nullptr); seq->setTag(100); _sprite->runAction(seq); }
void Sprite3DWithOBBPerfromanceTest::addOBBCallback(Ref* sender) { addOBBWithCount(10); }
void Sprite3DWithOBBPerfromanceTest::addOBBWithCount(float value) { for(int i = 0; i < value; i++) { Vec2 randompos = Vec2(CCRANDOM_0_1() * Director::getInstance()->getWinSize().width,CCRANDOM_0_1() * Director::getInstance()->getWinSize().height); Vec3 extents = Vec3(10,extents); auto obb = OBB(aabb); obb._center = Vec3(randompos.x,randompos.y,0); _obb.push_back(obb); } }
void Sprite3DWithOBBPerfromanceTest::delOBBCallback(Ref* sender) { delOBBWithCount(10); }
void Sprite3DWithOBBPerfromanceTest::delOBBWithCount(float value) { if(_obb.size() >= 10) { _obb.erase(_obb.begin(),_obb.begin() + value); _drawOBB->clear(); } else return; } void Sprite3DWithOBBPerfromanceTest::unproject(const Mat4& viewProjection,const Size* viewport,Vec3* src,Vec3* dst) { assert(dst);
assert(viewport->width != 0.0f && viewport->height !=0.0f); Vec4 screen(src->x / viewport->width,((viewport->height - src->y)) / viewport->height,src->z,1.0f);
screen.x = screen.x * 2.0f - 1.0f; screen.y = screen.y * 2.0f - 1.0f; screen.z = screen.z * 2.0f - 1.0f;
viewProjection.getInversed().transformVector(screen,&screen);
if (screen.w != 0.0f) { screen.x /= screen.w; screen.y /= screen.w; screen.z /= screen.w; }
dst->set(screen.x,screen.y,screen.z); }
void Sprite3DWithOBBPerfromanceTest::calculateRayByLocationInView(Ray* ray,const Vec2& location) { auto dir = Director::getInstance(); auto view = dir->getWinSize(); Mat4 mat = dir->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); mat = dir->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
Vec3 src = Vec3(location.x,-1); Vec3 nearPoint; unproject(mat,&view,&src,&nearPoint);
src = Vec3(location.x,1); Vec3 farPoint; unproject(mat,&farPoint);
Vec3 direction; Vec3::subtract(farPoint,nearPoint,&direction); direction.normalize();
ray->_origin = nearPoint; ray->_direction = direction; } 10.3D模型的镜像
Sprite3DMirrorTest::Sprite3DMirrorTest() : _sprite(nullptr) ,_mirrorSprite(nullptr) { auto s = Director::getInstance()->getWinSize(); addNewSpriteWithCoords( Vec2(s.width/2,s.height/2) ); } std::string Sprite3DMirrorTest::title() const { return"Sprite3D Mirror Test"; } std::string Sprite3DMirrorTest::subtitle() const { return ""; }
void Sprite3DMirrorTest::addNewSpriteWithCoords(Vec2 p) { std::string fileName = "Sprite3DTest/orc.c3b"; auto sprite = Sprite3D::create(fileName); sprite->setScale(5); sprite->setRotation3D(Vec3(0,0)); addChild(sprite); sprite->setPosition( Vec2( p.x - 80,p.y) );
//test attach auto sp = Sprite3D::create("Sprite3DTest/axe.c3b"); sprite->getAttachNode("Bip001 R Hand")->addChild(sp);
auto animation = Animation3D::create(fileName); if (animation) { auto animate = Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate)); } _sprite = sprite; _hasWeapon = true;
//create mirror Sprite3D 镜像 sprite = Sprite3D::create(fileName); sprite->setScale(5); sprite->setScaleX(-5); sprite->setCullFace(GL_FRONT); sprite->setRotation3D(Vec3(0,0)); addChild(sprite); sprite->setPosition( Vec2( p.x + 80,p.y) );
//test attach sp = Sprite3D::create("Sprite3DTest/axe.c3b"); sprite->getAttachNode("Bip001 R Hand")->addChild(sp);
animation = Animation3D::create(fileName); if (animation) { auto animate = Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate)); } _mirrorSprite = sprite; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |