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

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

发布时间:2020-12-14 20:15:43 所属栏目:百科 来源:网络整理
导读:Cocos2d-x 3.3 的3D开发功能介绍 sdhjob 2014-09-28 11:07:46 5094 次阅读 本文主要介绍Cocos2d-x 3.3版本中强大的3D功能。 主要有以下功能: 1. 基本的Sprite3D使用,加载静态模型和动态模型,查看Sprite3DBasicTest; 2. Sprite3D对象的旋转,缩放等Action

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

sdhjob2014-09-28 11:07:465094 次阅读

本文主要介绍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里面的源码:

1
2
3
4
5
6
7
8
#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模型

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
void Sprite3DBasicTest::addNewSpriteWithCoords(Vec2p)
{
//这里的obj可以使用3dmax直接导出
////option1:loadaobjthatcontainthetextureinit第一种方法是在模型文件中包含了纹理
//autosprite=Sprite3D::create("sprite3dTest/scene01.obj");
//option2:loadobjandassignthetexture第二种方法是在模型文件中不包含纹理
autosprite=Sprite3D::create( "Sprite3DTest/boss1.obj" );
sprite->setScale(3.f);
sprite->setTexture( "Sprite3DTest/boss.png" );
//在Sprite3D中包含了一些基本的Shader特效,下面是让3D模型实现outline
//sprite->setEffect(cocos2d::EFFECT_OUTLINE);
//addtoscene
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,-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
}
void Sprite3DBasicTest::onTouchesEnded(conststd::vector<Touch*>&touches,Event*event)
{
for (autotouch:touches)
{
autolocation=touch->getLocation();
//触摸屏幕添加3D模型
addNewSpriteWithCoords(location);
}
}


2.透过触摸屏幕拖动模型移动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
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));
//addtoscene
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));
//addtoscene
addChild(sprite2);
sprite2->runAction(RepeatForever::create(RotateBy::create(3,-360)));
//Makesprite1touchable
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 ( "sprite3dbegan...x=%f,y=%f" ,touch->getLocation().x,touch->getLocation().y);
target->setOpacity(100);
return true ;
}
return false ;
};
listener1->onTouchMoved=[](Touch*touch,Event*event){
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 ( "sprite3donTouchesEnded.." );
target->setOpacity(255);
};
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1,sprite1);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener1->clone(),sprite2);
}


3.在一个Sprite3D上使用Shader

  • Effect3D继承REF封装了Shader的处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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;
};


  • Effect3DOutline继承了Effect3D,封装了Outline类型的Shader

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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;
//weakreference
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 );
};


  • EffectSprite3D继承了Sprite3D封装了对Effect3DOutline的调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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_torder);
virtual void draw(Renderer*renderer, const Mat4&transform,uint32_tflags)override;
protected :
EffectSprite3D();
virtual ~EffectSprite3D();
std::vector<std::tuple<ssize_t,Effect3D*,CustomCommand>>_effects;
Effect3D*_defaultEffect;
CustomCommand_command;
};


Sprite3DEffectTest

