加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-14 20:23:29 所属栏目:百科 来源:网络整理
导读:今天下载了Cocos2d-x 3.3,3D功能果然强大 主要有以下功能: 1. 基本的Sprite3D使用,加载静态模型和动态模型,看 Sprite3DBasicTest 2.Sprite3D对象的旋转,缩放等Action操作 3.Sprite3D中使用Shader特效,实现outLine 4.Animate3D来创建3D动画 5.动态增加3

今天下载了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",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,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));

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,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,用Animation3D,和Animate3D来创建动画

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));

effect->setOutlineWidth(0.01f);

sprite->addEffect(effect,-1);


Effect3DOutline* effect2 =Effect3DOutline::create();

effect2->setOutlineWidth(0.02f);

effect2->setOutlineColor(Vec3(1,0));

sprite->addEffect(effect2,-2);


sprite->setScale(3);

sprite->setRotation3D(Vec3(0,0));

addChild(sprite);

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

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);

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,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,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);

}


void AttachmentTest::addNewSpriteWithCoords(Vec2 p)

{

std::string fileName ="Sprite3DTest/orc.c3b";

auto sprite = Sprite3D::create(fileName);

sprite->setScale(5);

sprite->setRotation3D(Vec3(0,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));

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);

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,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,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,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,1):Color4F(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,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,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,0.f));

auto seq = Sequence::create(rot,_moveAction,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,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,-1);

Vec3 nearPoint;

unproject(mat,&view,&src,&nearPoint);

src = Vec3(location.x,1);

Vec3 farPoint;

unproject(mat,&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,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,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;

}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读