您的位置:首页 > 移动开发 > Cocos引擎

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

2015-02-24 12:07 393 查看
今天下载了Cocos2d-x 3.3,3D功能果然强大

主要有以下功能:

1. 基本的Sprite3D使用,加载静态模型和动态模型,看 Sprite3DBasicTest

2.Sprite3D对象的旋转,缩放等Action操作

3.Sprite3D中使用Shader特效,实现outLine

4.Animate3D来创建3D动画

5.动态增加3D骨骼,实现怪物添加手持武器功能
6,动态修改骨骼皮肤实现换装功能Sprite3DReskinTest
7.通过包围盒实现3D模型碰撞,Sprite3DWithOBBPerfromanceTest
8.实现水平镜像3D模型,Sprite3DMirrorTest

下面介绍一下Sprite3DTest里面的源码

#include "Sprite3DTest.h"
#include "3d/CCAnimation3D.h"
#include "3d/CCAnimate3D.h"
#include "3d/CCAttachNode.h"
#include "3d/CCRay.h"
#include "3d/CCSprite3D.h"
#include "renderer/CCVertexIndexBuffer.h"
#include "DrawNode3D.h"

1.在Scene中添加3D模型



void Sprite3DBasicTest::addNewSpriteWithCoords(Vec2 p)
{
//这里的obj可以使用3dmax直接导出
// //option 1: load a obj that contain the texture in it 第一种方法是在模型文件中包含了纹理
// auto sprite = Sprite3D::create("sprite3dTest/scene01.obj");

//option 2: load obj and assign the texture 第二种方法是在模型文件中不包含纹理
auto sprite =Sprite3D::create("Sprite3DTest/boss1.obj");
sprite->setScale(3.f);
sprite->setTexture("Sprite3DTest/boss.png");

//在Sprite3D中包含了一些基本的Shader特效,下面是让3D模型实现outline
//sprite->setEffect(cocos2d::EFFECT_OUTLINE);

//add to scene
addChild( sprite );
sprite->setPosition(
Vec2( p.x, p.y) );
ActionInterval* action;
float random = CCRANDOM_0_1();

if( random < 0.20 )
action = ScaleBy::create(3,2);
else if(random <0.40)
action = RotateBy::create(3,360);
else if( random <0.60)
action = Blink::create(1,3);
else if( random <0.8 )
action = TintBy::create(2,0, -255, -255);
else
action = FadeOut::create(2);
auto action_back = action->reverse();
auto seq = Sequence::create( action, action_back,nullptr );

sprite->runAction( RepeatForever::create(seq) );
//以上大家看到Sprite3D起始和Sprite类似都可以实现各种Action
}
void Sprite3DBasicTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event*
event)
{
for (auto touch: touches)
{
auto location = touch->getLocation();
//触摸屏幕添加3D模型
addNewSpriteWithCoords( location );
}
}
2.透过触摸屏幕拖动模型移动



Sprite3DHitTest::Sprite3DHitTest()
{
auto s =Director::getInstance()->getWinSize();
auto sprite1 =Sprite3D::create("Sprite3DTest/boss1.obj");

sprite1->setScale(4.f);
sprite1->setTexture("Sprite3DTest/boss.png");
sprite1->setPosition(
Vec2(s.width/2, s.height/2) );

//add to scene
addChild( sprite1 );
sprite1->runAction(RepeatForever::create(RotateBy::create(3,360)));

auto sprite2 =Sprite3D::create("Sprite3DTest/boss1.obj");

sprite2->setScale(4.f);
sprite2->setTexture("Sprite3DTest/boss.png");
sprite2->setPosition(
Vec2(s.width/2, s.height/2) );
sprite2->setAnchorPoint(Vec2(0.5,0.5));

//add to scene
addChild( sprite2 );
sprite2->runAction(RepeatForever::create(RotateBy::create(3, -360)));

// Make sprite1 touchable
auto listener1 =EventListenerTouchOneByOne::create();
listener1->setSwallowTouches(true);

listener1->onTouchBegan = [](Touch* touch,Event* event){
auto target =
static_cast<Sprite3D*>(event->getCurrentTarget());


Rect rect = target->getBoundingBox();

if (rect.containsPoint(touch->getLocation()))
{
log("sprite3d began... x = %f, y = %f", touch->getLocation().x, touch->getLocation().y);
target->setOpacity(100);
return
true;

}
return
false;

};

listener1->onTouchMoved = [](Touch* touch,Event* event){
auto target =
static_cast<Sprite3D*>(event->getCurrentTarget());

target->setPosition(target->getPosition() + touch->getDelta());
};

listener1->onTouchEnded = [=](Touch* touch,Event* event){
auto target = static_cast<Sprite3D*>(event->getCurrentTarget());
log("sprite3d onTouchesEnded.. ");
target->setOpacity(255);
};

_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(), sprite2);

}
3.在一个Sprite3D上使用Shader

Effect3D继承REF封装了Shader的处理
Effect3DOutline继承了Effect3D,封装了Outline类型的Shader
EffectSprite3D继承了Sprite3D封装了对Effect3DOutline的调用