1
2
3
4
5
6
7
8
9
10
class Sprite3DEffectTest: public Sprite3DTestDemo
{
public :
CREATE_FUNC(Sprite3DEffectTest);
Sprite3DEffectTest();
virtual std::stringtitle() const override;
virtual std::stringsubtitle() const override;
void addNewSpriteWithCoords(Vec2p);
void onTouchesEnded(conststd::vector<Touch*>&touches,Event*event);
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
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)
{
autoprogram=GLProgramCache::getInstance()->getGLProgram(_keySkinnedInGLProgramCache);
if (program==nullptr)
{
program=GLProgram::createWithFilenames(_vertSkinnedShaderFile,_fragSkinnedShaderFile);
GLProgramCache::getInstance()->addGLProgram(program,_keySkinnedInGLProgramCache);
}
return program;
}
else
{
autoprogram=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*)
{
autoglProgram=_glProgramState->getGLProgram();
glProgram->reset();
glProgram->initWithFilenames(_vertShaderFile,_fragShaderFile);
glProgram->link();lProgram->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:SettinganullpointeroranullmeshEffectSprite3DtoEffect3D" );
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();
long offset=0;
for (autoi=0;i<mesh->getMeshVertexAttribCount();i++)
{
automeshvertexattrib=mesh->getMeshVertexAttribute(i);
_glProgramState->setVertexAttribPointer(s_attributeNames[meshvertexattrib.vertexAttrib],
meshvertexattrib.size,
meshvertexattrib.type,
GL_FALSE,
mesh->getVertexSizeInBytes(),
( 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));
}
}
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
Color4Fcolor(_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);
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,
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, const cocos2d::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);
}
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的加载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
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 );
}
void Sprite3DEffectTest::addNewSpriteWithCoords(Vec2p)
{
//option2:loadobjandassignthetexture
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,0));
//sprite->setEffect3D(effect);
sprite->setScale(6.f);
//addtoscene
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,-255);
else
action=FadeOut::create(2);
autoaction_back=action->reverse();
autoseq=Sequence::create(action,nullptr);
sprite->runAction(RepeatForever::create(seq));
}
void Sprite3DEffectTest::onTouchesEnded(conststd::vector<Touch*>&touches,Event*event)
{
for (autotouch:touches)
{
autolocation=touch->getLocation();
addNewSpriteWithCoords(location);
}
}


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

用Sprite3D来加载c3b,用Animation3D,和Animate3D来创建动画

1
2
3
4
5
6
autoanimation=Animation3D::create(fileName);
if (animation)
{
autoanimate=Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate));
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
void Sprite3DWithSkinTest::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));
autoanimation=Animation3D::create(fileName);
if (animation)
{
autoanimate=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.在以上模型和动画中添加特效(方法和在静态模型上一样)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void Sprite3DWithSkinOutlineTest::addNewSpriteWithCoords(Vec2p)
{
std::stringfileName= "Sprite3DTest/orc.c3b" ;
autosprite=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));
autoanimation=Animation3D::create(fileName);
if (animation)
{
autoanimate=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个动画之间的切换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
Animate3DTest::Animate3DTest():_hurt(nullptr),_swim(nullptr),_sprite(nullptr),_moveAction(nullptr),_elapseTransTime(0.f)
{ //添加小乌龟
addSprite3D();
autolistener=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::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));
addChild(sprite);
_sprite=sprite;
autoanimation=Animation3D::create(fileName);
if (animation)
{ //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);
}
//当触摸小乌龟则改变动画
void Animate3DTest::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);
}
void Animate3DTest::renewCallBack()
{
//rerunswimaction
_sprite->runAction(_swim);
_state=State::HURT_TO_SWIMMING;
_elapseTransTime=0.0f;
}
void Animate3DTest::onTouchesEnded(conststd::vector<Touch*>&touches,Event*event)
{
for (autotouch:touches)
{
autolocation=touch->getLocation();
if (_sprite)
{
float len=(_sprite->getPosition()-location).length();
if (len<40)
{
//hurtthetortoise在游动状态改变为被抓住的动画
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,nullptr);
seq->setTag(101);
_sprite->runAction(seq);
}
return ;
}
}
}
}


