当前位置: 首页 > 工具软件 > Ogre-Next > 使用案例 >

ogre-next 学习笔记 - Day 4

周翰池
2023-12-01

ogre-next 学习笔记 - Day 4


从之前的学习中,找到hlms的材质路径,打开看一看。
并没有发现什么不同之处。那应该就是代码实现的不同了。

先看看 Hlms : OgreHlms.h

 /** HLMS stands for "High Level Material System".

        The Hlms has multiple caches:

        mRenderableCache
            This cache contains all the properties set to a Renderable class and can be evaluated
            early, when a Renderable is assigned a datablock i.e. inside Renderable::setDatablock.
            Contains properties such as whether the material has normal mapping, if the mesh
            has UV sets, evaluates if the material requires tangents for normal mapping, etc.
            The main function in charge of filling this cache is Hlms::calculateHashFor

        mPassCache
            This cache contains per-pass information, such as how many lights are in the scene,
            whether this is a shadow mapping pass, etc.
            The main function in charge of filling this cache is Hlms::preparePassHash

        mShaderCodeCache
            Contains a cache of unique shaders (from Hlms templates -> actual valid shader code)
            based on the properties merged from mRenderableCache & mPassCache.
            However it is possible that two shaders are exactly the same and thus be duplicated,
            this can happen if two combinations of properties end up producing the exact same code.
            The Microcode cache (GpuProgramManager::setSaveMicrocodesToCache) can help with that issue.

        mShaderCache
            Contains a cache of the PSOs. The difference between this and mShaderCodeCache is
            that PSOs require additional information, such as HlmsMacroblock. HlmsBlendblock.
            For more information of all that is required, see HlmsPso
    */
HLMS 代表“高级材料系统”。

Hlms 有多个缓存:

渲染缓存
    此缓存包含设置为 Renderable 类的所有属性,并且可以在为 Renderable 分配数据块时进行早期评估,即在 Renderable::setDatablock 中。
    包含诸如材质是否具有法线贴图、网格是否具有 UV 集、评估材料是否需要法线贴图的切线等属性。
    负责填充这个缓存的主要函数是 Hlms::calculateHashFor

pass缓存
    这个缓存包含每个通道的信息,比如场景中有多少灯,这是否是一个阴影贴图通道等等。
    负责填充这个缓存的主要函数是 Hlms::preparePassHash

着色器代码缓存
    包含基于从 mRenderableCache 和 mPassCache 合并的属性的唯一着色器缓存(来自 Hlms 模板 -> 实际有效着色器代码)。
    然而,两个着色器可能完全相同并因此被复制,
    如果两种属性组合最终产生完全相同的代码,就会发生这种情况。
    微码缓存 (GpuProgramManager::setSaveMicrocodesToCache) 可以帮助解决这个问题。

着色器缓存
    包含 PSO 的缓存。这与 mShaderCodeCache 的区别在于 PSO 需要额外的信息,例如 HlmsMacroblock。 HlmsBlendblock。
    有关所需的所有信息的更多信息,请参阅 HlmsPso

google翻译,随便看看,大概率不知道说的啥。

这里涉及到几个函数

 Renderable::setDatablock
 Hlms::calculateHashFor
 Hlms::preparePassHash
 GpuProgramManager::setSaveMicrocodesToCache

虽然不知道干啥的,但是名字里有奇怪的东西,Hash?忽略忽略

看看怎么用的吧。

项目里关于hlms的有4个

  • OgreHlmsPbs
  • OgreHlmsPbsMobile
  • OgreHlmsUnlit
  • OgreHlmsUnlitMobile

分成两类,
Pbs : 基于物理的材质,果然够高级

/*
Physically based shading implementation specfically designed for OpenGL 3+, D3D11 and other RenderSystems which support uniform buffers
*/

Unlit :无光照材质

/*
Implementation without lighting or skeletal animation specfically designed for
        OpenGL 3+, D3D11 and other RenderSystems which support uniform buffers.
        Useful for GUI, ParticleFXs, other misc objects that don't require lighting.
*/

再看看Sample,只有一个与Hlms可能有关,

Sample_PbsMaterials
因为之前分析过Sample的基本结构,知道了怎么看。

virtual Ogre::CompositorWorkspace* setupCompositor()
{
    Ogre::CompositorManager2 *compositorManager = mRoot->getCompositorManager2();
    return compositorManager->addWorkspace( mSceneManager, mRenderWindow, mCamera,
                                            "PbsMaterialsWorkspace", true );
}

workspace 不知道是啥东西

virtual void setupResources(void)
{
    GraphicsSystem::setupResources();

    Ogre::ConfigFile cf;
    cf.load(mResourcePath + "resources2.cfg");

    Ogre::String dataFolder = cf.getSetting( "DoNotUseAsResource", "Hlms", "" );

    if( dataFolder.empty() )
        dataFolder = "./";
    else if( *(dataFolder.end() - 1) != '/' )
        dataFolder += "/";

    dataFolder += "2.0/scripts/materials/PbsMaterials";

    addResourceLocation( dataFolder, "FileSystem", "General" );
}

