Cocos2d-x 3.3 的3D开发功能介绍

Cocos2d-x 3.3 的3D开发功能介绍,第1张

概述Cocos2d-x 3.3 的3D开发功能介绍 sdhjob2014-09-28 11:07:465094 次阅读 本文主要介绍Cocos2d-x 3.3版本中强大的3D功能。 主要有以下功能: 1. 基本的Sprite3D使用,加载静态模型和动态模型,查看Sprite3DBasicTest; 2. Sprite3D对象的旋转,缩放等Action *** 作; 3. Sprite3D中使用Shader特效 Cocos2d-x 3.3 的3D开发功能介绍

sdhjob2014-09-28 11:07:465094 次阅读

本文主要介绍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里面的源码:

1 2 3 4 5 6 7 8 #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模型

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 voID Sprite3DBasicTest::addNewSpriteWithCoords(Vec2p) { //这里的obj可以使用3dmax直接导出 ////option1:loadaobjthatcontainthetextureinit第一种方法是在模型文件中包含了纹理 //autosprite=Sprite3D::create("sprite3dTest/scene01.obj"); //option2:loadobjandassignthetexture第二种方法是在模型文件中不包含纹理 autosprite=Sprite3D::create( "Sprite3DTest/boss1.obj" ); sprite->setScale(3.f); sprite->setTexture( "Sprite3DTest/boss.png" ); //在Sprite3D中包含了一些基本的Shader特效,下面是让3D模型实现outline //sprite->setEffect(cocos2d::EFFECT_OUTliNE); //addtoscene 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,-255,-255); else action=FadeOut::create(2); autoaction_back=action->reverse(); autoseq=Sequence::create(action,action_back,nullptr); sprite->runAction(RepeatForever::create(seq)); //以上大家看到Sprite3D起始和Sprite类似都可以实现各种Action } voID Sprite3DBasicTest::ontouchesEnded(conststd::vector<touch*>&touches,Event*event) { for (autotouch:touches) { autolocation=touch->getLocation(); //触摸屏幕添加3D模型 addNewSpriteWithCoords(location); } }


2.透过触摸屏幕拖动模型移动

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 Sprite3DHitTest::Sprite3DHittest() { autos=Director::getInstance()->getWinSize(); autosprite1=Sprite3D::create( "Sprite3DTest/boss1.obj" ); sprite1->setScale(4.f); sprite1->setTexture( "Sprite3DTest/boss.png" ); sprite1->setposition(Vec2(s.wIDth/2,s.height/2)); //addtoscene addChild(sprite1); sprite1->runAction(RepeatForever::create(RotateBy::create(3,360))); autosprite2=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)); //addtoscene addChild(sprite2); sprite2->runAction(RepeatForever::create(RotateBy::create(3,-360))); //Makesprite1touchable autoListener1=EventListenertouchOneByOne::create(); Listener1->setSwallowtouches( true ); Listener1->ontouchBegan=[](touch*touch,Event*event){ autotarget= static_cast <Sprite3D*>(event->getCurrentTarget()); Rectrect=target->getBoundingBox(); if (rect.containsPoint(touch->getLocation())) { log ( "sprite3dbegan...x=%f,y=%f" ,touch->getLocation().x,touch->getLocation().y); target->setopacity(100); return true ; } return false ; }; Listener1->ontouchmoved=[](touch*touch,Event*event){ autotarget= static_cast <Sprite3D*>(event->getCurrentTarget()); target->setposition(target->getposition()+touch->getDelta()); }; Listener1->ontouchended=[=](touch*touch,Event*event){ autotarget= static_cast <Sprite3D*>(event->getCurrentTarget()); log ( "sprite3dontouchesEnded.." ); target->setopacity(255); }; _eventdispatcher->addEventListenerWithSceneGraPHPriority(Listener1,sprite1); _eventdispatcher->addEventListenerWithSceneGraPHPriority(Listener1->clone(),sprite2); }


3.在一个Sprite3D上使用Shader

Effect3D继承REF封装了Shader的处理

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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; };


Effect3DOutline继承了Effect3D,封装了Outline类型的Shader

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 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; //weakreference 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 ); };


EffectSprite3D继承了Sprite3D封装了对Effect3DOutline的调用

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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_torder); virtual voID draw(Renderer*renderer, const Mat4&transform,uint32_tflags)overrIDe; protected : EffectSprite3D(); virtual ~EffectSprite3D(); std::vector<std::tuple<ssize_t,Effect3D*,CustomCommand>>_effects; Effect3D*_defaultEffect; CustomCommand_command; };