7.动态添加武器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
AttachmentTest::AttachmentTest():_hasWeapon( false ),_sprite(nullptr)
{
autos=Director::getInstance()->getWinSize();
addNewSpriteWithCoords(Vec2(s.width/2,s.height/2));
autolistener=EventListenerTouchAllAtOnce::create();
listener->onTouchesEnded=CC_CALLBACK_2(AttachmentTest::onTouchesEnded, this );
}
void AttachmentTest::addNewSpriteWithCoords(Vec2p)
{
std::stringfileName= "Sprite3DTest/orc.c3b" ;
autosprite=Sprite3D::create(fileName);
sprite->setScale(5);
sprite->setRotation3D(Vec3(0,p.y));
//testattach亮点在这里,获取某个骨骼,Bip001RHand是在3Dmax定义的
autosp=Sprite3D::create( "Sprite3DTest/axe.c3b" );
sprite->getAttachNode( "Bip001RHand" )->addChild(sp);
autoanimation=Animation3D::create(fileName);
if (animation)
{
autoanimate=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
{
autosp=Sprite3D::create( "Sprite3DTest/axe.c3b" );
_sprite->getAttachNode( "Bip001RHand" )->addChild(sp);
}
_hasWeapon=!_hasWeapon;
}


8.动态修改材质Mesh(这个demo好,美女的模型超赞)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
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 );
TTFConfigttfConfig( "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, this ));
autolabel3=Label::createWithTTF(ttfConfig, "Coat" );
autoitem3=MenuItemLabel::create(label3,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchCoat, this ));
autolabel4=Label::createWithTTF(ttfConfig, "Pants" );
autoitem4=MenuItemLabel::create(label4,CC_CALLBACK_1(Sprite3DReskinTest::menuCallback_switchPants, this ));
autolabel5=Label::createWithTTF(ttfConfig, "Shoes" );
autoitem5=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));
autopMenu1=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支持了多套材质
autosubMesh=_sprite->getMeshByName(_girlHair[i]);
if (subMesh)
{
if (i==_useHairId)
{
subMesh->setVisible( true );
}
else
{
subMesh->setVisible( false );
}
}
}
}
}
void Sprite3DReskinTest::menuCallback_switchGlasses(Ref*sender)
{
autosubMesh=_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++)
{
autosubMesh=_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++)
{
autosubMesh=_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++)
{
autosubMesh=_sprite->getMeshByName(_girlShoes[i]);
if (subMesh)
{
if (i==_useShoesId)
{
subMesh->setVisible( true );
}
else
{
subMesh->setVisible( false );
}
}
}
}
}
std::stringSprite3DReskinTest::title() const
{
return "TestingSprite3DReskin" ;
}
std::stringSprite3DReskinTest::subtitle() const
{
return "" ;
}
void Sprite3DReskinTest::addNewSpriteWithCoords(Vec2p)
{
_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::stringfileName= "Sprite3DTest/ReskinGirl.c3b" ;
autosprite=Sprite3D::create(fileName);
sprite->setScale(4);
sprite->setRotation3D(Vec3(0,0));
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);
if (animation)
{
autoanimate=Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate));
}
_sprite=sprite;
}


9.包围盒与3D模型碰撞的实现

