IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> ogre 学习笔记 - Day 6 -> 正文阅读

[游戏开发]ogre 学习笔记 - Day 6

ogre 学习笔记 - Day 6


由于samples不具备由浅入深的设定,那么就按照需求来学习了。
一般应用的基本需求,模型,材质,灯光,天空盒,场景。
通过运行一些sample,发现[Bump Mapping]加载了很多mesh, material,light。
在 DefaultSamplesPlugin 找 搜索 “Bump Mapping”,竟然没有!好吧,只能全局搜了。
打开vscode,搜索"Bump Mapping",竟然在 Sample_Dot3Bump 里。
Bump Mapping : 凹凸贴图,先忽略这个功能了。

[Sample_Dot3Bump]

加载材质


打开 Dot3Bump.h,发现内容不多,很好。
先总览一遍函数。

class Sample_Dot3Bump : public SdkSample
{
	bool frameRenderingQueued(const FrameEvent& evt);
	void itemSelected(SelectMenu* menu);
	void checkBoxToggled(CheckBox* box);
	void setupContent();
	void setupModels();
	void setupLights();
	void setupControls();
}

在之前的学习中,已知了 setupContent 函数

    void setupContent()
    {
#ifdef OGRE_BUILD_COMPONENT_RTSHADERSYSTEM
        // Make this viewport work with shader generator scheme.
        mViewport->setMaterialScheme(RTShader::ShaderGenerator::DEFAULT_SCHEME_NAME);
#endif

        // create our main node to attach our entities to
        mObjectNode = mSceneMgr->getRootSceneNode()->createChildSceneNode();

        setupModels();
        setupLights();
        setupControls();

        mCameraMan->setStyle(CS_ORBIT);
        mCameraMan->setYawPitchDist(Radian(0), Radian(0), 500);
    }
  1. 设置 shader生成方案?不在本次学习中,先忽略。

  2. 创建一个获取root场景节点,并创建一个节点。

  3. setupModels

    void setupModels()
    {
        StringVector matNames;
    
        matNames.push_back("Examples/BumpMapping/MultiLight");
        matNames.push_back("Examples/BumpMapping/MultiLightSpecular");
        // ...
    
        mPossibilities["ogrehead.mesh"] = matNames;
        mPossibilities["knot.mesh"] = matNames;
    
        matNames.clear();
        // ...
        mPossibilities["athene.mesh"] = matNames;
    
        for (std::map<String, StringVector>::iterator it = mPossibilities.begin(); it != mPossibilities.end(); it++)
        {
            // load each mesh with non-default hardware buffer usage options
            MeshPtr mesh = MeshManager::getSingleton().load(it->first, ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                HardwareBuffer::HBU_DYNAMIC_WRITE_ONLY);
    
            // build tangent vectors for our mesh
            unsigned short src, dest;
            if (!mesh->suggestTangentVectorBuildParams(VES_TANGENT, src, dest))
            {
                mesh->buildTangentVectors(VES_TANGENT, src, dest);
                // this version cleans mirrored and rotated UVs but requires quality models
                // mesh->buildTangentVectors(VES_TANGENT, src, dest, true, true);
            }
    
            // create an entity from the mesh and set the first available material
            Entity* ent = mSceneMgr->createEntity(mesh->getName(), mesh->getName());
            ent->setMaterialName(it->second.front());
        }
    }
    
    • 添加了一堆的材质名称。
      在文件/文件夹中查找,发现这些名称都位于 Examples.material里.
      .material,按后缀来看是一个材质文件。

      material Examples/SphereMappedRustySteel
      {
      	technique
      	{
      		pass
      		{
      			texture_unit
      			{
      				texture RustySteel.jpg
      			}
      
      			texture_unit
      			{
      				texture spheremap.png
      				colour_op_ex add src_texture src_current
      				colour_op_multipass_fallback one one
      				env_map spherical
      			}
      		}
      	}
      }
      

      .material :材质文件

      • material : 材质定义,.material 包含多个 material

        • technique : 效果文件的一种名称定义,为了实现这种效果需要几种或者可以有几种**技巧或技术,一个material可以包含多个technique。
          • pass :为了实现上面的technique需要的步骤,一个technique可以包含多个pass
            • lighting : 是否启用光照
            • scene_blend alpha_blend
            • cull_hardware none : 硬件背面剔除/背面消隐
            • cull_software none : 软件背面剔除/背面消隐
            • texture_uint : 纹理属性
              • texture xxx.jpg cubic: 文件名称, cubic 立方体,可选的
              • tex_address_mode : 寻址模式
              • filtering none : 采样方式

      涉及挺多的,就不一一列举了

    • 赋给了 mPossibilities[.mesh],按照这种定义,应该是这个mesh可以使用这些材质。

    • load mesh

    • 创建entity

    • 设置材质

      void Entity::setMaterialName( const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */)
      {
          // Set for all subentities
          SubEntityList::iterator i;
          for (i = mSubEntityList.begin(); i != mSubEntityList.end(); ++i)
          {
              (*i)->setMaterialName(name, groupName);
          }
      }
      
      void SubEntity::setMaterialName( const String& name, const String& groupName /* = ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME */)
      {
          MaterialPtr material = MaterialManager::getSingleton().getByName(name, groupName);
      
          if( !material )
          {
              //...
          }
      
          setMaterial( material );
      }
      
      void SubEntity::setMaterial( const MaterialPtr& material )
      {
          mMaterialPtr = material;
          
          if (!mMaterialPtr)
          {
              // ...
          }
          
          // Ensure new material loaded (will not load again if already loaded)
          mMaterialPtr->load();
      
          // tell parent to reconsider material vertex processing options
          mParentEntity->reevaluateVertexProcessing();
      }
      

      想起了之前对SampleBrowser代码的分析,在SampleBorwser里有一个 StartupSample 的配置

      Ogre::String startupSampleTitle = cfg.getSetting("StartupSample");
      

      找到并打开 samples.cfg, 加入

      StartupSample=Bump Mapping
      

      直接启动BumpMapping.


      那么问题来了,通过一个材质名称是怎么找到材质文件的呢?有可能跟samples.cfg一样。调试看看。
      一路追踪,发现进入到

      ResourcePtr ResourceManager::getResourceByName(const String& name, const String& groupName) const
      

      通过名称获取材质。

      ResourcePtr ResourceManager::getResourceByName(const String& name, const String& groupName) const
      {
          OGRE_LOCK_AUTO_MUTEX;
      
          // resource should be in global pool
          bool isGlobal = ResourceGroupManager::getSingleton().isResourceGroupInGlobalPool(groupName);
      
          if(isGlobal)
          {
              auto it = mResources.find(name);
              if( it != mResources.end())
              {
                  return it->second;
              }
          }
      
          // look in all grouped pools
          if (groupName == ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME)
          {
              auto iter = mResourcesWithGroup.begin();
              auto iterE = mResourcesWithGroup.end();
              for ( ; iter != iterE ; ++iter )
              {
                  auto resMapIt = iter->second.find(name);
      
                  if( resMapIt != iter->second.end())
                  {
                      return resMapIt->second;
                  }
              }
          }
          else if (!isGlobal)
          {
              // look in the grouped pool
              auto itGroup = mResourcesWithGroup.find(groupName);
              if( itGroup != mResourcesWithGroup.end())
              {
                  auto it = itGroup->second.find(name);
      
                  if( it != itGroup->second.end())
                  {
                      return it->second;
                  }
              }
      
          #if !OGRE_RESOURCEMANAGER_STRICT
              // fall back to global
              auto it = mResources.find(name);
              if( it != mResources.end())
              {
                  return it->second;
              }
          #endif
          }
      
          return ResourcePtr();
      }
      
      bool ResourceGroupManager::isResourceGroupInGlobalPool(const String& name) const
      {
          ResourceGroup* grp = getResourceGroup(name);
          if (!grp)
          {
              // ...
          }
          return grp->inGlobalPool;
      }
      
      ResourceGroupManager::ResourceGroup* ResourceGroupManager::getResourceGroup(const String& name) const
      {
          OGRE_LOCK_AUTO_MUTEX;
          ResourceGroupMap::const_iterator i = mResourceGroupMap.find(name);
          return i != mResourceGroupMap.end() ? i->second : NULL;
      }
      

      先通过group name 判断是否是global group,通过 mResourceGroupMap 来判断组。找找 mResourceGroupMap 如何初始化的。

      void ResourceGroupManager::createResourceGroup(const String& name, bool inGlobalPool)
      {
          // ...
          ResourceGroup* grp = OGRE_NEW_T(ResourceGroup, MEMCATEGORY_RESOURCE)();
          grp->groupStatus = ResourceGroup::UNINITIALSED;
          grp->name = name;
          grp->inGlobalPool = inGlobalPool;
          grp->customStageCount = 0;
      
          // ...
          mResourceGroupMap.emplace(name, grp);
      }
      

      mResourceGroupMap.emplace(name, grp); 处下断点。调试

      ResourceGroupManager::ResourceGroupManager()
      : mLoadingListener(0), mCurrentGroup(0)
      {
          // Create the 'General' group
          createResourceGroup(DEFAULT_RESOURCE_GROUP_NAME, true); // the "General" group is synonymous to global pool
          // Create the 'Internal' group
          createResourceGroup(INTERNAL_RESOURCE_GROUP_NAME, true);
          // Create the 'Autodetect' group (only used for temp storage)
          createResourceGroup(AUTODETECT_RESOURCE_GROUP_NAME, true); // autodetect includes the global pool
          // default world group to the default group
          mWorldGroupName = DEFAULT_RESOURCE_GROUP_NAME;
      }
      

      在 ResourceGroupManager 的构造函数里,创建了3个全局资源组。

      • General
      • OgreInternal
      • OgreAutodetect
      const char* const RGN_DEFAULT = "General";
      const char* const RGN_INTERNAL = "OgreInternal";
      const char* const RGN_AUTODETECT = "OgreAutodetect";
      
      const String ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME = RGN_DEFAULT;
      const String ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME = RGN_INTERNAL;
      const String ResourceGroupManager::AUTODETECT_RESOURCE_GROUP_NAME = RGN_AUTODETECT;
      

      继续调试

      void ResourceGroupManager::addResourceLocation(const String& name, 
      const String& locType, const String& resGroup, bool recursive, bool readOnly)
      {
          // ...
          ResourceGroup* grp = getResourceGroup(resGroup);
          if (!grp)
          {
              createResourceGroup(resGroup);
              grp = getResourceGroup(resGroup);
          }
          // ...
      }
      
      void ApplicationContextBase::locateResources()
      {
          // ...
          Ogre::ConfigFile cf;
          Ogre::String resourcesPath = mFSLayer->getConfigFilePath("resources.cfg");
          // ...
          cf.load(resourcesPath);
          // ...
          rgm.addResourceLocation(arch, type, sec);
      }
      
      void ApplicationContextBase::setup()
      {
          // ...
          locateResources();
          // ...
          loadResources();
          // ...
      }
      

      在ApplicationContextBase::locateResources 里又添加了三个

      • BSPWorld
      • Essential
      • Tests

      在locateResources(定位资源)里使用了 “resources.cfg”,与"samples.cfg"相同,应该与samples.cfg在同一位置。

      Ogre::String resourcesPath = mFSLayer->getConfigFilePath("resources.cfg");
      

      打开 resources.cfg 文件,与samples.cfg 格式相同,ini 文件格式。
      key有两种,FileSystem / Zip,通过value 找到对应的位置,很明显,FileSystem是指文件夹,Zip是压缩文件.
      打开一个zip文件,里面的格式与FileSystem相同,只是一个压缩,一个未压缩。明显,zip更省内存。

      在 resources.cfg 文件里,指定了很多文件路径。那么,通过文件名加载资源时,就会遍历这些文件夹去查找资源。同时,提供了一个资源组,指定资源组,可以避免不需要的搜索。
      同样的,如果存在同名文件该怎么办?

      通过ConfigFile::load加载 resources.cfg,分析文件。分析完,通过
      rgm.addResourceLocation(arch, type, sec); 加入资源。完成资源定位。


      以上的操作只做了创建资源组,未初始化。

      void SampleBrowser::loadResources()
      {
          Ogre::ResourceGroupManager::getSingleton().initialiseResourceGroup("Essential");
          // ...
      }
      

      // 初始化资源组

      void ResourceGroupManager::initialiseResourceGroup(const String& name)
      {
          LogManager::getSingleton().logMessage("Initialising resource group " + name);
          ResourceGroup* grp = getResourceGroup(name);
          // ...
          if (grp->groupStatus == ResourceGroup::UNINITIALSED)
          {
              // in the process of initialising
              grp->groupStatus = ResourceGroup::INITIALISING;
              // Set current group
              parseResourceGroupScripts(grp);
              mCurrentGroup = grp;
              LogManager::getSingleton().logMessage("Creating resources for group " + name);
              createDeclaredResources(grp);
              grp->groupStatus = ResourceGroup::INITIALISED;
              LogManager::getSingleton().logMessage("All done");
              // Reset current group
              mCurrentGroup = 0;
          }
      }
      
      void ResourceGroupManager::parseResourceGroupScripts(ResourceGroup* grp) const
      

      从代码来看,把资源文件定义为了script。分析文件,加载脚本。
      ScriptLoader / ScriptCompiler, 大概就是导入/加载脚本的。至于如何做的,暂时就不深入了。


      到这里,知道了如何通过 group name获取相关资源。回到 ResourceManager::getResourceByName

      资源存储在 mResources / mResourcesWithGroup里。

      从已获取的信息不知道这两个值是初始化的。找吧。>_<

      void ResourceManager::addImpl( ResourcePtr& res )
      {
          // ...
          result = mResources.emplace(res->getName(), res);
          // ...
          auto resgroup = mResourcesWithGroup.emplace(res->getGroup(), ResourceMap()).first;
      }
      
      ResourcePtr ResourceManager::createResource(const String& name, const String& group,
      bool isManual, ManualResourceLoader* loader, const NameValuePairList* params)
      {
          ResourcePtr ret = ResourcePtr(
              createImpl(name, getNextHandle(), group, isManual, loader, params));
          if (params)
              ret->setParameterList(*params);
      
          addImpl(ret);
          // ...
      }
      
      MaterialPtr MaterialManager::create (const String& name, const String& group,
                                  bool isManual, ManualResourceLoader* loader,
                                  const NameValuePairList* createParams)
      {
          return static_pointer_cast<Material>(createResource(name,group,isManual,loader,createParams));
      }
      
      void MaterialManager::initialise(void)
      {
          // ...
          mDefaultSettings = create("DefaultSettings", ResourceGroupManager::INTERNAL_RESOURCE_GROUP_NAME);
          // ...
      }
      
      void Root::oneTimePostWindowInit(void)
      {
          // ...
          mMaterialManager->initialise();
          // ...
      }      
      
      RenderWindow* Root::createRenderWindow(const String &name, unsigned int width, unsigned int height,
          bool fullScreen, const NameValuePairList *miscParams)
      {
          // ...
          oneTimePostWindowInit();
      }
      

      竟然是在 createRenderWindow 的时候创建的资源。
      大致的结果就是资源加载后,存放在mResourcs / mResourcesWithGroup里。
      mResoures 是全局资源,mResourcesWithGroup 是组资源。

      到这里就知道了,如何通过名称获取材质资源。

  4. setupLights

    void setupLights()
    {
        // ...
        Light* l;
        BillboardSet* bbs;
    
        // create white light
        l = mSceneMgr->createLight();
        mLightPivot1->createChildSceneNode(Vector3(200, 0, 0))->attachObject(l);
        l->setDiffuseColour(1, 1, 1);
        l->setSpecularColour(1, 1, 1);
        // create white flare
        bbs = mSceneMgr->createBillboardSet();
        bbs->setMaterialName("Examples/Flare");
        bbs->createBillboard(200, 0, 0)->setColour(ColourValue::White);
        // ...
    }
    

    创建了一个light,一个billboard

  5. setupControls

    void setupControls()
    {
        // ...
    }
    

    创建UI

  6. itemSelected

    void itemSelected(SelectMenu* menu)
    {
        if (menu == mMeshMenu)
        {
            // change to the selected entity
            mObjectNode->detachAllObjects();
            mObjectNode->attachObject(mSceneMgr->getEntity(mMeshMenu->getSelectedItem()));
    
            // remember which material is currently selected
            int index = std::max<int>(0, mMaterialMenu->getSelectionIndex());
    
            // update the material menu's options
            mMaterialMenu->setItems(mPossibilities[mMeshMenu->getSelectedItem()]);
    
            mMaterialMenu->selectItem(index);   // select the material with the saved index
        }
        else
        {
            // set the selected material for the active mesh
            ((Entity*)mObjectNode->getAttachedObject(0))->setMaterialName(menu->getSelectedItem());
        }
    }
    

    当选择了 Mesh 后,获取 Entity ,并attach到node上。
    当选择了 Material ,给Entity设置材质

  7. checkBoxToggled

    void checkBoxToggled(CheckBox* box)
    {
        if (StringUtil::startsWith(box->getName(), "Light", false))
        {
            // get the light pivot that corresponds to this checkbox
            SceneNode* pivot = box->getName() == "Light1" ? mLightPivot1 : mLightPivot2;
    
            // toggle visibility of light and billboard set
            pivot->setVisible(box->isChecked());
        }
        else if (box->getName() == "MoveLights")
        {
            mMoveLights = !mMoveLights;
        }
    }
    

    启用或禁用光照。