class Effect3D : publicRef
{
public:
virtual void draw(constMat4 &transform) =0;
virtual void setTarget(EffectSprite3D *sprite) =0;
protected:
Effect3D() : _glProgramState(nullptr) {}
virtual ~Effect3D()
{
CC_SAFE_RELEASE(_glProgramState);
}
protected:
GLProgramState* _glProgramState;
};

class Effect3DOutline: publicEffect3D
{
public:
static Effect3DOutline* create();

void setOutlineColor(constVec3& color);

void setOutlineWidth(float width);

virtual void draw(constMat4 &transform) override;
virtual void setTarget(EffectSprite3D *sprite) override;
protected:

Effect3DOutline();
virtual ~Effect3DOutline();

bool init();

Vec3 _outlineColor;
float _outlineWidth;
//weak reference
EffectSprite3D* _sprite;
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
EventListenerCustom* _backToForegroundListener;
#endif

protected:
static const
std::string _vertShaderFile;
static const
std::string _fragShaderFile;
static const
std::string _keyInGLProgramCache;

static const
std::string _vertSkinnedShaderFile;
static const
std::string _fragSkinnedShaderFile;
static const
std::string _keySkinnedInGLProgramCache;

static GLProgram* getOrCreateProgram(bool isSkinned =false);
};

class EffectSprite3D : publicSprite3D
{
public:
static EffectSprite3D* createFromObjFileAndTexture(conststd::string& objFilePath,const
std::string& textureFilePath);
static EffectSprite3D* create(conststd::string& path);

void setEffect3D(Effect3D* effect);
void addEffect(Effect3DOutline* effect,ssize_t order);
virtual void draw(Renderer *renderer,constMat4 &transform,
uint32_t flags) override;
protected:
EffectSprite3D();
virtual ~EffectSprite3D();

std::vector<std::tuple<ssize_t,Effect3D*,CustomCommand>> _effects;
Effect3D* _defaultEffect;
CustomCommand _command;
};

class Sprite3DEffectTest :
public Sprite3DTestDemo
{
public:
CREATE_FUNC(Sprite3DEffectTest);
Sprite3DEffectTest();
virtual std::string title()const override;
virtual std::string subtitle()const override;

void addNewSpriteWithCoords(Vec2 p);

void onTouchesEnded(conststd::vector<Touch*>& touches,Event* event);
};



const std::stringEffect3DOutline::_vertShaderFile ="Shaders3D/OutLine.vert";
const std::stringEffect3DOutline::_fragShaderFile ="Shaders3D/OutLine.frag";
const std::stringEffect3DOutline::_keyInGLProgramCache ="Effect3DLibrary_Outline";

const std::stringEffect3DOutline::_vertSkinnedShaderFile ="Shaders3D/SkinnedOutline.vert";
const std::stringEffect3DOutline::_fragSkinnedShaderFile ="Shaders3D/OutLine.frag";
const std::stringEffect3DOutline::_keySkinnedInGLProgramCache ="Effect3DLibrary_Outline";
GLProgram* Effect3DOutline::getOrCreateProgram(bool isSkinned/* = false */ )
{
if(isSkinned)
{
auto program = GLProgramCache::getInstance()->getGLProgram(_keySkinnedInGLProgramCache);
if(program == nullptr)
{
program = GLProgram::createWithFilenames(_vertSkinnedShaderFile,_fragSkinnedShaderFile);
GLProgramCache::getInstance()->addGLProgram(program,_keySkinnedInGLProgramCache);
}
return program;
}
else
{
auto program = GLProgramCache::getInstance()->getGLProgram(_keyInGLProgramCache);
if(program == nullptr)
{
program = GLProgram::createWithFilenames(_vertShaderFile,_fragShaderFile);
GLProgramCache::getInstance()->addGLProgram(program,_keyInGLProgramCache);
}
return program;
}

}

Effect3DOutline* Effect3DOutline::create()
{
Effect3DOutline* effect =new (std::nothrow)Effect3DOutline();
if(effect && effect->init())
{
effect->autorelease();
return effect;
}
else
{
CC_SAFE_DELETE(effect);
return nullptr;
}
}

bool Effect3DOutline::init()
{

return true;
}

Effect3DOutline::Effect3DOutline()
: _outlineWidth(1.0f)
, _outlineColor(1,1,1)
, _sprite(nullptr)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
_backToForegroundListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED,
[this](EventCustom*)
{

auto glProgram = _glProgramState->getGLProgram();
glProgram->reset();
glProgram->initWithFilenames(_vertShaderFile, _fragShaderFile);
glProgram->link();
glProgram->updateUniforms();
}
);
Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backToForegroundListener, -1);
#endif
}

Effect3DOutline::~Effect3DOutline()
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundListener);
#endif
}

void Effect3DOutline::setOutlineColor(constVec3& color)
{
if(_outlineColor != color)
{
_outlineColor = color;
if(_glProgramState)
_glProgramState->setUniformVec3("OutLineColor",_outlineColor);
}
}

void Effect3DOutline::setOutlineWidth(float width)
{
if(_outlineWidth != width)
{
_outlineWidth = width;
if(_glProgramState)
_glProgramState->setUniformFloat("OutlineWidth",_outlineWidth);
}
}

void Effect3DOutline::setTarget(EffectSprite3D *sprite)
{
CCASSERT(nullptr != sprite &&nullptr != sprite->getMesh(),"Error:
Setting a null pointer or a null mesh EffectSprite3D to Effect3D");

if(sprite != _sprite)
{
GLProgram* glprogram;
if(!sprite->getMesh()->getSkin())
glprogram = GLProgram::createWithFilenames(_vertShaderFile,_fragShaderFile);
else
glprogram = GLProgram::createWithFilenames(_vertSkinnedShaderFile,_fragSkinnedShaderFile);

_glProgramState =
GLProgramState::create(glprogram);

_glProgramState->retain();
_glProgramState->setUniformVec3("OutLineColor",_outlineColor);
_glProgramState->setUniformFloat("OutlineWidth",_outlineWidth);

_sprite = sprite;

auto mesh = sprite->getMesh();
long offset = 0;
for (auto i =0; i < mesh->getMeshVertexAttribCount(); i++)
{
auto meshvertexattrib = mesh->getMeshVertexAttribute(i);

_glProgramState->setVertexAttribPointer(s_attributeNames[meshvertexattrib.vertexAttrib],
meshvertexattrib.size,
meshvertexattrib.type,

GL_FALSE,
mesh->getVertexSizeInBytes(),
(void*)offset);
offset += meshvertexattrib.attribSizeBytes;
}

Color4F color(_sprite->getDisplayedColor());
color.a = _sprite->getDisplayedOpacity() /255.0f;
_glProgramState->setUniformVec4("u_color",Vec4(color.r, color.g, color.b,
color.a));
}

}

static void MatrixPalleteCallBack(GLProgram* glProgram,Uniform* uniform,int paletteSize,const
float* palette)
{
glUniform4fv( uniform->location, (GLsizei)paletteSize, (constfloat*)palette );
}

void Effect3DOutline::draw(constMat4 &transform)
{
//draw
Color4F color(_sprite->getDisplayedColor());
color.a = _sprite->getDisplayedOpacity() /255.0f;
_glProgramState->setUniformVec4("u_color",Vec4(color.r, color.g, color.b,
color.a));
if(_sprite &&
_sprite->getMesh())
{
glEnable(GL_CULL_FACE);
glCullFace(GL_FRONT);
glEnable(GL_DEPTH_TEST);

auto mesh = _sprite->getMesh();
glBindBuffer(GL_ARRAY_BUFFER, mesh->getVertexBuffer());

auto skin = _sprite->getMesh()->getSkin();
if(_sprite && skin)
{
auto function =
std::bind(MatrixPalleteCallBack,std::placeholders::_1,std::placeholders::_2,
skin->getMatrixPaletteSize(), (float*)skin->getMatrixPalette());
_glProgramState->setUniformCallback("u_matrixPalette", function);
}

if(_sprite)
_glProgramState->apply(transform);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getIndexBuffer());
glDrawElements(mesh->getPrimitiveType(), mesh->getIndexCount(), mesh->getIndexFormat(),0);
CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, mesh->getIndexCount());

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);
glBindBuffer(GL_ARRAY_BUFFER,0);
glDisable(GL_DEPTH_TEST);
glCullFace(GL_BACK);
glDisable(GL_CULL_FACE);
}
}

void EffectSprite3D::draw(cocos2d::Renderer *renderer,constcocos2d::Mat4
&transform,uint32_t flags)
{
for(auto &effect : _effects)
{
if(std::get<0>(effect) >=0)
break;
CustomCommand &cc =
std::get<2>(effect);
cc.func = CC_CALLBACK_0(Effect3D::draw,std::get<1>(effect),transform);
renderer->addCommand(&cc);

}

if(!_defaultEffect)
{
Sprite3D::draw(renderer, transform, flags);
}
else
{
_command.init(_globalZOrder);
_command.func =CC_CALLBACK_0(Effect3D::draw,_defaultEffect, transform);
renderer->addCommand(&_command);
}

for(auto &effect : _effects)
{
if(std::get<0>(effect) <=0)
continue;
CustomCommand &cc =
std::get<2>(effect);
cc.func = CC_CALLBACK_0(Effect3D::draw,std::get<1>(effect),transform);
renderer->addCommand(&cc);

}
}
//Sprite3DEffectTest中实现了对Sprite3DEffect的加载

Sprite3DEffectTest::Sprite3DEffectTest()
{
auto s =Director::getInstance()->getWinSize();
addNewSpriteWithCoords(Vec2(s.width/2, s.height/2)
);

auto listener =EventListenerTouchAllAtOnce::create();
listener->onTouchesEnded =
CC_CALLBACK_2(Sprite3DEffectTest::onTouchesEnded,this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
}

void Sprite3DEffectTest::addNewSpriteWithCoords(Vec2 p)
{
//option 2: load obj and assign the texture
auto sprite =EffectSprite3D::createFromObjFileAndTexture("Sprite3DTest/boss1.obj","Sprite3DTest/boss.png");
Effect3DOutline* effect =Effect3DOutline::create();
sprite->addEffect(effect, -1);
effect->setOutlineColor(Vec3(1,0,0));
effect->setOutlineWidth(0.01f);

Effect3DOutline* effect2 =Effect3DOutline::create();
sprite->addEffect(effect2, -2);
effect2->setOutlineWidth(0.02f);
effect2->setOutlineColor(Vec3(1,1,0));
//sprite->setEffect3D(effect);
sprite->setScale(6.f);

//add to scene
addChild( sprite );

sprite->setPosition(
Vec2( p.x, p.y) );

ActionInterval* action;
float random = CCRANDOM_0_1();

if( random < 0.20 )
action = ScaleBy::create(3,2);
else if(random <0.40)
action = RotateBy::create(3,360);
else if( random <0.60)
action = Blink::create(1,3);
else if( random <0.8 )
action = TintBy::create(2,0, -255, -255);
else
action = FadeOut::create(2);
auto action_back = action->reverse();
auto seq = Sequence::create( action, action_back,nullptr );

sprite->runAction( RepeatForever::create(seq) );
}

void Sprite3DEffectTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event*
event)
{
for (auto touch: touches)
{
auto location = touch->getLocation();

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

用Sprite3D来加载c3b,用[b]Animation3D,和[b]Animate3D来创建动画[/b][/b]
auto animation =
Animation3D::create(fileName);

if (animation)
{
auto animate =
Animate3D::create(animation);

sprite->runAction(RepeatForever::create(animate));


}



void Sprite3DWithSkinTest::addNewSpriteWithCoords(Vec2 p)
{
std::string fileName ="Sprite3DTest/orc.c3b";
auto sprite =
EffectSprite3D::create(fileName);

sprite->setScale(3);
sprite->setRotation3D(Vec3(0,180,0));
addChild(sprite);
sprite->setPosition(
Vec2( p.x, p.y) );

auto animation =
Animation3D::create(fileName);

if (animation)
{
auto animate =
Animate3D::create(animation);

bool inverse = (std::rand() %3 ==0);

int rand2 = std::rand();
float speed = 1.0f;
if(rand2 % 3 ==1)
{
speed = animate->getSpeed() +
CCRANDOM_0_1();
}
else if(rand2 %3 ==2)
{
speed = animate->getSpeed() -
0.5 * CCRANDOM_0_1();
}
animate->setSpeed(inverse ? -speed : speed);

sprite->runAction(RepeatForever::create(animate));
}
}
5.在以上模型和动画中添加特效(方法和在静态模型上一样)



void Sprite3DWithSkinOutlineTest::addNewSpriteWithCoords(Vec2 p)
{
std::string fileName ="Sprite3DTest/orc.c3b";
auto sprite =
EffectSprite3D::create(fileName);


Effect3DOutline* effect =Effect3DOutline::create();
effect->setOutlineColor(Vec3(1,0,0));
effect->setOutlineWidth(0.01f);
sprite->addEffect(effect, -1);

Effect3DOutline* effect2 =Effect3DOutline::create();
effect2->setOutlineWidth(0.02f);
effect2->setOutlineColor(Vec3(1,1,0));
sprite->addEffect(effect2, -2);

sprite->setScale(3);
sprite->setRotation3D(Vec3(0,180,0));
addChild(sprite);
sprite->setPosition(
Vec2( p.x, p.y) );

auto animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);
bool inverse = (std::rand() %3 ==0);

int rand2 = std::rand();
float speed = 1.0f;
if(rand2 % 3 ==1)
{
speed = animate->getSpeed() +
CCRANDOM_0_1();
}
else if(rand2 %3 ==2)
{
speed = animate->getSpeed() -
0.5 * CCRANDOM_0_1();
}
animate->setSpeed(inverse ? -speed : speed);

sprite->runAction(RepeatForever::create(animate));
}
}
6.动画的切换
既然每个3D动画是Action就可以通过切换每个Sprite3D的Action来切换动画,下面是一个小乌龟的2个动画之间的切换



Animate3DTest::Animate3DTest()
: _hurt(nullptr)
, _swim(nullptr)
, _sprite(nullptr)
, _moveAction(nullptr)
, _elapseTransTime(0.f)
{ //添加小乌龟
addSprite3D();

auto listener =EventListenerTouchAllAtOnce::create();
listener->onTouchesEnded =
CC_CALLBACK_2(Animate3DTest::onTouchesEnded,this);
_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::string fileName ="Sprite3DTest/tortoise.c3b";
auto sprite = Sprite3D::create(fileName);
sprite->setScale(0.1f);
auto s =Director::getInstance()->getWinSize();
sprite->setPosition(Vec2(s.width *4.f /5.f, s.height /2.f));
addChild(sprite);
_sprite = sprite;
auto animation = Animation3D::create(fileName);
if (animation)
{ //2个动画的时间不同,这些在3Dmax中定义
auto animate =
Animate3D::create(animation, 0.f,1.933f);

_swim = RepeatForever::create(animate);
sprite->runAction(_swim);

_swim->retain();
_hurt = Animate3D::create(animation,1.933f,2.8f);
_hurt->retain();
_state = State::SWIMMING;
}

_moveAction = MoveTo::create(4.f,Vec2(s.width /5.f, s.height
/ 2.f));
_moveAction->retain();
auto seq = Sequence::create(_moveAction,CallFunc::create(CC_CALLBACK_0(Animate3DTest::reachEndCallBack,this)),nullptr);
seq->setTag(100);
sprite->runAction(seq);
}
//当触摸小乌龟则改变动画
void Animate3DTest::reachEndCallBack()
{
_sprite->stopActionByTag(100);
auto inverse = (MoveTo*)_moveAction->reverse();
inverse->retain();
_moveAction->release();
_moveAction = inverse;
auto rot = RotateBy::create(1.f,Vec3(0.f,180.f,0.f));
auto seq = Sequence::create(rot,_moveAction,CallFunc::create(CC_CALLBACK_0(Animate3DTest::reachEndCallBack,this)),nullptr);
seq->setTag(100);
_sprite->runAction(seq);
}