这里在setupResources时,添加了 Hlms材质,但是,按照resources2.cfg的注释说明,不能直接导入资源,这里又按照之前的方式定位了资源?只定位了pbsMaterials。所以它的意思应该是不能以资源的方式导入hlms文件下的东西,而是用hlms导入。

void MainEntryPoints::createSystems( GameState **outGraphicsGameState,
                                         GraphicsSystem **outGraphicsSystem,
                                         GameState **outLogicGameState,
                                         LogicSystem **outLogicSystem )
    {
        PbsMaterialsGameState *gfxGameState = new PbsMaterialsGameState(
        "Shows how to use the PBS material system. There's nothing really fancy,\n"
        "it's just programmer art. The PBS materials can be setup from script or\n"
        "code. This sample does both. At the time being, not all settings from the\n"
        "PBS implementation can be tweaked with scripts. See PbsDatablock::PbsDatablock\n"
        "constructor documentation. Also see the Hlms section of the porting guide in\n"
        "the Docs/2.0 folder.\n"
        "\n"
        "The sphere palette shows what happens when tweaking the roughness around the\n"
        "X axis; and the fresnel term around the Z axis.\n"
        "The scene is being lit by a white directional light (3-split PSSM) and two spot\n"
        "lights, one of warm colour, one cold. Both are also shadowed."
        "\n"
        "Of all the features supported by the PBS implementation, perhaps the hardest to\n"
        "to understand is the Detail Weight Map. It allows you to 'paint' the detail maps\n"
        "over the mesh, by controlling weight of each of the 4 maps via the RGBA channels\n"
        "of the weight map. 'R' controls the detail map 0, 'G' the detail map 1,\n"
        "'B' the detail map 2, and 'A' the detail map 3.\n"
        "\n"
        "This sample depends on the media files:\n"
        "   * Samples/Media/2.0/scripts/Compositors/PbsMaterials.compositor\n"
        "   * Samples/Media/2.0/materials/PbsMaterials/PbsMaterials.material\n"
        "\n"
        "Known issues:\n"
        " * Non shadow casting point & spot lights require Forward3D to be enabled (on desktop).\n"
        "   This is by design (more implementations will come: Forward+ & Deferred; for now the\n"
        "   only ones working are Forward3D and Forward Clustered).\n"
        "\n"
        "LEGAL: Uses Saint Peter's Basilica (C) by Emil Persson under CC Attrib 3.0 Unported\n"
        "See Samples/Media/materials/textures/Cubemaps/License.txt for more information." );

        GraphicsSystem *graphicsSystem = new PbsMaterialsGraphicsSystem( gfxGameState );

        gfxGameState->_notifyGraphicsSystem( graphicsSystem );

        *outGraphicsGameState = gfxGameState;
        *outGraphicsSystem = graphicsSystem;
    }

一堆的文字,主要是说明这个sample是做什么的。
这个sample主要是通过代码与通过脚本的方式演示PBS,对场景对象做了一些说明。对于PBS(或者PBR)是什么相信网上应该有很多文章说明。之前有过写PBR的想法,网上已经很详细了,没必要再写一篇。如果哪天有闲了,可以把ogre如何实现PBR的算法细节看一看,写一些。

这个文件很简单,回想之前流程的分析,最终会调用到GameState里。就是被吐槽的createScene0,createScene1。
看看 PbsMaterialsGameState, 就是说,这个类才是真正调用pbs的地方。


PbsMaterialsGameState::createScene01



        Ogre::v1::MeshPtr planeMeshV1 = Ogre::v1::MeshManager::getSingleton().createPlane( "Plane v1",
                                            Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME,
                                            Ogre::Plane( Ogre::Vector3::UNIT_Y, 1.0f ), 50.0f, 50.0f,
                                            1, 1, true, 1, 4.0f, 4.0f, Ogre::Vector3::UNIT_Z,
                                            Ogre::v1::HardwareBuffer::HBU_STATIC,
                                            Ogre::v1::HardwareBuffer::HBU_STATIC );

        Ogre::MeshPtr planeMesh = Ogre::MeshManager::getSingleton().createManual(
                    "Plane", Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME );

        planeMesh->importV1( planeMeshV1.get(), true, true, true );

planeMesh->importV1 这应该是为了兼容1.x的mesh


Ogre::Item *item = sceneManager->createItem  

Item,基于mesh的离散的,可移动的实例。
这个定义怎么那么熟悉呢?这不是跟Entity的定义是一样的吗?

// Defines an instance of a discrete, movable object based on a Mesh.
class _OgreExport Item : public MovableObject, public Resource::Listener
// Defines an instance of a discrete, movable object based on a Mesh.
class _OgreExport Entity : public MovableObject, public Resource::Listener

item应该是特定为hlms设计的。


item->setDatablock( "Marble" );

/// Sets the given HLMS databloock to all SubEntities
    void setDatablock(IdString datablockName);

这个突然冒出来的Marbe是随便定义的还是要跟哪个数据对应呢?
随便改个名字试试,发现有异常,说明不能随便设置。