Sprite3DEffectTest

1 2 3 4 5 6 7 8 9 10 class Sprite3DEffectTest: public Sprite3DTestDemo { public : CREATE_FUNC(Sprite3DEffectTest); Sprite3DEffecttest(); virtual std::stringTitle() const overrIDe; virtual std::stringsubTitle() const overrIDe; voID addNewSpriteWithCoords(Vec2p); voID ontouchesEnded(conststd::vector<touch*>&touches,Event*event); };

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 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) { autoprogram=GLProgramCache::getInstance()->getGLProgram(_keySkinnedInGLProgramCache); if (program==nullptr) { program=GLProgram::createWithfilenames(_vertSkinnedShaderfile,_fragSkinnedShaderfile); GLProgramCache::getInstance()->addGLProgram(program,_keySkinnedInGLProgramCache); } return program; } else { autoprogram=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*) { autoglProgram=_glProgramState->getGLProgram(); glProgram->reset(); glProgram->initWithfilenames(_vertShaderfile,_fragShaderfile); glProgram->link();lProgram->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:SettinganullpointeroranullmeshEffectSprite3DtoEffect3D" ); 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; automesh=sprite->getMesh(); long offset=0; for (autoi=0;i<mesh->getMeshVertexAttribCount();i++) { automeshvertexattrib=mesh->getMeshVertexAttribute(i); _glProgramState->setVertexAttribPointer(s_attributenames[meshvertexattrib.vertexAttrib], meshvertexattrib.size, meshvertexattrib.type, GL_FALSE, mesh->getVertexSizeInBytes(), ( voID *)offset); offset+=meshvertexattrib.attribSizeBytes; } color4Fcolor(_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 color4Fcolor(_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); automesh=_sprite->getMesh(); glBindBuffer(GL_ARRAY_BUFFER,mesh->getVertexBuffer()); autoskin=_sprite->getMesh()->getSkin(); if (_sprite&&skin) { autofunction=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, const cocos2d::Mat4&transform,uint32_tflags) { 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的加载

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 Sprite3DEffectTest::Sprite3DEffecttest() { autos=Director::getInstance()->getWinSize(); addNewSpriteWithCoords(Vec2(s.wIDth/2,s.height/2)); autoListener=EventListenertouchAllAtOnce::create(); Listener->ontouchesEnded=CC_CALLBACK_2(Sprite3DEffectTest::ontouchesEnded, this ); _eventdispatcher->addEventListenerWithSceneGraPHPriority(Listener, this ); } voID Sprite3DEffectTest::addNewSpriteWithCoords(Vec2p) { //option2:loadobjandassignthetexture autosprite=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,0)); //sprite->setEffect3D(effect); sprite->setScale(6.f); //addtoscene 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,-255); else action=FadeOut::create(2); autoaction_back=action->reverse(); autoseq=Sequence::create(action,nullptr); sprite->runAction(RepeatForever::create(seq)); } voID Sprite3DEffectTest::ontouchesEnded(conststd::vector<touch*>&touches,Event*event) { for (autotouch:touches) { autolocation=touch->getLocation(); addNewSpriteWithCoords(location); } }


4.加载包含了3D纹理和动画的C3B文件,具体转化方法为在tools下使用fbx-conv.exe将3dmax导出的文件转化为c3b

用Sprite3D来加载c3b,用Animation3D,和Animate3D来创建动画

1 2 3 4 5 6 autoanimation=Animation3D::create(filename); if (animation) { autoanimate=Animate3D::create(animation); sprite->runAction(RepeatForever::create(animate)); }

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 voID Sprite3DWithSkinTest::addNewSpriteWithCoords(Vec2p) { std::stringfilename= "Sprite3DTest/orc.c3b" ; autosprite=EffectSprite3D::create(filename); sprite->setScale(3); sprite->setRotation3D(Vec3(0,180,0)); addChild(sprite); sprite->setposition(Vec2(p.x,p.y)); autoanimation=Animation3D::create(filename); if (animation) { autoanimate=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.在以上模型和动画中添加特效(方法和在静态模型上一样)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 voID Sprite3DWithSkinOutlineTest::addNewSpriteWithCoords(Vec2p) { std::stringfilename= "Sprite3DTest/orc.c3b" ; autosprite=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)); autoanimation=Animation3D::create(filename); if (animation) { autoanimate=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个动画之间的切换

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 Animate3DTest::Animate3Dtest():_hurt(nullptr),_swim(nullptr),_sprite(nullptr),_moveAction(nullptr),_elapseTransTime(0.f) { //添加小乌龟 addSprite3D(); autoListener=EventListenertouchAllAtOnce::create(); Listener->ontouchesEnded=CC_CALLBACK_2(Animate3DTest::ontouchesEnded, this ); _eventdispatcher->addEventListenerWithSceneGraPHPriority(Listener, 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::stringfilename= "Sprite3DTest/tortoise.c3b" ; autosprite=Sprite3D::create(filename); sprite->setScale(0.1f); autos=Director::getInstance()->getWinSize(); sprite->setposition(Vec2(s.wIDth*4.f/5.f,s.height/2.f)); addChild(sprite); _sprite=sprite; autoanimation=Animation3D::create(filename); if (animation) { //2个动画的时间不同,这些在3Dmax中定义 autoanimate=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(); autoseq=Sequence::create(_moveAction,CallFunc::create(CC_CALLBACK_0(Animate3DTest::reachEndCallBack, this )),nullptr); seq->setTag(100); sprite->runAction(seq); } //当触摸小乌龟则改变动画 voID Animate3DTest::reachEndCallBack() { _sprite->stopActionByTag(100); autoinverse=(Moveto*)_moveAction->reverse(); inverse->retain(); _moveAction->release(); _moveAction=inverse; autorot=RotateBy::create(1.f,Vec3(0.f,180.f,0.f)); autoseq=Sequence::create(rot,_moveAction,nullptr); seq->setTag(100); _sprite->runAction(seq); } voID Animate3DTest::renewCallBack() { //rerunswimaction _sprite->runAction(_swim); _state=State::HURT_TO_SWIMMING; _elapseTransTime=0.0f; } voID Animate3DTest::ontouchesEnded(conststd::vector<touch*>&touches,Event*event) { for (autotouch:touches) { autolocation=touch->getLocation(); if (_sprite) { float len=(_sprite->getposition()-location).length(); if (len<40) { //hurtthetortoise在游动状态改变为被抓住的动画 if (_state==State::SWIMMING) { _elapseTransTime=0.0f; _state=State::SWIMMING_TO_HURT; _sprite->stopAction(_hurt); _sprite->runAction(_hurt); autodelay=DelayTime::create(_hurt->getDuration()-Animate3D::getTransitionTime()); autoseq=Sequence::create(delay,CallFunc::create(CC_CALLBACK_0(Animate3DTest::renewCallBack,nullptr); seq->setTag(101); _sprite->runAction(seq); } return ; } } } }


7.动态添加武器

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 AttachmentTest::Attachmenttest():_hasWeapon( false ),_sprite(nullptr) { autos=Director::getInstance()->getWinSize(); addNewSpriteWithCoords(Vec2(s.wIDth/2,s.height/2)); autoListener=EventListenertouchAllAtOnce::create(); Listener->ontouchesEnded=CC_CALLBACK_2(AttachmentTest::ontouchesEnded, this ); } voID AttachmentTest::addNewSpriteWithCoords(Vec2p) { std::stringfilename= "Sprite3DTest/orc.c3b" ; autosprite=Sprite3D::create(filename); sprite->setScale(5); sprite->setRotation3D(Vec3(0,p.y)); //testattach亮点在这里,获取某个骨骼,Bip001RHand是在3Dmax定义的 autosp=Sprite3D::create( "Sprite3DTest/axe.c3b" ); sprite->getAttachNode( "Bip001RHand" )->addChild(sp); autoanimation=Animation3D::create(filename); if (animation) { autoanimate=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 { autosp=Sprite3D::create( "Sprite3DTest/axe.c3b" ); _sprite->getAttachNode( "Bip001RHand" )->addChild(sp); } _hasWeapon=!_hasWeapon; }


8.动态修改材质Mesh(这个demo好,美女的模型超赞)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 Sprite3DReskinTest::Sprite3DReskintest():_sprite(nullptr) { autos=Director::getInstance()->getWinSize(); addNewSpriteWithCoords(Vec2(s.wIDth/2,s.height/2)); autoListener=EventListenertouchAllAtOnce::create(); Listener->ontouchesEnded=CC_CALLBACK_2(Sprite3DReskinTest::ontouchesEnded, this ); TTFConfigttfConfig( "Fonts/arial.ttf" ,20); autolabel1=Label::createWithTTF(ttfConfig, "Hair" ); autoitem1=MenuItemLabel::create(label1,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchHair, this )); autolabel2=Label::createWithTTF(ttfConfig, "Glasses" ); autoitem2=MenuItemLabel::create(label2,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchGlasses, this )); autolabel3=Label::createWithTTF(ttfConfig, "Coat" ); autoitem3=MenuItemLabel::create(label3,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchCoat, this )); autolabel4=Label::createWithTTF(ttfConfig, "Pants" ); autoitem4=MenuItemLabel::create(label4,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchPants, this )); autolabel5=Label::createWithTTF(ttfConfig, "Shoes" ); autoitem5=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)); autopMenu1=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支持了多套材质 autosubMesh=_sprite->getMeshByname(_girlHair[i]); if (subMesh) { if (i==_useHairID) { subMesh->setVisible( true ); } else { subMesh->setVisible( false ); } } } } } voID Sprite3DReskinTest::menuCallback_switchGlasses(Ref*sender) { autosubMesh=_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++) { autosubMesh=_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++) { autosubMesh=_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++) { autosubMesh=_sprite->getMeshByname(_girlShoes[i]); if (subMesh) { if (i==_useShoesID) { subMesh->setVisible( true ); } else { subMesh->setVisible( false ); } } } } } std::stringSprite3DReskinTest::Title() const { return "TestingSprite3DReskin" ; } std::stringSprite3DReskinTest::subTitle() const { return "" ; } voID Sprite3DReskinTest::addNewSpriteWithCoords(Vec2p) { _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::stringfilename= "Sprite3DTest/ReskinGirl.c3b" ; autosprite=Sprite3D::create(filename); sprite->setScale(4); sprite->setRotation3D(Vec3(0,0)); autogirlPants=sprite->getMeshByname(_girlPants[1]); if (girlPants) { girlPants->setVisible( false ); } autogirlShoes=sprite->getMeshByname(_girlShoes[1]); if (girlShoes) { girlShoes->setVisible( false ); } autogirlHair=sprite->getMeshByname(_girlHair[1]); if (girlHair) { girlHair->setVisible( false ); } autogirlUpBody=sprite->getMeshByname(_girlUpperBody[1]); if (girlUpBody) { girlUpBody->setVisible( false ); } addChild(sprite); sprite->setposition(Vec2(p.x,p.y-60)); autoanimation=Animation3D::create(filename); if (animation) { autoanimate=Animate3D::create(animation); sprite->runAction(RepeatForever::create(animate)); } _sprite=sprite; }


