zoukankan      html  css  js  c++  java
  • Cocos2d-x 的3D开发功能介绍

    主要有以下功能:

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

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

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

    4.Animate3D来创建3D动画

    5.动态增加3D骨骼,实现怪物添加手持武器功能

    6,动态修改骨骼皮肤实现换装功能Sprite3DReskinTest

    7.通过包围盒实现3D模型碰撞,Sprite3DWithOBBPerfromanceTest

    8.实现水平镜像3D模型,Sprite3DMirrorTest


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



    #include "Sprite3DTest.h"

    #include "3d/CCAnimation3D.h"

    #include "3d/CCAnimate3D.h"

    #include "3d/CCAttachNode.h"

    #include "3d/CCRay.h"

    #include "3d/CCSprite3D.h"

    #include "renderer/CCVertexIndexBuffer.h"

    #include "DrawNode3D.h"


    1.在Scene中添加3D模型


    void Sprite3DBasicTest::addNewSpriteWithCoords(Vec2 p)

    {

    //这里的obj可以使用3dmax直接导出

    //    //option 1: load a obj that contain the texture in it  第一种方法是在模型文件中包含了纹理

    //    auto sprite = Sprite3D::create("sprite3dTest/scene01.obj");    

        //option 2: load obj and assign the texture   第二种方法是在模型文件中不包含纹理

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

        sprite->setScale(3.f);

        sprite->setTexture("Sprite3DTest/boss.png");

        //在Sprite3D中包含了一些基本的Shader特效,下面是让3D模型实现outline

        //sprite->setEffect(cocos2d::EFFECT_OUTLINE);    

        //add to scene

        addChild( sprite );

        sprite->setPositionVec2( 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->runActionRepeatForever::create(seq) );

    //以上大家看到Sprite3D起始和Sprite类似都可以实现各种Action

    }

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

    {

        for (auto touch: touches)

        {

            auto location = touch->getLocation();

            //触摸屏幕添加3D模型

            addNewSpriteWithCoords( location );

        }

    }

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



    Sprite3DHitTest::Sprite3DHitTest()

    {

        auto s =Director::getInstance()->getWinSize();

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

        

        sprite1->setScale(4.f);

        sprite1->setTexture("Sprite3DTest/boss.png");

        sprite1->setPositionVec2(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->setPositionVec2(s.width/2, s.height/2) );

        sprite2->setAnchorPoint(Vec2(0.5,0.5));

        

        //add to scene

        addChild( sprite2 );

        sprite2->runAction(RepeatForever::create(RotateBy::create(3, -360)));

        

        

        // Make sprite1 touchable

        auto listener1 =EventListenerTouchOneByOne::create();

        listener1->setSwallowTouches(true);

        

        listener1->onTouchBegan = [](Touch* touch,Event* event){

            auto target = static_cast<Sprite3D*>(event->getCurrentTarget());

          

            Rect rect = target->getBoundingBox();        

            if (rect.containsPoint(touch->getLocation()))

            {

                log("sprite3d began... x = %f, y = %f", touch->getLocation().x, touch->getLocation().y);

                target->setOpacity(100);

                return true;

            }

            return false;

        };

        

        listener1->onTouchMoved = [](Touch* touch,Event* event){

            auto target = static_cast<Sprite3D*>(event->getCurrentTarget());

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

        };

        

        listener1->onTouchEnded = [=](Touch* touch,Event* event){

            auto target = static_cast<Sprite3D*>(event->getCurrentTarget());

            log("sprite3d onTouchesEnded.. ");

            target->setOpacity(255);

        };

        

        _eventDispatcher->addEventListenerWithSceneGraphPriority(listener1, sprite1);

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

        

    }

    3.在一个Sprite3D上使用Shader


    Effect3D继承REF封装了Shader的处理

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

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

    class Effect3D : publicRef

    {

    public:

        virtual void draw(constMat4 &transform) = 0;

        virtual void setTarget(EffectSprite3D *sprite) =0;

    protected:

        Effect3D() : _glProgramState(nullptr) {}

        virtual ~Effect3D()

        {

            CC_SAFE_RELEASE(_glProgramState);

        }

    protected:

        GLProgramState* _glProgramState;

    };


    class Effect3DOutline: publicEffect3D

    {

    public:

        static Effect3DOutline* create();

        

        void setOutlineColor(constVec3& color);

        

        void setOutlineWidth(float width);

        

        virtual void draw(constMat4 &transform) override;

        virtual void setTarget(EffectSprite3D *sprite) override;

    protected:

        

        Effect3DOutline();

        virtual ~Effect3DOutline();

        

        bool init();

        

        Vec3 _outlineColor;

        float _outlineWidth;

        //weak reference

        EffectSprite3D* _sprite;

    #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

        EventListenerCustom* _backToForegroundListener;

    #endif

        

    protected:

        static const std::string _vertShaderFile;

        static const std::string _fragShaderFile;

        static const std::string _keyInGLProgramCache;

        

        static const std::string _vertSkinnedShaderFile;

        static const std::string _fragSkinnedShaderFile;

        static const std::string _keySkinnedInGLProgramCache;

        

        static GLProgram* getOrCreateProgram(bool isSkinned =false);

    };

    class EffectSprite3D : publicSprite3D

    {

    public:

        static EffectSprite3D* createFromObjFileAndTexture(conststd::string& objFilePath, const std::string& textureFilePath);

        static EffectSprite3D* create(conststd::string& path);

        

        void setEffect3D(Effect3D* effect);

        void addEffect(Effect3DOutline* effect,ssize_t order);

        virtual void draw(Renderer *renderer,const Mat4 &transform, uint32_t flags) override;

    protected:

        EffectSprite3D();

        virtual ~EffectSprite3D();

        

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

        Effect3D* _defaultEffect;

        CustomCommand _command;

    };


    class Sprite3DEffectTest : public Sprite3DTestDemo

    {

    public:

        CREATE_FUNC(Sprite3DEffectTest);

        Sprite3DEffectTest();

        virtual std::string title()const override;

        virtual std::string subtitle()const override;

        

        void addNewSpriteWithCoords(Vec2 p);

        

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

    };




    const std::stringEffect3DOutline::_vertShaderFile = "Shaders3D/OutLine.vert";

    const std::stringEffect3DOutline::_fragShaderFile = "Shaders3D/OutLine.frag";

    const std::stringEffect3DOutline::_keyInGLProgramCache = "Effect3DLibrary_Outline";


    const std::stringEffect3DOutline::_vertSkinnedShaderFile = "Shaders3D/SkinnedOutline.vert";

    const std::stringEffect3DOutline::_fragSkinnedShaderFile = "Shaders3D/OutLine.frag";

    const std::stringEffect3DOutline::_keySkinnedInGLProgramCache = "Effect3DLibrary_Outline";

    GLProgramEffect3DOutline::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;

        }


    }


    Effect3DOutlineEffect3DOutline::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,11)

    _sprite(nullptr)

    {

    #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

        _backToForegroundListener = EventListenerCustom::create(EVENT_RENDERER_RECREATED,

                                                              [this](EventCustom*)

                                                              {

                                                                  auto glProgram = _glProgramState->getGLProgram();

                                                                  glProgram->reset();

                                                                  glProgram->initWithFilenames(_vertShaderFile, _fragShaderFile);

                                                                  glProgram->link();

                                                                  glProgram->updateUniforms();

                                                              }

                                                              );

        Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(_backToForegroundListener, -1);

    #endif

    }


    Effect3DOutline::~Effect3DOutline()

    {

    #if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)

        Director::getInstance()->getEventDispatcher()->removeEventListener(_backToForegroundListener);

    #endif

    }


    void Effect3DOutline::setOutlineColor(constVec3& color)

    {

        if(_outlineColor != color)

        {

            _outlineColor = color;

            if(_glProgramState)

                _glProgramState->setUniformVec3("OutLineColor",_outlineColor);

        }

    }


    void Effect3DOutline::setOutlineWidth(float width)

    {

        if(_outlineWidth != width)

        {

            _outlineWidth = width;

            if(_glProgramState)

                _glProgramState->setUniformFloat("OutlineWidth",_outlineWidth);

        }

    }


    void Effect3DOutline::setTarget(EffectSprite3D *sprite)

    {

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

        

        if(sprite != _sprite)

        {

            GLProgram* glprogram;

            if(!sprite->getMesh()->getSkin())

                glprogram = GLProgram::createWithFilenames(_vertShaderFile,_fragShaderFile);

            else

                glprogram = GLProgram::createWithFilenames(_vertSkinnedShaderFile,_fragSkinnedShaderFile);


            _glProgramState = GLProgramState::create(glprogram);


            _glProgramState->retain();

            _glProgramState->setUniformVec3("OutLineColor",_outlineColor);

            _glProgramState->setUniformFloat("OutlineWidth",_outlineWidth);

        

            

            _sprite = sprite;

            

            auto mesh = sprite->getMesh();

            long offset = 0;

            for (auto i =0; i < mesh->getMeshVertexAttribCount(); i++)

            {

                auto meshvertexattrib = mesh->getMeshVertexAttribute(i);

                

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

                                                        meshvertexattrib.size,

                                                        meshvertexattrib.type,

                                                        GL_FALSE,

                                                        mesh->getVertexSizeInBytes(),

                                                        (void*)offset);

                offset += meshvertexattrib.attribSizeBytes;

            }

            

            Color4F color(_sprite->getDisplayedColor());

            color.a = _sprite->getDisplayedOpacity() /255.0f;

            _glProgramState->setUniformVec4("u_color",Vec4(color.r, color.g, color.b, color.a));

        }

        

    }


    static void MatrixPalleteCallBack(GLProgram* glProgram, Uniform* uniform,int paletteSize, const float* palette)

    {

        glUniform4fv( uniform->location, (GLsizei)paletteSize, (constfloat*)palette );

    }


    void Effect3DOutline::draw(constMat4 &transform)

    {

        //draw

        Color4F color(_sprite->getDisplayedColor());

        color.a = _sprite->getDisplayedOpacity() /255.0f;

        _glProgramState->setUniformVec4("u_color",Vec4(color.r, color.g, color.b, color.a));

        if(_sprite && _sprite->getMesh())

        {

            glEnable(GL_CULL_FACE);

            glCullFace(GL_FRONT);

            glEnable(GL_DEPTH_TEST);

            

            auto mesh = _sprite->getMesh();

            glBindBuffer(GL_ARRAY_BUFFER, mesh->getVertexBuffer());

            

            auto skin = _sprite->getMesh()->getSkin();

            if(_sprite && skin)

            {

                auto function = std::bind(MatrixPalleteCallBack,std::placeholders::_1,std::placeholders::_2,

                                          skin->getMatrixPaletteSize(), (float*)skin->getMatrixPalette());

                _glProgramState->setUniformCallback("u_matrixPalette", function);

            }

            

            if(_sprite)

                _glProgramState->apply(transform);

     

            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->getIndexBuffer());

            glDrawElements(mesh->getPrimitiveType(), mesh->getIndexCount(), mesh->getIndexFormat(),0);

            CC_INCREMENT_GL_DRAWN_BATCHES_AND_VERTICES(1, mesh->getIndexCount());

            

            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0);

            glBindBuffer(GL_ARRAY_BUFFER,0);

            glDisable(GL_DEPTH_TEST);

            glCullFace(GL_BACK);

            glDisable(GL_CULL_FACE);

        }

    }


    void EffectSprite3D::draw(cocos2d::Renderer *renderer,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的加载

    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->setPositionVec2( 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->runActionRepeatForever::create(seq) );

    }


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

    {

        for (auto touch: touches)

        {

            auto location = touch->getLocation();

            

            addNewSpriteWithCoords( location );

        }

    }

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

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

       auto animation = Animation3D::create(fileName);

        if (animation)

        {

            auto animate = Animate3D::create(animation);

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

     }



    void Sprite3DWithSkinTest::addNewSpriteWithCoords(Vec2 p)

    {

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

        auto sprite = EffectSprite3D::create(fileName);

        sprite->setScale(3);

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

        addChild(sprite);

        sprite->setPositionVec2( p.x, p.y) );

        auto animation = Animation3D::create(fileName);

        if (animation)

        {

            auto animate = Animate3D::create(animation);

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


            int rand2 = std::rand();

            float speed = 1.0f;

            if(rand2 % 3 ==1)

            {

                speed = animate->getSpeed() + CCRANDOM_0_1();

            }

            else if(rand2 %3 == 2)

            {

                speed = animate->getSpeed() - 0.5 * CCRANDOM_0_1();

            }

            animate->setSpeed(inverse ? -speed : speed);


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

        }

    }

    5.在以上模型和动画中添加特效(方法和在静态模型上一样)



    void Sprite3DWithSkinOutlineTest::addNewSpriteWithCoords(Vec2 p)

    {

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

        auto sprite = EffectSprite3D::create(fileName);

        

        Effect3DOutline* effect =Effect3DOutline::create();

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

        effect->setOutlineWidth(0.01f);

        sprite->addEffect(effect, -1);


        

        Effect3DOutline* effect2 =Effect3DOutline::create();

        effect2->setOutlineWidth(0.02f);

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

        sprite->addEffect(effect2, -2);


        

        sprite->setScale(3);

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

        addChild(sprite);

        sprite->setPositionVec2( p.x, p.y) );

        

        auto animation =

  • 相关阅读:
    [你必须知道的.NET] 第四回:后来居上:class和struct
    [你必须知道的.NET]第十回:品味类型值类型与引用类型(下)-应用征途
    [你必须知道的.NET]第十一回:参数之惑传递的艺术(上)
    [你必须知道的.NET] 第一回:恩怨情仇:is和as
    [Anytao.History] 排名进入1000,未来值得努力
    [你必须知道的.NET] 第三回:历史纠葛:特性和属性
    [你必须知道的.NET] 第八回:品味类型值类型与引用类型(上)-内存有理
    [你必须知道的.NET] 第五回:深入浅出关键字把new说透
    [你必须知道的.NET]第十二回:参数之惑传递的艺术(下)
    .NET 3.5
  • 原文地址:https://www.cnblogs.com/Anzhongliu/p/6091916.html
Copyright © 2011-2022 走看看