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

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.jpg

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(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.透过触摸屏幕拖动模型移动

2.jpg

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()
{
     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的处理

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


  • 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_t order);
     virtual  void  draw(Renderer *renderer, const  Mat4 &transform, uint32_t flags) 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::string title() const  override;
     virtual  std::string subtitle() const  override;
     void  addNewSpriteWithCoords(Vec2 p);
     void  onTouchesEnded(conststd::vector<Touch*>& touches,Event* event);
};

3.jpg

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)
     {
         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();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: 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, const  cocos2d::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的加载

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

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

4.jpg

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(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.在以上模型和动画中添加特效(方法和在静态模型上一样)

5.jpg

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(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个动画之间的切换

6.jpg

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();
     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.动态添加武器

07.jpg

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)
{
     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好,美女的模型超赞)

8.jpg

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

9.jpg

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()
{
     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模型的镜像

000.jpg

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


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值