9.包围盒与3D模型碰撞的实现

AABB碰撞原理参考以下网址:http://cn.cocos2d-x.org/tutorial/show?id=1572

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 Sprite3DWithOBBPerfromanceTest::Sprite3DWithOBBPerfromancetest() { autoListener=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 ); autos=Director::getInstance()->getWinSize(); initDrawBox(); addNewSpriteWithCoords(Vec2(s.wIDth/2,s.height/2)); MenuItemFont::setFontname( "Fonts/arial.ttf" ); MenuItemFont::setFontSize(65); autodecrease=MenuItemFont::create( "-" ,CC_CALLBACK_1(Sprite3DWithOBBPerfromanceTest::delOBBCallback, this )); decrease->setcolor(color3B(0,200,20)); autoincrease=MenuItemFont::create( "+" ,CC_CALLBACK_1(Sprite3DWithOBBPerfromanceTest::addobBCallback, this )); increase->setcolor(color3B(0,20)); automenu=Menu::create(decrease,increase,nullptr); menu->alignItemsHorizontally(); menu->setposition(Vec2(s.wIDth/2,s.height-65)); addChild(menu,1); TTFConfigttfCount( "Fonts/MarkerFelt.ttf" ,30); _labelCubeCount=Label::createWithTTF(ttfCount, "0cubes" ); _labelCubeCount->setcolor(color3B(0,20)); _labelCubeCount->setposition(Vec2(s.wIDth/2,s.height-90)); addChild(_labelCubeCount); _hasCollIDer= false ; addobBCallback(nullptr); scheduleUpdate(); } std::stringSprite3DWithOBBPerfromanceTest::Title() const { return "OBBCollisonPerfromanceTest" ; } std::stringSprite3DWithOBBPerfromanceTest::subTitle() const { return "" ; } voID Sprite3DWithOBBPerfromanceTest::addNewOBBWithCoords(Vec2p) { Vec3extents=Vec3(10,10,10); AABBaabb(-extents,extents); autoobb=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 (autotouch:touches) { autolocation=touch->getLocationInVIEw(); if (_obb.size()>0) { _intersetList.clear(); Rayray; 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 (autotouch:touches) { autolocation=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, "%lucubes" ,_obb.size()); _labelCubeCount->setString(szText); if (_drawDeBUG) { _drawDeBUG->clear(); Mat4mat=_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(); Vec3corners[8]={}; _obbt.getCorners(corners); _drawDeBUG->drawCube(corners,color4F(0,1)); } if (_obb.size()>0) { _drawOBB->clear(); for ( int i=0;i<_obb.size();i++) { Vec3corners[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(Vec2p) { std::stringfilename= "Sprite3DTest/tortoise.c3b" ; autosprite=Sprite3D::create(filename); sprite->setScale(0.1f); autos=Director::getInstance()->getWinSize(); sprite->setposition(Vec2(s.wIDth*4.f/5.f,s.height/2.f)); addChild(sprite); _sprite=sprite; autoanimation=Animation3D::create(filename); if (animation) { autoanimate=Animate3D::create(animation,1.933f); sprite->runAction(RepeatForever::create(animate)); } _moveAction=Moveto::create(4.f,s.height/2.f)); _moveAction->retain(); autoseq=Sequence::create(_moveAction,CallFunc::create(CC_CALLBACK_0(Sprite3DWithOBBPerfromanceTest::reachEndCallBack,nullptr); seq->setTag(100); sprite->runAction(seq); AABBaabb=_sprite->getAABB(); _obbt=OBB(aabb); _drawDeBUG=DrawNode3D::create(); addChild(_drawDeBUG); } voID Sprite3DWithOBBPerfromanceTest::reachEndCallBack() { _sprite->stopActionByTag(100); autoinverse=(Moveto*)_moveAction->reverse(); inverse->retain(); _moveAction->release(); _moveAction=inverse; autorot=RotateBy::create(1.0f,0.f)); autoseq=Sequence::create(rot,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++) { Vec2randompos=Vec2(CCRANDOM_0_1()*Director::getInstance()->getWinSize().wIDth,CCRANDOM_0_1()*Director::getInstance()->getWinSize().height); Vec3extents=Vec3(10,10); AABBaabb(-extents,extents); autoobb=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); Vec4screen(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) { autodir=Director::getInstance(); autovIEw=dir->getWinSize(); Mat4mat=dir->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW); mat=dir->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION); Vec3src=Vec3(location.x,-1); Vec3nearPoint; unproject(mat,&vIEw,&src,&nearPoint); src=Vec3(location.x,1); Vec3farPoint; unproject(mat,&farPoint); Vec3direction; Vec3::subtract(farPoint,nearPoint,&direction); direction.normalize(); ray->_origin=nearPoint; ray->_direction=direction; }


10.3D模型的镜像

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 Sprite3DMirrorTest::Sprite3DMirrortest():_sprite(nullptr),_mirrorSprite(nullptr) { autos=Director::getInstance()->getWinSize(); addNewSpriteWithCoords(Vec2(s.wIDth/2,s.height/2)); } std::stringSprite3DMirrorTest::Title() const { return "Sprite3DMirrorTest" ; } std::stringSprite3DMirrorTest::subTitle() const { return "" ; } voID Sprite3DMirrorTest::addNewSpriteWithCoords(Vec2p) { std::stringfilename= "Sprite3DTest/orc.c3b" ; autosprite=Sprite3D::create(filename); sprite->setScale(5); sprite->setRotation3D(Vec3(0,0)); addChild(sprite); sprite->setposition(Vec2(p.x-80,p.y)); //testattach autosp=Sprite3D::create( "Sprite3DTest/axe.c3b" ); sprite->getAttachNode( "Bip001RHand" )->addChild(sp); autoanimation=Animation3D::create(filename); if (animation) { autoanimate=Animate3D::create(animation); sprite->runAction(RepeatForever::create(animate)); } _sprite=sprite; _hasWeapon= true ; //createmirrorSprite3D镜像 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)); //testattach sp=Sprite3D::create( "Sprite3DTest/axe.c3b" ); sprite->getAttachNode( "Bip001RHand" )->addChild(sp); animation=Animation3D::create(filename); if (animation) { autoanimate=Animate3D::create(animation); sprite->runAction(RepeatForever::create(animate)); } _mirrorSprite=sprite; }
总结

以上是内存溢出为你收集整理的Cocos2d-x 3.3 的3D开发功能介绍全部内容,希望文章能够帮你解决Cocos2d-x 3.3 的3D开发功能介绍所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1037395.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-24
下一篇2022-05-24

发表评论

登录后才能评论

评论列表(0条)

    保存