在运行之前,先修改之前的吐槽点,每次运行的时候都会把调整窗口,然后会发现VS的字体变得很大了,这个应该是分辨率的问题。在窗口创建的时候会发生这种情况。按照流程,找到创建窗口的地方。在GraphicsSystem::initialize里。调试看看,发现,它是全屏模式,但是分辨率又是800x600。这就在运行时把全屏分辨率改成了800x600。这里还有一个坑,如果把分辨率改成屏幕大小,任然全屏,运行时碰到调试代码后,VS会失去焦点,无法点击。所以,只能把全屏去掉。打开ogre.cfg的配置,把 Full Screen=Yes 改为 Full Screen=No.

既然不能随便设置,那么必然存在叫做 Marble 的某个东西。全局搜一下。
找到了,在 Samples\Media\2.0\scripts\materials\PbsMaterials\PbsMaterials.material 里。

hlms Marble pbs
{
	roughness	1.0
	detail_map0				MRAMOR6X6.jpg
	detail_offset_scale0 	0 0 5 5
	roughness_map			MRAMOR-bump.jpg
}

看看这个材质的配置,如果懂pbs或者pbr的同学,大致就懂这几个是干嘛用的了。
注意这个函数的参数,idString,它其实是一个Hash值。


    Ogre::HlmsPbsDatablock *datablock = static_cast<Ogre::HlmsPbsDatablock*>(
    item->getSubItem(0)->getDatablock() );

        Ogre::HlmsSamplerblock samplerblock( *datablock->getSamplerblock( Ogre::PBSM_ROUGHNESS ) );
    samplerblock.mU = Ogre::TAM_WRAP;
    samplerblock.mV = Ogre::TAM_WRAP;
    samplerblock.mW = Ogre::TAM_WRAP;
    //Set the new samplerblock. The Hlms system will
    //automatically create the API block if necessary
    datablock->setSamplerblock( Ogre::PBSM_ROUGHNESS, samplerblock );

获取Datablock,并且设置WarpMode.


    Ogre::HlmsManager *hlmsManager = mGraphicsSystem->getRoot()->getHlmsManager();
    Ogre::HlmsTextureManager *hlmsTextureManager = hlmsManager->getTextureManager();

    assert( dynamic_cast<Ogre::HlmsPbs*>( hlmsManager->getHlms( Ogre::HLMS_PBS ) ) );

    Ogre::HlmsPbs *hlmsPbs = static_cast<Ogre::HlmsPbs*>( hlmsManager->getHlms(Ogre::HLMS_PBS) );

设置完对象属性后,获取HlmsPbs。通过HlmsPbs创建Datablock,并设置属性。


上一个设置是通过script设置的,这个是通过代码设置的。符合之前的一大段的功能描述。

之后也就没什么特别的了,都是基本的场景设置,以及数据修改。

从上面的代码看的出,PBS的用法还是很简单的。就是多了一些专用的类。如果不看详细实现的话,简单易懂。当然,在此之前,需要先把PBS/PBR弄懂。

Hlms 还有 Unlit,但是没找到到sample。
看看代码,找到 OgreHlmsUnlit工程,发现 class HlmsUnlit,全局搜索,看看哪里被引用了。
发现在Sample_Tutorial_Distortion里有使用。很显然,这个sample不是用来说明HlmsUnlit的,那就直接看gamestate里的使用HlmsUnlit的地方。

Sample_Tutorial_Distortion


void DistortionGameState::createScene01(void)
Ogre::String datablockName = "DistMat" + Ogre::StringConverter::toString(i);
Ogre::HlmsUnlitDatablock *datablock = static_cast<Ogre::HlmsUnlitDatablock*>(
    hlmsUnlit->createDatablock(datablockName,
        datablockName,
        macroBlock,
        blendBlock,
        Ogre::HlmsParamVec()));

//Use non-color data as texture type because distortion is stored as x,y vectors to texture.
Ogre::HlmsTextureManager::TextureLocation texLocation = hlmsTextureManager->
    createOrRetrieveTexture("distort_deriv.png",
        Ogre::HlmsTextureManager::TEXTURE_TYPE_NON_COLOR_DATA);

datablock->setTexture(0, texLocation.xIdx, texLocation.texture);

//Set material to use vertex colors. Vertex colors are used to control distortion intensity (alpha value)
datablock->setUseColour(true);
//Random alpha value for objects. Alpha value is multiplier for distortion strenght
datablock->setColour(Ogre::ColourValue(1.0f, 1.0f, 1.0f, Ogre::Math::RangeRandom(0.25f, 0.5f)));

用法与HlmsPbs相同,但是这里是直接通过code来实现的。怎么通过 script实现呢?
在看pbs的材质时,发现,它有指定一个值叫做pbs

hlms AllSettings pbs

这第三个直接就是pbs,那,有没有unlit呢?或者啥都没写的呢?

打开 pbsMaterial.material的文件夹,回退到 material里,没有发现叫什么 Unlit的材质。
全局搜文本,也没有发现,所有的带hlms的材质都有pbs!
各种搜索一无所获!调试了几个sample也没有发现。只剩下慢慢看代码了。


拜拜了您!不干了!

 类似资料: