Cocos2d-x 的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 = (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |