昨天去成都参加GMGDC 全球移动游戏开发者大会,据蓝港互动CEO王峰谈到《手机游戏开发如何走好第一步》时谈到
目前手游公司有10000家,没错,红海,都快变黑海了
这么多公司和产品如何竞争,大量的同质化产品,(王峰给我的建议是与其在红海中厮杀不如想象未来的蓝海在哪,听明白的请举起右手)
先不管这些了,作为程序员来讲我们看到了20万的人才缺口(如果每家公司招20个人,听明白的请举起左手)
今天下载了Cocos2d-x 3.3,3D功能果然强大
主要有以下功能:
1. 基本的Sprite3D使用,加载静态模型和动态模型,看 Sprite3DBasicTest
2.Sprite3D对象的旋转,缩放等Action操作
3.Sprite3D中使用Shader特效,实现outLine
4.Animate3D来创建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));
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++ )
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;
}