void Animate3DTest::renewCallBack()
{
//rerun swim action
_sprite->runAction(_swim);
_state =State::HURT_TO_SWIMMING;
_elapseTransTime =
0.0f;
}

void Animate3DTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event*
event)
{
for (auto touch: touches)
{
auto location = touch->getLocation();

if (_sprite)
{
float len = (_sprite->getPosition() - location).length();
if (len < 40)
{
//hurt the tortoise 在游动状态改变为被抓住的动画
if (_state ==State::SWIMMING)
{
_elapseTransTime =0.0f;
_state =
State::SWIMMING_TO_HURT;

_sprite->stopAction(_hurt);
_sprite->runAction(_hurt);
auto delay =
DelayTime::create(_hurt->getDuration() -Animate3D::getTransitionTime());

auto seq =
Sequence::create(delay, CallFunc::create(CC_CALLBACK_0(Animate3DTest::renewCallBack,this)),nullptr);

seq->setTag(101);
_sprite->runAction(seq);
}
return;
}
}
}
}
7.动态添加武器



AttachmentTest::AttachmentTest()
: _hasWeapon(false)
, _sprite(nullptr)
{
auto s =Director::getInstance()->getWinSize();
addNewSpriteWithCoords(Vec2(s.width/2, s.height/2)
);
auto listener =EventListenerTouchAllAtOnce::create();
listener->onTouchesEnded =
CC_CALLBACK_2(AttachmentTest::onTouchesEnded,this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
}

void AttachmentTest::addNewSpriteWithCoords(Vec2 p)
{
std::string fileName ="Sprite3DTest/orc.c3b";
auto sprite = Sprite3D::create(fileName);
sprite->setScale(5);
sprite->setRotation3D(Vec3(0,180,0));
addChild(sprite);
sprite->setPosition(
Vec2( p.x, p.y) );
//test attach 亮点在这里,获取某个骨骼,Bip001 R Hand是在3Dmax定义的
auto sp =Sprite3D::create("Sprite3DTest/axe.c3b");
sprite->getAttachNode("Bip001 R Hand")->addChild(sp);

auto animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);

sprite->runAction(RepeatForever::create(animate));
}
_sprite = sprite;
_hasWeapon = true;
}

void AttachmentTest::onTouchesEnded(conststd::vector<Touch*>& touches,Event*
event)
{
if (_hasWeapon)
{

_sprite->removeAllAttachNode(); //去掉新骨骼节点

}
else
{
auto sp = Sprite3D::create("Sprite3DTest/axe.c3b");
_sprite->getAttachNode("Bip001 R Hand")->addChild(sp);
}
_hasWeapon = !_hasWeapon;
}
8.动态修改材质Mesh(这个demo好,美女的模型超赞)



