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);
}
-
设置 shader生成方案?不在本次学习中,先忽略。
-
创建一个获取root场景节点,并创建一个节点。
-
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 : 采样方式
- pass :为了实现上面的technique需要的步骤,一个technique可以包含多个pass
- technique : 效果文件的一种名称定义,为了实现这种效果需要几种或者可以有几种**技巧或技术,一个material可以包含多个technique。
-
…
涉及挺多的,就不一一列举了
-
-
赋给了 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 是组资源。到这里就知道了,如何通过名称获取材质资源。
-
-
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
-
setupControls
void setupControls() { // ... }
创建UI
-
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设置材质 -
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
继续吐槽