个人中心

联系我们

搜索 登录 免费注册
界面美化
业务优化
开发工具
图像管理
文档管理
Parasoft

文章详情

如何开始使用SilverLining(中文教程三):资源内存管理

2023-07-07 11:01:23

如何开始使用 SilverLining


本文为如何开始使用SilverLining(中文教程三):资源内存管理,继续查看>>

如何开始使用SilverLining(中文教程一):演示示例

如何开始使用SilverLining(中文教程二):渲染场景

如何开始使用SilverLining(中文教程四):集成技巧

如何开始使用SilverLining(中文教程五):调整外观


使用SilverLining的雾化效果

最后,SilverLining也会给你指导如何为你的场景配置雾。如果你在层状云层内或在降水内,SilverLining会要求你在场景中适当地设置雾气,以模拟在厚厚的云层内或在雨雪中。如果Atmosphere::GetFogEnabled()返回true,那么SilverLining会要求你查询Atmosphere::GetFogSettings(),以获得关于你当前所在的雾量的信息。


即使你不在里面或者不在云层下,SilverLining也可以帮助你设置雾气,使你的远处的地形与天空融为一体。SilverLining不断地计算出当前视野内地平线上的天空的平均颜色,并通过Atmosphere::GetHorizonColor()使其可以访问。将雾的颜色设置为这个颜色,并根据你先前传递给Atmosphere::SetVisibility()的能见度来设置密度,对于有轻度雾霾的场景,将产生真实的结果。


有可能模拟出一层厚厚的、紧贴地面的彩色雾气。如果Atmosphere::GetHorizonColor()不能为你的应用产生理想的结果,这可能是有用的。有效地,这允许你在接近地平线时将天空盒混合成一个指定的颜色。如果你用同样的颜色对你的地形进行雾化,你可以很好地掩盖地平线,而不是将地形一直渲染到地平线。


雾化层是通过Atmosphere::SetHaze()设置的。你可以模拟任何深度的雾霾,任何颜色和任何密度。将深度设置为0来禁用雾霾。重要的是要意识到,没有对雾霾进行光照;如果你想让天空在晚上融合成一个较暗的颜色,你必须预先将雾霾的颜色乘以场景中的光线。


AtmosphericConditions::SetVisibility()可以用来对场景中的云层应用大气透视效果--它使云层随着距离的增加而与天空融合。它不会使天空本身起雾--对于更厚的雾,可以使用Atmosphere::SetHaze()来实现体积式雾,或者使用AtmosphericConditions::SetFog()实现指数式雾。想想看,SetVisibility()只是模拟大气中影响大气透视的微粒物质;它只有在相对高的能见度下才有意义。如果你真的要模拟在雾中,请使用SetFog()代替。


下面是一个在OpenGL下设置雾的例子,使用GetHorizonColor()方法而不是指定颜色的雾化层。注意,这段代码不会导致天空被雾化;它只是为你的应用程序提供指导,让你的场景中的物体朝着与地平线相融合的颜色进行雾化。对于遮蔽天空的较厚的雾,除了这段代码之外,你还需要使用Atmosphere::SetHaze(),或者AtmosphericConditions::SetFog(),并将背景缓冲区清除为雾的颜色。


void SetSceneFog()

{

        glEnable(GL_FOG);

        glFogi(GL_FOG_MODE, GL_EXP);

 

        float hazeDensity = 1.0 / kVisibility;

 

        // Decrease fog density with altitude, to avoid fog effects through the vacuum of space.

        static const double H = 8435.0; // Pressure scale height of Earth's atmosphere

        double isothermalEffect = exp(-(atm->GetConditions()->GetLocation().GetAltitude() / H));     

        if (isothermalEffect <= 0) isothermalEffect = 1E-9;

        if (isothermalEffect > 1.0) isothermalEffect = 1.0;

        hazeDensity *= isothermalEffect;

 

        bool silverLiningHandledTheFog = false;

 

        if (atm->GetFogEnabled())

        {

                float density, r, g, b;

                // Note, the fog color returned is already lit

                atm->GetFogSettings(&density, &r, &g, &b);

 

                if (density > hazeDensity)

                {

                        glFogf(GL_FOG_DENSITY, density);

 

                        GLfloat fogColor[4] = {r, g, b, 1.0};

                        glFogfv(GL_FOG_COLOR, fogColor);

 

                        silverLiningHandledTheFog = true;

                }

        }

        

        if (!silverLiningHandledTheFog)

        {

                GLfloat fogColor[4];

                atm->GetHorizonColor(0, &fogColor[0], &fogColor[1], &fogColor[2]);

                glFogfv(GL_FOG_COLOR, fogColor);

 

                glFogf(GL_FOG_DENSITY, hazeDensity);

        }

}


而这里是设置雾气的等效DirectX9代码:


static void SetSceneFog()

{

        DWORD fogColor;

        float density, r, g, b;

 

        // If you're inside a cloud, SilverLining will request that you set the fog accordingly.

        if (atm->GetFogEnabled())

        {

                atm->GetFogSettings(&density, &r, &g, &b); // This fog color is pre-lit

        }

        else // Otherwise, setting the fog to the average color of the sky at the horizon works well.

        {

                atm->GetHorizonColor(0, &r, &g, &b);

                density = 1.0f / kVisibility;

 

        // Decrease fog density with altitude, to avoid fog effects through the vacuum of space.

        static const double H = 8435.0; // Pressure scale height of Earth's atmosphere

        double isothermalEffect = exp(-(atm->GetConditions()->GetLocation().GetAltitude() / H));

        if (isothermalEffect <= 0) isothermalEffect = 1E-9;

        if (isothermalEffect > 1.0) isothermalEffect = 1.0;

        density *= isothermalEffect;

        }

 

        BYTE cr, cg, cb, ca;

        cr = (BYTE)(r * 255.0);

        cg = (BYTE)(g * 255.0);

        cb = (BYTE)(b * 255.0);

        ca = 255;

 

        fogColor = D3DCOLOR_RGBA(cr, cg, cb, ca);

 

        // Enable fog blending.

        device->SetRenderState(D3DRS_FOGENABLE, TRUE);

 

        // Set the fog color.

        device->SetRenderState(D3DRS_FOGCOLOR, fogColor);

 

        // Set fog parameters.

        device->SetRenderState(D3DRS_FOGTABLEMODE, D3DFOG_EXP);

        device->SetRenderState(D3DRS_FOGDENSITY, *(DWORD *)(&density));

}


同样,DirectX11也是类似的,但是你需要把雾的参数传给你的着色器,而不是传给设备。


这就是它的全部内容了!使用上面的技术,你将能够把SilverLining的天空和云彩渲染整合到你的3D应用程序中,并使你场景中的物体与SilverLining渲染的天空和云彩保持一致的光和雾。


如果你的应用程序指定了它自己的雾--例如,你正在模拟在一个雾库里面--你可以告诉SilverLining把它的云雾变成一个指定的颜色和密度。参见AtmosphericConditions::SetFog()方法以获得更多信息。当你在浓雾中时,你通常会想把你的后部缓冲区清除为雾的颜色,而根本不调用SilverLining。在这种情况下,天空无论如何都是看不到的。当你离开模拟雾库的时候,记住要调用ClearFog(),因为调用SetFog()会覆盖SilverLining中所有其他的大气透视效果。


最后而不是首先绘制你的天幕

我们在上面的说明中描述了调用Atmosphere::DrawSky()作为你框架中的第一件事,以保持事情的简单性,并尽可能地与其他引擎兼容。当你开始整合你的SilverLining时,用这种方法开始是有意义的。然而,在某些情况下,最后而不是首先绘制天幕实际上会带来性能上的好处。


问题是,如果你先画出天幕,那么天幕的很多部分最终会被场景中的物体透支,这就是对填充率的一种浪费。在启用深度读取的情况下,最后画出天幕,只有场景中仍未清除的深度缓冲区的部分才会被天空填充。


要做到这一点,你必须在每一帧开始时自己清除深度缓冲区(但不要清除颜色缓冲区)。 在深度写入开启的情况下绘制场景中的非透明物体。然后,调用Atmosphere::DrawSky(),将clearDepth参数设置为false - 这将告诉SilverLining,你不希望DrawSky()在绘制天空盒之前清除深度缓冲区。最后,调用Atmosphere::DrawObjects()来绘制云层和降水,以及你场景中的半透明物体。


有些引擎根本就不使用深度缓冲区,而是使用深度纹理--这种技术在这种情况下将不起作用。然而,对于那些依赖深度缓冲区的引擎来说,如果你的应用程序是有填充率限制的,这个技术可以导致性能的轻微提升。


与多线程渲染器的集成

人们有时对 "多线程 "有不同的理解,但是SilverLining支持几种不同的方法。


一些引擎可能在不同的程序或线程中执行更新、剪裁和绘制。SilverLining允许你在这样的多线程引擎(比如OpenSceneGraph)中分别执行这些操作以获得更好的性能。


默认情况下,Atmosphere::DrawSky()将执行天空的更新、剪裁和绘制。然而,你可以在Atmosphere::DrawSky()之前调用Atmosphere::UpdateSkyAndClouds()来更新天空的星历模型以及云层的形状和位置。如果在调用Atmosphere::DrawSky()之前没有调用Atmosphere::UpdateSkyAndClouds(),DrawSky()将在渲染之前自行调用UpdateSkyAndClouds()。


同样地,Atmosphere::CullObjects()可以用来在调用Atmosphere::DrawObjects()之外对云层进行剔除。如果在DrawSky()之前没有调用CullObjects(),DrawSky()将自己调用CullObjects()。


一旦Atmosphere::UpdateSkyAndClouds()被调用,你就可以通过Atmosphere::GetCloudBounds()查询场景中的云的边界体积。


线程安全已经到位,以防止更新、剪裁和绘制在SilverLining中同时发生。


然而,你可能会追求真正的多线程渲染,其中命令缓冲区是为不同的视图并行建立的。对于OPENGL32CORE渲染器,我们也支持这一点。


请参考SilverLining::ThreadCameraStreamData类,以了解其工作原理的细节。这基本上是一个为每个视图实例化一些本地存储的问题,并将其作为一个可选的参数传递给SilverLining的方法。这使得SilverLining能够以一种线程安全的方式独立管理每个视图的渲染。在SDK的样本目录中,还有一个OpenGL多线程样本程序,说明如何使用ThreadCameraStream系统来同时渲染三个视图。


请注意,如果你要从不能共享资源的OpenGL上下文中渲染多个视图,你需要将配置设置textures-are-shared设为 "no"。


SilverLining的内存管理

默认情况下,SilverLining将使用new、delete、malloc和free来分配内存。然而,如果你愿意,你可以将SilverLining的内存管理重定向到你自己的内存管理器中。


SilverLining::Allocator类定义在公共头文件MemAlloc.h中。如果你扩展这个类,你可以实现你自己的Allocator::alloc()和Allocator::dealloc()方法来管理内存。在创建任何SilverLining对象之前,将你的Allocator派生类的实例化传递给Allocator::SetAllocator(),SilverLining库和渲染DLL将使用你自己的分配方案。


Allocator将捕获SilverLining中对new、delete、malloc和free的所有调用。SilverLining中的每个对象都派生自SilverLining::MemObject类,它重载了new和delete操作符,而不是全局重载new和delete。我们的STL对象也使用一个自定义的分配器,它通过SilverLining::Allocator进行分配。宏SL_VECTOR、SL_MAP、SL_LIST和SL_STRING被用来作为使用我们的分配器的STL对象的一种便利。


SilverLining的资源管理

默认情况下,SilverLining将直接从磁盘加载它的纹理、数据和着色器资源,相对于你在Atmosphere::Initialize()中指定的资源目录的路径。然而,SilverLining中所有的磁盘访问都被一个ResourceLoader类所抽象,所以你有能力钩住任何你希望的资源管理方案。


关于更多的细节,请看ResourceLoader的文档。例如,如果你想把SilverLining的所有数据、纹理和着色器包含在你自己的包文件中,你可以扩展ResourceLoader类并把它挂到你自己的资源管理器中。然后,在调用Atmosphere::Initialize()之前,将一个指向你派生的ResourceLoader的指针传入Atmosphere::SetResourceLoader(),所有的磁盘访问都将通过你自己的资源管理器进行。


值得注意的是,SilverLining的渲染器DLL也在我们的资源文件夹中,Windows必须直接从磁盘加载这些DLL。因此,尽管你可以将 SilverLining 中的所有其它资源移到一个虚拟文件系统中,但你确实需要至少保留一个包含渲染器 DLL 的资源文件夹。如果你想避免这种情况,你可以重建SilverLining库,以便静态地链接你想要的渲染器,并完全消除DLL的依赖性。获得授权的客户可以在SilverLining项目文件中找到构建目标,将OpenGL或各种DirectX渲染器直接静态地链接到SilverLining库中。


叠层云层

在你的场景中使用STRATOCUMULUS云层时要小心,它们是使用GPU光线投射渲染的,并且依赖于一个复杂的片段程序。与其他几乎可以在任何硬件上运行的云层不同,层积云确实需要一个支持Shader Model 3.0的系统,以及一个拥有快速碎片处理器的较新的GPU。如果你在已知的现代图形硬件上运行模拟,层积云层会给你带来每个碎片的光照和极其密集的云层,并且渲染时间不变。然而,对于系统要求不太受控制的消费者应用,你可能想坚持使用积云云层来代替。


还有一种新的STRATOCUMULUS_PARTICLES云类型,对你来说可能是更好的选择。和层积云一样,它表示非常密集的低云层--但它使用广告牌粒子而不是GPU光线投射。对于大型密集云层来说,它可以是一个非常有效的选择。


模拟沙尘暴

SilverLining包括一个SANDSTORM云层类型,用来模拟沙暴、沙尘暴或 "哈布"。


沙尘暴的基本高度应该等于你当地的地面高度。它们使用 "软粒子",以避免在你指定的高度上云层与地面相交时出现假象。


没有必要指定沙暴的厚度或密度。下面是一个设置50公里x50公里沙暴的例子,它位于距原点25公里处,地面高度为海平面:


// Sandstorms should be positioned at ground level. There is no need to set their

// density or thickness.

static void SetupSandstorm()

{

    CloudLayer *sandstormLayer;

 

    sandstormLayer = CloudLayerFactory::Create(SANDSTORM, *atm);

    sandstormLayer->SetIsInfinite(false);

    sandstormLayer->SetLayerPosition(0, -25000);

    sandstormLayer->SetBaseAltitude(0);

    sandstormLayer->SetBaseLength(50000);

    sandstormLayer->SetBaseWidth(50000);

    sandstormLayer->SeedClouds(*atm);

 

    atm->GetConditions()->AddCloudLayer(sandstormLayer); 

}


如果你有任何问题,请随时联系我们 https://www.dhorde.com/ 在线客服,电话 023-62585653,或邮箱 sales@dhorde.com


本文为如何开始使用SilverLining(中文教程三):资源内存管理,继续查看>>

如何开始使用SilverLining(中文教程一):演示示例

如何开始使用SilverLining(中文教程二):渲染场景

如何开始使用SilverLining(中文教程四):集成技巧

如何开始使用SilverLining(中文教程五):调整外观


联系我们

周一至周日 8:00-23:00

免费热线

023-62585653

Gavin:13082556879

Jillian:17558866126

Angela:13057566525

开发外包

ERP-一体化

小程序

企业微信客服二维码

企业微信客服

版权所有:重庆庚乾信息科技有限公司 ©2025 Gengqian Information Technology Co., Ltd. 渝ICP备2022008063号-2 渝公网安备50010702505508

版权所有:重庆庚乾信息科技有限公司

©2025 Gengqian Information Technology Co., Ltd. 渝ICP备2022008063号-2 渝公网安备50010702505508