Sprite3DReskinTest::Sprite3DReskinTest()
: _sprite(nullptr)
{
auto s = Director::getInstance()->getWinSize();
addNewSpriteWithCoords( Vec2(s.width/2, s.height/2) );

auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesEnded = CC_CALLBACK_2(Sprite3DReskinTest::onTouchesEnded,this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
TTFConfig ttfConfig("fonts/arial.ttf",20);
auto label1 = Label::createWithTTF(ttfConfig,"Hair");
auto item1 = MenuItemLabel::create(label1,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchHair,this) );
auto label2 = Label::createWithTTF(ttfConfig,"Glasses");
auto item2 = MenuItemLabel::create(label2,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchGlasses,this) );
auto label3 = Label::createWithTTF(ttfConfig,"Coat");
auto item3 = MenuItemLabel::create(label3,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchCoat,this) );
auto label4 = Label::createWithTTF(ttfConfig,"Pants");
auto item4 = MenuItemLabel::create(label4,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchPants,this) );
auto label5 = Label::createWithTTF(ttfConfig,"Shoes");
auto item5 = MenuItemLabel::create(label5,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchShoes,this) );
item1->setPosition( Vec2(VisibleRect::left().x+50, VisibleRect::bottom().y+item1->getContentSize().height*4 ) );
item2->setPosition( Vec2(VisibleRect::left().x+50, VisibleRect::bottom().y+item1->getContentSize().height *5 ) );
item3->setPosition( Vec2(VisibleRect::left().x+50, VisibleRect::bottom().y+item1->getContentSize().height*6 ) );
item4->setPosition( Vec2(VisibleRect::left().x+50, VisibleRect::bottom().y+item1->getContentSize().height *7 ) );
item5->setPosition( Vec2(VisibleRect::left().x+50, VisibleRect::bottom().y+item1->getContentSize().height *8 ) );
auto pMenu1 = CCMenu::create(item1,item2,item3,item4,item5,NULL);
pMenu1->setPosition(Vec2(0,0));
this->addChild(pMenu1,
10);

}
void Sprite3DReskinTest::menuCallback_switchHair(Ref* sender)
{
_useHairId++;
if(_useHairId > 1 )
{
_useHairId = 0;
}
if(_useHairId >= 0 && _sprite)
{
for(int i =0; i <2; i++ )
{ // 获取材质 可见3.3支持了多套材质
auto subMesh = _sprite->getMeshByName(_girlHair[i]);
if(subMesh)
{
if(i == _useHairId )
{
subMesh->setVisible(true);
}
else
{
subMesh->setVisible(false);
}
}
}
}
}
void Sprite3DReskinTest::menuCallback_switchGlasses(Ref* sender)
{
auto subMesh = _sprite->getMeshByName("Girl_Glasses01");
if(subMesh)
{
if(subMesh->isVisible())
{
subMesh->setVisible(false);
}
else
{
subMesh->setVisible(true);
}
}
}
void Sprite3DReskinTest::menuCallback_switchCoat(Ref* sender)
{
_useUpBodyId++;
if(_useUpBodyId > 1 )
{
_useUpBodyId = 0;
}
if(_useUpBodyId >= 0 && _sprite)
{
for(int i =0; i <2; i++ )
{
auto subMesh = _sprite->getMeshByName(_girlUpperBody[i]);
if(subMesh)
{
if(i == _useUpBodyId )
{
subMesh->setVisible(true);
}
else
{
subMesh->setVisible(false);
}
}
}
}
}
void Sprite3DReskinTest::menuCallback_switchPants(Ref* sender)
{
_usePantsId++;
if(_usePantsId > 1 )
{
_usePantsId = 0;
}
if(_usePantsId >= 0 && _sprite)
{
for(int i =0; i <2; i++ )
{
auto subMesh = _sprite->getMeshByName(_girlPants[i]);
if(subMesh)
{
if(i == _usePantsId )
{
subMesh->setVisible(true);
}
else
{
subMesh->setVisible(false);
}
}
}
}
}
void Sprite3DReskinTest::menuCallback_switchShoes(Ref* sender)
{
_useShoesId++;
if(_useShoesId > 1 )
{
_useShoesId = 0;
}
if(_useShoesId >=
0 && _sprite)
{
for(int i =0; i <2; i++ )
{
auto subMesh = _sprite->getMeshByName(_girlShoes[i]);
if(subMesh)
{
if(i == _useShoesId )
{
subMesh->setVisible(true);
}
else
{
subMesh->setVisible(false);
}
}
}
}

}
std::string Sprite3DReskinTest::title() const
{
return"Testing Sprite3D Reskin";
}
std::string Sprite3DReskinTest::subtitle() const
{
return "";
}

void Sprite3DReskinTest::addNewSpriteWithCoords(Vec2 p)
{
_girlPants[0]= "Girl_LowerBody01";
_girlPants[1]= "Girl_LowerBody02";
_girlUpperBody[0] = "Girl_UpperBody01";
_girlUpperBody[1] = "Girl_UpperBody02";
_girlShoes[0] = "Girl_Shoes01";
_girlShoes[1] = "Girl_Shoes02";
_girlHair[0]= "Girl_Hair01";
_girlHair[1]= "Girl_Hair02";
_usePantsId = 0;
_useUpBodyId = 0;
_useShoesId =0;
_useHairId = 0;

std::string fileName = "Sprite3DTest/ReskinGirl.c3b";
auto sprite = Sprite3D::create(fileName);
sprite->setScale(4);
sprite->setRotation3D(Vec3(0,0,0));
auto girlPants = sprite->getMeshByName(_girlPants[1]);
if(girlPants)
{
girlPants->setVisible(false);
}
auto girlShoes = sprite->getMeshByName(_girlShoes[1]);
if(girlShoes)
{
girlShoes->setVisible(false);
}
auto girlHair = sprite->getMeshByName(_girlHair[1]);
if(girlHair)
{
girlHair->setVisible(false);
}
auto girlUpBody = sprite->getMeshByName( _girlUpperBody[1]);
if(girlUpBody)
{
girlUpBody->setVisible(false);
}
addChild(sprite);
sprite->setPosition( Vec2( p.x, p.y-60) );
auto animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);

sprite->runAction(RepeatForever::create(animate));
}
_sprite = sprite;
}

9.包围盒与3D模型碰撞的实现
AABB碰撞原理参考以下网址 http://cn.cocos2d-x.org/tutorial/show?id=1572


Sprite3DWithOBBPerfromanceTest::Sprite3DWithOBBPerfromanceTest()
{
auto listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesBegan = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesBegan,this);
listener->onTouchesEnded = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesEnded,this);
listener->onTouchesMoved = CC_CALLBACK_2(Sprite3DWithOBBPerfromanceTest::onTouchesMoved,this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener,this);
auto s = Director::getInstance()->getWinSize();
initDrawBox();
addNewSpriteWithCoords(Vec2(s.width/2, s.height/2));
MenuItemFont::setFontName("fonts/arial.ttf");
MenuItemFont::setFontSize(65);
auto decrease = MenuItemFont::create(" - ", CC_CALLBACK_1(Sprite3DWithOBBPerfromanceTest::delOBBCallback,this));
decrease->setColor(Color3B(0,200,20));
auto increase = MenuItemFont::create(" + ", CC_CALLBACK_1(Sprite3DWithOBBPerfromanceTest::addOBBCallback,this));
increase->setColor(Color3B(0,200,20));

auto menu = Menu::create(decrease, increase,nullptr);
menu->alignItemsHorizontally();
menu->setPosition(Vec2(s.width/2, s.height-65));
addChild(menu, 1);

TTFConfig ttfCount("fonts/Marker Felt.ttf",30);
_labelCubeCount = Label::createWithTTF(ttfCount,"0 cubes");
_labelCubeCount->setColor(Color3B(0,200,20));
_labelCubeCount->setPosition(Vec2(s.width/2, s.height-90));
addChild(_labelCubeCount);
_hasCollider = false;
addOBBCallback(nullptr);
scheduleUpdate();
}
std::string Sprite3DWithOBBPerfromanceTest::title()
const
{
return"OBB Collison Perfromance Test";
}
std::string Sprite3DWithOBBPerfromanceTest::subtitle()
const
{
return "";
}
void Sprite3DWithOBBPerfromanceTest::addNewOBBWithCoords(Vec2 p)
{
Vec3 extents = Vec3(10,
10, 10);
AABB aabb(-extents, extents);
auto obb = OBB(aabb);
obb._center = Vec3(p.x,p.y,0);
_obb.push_back(obb);
}

void Sprite3DWithOBBPerfromanceTest::onTouchesBegan(const std::vector<Touch*>& touches, Event* event)
{
for (auto touch: touches)
{
auto location = touch->getLocationInView();

if(_obb.size() > 0)
{
_intersetList.clear();
Ray ray;
calculateRayByLocationInView(&ray,location);
for(int i =0; i < _obb.size(); i++)
{
if(ray.intersects(_obb[i]))
{
_intersetList.insert(i);
return;
}
}
}
}
}

void Sprite3DWithOBBPerfromanceTest::onTouchesEnded(const std::vector<Touch*>& touches, Event* event)
{

}

void Sprite3DWithOBBPerfromanceTest::onTouchesMoved(const std::vector<Touch*>& touches, Event* event)
{
for (auto touch: touches)
{
auto location = touch->getLocation();

for(int i =0; i < _obb.size(); i++)
{
if(_intersetList.find(i) != _intersetList.end())
_obb[i]._center = Vec3(location.x,location.y,0);
}
}
}

void Sprite3DWithOBBPerfromanceTest::update(float dt)
{
char szText[16];
sprintf(szText,"%lu cubes",_obb.size());
_labelCubeCount->setString(szText);

if (_drawDebug)
{
_drawDebug->clear();

Mat4 mat = _sprite->getNodeToWorldTransform();
mat.getRightVector(&_obbt._xAxis);
_obbt._xAxis.normalize();

mat.getUpVector(&_obbt._yAxis);
_obbt._yAxis.normalize();

mat.getForwardVector(&_obbt._zAxis);
_obbt._zAxis.normalize();

_obbt._center = _sprite->getPosition3D();

Vec3 corners[8] = {};
_obbt.getCorners(corners);
_drawDebug->drawCube(corners, Color4F(0,0,1,1));
}
if(_obb.size() > 0)
{
_drawOBB->clear();
for(int i =0; i < _obb.size(); i++)
{
Vec3 corners[8] = {};
_obb[i].getCorners(corners);
_drawOBB->drawCube(corners, _obbt.intersects(_obb[i])?Color4F(1,0,0,1):Color4F(0,1,0,1));
}
}
}

void Sprite3DWithOBBPerfromanceTest::initDrawBox()
{
_drawOBB = DrawNode3D::create();
addChild(_drawOBB);
}

void Sprite3DWithOBBPerfromanceTest::addNewSpriteWithCoords(Vec2 p)
{
std::string fileName = "Sprite3DTest/tortoise.c3b";
auto sprite = Sprite3D::create(fileName);
sprite->setScale(0.1f);
auto s = Director::getInstance()->getWinSize();
sprite->setPosition(Vec2(s.width * 4.f /5.f, s.height /2.f));
addChild(sprite);
_sprite = sprite;
auto animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation,0.f,1.933f);
sprite->runAction(RepeatForever::create(animate));
}

_moveAction = MoveTo::create(4.f, Vec2(s.width /5.f, s.height /2.f));
_moveAction->retain();
auto seq = Sequence::create(_moveAction, CallFunc::create(CC_CALLBACK_0(Sprite3DWithOBBPerfromanceTest::reachEndCallBack,this)),nullptr);
seq->setTag(100);
sprite->runAction(seq);

AABB aabb = _sprite->getAABB();
_obbt = OBB(aabb);

_drawDebug = DrawNode3D::create();
addChild(_drawDebug);
}

void Sprite3DWithOBBPerfromanceTest::reachEndCallBack()
{
_sprite->stopActionByTag(100);
auto inverse = (MoveTo*)_moveAction->reverse();
inverse->retain();
_moveAction->release();
_moveAction = inverse;
auto rot = RotateBy::create(1.0f, Vec3(0.f,180.f,0.f));
auto seq = Sequence::create(rot, _moveAction, CallFunc::create(CC_CALLBACK_0(Sprite3DWithOBBPerfromanceTest::reachEndCallBack,this)),nullptr);
seq->setTag(100);
_sprite->runAction(seq);
}

void Sprite3DWithOBBPerfromanceTest::addOBBCallback(Ref* sender)
{
addOBBWithCount(10);
}

void Sprite3DWithOBBPerfromanceTest::addOBBWithCount(float value)
{
for(int i =
0; i < value; i++)
{
Vec2 randompos = Vec2(CCRANDOM_0_1() * Director::getInstance()->getWinSize().width,CCRANDOM_0_1() * Director::getInstance()->getWinSize().height);
Vec3 extents = Vec3(10,
10, 10);
AABB aabb(-extents, extents);
auto obb = OBB(aabb);
obb._center = Vec3(randompos.x,randompos.y,0);
_obb.push_back(obb);
}
}

void Sprite3DWithOBBPerfromanceTest::delOBBCallback(Ref* sender)
{
delOBBWithCount(10);
}

void Sprite3DWithOBBPerfromanceTest::delOBBWithCount(float value)
{
if(_obb.size() >= 10)
{
_obb.erase(_obb.begin(),_obb.begin() + value);
_drawOBB->clear();
}
else
return;
}
void Sprite3DWithOBBPerfromanceTest::unproject(const Mat4& viewProjection,const Size* viewport, Vec3* src, Vec3* dst)
{
assert(dst);

assert(viewport->width != 0.0f && viewport->height !=0.0f);
Vec4 screen(src->x / viewport->width, ((viewport->height - src->y)) / viewport->height, src->z,1.0f);

screen.x = screen.x * 2.0f -
1.0f;
screen.y = screen.y * 2.0f -
1.0f;
screen.z = screen.z * 2.0f -
1.0f;

viewProjection.getInversed().transformVector(screen, &screen);

if (screen.w != 0.0f)
{
screen.x /= screen.w;
screen.y /= screen.w;
screen.z /= screen.w;
}

dst->set(screen.x, screen.y, screen.z);
}

void Sprite3DWithOBBPerfromanceTest::calculateRayByLocationInView(Ray* ray,const Vec2& location)
{
auto dir = Director::getInstance();
auto view = dir->getWinSize();
Mat4 mat = dir->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
mat = dir->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);

Vec3 src = Vec3(location.x, location.y, -1);
Vec3 nearPoint;
unproject(mat, &view, &src, &nearPoint);

src = Vec3(location.x, location.y, 1);
Vec3 farPoint;
unproject(mat, &view, &src, &farPoint);

Vec3 direction;
Vec3::subtract(farPoint, nearPoint, &direction);
direction.normalize();

ray->_origin = nearPoint;
ray->_direction = direction;
}
10.3D模型的镜像



Sprite3DMirrorTest::Sprite3DMirrorTest()
: _sprite(nullptr)
, _mirrorSprite(nullptr)
{
auto s = Director::getInstance()->getWinSize();
addNewSpriteWithCoords( Vec2(s.width/2, s.height/2) );
}
std::string Sprite3DMirrorTest::title() const
{
return"Sprite3D Mirror Test";
}
std::string Sprite3DMirrorTest::subtitle() const
{
return "";
}

void Sprite3DMirrorTest::addNewSpriteWithCoords(Vec2 p)
{
std::string fileName = "Sprite3DTest/orc.c3b";
auto sprite = Sprite3D::create(fileName);
sprite->setScale(5);
sprite->setRotation3D(Vec3(0,180,0));
addChild(sprite);
sprite->setPosition( Vec2( p.x - 80, p.y) );

//test attach
auto sp = Sprite3D::create("Sprite3DTest/axe.c3b");
sprite->getAttachNode("Bip001 R Hand")->addChild(sp);

auto animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);

sprite->runAction(RepeatForever::create(animate));
}
_sprite = sprite;
_hasWeapon = true;

//create mirror Sprite3D 镜像
sprite = Sprite3D::create(fileName);
sprite->setScale(5);
sprite->setScaleX(-5);
sprite->setCullFace(GL_FRONT);
sprite->setRotation3D(Vec3(0,180,0));
addChild(sprite);
sprite->setPosition( Vec2( p.x + 80, p.y) );

//test attach
sp = Sprite3D::create("Sprite3DTest/axe.c3b");
sprite->getAttachNode("Bip001 R Hand")->addChild(sp);

animation = Animation3D::create(fileName);
if (animation)
{
auto animate = Animate3D::create(animation);

sprite->runAction(RepeatForever::create(animate));
}
_mirrorSprite = sprite;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: