主要有以下功能:
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下使用@H_840_2404@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 =