AABB碰撞原理参考以下网址:http://cn.cocos2d-x.org/tutorial/show?id=1572

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
Sprite3DWithOBBPerfromanceTest::Sprite3DWithOBBPerfromanceTest()
{
autolistener=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 );
autos=Director::getInstance()->getWinSize();
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, this ));
increase->setColor(Color3B(0,20));
automenu=Menu::create(decrease,increase,nullptr);
menu->alignItemsHorizontally();
menu->setPosition(Vec2(s.width/2,s.height-65));
addChild(menu,1);
TTFConfigttfCount( "fonts/MarkerFelt.ttf" ,30);
_labelCubeCount=Label::createWithTTF(ttfCount, "0cubes" );
_labelCubeCount->setColor(Color3B(0,20));
_labelCubeCount->setPosition(Vec2(s.width/2,s.height-90));
addChild(_labelCubeCount);
_hasCollider= false ;
addOBBCallback(nullptr);
scheduleUpdate();
}
std::stringSprite3DWithOBBPerfromanceTest::title() const
{
return "OBBCollisonPerfromanceTest" ;
}
std::stringSprite3DWithOBBPerfromanceTest::subtitle() const
{
return "" ;
}
void Sprite3DWithOBBPerfromanceTest::addNewOBBWithCoords(Vec2p)
{
Vec3extents=Vec3(10,10,10);
AABBaabb(-extents,extents);
autoobb=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 (autotouch:touches)
{
autolocation=touch->getLocationInView();
if (_obb.size()>0)
{
_intersetList.clear();
Rayray;
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 (autotouch:touches)
{
autolocation=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, "%lucubes" ,_obb.size());
_labelCubeCount->setString(szText);
if (_drawDebug)
{
_drawDebug->clear();
Mat4mat=_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();
Vec3corners[8]={};
_obbt.getCorners(corners);
_drawDebug->drawCube(corners,Color4F(0,1));
}
if (_obb.size()>0)
{
_drawOBB->clear();
for ( int i=0;i<_obb.size();i++)
{
Vec3corners[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(Vec2p)
{
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));
addChild(sprite);
_sprite=sprite;
autoanimation=Animation3D::create(fileName);
if (animation)
{
autoanimate=Animate3D::create(animation,1.933f);
sprite->runAction(RepeatForever::create(animate));
}
_moveAction=MoveTo::create(4.f,s.height/2.f));
_moveAction->retain();
autoseq=Sequence::create(_moveAction,CallFunc::create(CC_CALLBACK_0(Sprite3DWithOBBPerfromanceTest::reachEndCallBack,nullptr);
seq->setTag(100);
sprite->runAction(seq);
AABBaabb=_sprite->getAABB();
_obbt=OBB(aabb);
_drawDebug=DrawNode3D::create();
addChild(_drawDebug);
}
void Sprite3DWithOBBPerfromanceTest::reachEndCallBack()
{
_sprite->stopActionByTag(100);
autoinverse=(MoveTo*)_moveAction->reverse();
inverse->retain();
_moveAction->release();
_moveAction=inverse;
autorot=RotateBy::create(1.0f,0.f));
autoseq=Sequence::create(rot,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++)
{
Vec2randompos=Vec2(CCRANDOM_0_1()*Director::getInstance()->getWinSize().width,CCRANDOM_0_1()*Director::getInstance()->getWinSize().height);
Vec3extents=Vec3(10,10);
AABBaabb(-extents,extents);
autoobb=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);
Vec4screen(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)
{
autodir=Director::getInstance();
autoview=dir->getWinSize();
Mat4mat=dir->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_MODELVIEW);
mat=dir->getMatrix(MATRIX_STACK_TYPE::MATRIX_STACK_PROJECTION);
Vec3src=Vec3(location.x,-1);
Vec3nearPoint;
unproject(mat,&view,&src,&nearPoint);
src=Vec3(location.x,1);
Vec3farPoint;
unproject(mat,&farPoint);
Vec3direction;
Vec3::subtract(farPoint,nearPoint,&direction);
direction.normalize();
ray->_origin=nearPoint;
ray->_direction=direction;
}


10.3D模型的镜像

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Sprite3DMirrorTest::Sprite3DMirrorTest():_sprite(nullptr),_mirrorSprite(nullptr)
{
autos=Director::getInstance()->getWinSize();
addNewSpriteWithCoords(Vec2(s.width/2,s.height/2));
}
std::stringSprite3DMirrorTest::title() const
{
return "Sprite3DMirrorTest" ;
}
std::stringSprite3DMirrorTest::subtitle() const
{
return "" ;
}
void Sprite3DMirrorTest::addNewSpriteWithCoords(Vec2p)
{
std::stringfileName= "Sprite3DTest/orc.c3b" ;
autosprite=Sprite3D::create(fileName);
sprite->setScale(5);
sprite->setRotation3D(Vec3(0,0));
addChild(sprite);
sprite->setPosition(Vec2(p.x-80,p.y));
//testattach
autosp=Sprite3D::create( "Sprite3DTest/axe.c3b" );
sprite->getAttachNode( "Bip001RHand" )->addChild(sp);
autoanimation=Animation3D::create(fileName);
if (animation)
{
autoanimate=Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate));
}
_sprite=sprite;
_hasWeapon= true ;
//createmirrorSprite3D镜像
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));
//testattach
sp=Sprite3D::create( "Sprite3DTest/axe.c3b" );
sprite->getAttachNode( "Bip001RHand" )->addChild(sp);
animation=Animation3D::create(fileName);
if (animation)
{
autoanimate=Animate3D::create(animation);
sprite->runAction(RepeatForever::create(animate));
}
_mirrorSprite=sprite;
}

(编辑:李大同)

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

    推荐文章
      热点阅读