ogre 学习笔记 - Day 7

ogre 学习笔记 - Day 7


[Sample_ParticleFX]

粒子效果

    void setupParticles()
    {
        ParticleSystem::setDefaultNonVisibleUpdateTimeout(5);  // set nonvisible timeout

        ParticleSystem* ps;

        // create some nice fireworks and place it at the origin
        ps = mSceneMgr->createParticleSystem("Fireworks", "Examples/Fireworks");
        mSceneMgr->getRootSceneNode()->attachObject(ps);

        // create a green nimbus around the ogre head
        ps = mSceneMgr->createParticleSystem("Nimbus", "Examples/GreenyNimbus");
        mSceneMgr->getRootSceneNode()->attachObject(ps);

        ps = mSceneMgr->createParticleSystem("Rain", "Examples/Rain");  // create a rainstorm
        ps->fastForward(5);   // fast-forward the rain so it looks more natural
        mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(0, 1000, 0))->attachObject(ps);

        // create aureola around ogre head perpendicular to the ground
        ps = mSceneMgr->createParticleSystem("Aureola", "Examples/Aureola");
        mSceneMgr->getRootSceneNode()->attachObject(ps);

        // create shared pivot node for spinning the fountains
        mFountainPivot = mSceneMgr->getRootSceneNode()->createChildSceneNode();

        ps = mSceneMgr->createParticleSystem("Fountain1", "Examples/PurpleFountain");  // create fountain 1
        // attach the fountain to a child node of the pivot at a distance and angle
        mFountainPivot->createChildSceneNode(Vector3(200, -100, 0), Quaternion(Degree(20), Vector3::UNIT_Z))->attachObject(ps);
        
        ps = mSceneMgr->createParticleSystem("Fountain2", "Examples/PurpleFountain");  // create fountain 2
        // attach the fountain to a child node of the pivot at a distance and angle
        mFountainPivot->createChildSceneNode(Vector3(-200, -100, 0), Quaternion(Degree(-20), Vector3::UNIT_Z))->attachObject(ps);
    }

ps = mSceneMgr->createParticleSystem(“Fireworks”, “Examples/Fireworks”);

粒子材质

particle_system Examples/Fireworks
{
    material Examples/Flare
    point_rendering            false
    particle_width             10
    particle_height            10
    cull_each                  false
    quota                      1000
    emit_emitter_quota         10
    billboard_type             point
    
    // Emitter that emits multiple Point emitters with name 'explosion'
    emitter Box
    {
        name                    mainEmitter
        emit_emitter            explosion
        angle                   30
        emission_rate           1000
        time_to_live            3
        direction               0 1 0
        velocity                200
    }

    // This Point emitter is emitted by the Box emitter and emits billboard particles itself
    emitter Point
    {
        name                    explosion
        angle                   180
        emission_rate           100
        time_to_live            2
        direction               0 1 0
        velocity                80
        duration                -1
        repeat_delay_min        2
        repeat_delay_max        3
    }

    // Make em float downwards
    affector LinearForce
    {
        force_vector            0 -100 0
        force_application       add
    }

    // Give em some nice colours
    affector ColourInterpolator
    {
        time0                   0
        colour0                 1 1 0
        time1                   0.5
        colour1                 1 0 0
        time2                   0.9
        colour2                 0 0 1
    }
}

粒子以及粒子发射器属性配置,暂时不深究

mSceneMgr->getRootSceneNode()->attachObject(ps);
这里有个注意点,创建的所有的ParticleSystem都 attach 到了 RootSceneNode 上。
也就是说 相同类型的 object 可以 attach 多个到同一节点上,也就意味着不能通过类型获取到 object。

[Sample_Shadows]

阴影

    if (mRoot->getRenderSystem()->getCapabilities()->hasCapability(RSC_HWSTENCIL))
    {
        mSceneMgr->setShadowTechnique(SHADOWTYPE_STENCIL_MODULATIVE);
        mCurrentShadowTechnique = SHADOWTYPE_STENCIL_MODULATIVE;
    }
    else
    {
        mSceneMgr->setShadowTechnique(SHADOWTYPE_TEXTURE_MODULATIVE);
        mCurrentShadowTechnique = SHADOWTYPE_TEXTURE_MODULATIVE;
    }

启用阴影


pPlaneEnt->setCastShadows(false);

设置是否产生阴影


mSceneMgr->setShadowTextureSettings(1024, 2);

设置基于纹理阴影的纹理属性


mSceneMgr->setShadowColour(ColourValue(0.5, 0.5, 0.5));

设置阴影颜色


mSceneMgr->setShadowTexturePixelFormat(PF_BYTE_RGBA);

设置基于纹理阴影的纹理像素格式


mSceneMgr->setShadowTextureCasterMaterial(themat);

设置阴影的材质


mSceneMgr->setShadowTextureSelfShadow(true);    

设置是否启用基于纹理阴影的自阴影


[Sample_SkeletalAnimation]

骨骼动画

void setupContent()
{
    mShaderGenerator->invalidateScheme(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
    mViewport->setMaterialScheme(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);

    //Add the hardware skinning to the shader generator default render state
    mSrsHardwareSkinning = mShaderGenerator->createSubRenderState<RTShader::HardwareSkinning>();
    Ogre::RTShader::RenderState* renderState = mShaderGenerator->getRenderState(Ogre::RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
    renderState->addTemplateSubRenderState(mSrsHardwareSkinning);
}        

设置RTSystem属性,并启用硬件蒙皮

SkeletonPtr skel = static_pointer_cast<Skeleton>(SkeletonManager::getSingleton().load("jaiqua.skeleton",
           ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME));

加载骨骼

void setupModels()
{
   tweakSneakAnim();

   SceneNode* sn = NULL;
   Entity* ent = NULL;
   AnimationState* as = NULL;

   // make sure we can get the buffers for bbox calculations
   MeshManager::getSingleton().load("jaiqua.mesh",
                                       ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                       HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY,
                                       HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY, true, true);

   auto& controllerMgr = ControllerManager::getSingleton();

   for (int i = 0; i < NUM_MODELS; i++)
   {
       // create scene nodes for the models at regular angular intervals
       sn = mSceneMgr->getRootSceneNode()->createChildSceneNode();
       sn->yaw(Radian(Math::TWO_PI * (float)i / (float)NUM_MODELS));
       sn->translate(0, 0, -20, Node::TS_LOCAL);
       mModelNodes.push_back(sn);

       // create and attach a jaiqua entity
       ent = mSceneMgr->createEntity("Jaiqua" + StringConverter::toString(i + 1), "jaiqua.mesh");
       ent->setMaterialName("jaiqua");
       sn->attachObject(ent);
   
       // enable the entity's sneaking animation at a random speed and loop it manually since translation is involved
       as = ent->getAnimationState("Sneak");
       as->setEnabled(true);
       as->setLoop(false);

       controllerMgr.createController(controllerMgr.getFrameTimeSource(),
                                       AnimationStateControllerValue::create(as, true),
                                       ScaleControllerFunction::create(Math::RangeRandom(0.5, 1.5)));
       mAnimStates.push_back(as);
   }

   // create name and value for skinning mode
   StringVector names;
   names.push_back("Help");
   names.push_back("Skinning");
   names.push_back(mBoneBoundingBoxesItemName);
   
   // create a params panel to display the help and skinning mode
   mStatusPanel = mTrayMgr->createParamsPanel(TL_TOPLEFT, "HelpMessage", 200, names);
   mStatusPanel->setParamValue("Help", "H / F1");
   String value = "Software";
   enableBoneBoundingBoxMode( false );  // update status panel entry

   // change the value if hardware skinning is enabled
   MaterialPtr entityMaterial = ent->getSubEntity(0)->getMaterial();
   if(entityMaterial)
   {
       Technique* bestTechnique = entityMaterial->getBestTechnique();
       if(bestTechnique)
       {
           Pass* pass = bestTechnique->getPass(0);
           if (pass && pass->hasVertexProgram() && pass->getVertexProgram()->isSkeletalAnimationIncluded()) 
           {
               value = "Hardware";
           }
       }
   }
   mStatusPanel->setParamValue("Skinning", value);
}
   
  1. tweakSneakAnim();
    从代码可以看出来,动画是在.skeleton里的。调整骨骼动画,通常这一步不需要的,动画通常由动画师制作好,程序不需要去修改。不在此对这一操作深入。想深入,需要对骨骼动画有所了解。现在这个阶段,可以不看。

  2. 加载 mesh,确保可以获得用于bbox计算的缓冲区? 这个操作有点奇怪,先记住。HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY 硬件可写。硬件读写状态,从硬件读取数据会非常耗时。

  3. 创建动画控制器

    auto& controllerMgr = ControllerManager::getSingleton();
    
    for (int i = 0; i < NUM_MODELS; i++)
    {
        // create scene nodes for the models at regular angular intervals
        sn = mSceneMgr->getRootSceneNode()->createChildSceneNode();
        sn->yaw(Radian(Math::TWO_PI * (float)i / (float)NUM_MODELS));
        sn->translate(0, 0, -20, Node::TS_LOCAL);
        mModelNodes.push_back(sn);
    
        // create and attach a jaiqua entity
        ent = mSceneMgr->createEntity("Jaiqua" + StringConverter::toString(i + 1), "jaiqua.mesh");
        ent->setMaterialName("jaiqua");
        sn->attachObject(ent);
    
        // enable the entity's sneaking animation at a random speed and loop it manually since translation is involved
        as = ent->getAnimationState("Sneak");
        as->setEnabled(true);
        as->setLoop(false);
    
        controllerMgr.createController(controllerMgr.getFrameTimeSource(),
                                        AnimationStateControllerValue::create(as, true),
                                        ScaleControllerFunction::create(Math::RangeRandom(0.5, 1.5)));
        mAnimStates.push_back(as);
    }
    

    从上面的操作,只创建了一个mesh Entity,并没有绑定骨骼。然后就开始获取AnimationState。因为动画在skeleton里,能获取就说明绑定了,什么时候绑定的?
    看看 Entity的代码,发现里面有 Mesh,Mesh里有skeleton,通过调试,发现,在 read Mesh的时候,有一个 M_MESH_SKELETON_LINK。也就是说在读取mesh的时候就绑定了骨骼。

    • 调试过程
      找到Mesh 中有String mSkeletonName; SkeletonPtr mSkeleton; 之后,搜索 "mSkeletonName = " 赋值的地方,发现只有3个,每个地方下一个断点。调试,走到了 Mesh::setSkeletonName。查看调用堆栈,找到了 readMesh -> readSkeletonLink.

    Controller<Real>* ControllerManager::createController(const ControllerValueRealPtr& src,
            const ControllerValueRealPtr& dest, const ControllerFunctionRealPtr& func);
    

    创建动画控制器,该函数没有详细的说明。看看 Controller 类。这个类很简单,除了一个get,set,只有一个Updata

    void update(void)
    {
        if(mEnabled)
            mDest->setValue(mFunc->calculate(mSource->getValue()));
    }
    

    AnimationStateControllerValue::create(as, true),通过entity获取到的AnimationState创建一个ControllerValue,该ControllerValue应该是绑定在 该Entity的AnimationState上。
    通过第三个参数func,与第一个参数计算当前的值,设置给Dest。
    按照这个猜测,上面应该是获取ControllerManager最后一帧的时间,给获取到的AnimationState 随机加 [0.5 - 1.5] 的时间。

[Terrain]

地形

void setupContent()
{
 //! [terrain_create]
       mTerrainGroup = new Ogre::TerrainGroup(mSceneMgr, Ogre::Terrain::ALIGN_X_Z, TERRAIN_SIZE, TERRAIN_WORLD_SIZE);
       mTerrainGroup->setFilenameConvention(TERRAIN_FILE_PREFIX, TERRAIN_FILE_SUFFIX);
       mTerrainGroup->setOrigin(mTerrainPos);
       //! [terrain_create]
       
       configureTerrainDefaults(l);
#ifdef PAGING
       // Paging setup
       mPageManager = OGRE_NEW PageManager();
       // Since we're not loading any pages from .page files, we need a way just
       // to say we've loaded them without them actually being loaded
       mPageManager->setPageProvider(&mDummyPageProvider);
       mPageManager->addCamera(mCamera);
       mTerrainPaging = OGRE_NEW TerrainPaging(mPageManager);
       PagedWorld* world = mPageManager->createWorld();
       mTerrainPaging->createWorldSection(world, mTerrainGroup, 2000, 3000,
                                          TERRAIN_PAGE_MIN_X, TERRAIN_PAGE_MIN_Y,
                                          TERRAIN_PAGE_MAX_X, TERRAIN_PAGE_MAX_Y);
#else
       //! [define_loop]
       for (long x = TERRAIN_PAGE_MIN_X; x <= TERRAIN_PAGE_MAX_X; ++x)
           for (long y = TERRAIN_PAGE_MIN_Y; y <= TERRAIN_PAGE_MAX_Y; ++y)
               defineTerrain(x, y);
       // sync load since we want everything in place when we start
       mTerrainGroup->loadAllTerrains(true);
       //! [define_loop]
#endif
//! [init_blend]
   if (mTerrainsImported)
   {
       for (const auto& ti : mTerrainGroup->getTerrainSlots())
       {
           initBlendMaps(ti.second->instance);
       }
   }

   mTerrainGroup->freeTemporaryResources();
   //! [init_blend]
}

先创建一个 TreeainGroup, 指定场景;对齐方式(指定一个平面),这里是XZ平面(水平面);地形大小(顶点数);在世界当中的大小

TerrainGroup::TerrainGroup(SceneManager* sm, Terrain::Alignment align, 
       uint16 terrainSize, Real terrainWorldSize)
{

}

mTerrainGroup->setFilenameConvention 设置命名约定?
mTerrainGroup->defineTerrain(x, y, 0.0f); 定义一个指定位置的固定高度

       String filename = mTerrainGroup->generateFilename(x, y);
       if (ResourceGroupManager::getSingleton().resourceExists(mTerrainGroup->getResourceGroup(), filename))
       {
           mTerrainGroup->defineTerrain(x, y);
       }
       else
       {
           Image img;
           getTerrainImage(x % 2 != 0, y % 2 != 0, img);
           mTerrainGroup->defineTerrain(x, y, &img);
           mTerrainsImported = true;
       }

按照定义生成一个dat文件

mTerrainGroup->loadAllTerrains(true);

导入地形,参数:是否异步。


从这两天对几个特定sample的学习,发现ogre在每个功能的基本使用上都挺简单的。

但是,随着时间的推移,一步步深入,越来越多的东西没有理解,都只能去按照注释简单的翻译,无法知道它的具体作用。终归为对ogre的实现都没有深入的去看。

毕竟这是一个学习过程。

所以到这里,把引擎最基本的功能(Material, Mesh, Scene, Light, Skybox, Particle, Skybox, Shadow, Animation, Terrain)稍微过了一遍之后,剩下的sample就暂时不看了,那些sample基本都是一些高级应用,看了也无法真正理解(说难听点,就是看也看不懂)。

接下来去看这些基本功能的代码,去分析理解代码。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值