到这里,创建light,billboard,创建entity,加载material,加载mesh。
由于资源种类众多,后续再深究。

[Sample_SkyBox]

加载天空盒

void setupContent()
{
    // ...
    mSceneMgr->setSkyBox(true, "Examples/SpaceSkyBox", 5000);  // set our skybox
    // ...
}

设置skybox

material Examples/SpaceSkyBox
{
	technique
	{
		pass
		{
			lighting off
			depth_write off

			texture_unit
			{
				texture stevecube.jpg cubic
				tex_address_mode clamp
			}
		}
	}
}

不得不吐槽这资源的设置,不花点时间都找不到texture在哪里。 这名称 stevecube.jpg,找都找不到。

Samples/Media/packs/skybox.zip 
{
    stevecube_bk.jpg
    stevecube_dn.jpg
    stevecube_fr.jpg
    stevecube_lf.jpg
    stevecube_rt.jpg
    stevecube_up.jpg
}

[Sample_BSP]

加载场景

void loadResources()
{
    /* NOTE: The browser initialises everything at the beginning already, so we use a 0 init proportion.
        If you're not compiling this sample for use with the browser, then leave the init proportion at 0.7. */

    // associate the world geometry with the world resource group, and then load the group
    ResourceGroupManager& rgm = ResourceGroupManager::getSingleton();
    rgm.setCustomStagesForResourceGroup("BSPWorld", mSceneMgr->estimateWorldGeometry("maps/oa_rpg3dm2.bsp"));
    rgm.initialiseResourceGroup("BSPWorld");
    rgm.loadResourceGroup("BSPWorld");
    // one would register a ResourceGroupListener for this, if we were not to call it right away
    mSceneMgr->setWorldGeometry("maps/oa_rpg3dm2.bsp");

    mTrayMgr->hideLoadingBar();
}

加载 bspScene

	Samples/Media/packs/oa_rpg3dm2.pk3

继续吐槽

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-12-06 15:34:42  更:2021-12-06 15:34:49 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 20:33:03-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码