Cocos2d-x 3.3 的3D开发功能介绍
昨天去成都参加GMGDC 全球移动游戏开发者大会,据蓝港互动CEO王峰谈到《手机游戏开发如何走好第一步》时谈到 目前手游公司有10000家,没错,红海,都快变黑海了 这么多公司和产品如何竞争,大量的同质化产品,(王峰给我的建议是与其在红海中厮杀不如想象未来的蓝海在哪,听明白的请举起右手) 先不管这些了,作为程序员来讲我们看到了20万的人才缺口(如果每家公司招20个人,听明白的请举起左手) 今天下载了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模型 voidSprite3DBasicTest::addNewSpriteWithCoords(Vec2p) { //这里的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 第二种方法是在模型文件中不包含纹理 autosprite =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; floatrandom =CCRANDOM_0_1();
if( random <0.20) action =ScaleBy::create(3,2); elseif(random <0.40) action =RotateBy::create(3,360); elseif( random <0.60) action =Blink::create(1,3); elseif( random <0.8) action =TintBy::create(2,0,-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 } voidSprite3DBasicTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event* event) for(autotouch: touches) { autolocation = touch->getLocation(); //触摸屏幕添加3D模型 addNewSpriteWithCoords( location ); } } 2.透过触摸屏幕拖动模型移动 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) );
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)); addChild( sprite2 ); sprite2->runAction(RepeatForever::create(RotateBy::create(3,-360)));
// Make sprite1 touchable 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("sprite3d began... x = %f,y = %f",touch->getLocation().x,touch->getLocation().y); target->setOpacity(100); returntrue; } returnfalse; };
listener1->onTouchMoved= [](Touch* touch,51); font-family:Arial; font-size:14px; line-height:26px"> 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("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的调用
classEffect3D :publicRef { public: virtualvoiddraw(constMat4&transform) =0; virtualvoidsetTarget(EffectSprite3D*sprite) =0; protected: Effect3D() :_glProgramState(nullptr) {} virtual~Effect3D() { CC_SAFE_RELEASE(_glProgramState); } GLProgramState* _glProgramState; }; classEffect3DOutline:publicEffect3D staticEffect3DOutline* create(); voidsetOutlineColor(constVec3& color); voidsetOutlineWidth(floatwidth); virtualvoiddraw(constMat4&transform) override; virtualvoidsetTarget(EffectSprite3D*sprite) override; protected: Effect3DOutline(); virtual~Effect3DOutline(); boolinit(); Vec3 _outlineColor; float_outlineWidth; //weak reference EffectSprite3D* _sprite; #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID) EventListenerCustom* _backToForegroundListener; #endif
staticconststd::string_vertShaderFile; staticconststd::string_fragShaderFile; staticconststd::string_keyInGLProgramCache; staticconststd::string_vertSkinnedShaderFile; staticconststd::string_fragSkinnedShaderFile; staticconststd::string_keySkinnedInGLProgramCache; staticGLProgram* getOrCreateProgram(boolisSkinned =false); }; classEffectSprite3D :publicSprite3D staticEffectSprite3D* createFromObjFileAndTexture(conststd::string& objFilePath,conststd::string& textureFilePath); staticEffectSprite3D* create(conststd::string& path); voidsetEffect3D(Effect3D* effect); voidaddEffect(Effect3DOutline* effect,ssize_torder); virtualvoiddraw(Renderer*renderer,constMat4&transform,uint32_tflags) override; EffectSprite3D(); virtual~EffectSprite3D(); std::vector<std::tuple<ssize_t,Effect3D*,CustomCommand>> _effects; Effect3D* _defaultEffect; CustomCommand_command; }; classSprite3DEffectTest :publicSprite3DTestDemo public: CREATE_FUNC(Sprite3DEffectTest); Sprite3DEffectTest(); virtualstd::stringtitle()constoverride; virtualstd::stringsubtitle()constoverride; voidaddNewSpriteWithCoords(Vec2p); voidonTouchesEnded(conststd::vector<Touch*>& touches,Event* event); }; conststd::stringEffect3DOutline::_vertShaderFile ="Shaders3D/OutLine.vert"; conststd::stringEffect3DOutline::_fragShaderFile ="Shaders3D/OutLine.frag"; conststd::stringEffect3DOutline::_keyInGLProgramCache ="Effect3DLibrary_Outline"; conststd::stringEffect3DOutline::_vertSkinnedShaderFile ="Shaders3D/SkinnedOutline.vert"; conststd::stringEffect3DOutline::_fragSkinnedShaderFile ="Shaders3D/OutLine.frag"; conststd::stringEffect3DOutline::_keySkinnedInGLProgramCache ="Effect3DLibrary_Outline"; GLProgram*Effect3DOutline::getOrCreateProgram(boolisSkinned/* = false */) if(isSkinned) autoprogram =GLProgramCache::getInstance()->getGLProgram(_keySkinnedInGLProgramCache); if(program ==nullptr) { program =GLProgram::createWithFilenames(_vertSkinnedShaderFile,_fragSkinnedShaderFile); GLProgramCache::getInstance()->addGLProgram(program,_keySkinnedInGLProgramCache); } returnprogram; autoprogram =GLProgramCache::getInstance()->getGLProgram(_keyInGLProgramCache); program =GLProgram::createWithFilenames(_vertShaderFile,_fragShaderFile); _keyInGLProgramCache); } Effect3DOutline*Effect3DOutline::create() { Effect3DOutline* effect =new(std::nothrow)Effect3DOutline(); if(effect && effect->init()) effect->autorelease(); returneffect; CC_SAFE_DELETE(effect); returnnullptr; boolEffect3DOutline::init() {
returntrue; Effect3DOutline::Effect3DOutline() :_outlineWidth(1.0f) ,_outlineColor(1,1,1) (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(); glProgram->updateUniforms(); } ); Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backToForegroundListener,-1); #endif Effect3DOutline::~Effect3DOutline() Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundListener); voidEffect3DOutline::setOutlineColor(constVec3& color) if(_outlineColor!= color) _outlineColor= color; if(_glProgramState) _glProgramState->setUniformVec3("OutLineColor",_outlineColor); voidEffect3DOutline::setOutlineWidth(floatwidth) if(_outlineWidth!= width) _outlineWidth= width; _glProgramState->setUniformFloat("OutlineWidth",_outlineWidth); voidEffect3DOutline::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; automesh = sprite->getMesh(); longoffset =0; for(autoi =0; i < mesh->getMeshVertexAttribCount(); i++) { automeshvertexattrib = mesh->getMeshVertexAttribute(i);
_glProgramState->setVertexAttribPointer(s_attributeNames[meshvertexattrib.vertexAttrib], meshvertexattrib.size,51); font-family:Arial; font-size:14px; line-height:26px"> meshvertexattrib.type,51); font-family:Arial; font-size:14px; line-height:26px"> GL_FALSE,51); font-family:Arial; font-size:14px; line-height:26px"> mesh->getVertexSizeInBytes(),51); font-family:Arial; font-size:14px; line-height:26px"> (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)); staticvoidMatrixPalleteCallBack(GLProgram* glProgram,Uniform* uniform,intpaletteSize,constfloat* palette) glUniform4fv( uniform->location,(GLsizei)paletteSize,(constfloat*)palette ); voidEffect3DOutline::draw(constMat4&transform) { //draw Color4Fcolor(_sprite->getDisplayedColor()); color.a=_sprite->getDisplayedOpacity() /255.0f; _glProgramState->setUniformVec4("u_color",51); font-family:Arial; font-size:14px; line-height:26px"> 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,51); font-family:Arial; font-size:14px; line-height:26px"> 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_ARRAY_BUFFER,51); font-family:Arial; font-size:14px; line-height:26px"> glDisable(GL_DEPTH_TEST); glCullFace(GL_BACK); glDisable(GL_CULL_FACE); voidEffectSprite3D::draw(cocos2d::Renderer*renderer,constcocos2d::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); { _command.init(_globalZOrder); _command.func=CC_CALLBACK_0(Effect3D::draw,_defaultEffect,51); font-family:Arial; font-size:14px; line-height:26px"> renderer->addCommand(&_command); if(std::get<0>(effect) <=0) continue; //Sprite3DEffectTest中实现了对Sprite3DEffect的加载 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); voidSprite3DEffectTest::addNewSpriteWithCoords(Vec2p) //option 2: load obj and assign the texture 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,1,0)); //sprite->setEffect3D(effect); sprite->setScale(6.f); addChild( sprite ); y) ); nullptr); voidSprite3DEffectTest::onTouchesEnded(conststd::vector<Touch*>& touches,51); font-family:Arial; font-size:14px; line-height:26px"> 4.加载包含了3D纹理和动画的C3B文件,具体转化方法为在tools下使用fbx-conv.exe将3dmax导出的文件转化为c3b
用Sprite3D来加载c3b,用Animation3D,和Animate3D来创建动画 autoanimation =Animation3D::create(fileName); if(animation) { autoanimate =Animate3D::create(animation); sprite->runAction(RepeatForever::create(animate));
voidSprite3DWithSkinTest::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) ); boolinverse = (std::rand() %3==0); intrand2 =std::rand(); floatspeed =1.0f; if(rand2 %3==1) speed = animate->getSpeed() +CCRANDOM_0_1(); elseif(rand2 %3==2) speed = animate->getSpeed() -0.5*CCRANDOM_0_1(); animate->setSpeed(inverse ? -speed : speed); sprite->runAction(RepeatForever::create(animate)); 5.在以上模型和动画中添加特效(方法和在静态模型上一样) voidSprite3DWithSkinOutlineTest::addNewSpriteWithCoords(Vec2p) std::stringfileName ="Sprite3DTest/orc.c3b"; autosprite =EffectSprite3D::create(fileName);
Effect3DOutline* effect =Effect3DOutline::create(); effect->setOutlineColor(Vec3(1,51); font-family:Arial; font-size:14px; line-height:26px"> effect->setOutlineWidth(0.01f); sprite->addEffect(effect,-1); Effect3DOutline* effect2 =Effect3DOutline::create(); effect2->setOutlineWidth(0.02f); effect2->setOutlineColor(Vec3(1,51); font-family:Arial; font-size:14px; line-height:26px"> sprite->addEffect(effect2,-2); sprite->setScale(3); sprite->setRotation3D(Vec3(0,51); font-family:Arial; font-size:14px; line-height:26px"> addChild(sprite); autoanimation =Animation3D::create(fileName); if(animation) autoanimate =Animate3D::create(animation); 6.动画的切换 既然每个3D动画是Action就可以通过切换每个Sprite3D的Action来切换动画,下面是一个小乌龟的2个动画之间的切换 Animate3DTest::Animate3DTest() :_hurt(nullptr) _swim(nullptr) (nullptr) (nullptr) (0.f) {//添加小乌龟 addSprite3D(); listener->onTouchesEnded=CC_CALLBACK_2(Animate3DTest::onTouchesEnded,this); scheduleUpdate(); Animate3DTest::~Animate3DTest() { CC_SAFE_RELEASE(_moveAction); CC_SAFE_RELEASE(_hurt); CC_SAFE_RELEASE(_swim); voidAnimate3DTest::update(floatdt) { 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; _sprite->stopAction(_swim); _state=State::HURT; voidAnimate3DTest::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)); _sprite= sprite; { //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); //当触摸小乌龟则改变动画 voidAnimate3DTest::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); } voidAnimate3DTest::renewCallBack() //rerun swim action _sprite->runAction(_swim); _state=State::HURT_TO_SWIMMING; _elapseTransTime=0.0f; voidAnimate3DTest::onTouchesEnded(conststd::vector<Touch*>& touches,51); font-family:Arial; font-size:14px; line-height:26px"> floatlen = (_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); autodelay =DelayTime::create(_hurt->getDuration() -Animate3D::getTransitionTime()); autoseq =Sequence::create(delay,CallFunc::create(CC_CALLBACK_0(Animate3DTest::renewCallBack,51); font-family:Arial; font-size:14px; line-height:26px"> seq->setTag(101); _sprite->runAction(seq); } return; } 7.动态添加武器 AttachmentTest::AttachmentTest() :_hasWeapon(false) height/2) ); listener->onTouchesEnded=CC_CALLBACK_2(AttachmentTest::onTouchesEnded,51); font-family:Arial; font-size:14px; line-height:26px"> } voidAttachmentTest::addNewSpriteWithCoords(Vec2p) sprite->setScale(5); y) ); //test attach 亮点在这里,获取某个骨骼,Bip001 R Hand是在3Dmax定义的 autosp =Sprite3D::create("Sprite3DTest/axe.c3b"); sprite->getAttachNode("Bip001 R Hand")->addChild(sp); autoanimate =Animate3D::create(animation); _sprite= sprite; _hasWeapon=true; voidAttachmentTest::onTouchesEnded(conststd::vector<Touch*>& touches,51); font-family:Arial; font-size:14px; line-height:26px"> { if(_hasWeapon) { _sprite->removeAllAttachNode(); //去掉新骨骼节点 } else { autosp = Sprite3D::create("Sprite3DTest/axe.c3b"); _sprite->getAttachNode("Bip001 R Hand")->addChild(sp); _hasWeapon = !_hasWeapon; 8.动态修改材质Mesh(这个demo好,美女的模型超赞) 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); _eventDispatcher->addEventListenerWithSceneGraphPriority(listener,51); font-family:Arial; font-size:14px; line-height:26px"> TTFConfig ttfConfig("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,51); font-family:Arial; font-size:14px; line-height:26px"> autolabel3 = Label::createWithTTF(ttfConfig,"Coat"); autoitem3 = MenuItemLabel::create(label3,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchCoat,51); font-family:Arial; font-size:14px; line-height:26px"> autolabel4 = Label::createWithTTF(ttfConfig,"Pants"); autoitem4 = MenuItemLabel::create(label4,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchPants,51); font-family:Arial; font-size:14px; line-height:26px"> autolabel5 = Label::createWithTTF(ttfConfig,"Shoes"); autoitem5 = MenuItemLabel::create(label5,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchShoes,51); font-family:Arial; font-size:14px; line-height:26px"> 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,51); font-family:Arial; font-size:14px; line-height:26px"> this->addChild(pMenu1,10); voidSprite3DReskinTest::menuCallback_switchHair(Ref* sender) _useHairId++; if(_useHairId >1) _useHairId =0; if(_useHairId >=0 && _sprite) for(inti =0; i <2; i++ ) { // 获取材质 可见3.3支持了多套材质 autosubMesh = _sprite->getMeshByName(_girlHair[i]); if(subMesh) { if(i == _useHairId ) subMesh->setVisible(true); else subMesh->setVisible(false); } voidSprite3DReskinTest::menuCallback_switchGlasses(Ref* sender) autosubMesh = _sprite->getMeshByName("Girl_Glasses01"); if(subMesh) if(subMesh->isVisible()) subMesh->setVisible(false); else subMesh->setVisible(true); voidSprite3DReskinTest::menuCallback_switchCoat(Ref* sender) _useUpBodyId++; if(_useUpBodyId >1) _useUpBodyId =0; if(_useUpBodyId >=0 && _sprite) autosubMesh = _sprite->getMeshByName(_girlUpperBody[i]); if(subMesh) { if(i == _useUpBodyId ) { subMesh->setVisible(true); } else subMesh->setVisible(false); voidSprite3DReskinTest::menuCallback_switchPants(Ref* sender) _usePantsId++; if(_usePantsId >1) _usePantsId =0; if(_usePantsId >=0 && _sprite) autosubMesh = _sprite->getMeshByName(_girlPants[i]); if(i == _usePantsId ) voidSprite3DReskinTest::menuCallback_switchShoes(Ref* sender) _useShoesId++; if(_useShoesId >1) _useShoesId =0; if(_useShoesId >=0 && _sprite) for(inti =0; i <2; i++ ) autosubMesh = _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""; voidSprite3DReskinTest::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"; autosprite = Sprite3D::create(fileName); sprite->setScale(4); sprite->setRotation3D(Vec3(0,51); font-family:Arial; font-size:14px; line-height:26px"> 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); autoanimate = Animate3D::create(animation); sprite->runAction(RepeatForever::create(animate)); _sprite = sprite; 9.包围盒与3D模型碰撞的实现 AABB碰撞原理参考以下网址 http://cn.cocos2d-x.org/tutorial/show?id=1572 Sprite3DWithOBBPerfromanceTest::Sprite3DWithOBBPerfromanceTest() listener->onTouchesBegan = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesBegan,51); font-family:Arial; font-size:14px; line-height:26px"> listener->onTouchesEnded = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesEnded,51); font-family:Arial; font-size:14px; line-height:26px"> listener->onTouchesMoved = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesMoved,51); font-family:Arial; font-size:14px; line-height:26px"> 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,51); font-family:Arial; font-size:14px; line-height:26px"> increase->setColor(Color3B(0,20)); automenu = Menu::create(decrease,increase,51); font-family:Arial; font-size:14px; line-height:26px"> 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,51); font-family:Arial; font-size:14px; line-height:26px"> _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 voidSprite3DWithOBBPerfromanceTest::addNewOBBWithCoords(Vec2 p) Vec3 extents = Vec3(10,10,10); AABB aabb(-extents,extents); autoobb = OBB(aabb); obb._center = Vec3(p.x,p.y,0); _obb.push_back(obb); voidSprite3DWithOBBPerfromanceTest::onTouchesBegan(conststd::vector<Touch*>& touches,Event* event) autolocation = touch->getLocationInView(); if(_obb.size() >0) _intersetList.clear(); Ray ray; calculateRayByLocationInView(&ray,location); for(inti =0; i < _obb.size(); i++) if(ray.intersects(_obb[i])) _intersetList.insert(i); return; voidSprite3DWithOBBPerfromanceTest::onTouchesEnded(conststd::vector<Touch*>& touches,51); font-family:Arial; font-size:14px; line-height:26px"> voidSprite3DWithOBBPerfromanceTest::onTouchesMoved(conststd::vector<Touch*>& touches,51); font-family:Arial; font-size:14px; line-height:26px"> autolocation = touch->getLocation(); for(inti =0; i < _obb.size(); i++) if(_intersetList.find(i) != _intersetList.end()) _obb[i]._center = Vec3(location.x,location.y,51); font-family:Arial; font-size:14px; line-height:26px"> voidSprite3DWithOBBPerfromanceTest::update(floatdt) charszText[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(); Vec3 corners[8] = {}; _obb[i].getCorners(corners); _drawOBB->drawCube(corners,_obbt.intersects(_obb[i])?Color4F(1,1):Color4F(0,51); font-family:Arial; font-size:14px; line-height:26px"> voidSprite3DWithOBBPerfromanceTest::initDrawBox() _drawOBB = DrawNode3D::create(); addChild(_drawOBB); voidSprite3DWithOBBPerfromanceTest::addNewSpriteWithCoords(Vec2 p) std::string fileName ="Sprite3DTest/tortoise.c3b"; sprite->setScale(0.1f); sprite->setPosition(Vec2(s.width *4.f/5.f,s.height /2.f)); autoanimate = Animate3D::create(animation,1.933f); _moveAction = MoveTo::create(4.f,Vec2(s.width /5.f,51); font-family:Arial; font-size:14px; line-height:26px"> _moveAction->retain(); autoseq = Sequence::create(_moveAction,CallFunc::create(CC_CALLBACK_0(Sprite3DWithOBBPerfromanceTest::reachEndCallBack,51); font-family:Arial; font-size:14px; line-height:26px"> seq->setTag(100); sprite->runAction(seq); AABB aabb = _sprite->getAABB(); _obbt = OBB(aabb); _drawDebug = DrawNode3D::create(); addChild(_drawDebug); voidSprite3DWithOBBPerfromanceTest::reachEndCallBack() _sprite->stopActionByTag(100); autoinverse = (MoveTo*)_moveAction->reverse(); inverse->retain(); _moveAction->release(); _moveAction = inverse; autorot = RotateBy::create(1.0f,Vec3(0.f,0.f)); autoseq = Sequence::create(rot,_moveAction,51); font-family:Arial; font-size:14px; line-height:26px"> _sprite->runAction(seq); voidSprite3DWithOBBPerfromanceTest::addOBBCallback(Ref* sender) addOBBWithCount(10); voidSprite3DWithOBBPerfromanceTest::addOBBWithCount(floatvalue) for(inti =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,51); font-family:Arial; font-size:14px; line-height:26px"> AABB aabb(-extents,51); font-family:Arial; font-size:14px; line-height:26px"> autoobb = OBB(aabb); obb._center = Vec3(randompos.x,randompos.y,51); font-family:Arial; font-size:14px; line-height:26px"> _obb.push_back(obb); voidSprite3DWithOBBPerfromanceTest::delOBBCallback(Ref* sender) delOBBWithCount(10); voidSprite3DWithOBBPerfromanceTest::delOBBWithCount(floatvalue) if(_obb.size() >=10) _obb.erase(_obb.begin(),_obb.begin() + value); return; voidSprite3DWithOBBPerfromanceTest::unproject(constMat4& viewProjection,constSize* 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); voidSprite3DWithOBBPerfromanceTest::calculateRayByLocationInView(Ray* ray,constVec2& location) autodir = Director::getInstance(); autoview = 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,51); font-family:Arial; font-size:14px; line-height:26px"> Vec3 nearPoint; unproject(mat,&view,&src,&nearPoint); src = Vec3(location.x,1); Vec3 farPoint; Vec3 direction; Vec3::subtract(farPoint,nearPoint,&direction); direction.normalize(); ray->_origin = nearPoint; ray->_direction = direction; 10.3D模型的镜像 Sprite3DMirrorTest::Sprite3DMirrorTest() ,_mirrorSprite(nullptr) 2) ); std::string Sprite3DMirrorTest::title()const return"Sprite3D Mirror Test"; std::string Sprite3DMirrorTest::subtitle()const voidSprite3DMirrorTest::addNewSpriteWithCoords(Vec2 p) std::string fileName ="Sprite3DTest/orc.c3b"; sprite->setScale(5); sprite->setPosition( Vec2( p.x -80,p.y) ); //test attach autosp = Sprite3D::create("Sprite3DTest/axe.c3b"); sprite->getAttachNode("Bip001 R Hand")->addChild(sp); _hasWeapon =true; //create mirror Sprite3D 镜像 sprite = Sprite3D::create(fileName); sprite->setScale(5); sprite->setScaleX(-5); sprite->setCullFace(GL_FRONT); sprite->setRotation3D(Vec3(0,51); font-family:Arial; font-size:14px; line-height:26px"> addChild(sprite); sprite->setPosition( Vec2( p.x +80,p.y) ); sp = Sprite3D::create("Sprite3DTest/axe.c3b"); animation = Animation3D::create(fileName); _mirrorSprite = sprite; } (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |