本文主要是介绍【UE4源代码观察】观察TargetPlatform模块,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
前情提要与本次目标
在之前的博客《【UE4源代码观察】观察 RHI、D3D11RHI、RenderCore 这三个模块的依赖关系》中,我将RHI
、D3D11RHI
、RenderCore
这三个模块加入了我的空白工程中并确保可以成功编译。然而当时RenderCore
模块有一个比较大的缺失:没有让shader相关的功能正常编译,因为它需要TargetPlatform
模块中的内容。
因此,这次我想观察一下这个模块,并希望能完成下面目标:
- 了解这个模块的大体结构是什么,大概要做些什么事情
- 将这个模块加入到我的空白工程中,至少保证
RenderCore
模块中的shader相关功能可以正常编译,其他暂时用不到的部分如果比较麻烦可以先放弃。
观察:模块类
在TargetPlatformManagerModule.cpp
中指定了这个模块由FTargetPlatformManagerModule
类来实现:
IMPLEMENT_MODULE(FTargetPlatformManagerModule, TargetPlatform);
而FTargetPlatformManagerModule
继承了ITargetPlatformManagerModule
:
/*** Module for the target platform manager*/
class FTargetPlatformManagerModule: public ITargetPlatformManagerModule
由于FTargetPlatformManagerModule
是定义在cpp文件中的,所以不会在其他地方发现有他的继承者了。
这个模块有一个和其他大多数模块醒目的区别:除了上面的FTargetPlatformManagerModule
这一模块类,这个模块里还有其他IModuleInterface
类,而他们每一个都对应了一个格式的领域,定义了这个领域中格式的模块的通用接口。下面逐个看下这些领域:
IAudioFormatModule
它有如下子类(分别被定义到了各自独立的模块中):
FAudioPlatformADPCMModule
FAudioPlatformOggModule
FAudioPlatformOpusModule
IAudioFormatModule
只定义了一个函数:
/**
* Gets the audio format.** @return The audio format interface.*/
virtual IAudioFormat* GetAudioFormat() = 0;
而IAudioFormat
同样定义在TargetPlatform
模块中:
/*** Interface for audio formats.*/
class IAudioFormat
它的子类如下:
FAudioFormatADPCM
FAudioFormatOgg
FAudioFormatOpus
和模块一一对应。
IShaderFormatModule
它有如下子类(分别被定义到了各自独立的模块中):
FMetalShaderFormatModule
FShaderFormatOpenGLModule
FShaderFormatVectorVMModule
FVulkanShaderFormatModule
FShaderFormatD3DModule
IShaderFormatModule
只定义了一个函数:
/**
* Gets the shader format.** @return The shader format interface.*/
virtual IShaderFormat* GetShaderFormat() = 0;
而IShaderFormat
同样定义在TargetPlatform
模块中:
/*** IShaderFormat, shader pre-compilation abstraction*/
class IShaderFormat
它的子类如下:
FMetalShaderFormat
FShaderFormatGLSL
FShaderFormatVectorVM
FShaderFormatVulkan
FShaderFormatD3D
和模块一一对应。
ITextureFormatModule
它有如下子类(分别被定义到了各自独立的模块中):
FTextureFormatAndroidModule
FTextureFormatASTCModule
FTextureFormatDXTModule
FTextureFormatIntelISPCTexCompModule
FTextureFormatPVRModule
FTextureFormatUncompressed
ITextureFormatModule
只定义了一个函数:
/*** Gets the texture format.** @return The texture format interface.*/
virtual ITextureFormat* GetTextureFormat() = 0;
而ITextureFormat
同样定义在TargetPlatform
模块中:
/*** Interface for texture compression modules.*/
class ITextureFormat
它的子类如下:
FTextureFormatAndroid
FTextureFormatASTC
FTextureFormatDXT
FTextureFormatIntelISPCTexComp
FTextureFormatPVR
FTextureFormatUncompressed
和模块一一对应。
ITargetPlatformModule
之前三个的情况都类似,而ITargetPlatformModule
与他们则差别很大,ITargetPlatformModule
和ITargetPlatform
的关系变得更复杂了。
对于ITargetPlatformModule
,它的子类如下:
ITargetPlatformModule
有一个函数来获得一个ITargetPlatform
:
virtual ITargetPlatform* GetTargetPlatform()
{return nullptr;
};
还有一个函数来获得多个ITargetPlatform
:
/**
* Gets the module's target platforms. This should be overridden by each platform, but * currently, we are re-using the single internal GetTargetPlatform method the old TPModules will implement** @return The target platform.*/
virtual TArray<ITargetPlatform*> GetTargetPlatforms()
{TArray<ITargetPlatform*> TargetPlatforms;ITargetPlatform* TargetPlatform = GetTargetPlatform();if (TargetPlatform != nullptr){TargetPlatforms.Add(TargetPlatform);}return TargetPlatforms;
}
看来,ITargetPlatformModule
可能对应一个或多个,但外界应该总是访问TArray<ITargetPlatform*> GetTargetPlatforms()
。如果对应一个,则直接重写ITargetPlatform* GetTargetPlatform
函数,此时TArray<ITargetPlatform*> GetTargetPlatforms()
仍旧可以正确返回。而如果是对应多个,则直接重写TArray<ITargetPlatform*> GetTargetPlatforms()
。
对于ITargetPlatform
,它有一个唯一的子类:
/*** Base class for target platforms.*/
class TARGETPLATFORM_VTABLE FTargetPlatformBase : public ITargetPlatform
随后,FTargetPlatformBase
也有一个唯一的子类:
/*** Template for target platforms.** @param TPlatformProperties Type of platform properties.*/
template<typename TPlatformProperties>
class TTargetPlatformBase : public FTargetPlatformBase
而TTargetPlatformBase
则由丰富的子类继承关系:
模块在返回ITargetPlatform
是可以指定模板的参数的,例如:
FWindowsTargetPlatformModule
对应的是:
virtual ITargetPlatform* GetTargetPlatform( ) override
{if (Singleton == nullptr && TGenericWindowsTargetPlatform<true, false, false>::IsUsable()){Singleton = new TGenericWindowsTargetPlatform<true, false, false>();}return Singleton;
}
而FWindowsServerTargetPlatformModule
对应的是:
virtual ITargetPlatform* GetTargetPlatform( )
{if (Singleton == nullptr && TGenericWindowsTargetPlatform<false, true, false>::IsUsable()){Singleton = new TGenericWindowsTargetPlatform<false, true, false>();}return Singleton;
}
观察:如何获取格式
对于Audio、Shader、Texture,ITargetPlatformManagerModule
分别定义了GetAudioFormats
、GetShaderFormats
、GetTextureFormats
函数来获取所有格式,这些函数的实现可以在FTargetPlatformManagerModule
中被找到,方法都是相同的:通过模块的名字来找。例如对于Audio:
TArray<FName> Modules;FModuleManager::Get().FindModules(TEXT("*AudioFormat*"), Modules);if (!Modules.Num())
{UE_LOG(LogTargetPlatformManager, Error, TEXT("No target audio formats found!"));
}for (int32 Index = 0; Index < Modules.Num(); Index++)
{IAudioFormatModule* Module = FModuleManager::LoadModulePtr<IAudioFormatModule>(Modules[Index]);if (Module){IAudioFormat* Format = Module->GetAudioFormat();if (Format != nullptr){Results.Add(Format);}}
}
尝试寻找名字中带有AudioFormat的模块,随后将这些模块尝试转为IAudioFormatModule
类型,如果成功的话就调用GetAudioFormat()
函数来获得IAudioFormat
。
对于Texture,方法是一样的,只不过关键字为TextureFormat。对于Shader则是ShaderFormat。
此外值得一提的是,PhysXCooking似乎也被看作一个格式,GetPhysXCooking()
函数也是类似的操作,在寻找开头为PhysXCooking的IPhysXCookingModule
类型的模块,之后想得到IPhysXCooking
类。IPhysXCookingModule
和IPhysXCooking
都不在TargetPlatform模块中定义,而是在PhysicsCore
模块中定义:
/*** Interface for PhysX format modules.*/
class PHYSICSCORE_API IPhysXCookingModule : public IModuleInterface
/*** IPhysXCooking, PhysX cooking and serialization abstraction
**/
class PHYSICSCORE_API IPhysXCooking
不过,它最终只获得了一个格式:
我想,既然在TargetPlatform模块
中出现,那我想应该是过去存在或是未来将要存在这种格式的多个实例?
而ITargetPlatform的情况则稍微复杂些。首先,FTargetPlatformManagerModule
拥有一个ITargetPlatform
的列表:
// Holds the list of discovered platforms.
TArray<ITargetPlatform*> Platforms;
GetTargetPlatforms
函数实际是返回这个列表,实际获得这个列表的值是通过DiscoverAvailablePlatforms
函数完成的。
virtual const TArray<ITargetPlatform*>& GetTargetPlatforms() override
{if (Platforms.Num() == 0 || bForceCacheUpdate){DiscoverAvailablePlatforms();}return Platforms;
}
关于Platforms
列表的逻辑我没有深究,简单来看还和FPlatformInfo
有关:
对于每一个FPlatformInfo
,都试图得到一个ITargetPlatformModule
:
// there are two ways targetplatform modules are setup: a single DLL per TargetPlatform, or a DLL for the platform
// that returns multiple TargetPlatforms. we try single first, then full platform
FName FullPlatformModuleName = *(PlatInfo.IniPlatformName + TEXT("TargetPlatform"));
FName SingleTargetPlatformModuleName = *(PlatInfo.TargetPlatformName.ToString() + TEXT("TargetPlatform"));
bool bFullPlatformModuleNameIsValid = !PlatInfo.IniPlatformName.IsEmpty();ITargetPlatformModule* Module = nullptr;if (FModuleManager::Get().ModuleExists(*SingleTargetPlatformModuleName.ToString()))
{Module = FModuleManager::LoadModulePtr<ITargetPlatformModule>(SingleTargetPlatformModuleName);
}
else if (bFullPlatformModuleNameIsValid && FModuleManager::Get().ModuleExists(*FullPlatformModuleName.ToString()))
{Module = FModuleManager::LoadModulePtr<ITargetPlatformModule>(FullPlatformModuleName);
}
最终得到的数目比FPlatformInfo
的数目要少:
观察:依赖模块
对TargetPlatform.Build.cs
文件进行观察:
1.依赖模块:
PrivateDependencyModuleNames.Add("Core");
PrivateDependencyModuleNames.Add("SlateCore");
PrivateDependencyModuleNames.Add("Slate");
PrivateDependencyModuleNames.Add("EditorStyle");
PrivateDependencyModuleNames.Add("Projects");
PublicDependencyModuleNames.Add("AudioPlatformConfiguration");
PublicDependencyModuleNames.Add("DesktopPlatform");
PublicDependencyModuleNames.Add("LauncherPlatform");
2.需要include的模块:
PrivateIncludePathModuleNames.Add("Engine");
PrivateIncludePathModuleNames.Add("PhysicsCore");
3. 动态加载的模块
动态加载的模块有很多条件。
首先是PhysXCooking
模块:
if (Target.bBuildDeveloperTools == true && Target.bBuildRequiresCookedData && Target.bCompileAgainstEngine && Target.bCompilePhysX)
{DynamicallyLoadedModuleNames.Add("PhysXCooking");
}
剩下的所有模块的条件都是:
// no need for all these modules if the program doesn't want developer tools at all (like UnrealFileServer)
if (!Target.bBuildRequiresCookedData && Target.bBuildDeveloperTools)
首先是一些所有平台都需要的模块:
// these are needed by multiple platform specific target platforms, so we make sure they are built with the base editor
DynamicallyLoadedModuleNames.Add("ShaderPreprocessor");
DynamicallyLoadedModuleNames.Add("ShaderFormatOpenGL");
DynamicallyLoadedModuleNames.Add("ImageWrapper");
其中ShaderPreprocessor
和ImageWrapper
是目前还不了解的,之后待研究。
而剩下的都是上面讨论的一些和一个格式对应的模块,他们根据平台有不同的情况,具体如下:
TargetPlatform是Win32/Win64 | TargetPlatform是Mac | InPlatformGroup(Linux) | |
---|---|---|---|
- | TextureFormatDXT | TextureFormatDXT | TextureFormatDXT |
TextureFormatPVR | TextureFormatPVR | TextureFormatPVR | |
TextureFormatASTC | TextureFormatASTC | TextureFormatASTC | |
TextureFormatUncompressed | TextureFormatUncompressed | TextureFormatUncompressed | |
TextureFormatIntelISPCTexComp | - | - | |
ShaderFormatOpenGL | ShaderFormatOpenGL | ShaderFormatOpenGL | |
ShaderFormatD3D | - | - | |
MetalShaderFormat | - | - | |
bCompileAgainstEngine | AudioFormatADPCM | AudioFormatADPCM | AudioFormatADPCM |
AudioFormatOgg | AudioFormatOgg | AudioFormatOgg | |
AudioFormatOpus | AudioFormatOpus | AudioFormatOpus | |
TargetType是Editor或Program | AndroidTargetPlatform | AndroidTargetPlatform | AndroidTargetPlatform |
IOSTargetPlatform | IOSTargetPlatform | - | |
TVOSTargetPlatform | TVOSTargetPlatform | - | |
MacTargetPlatform | - | - | |
MacNoEditorTargetPlatform | - | - | |
MacServerTargetPlatform | - | - | |
MacClientTargetPlatform | - | - |
这么看来Windows平台上模块是最全的?
另外值得一提的是,我发现:还有的依赖模块是上面分析的.Build.cs
文件中所没有的。最后找到在UnrealBuildTool
中还有操作:
在\Engine\Source\Programs\UnrealBuildTool\Platform
路径中,有
这些文件夹,例如对于Windows,有UEBuildWindows.cs
文件,有一个ModifyModuleRulesForActivePlatform
函数:
/// <summary>
/// Modify the rules for a newly created module, in a target that's being built for this platform.
/// This is not required - but allows for hiding details of a particular platform.
/// </summary>
/// <param name="ModuleName">The name of the module</param>
/// <param name="Rules">The module rules</param>
/// <param name="Target">The target being build</param>
public override void ModifyModuleRulesForActivePlatform(string ModuleName, ModuleRules Rules, ReadOnlyTargetRules Target)
这个函数尝试改变一些模块依赖,例如这里指定了为TargetPlatform模块
增加了一些模块
:
// allow standalone tools to use target platform modules, without needing Engine
if (ModuleName == "TargetPlatform")
{if (Target.bForceBuildTargetPlatforms){Rules.DynamicallyLoadedModuleNames.Add("WindowsTargetPlatform");Rules.DynamicallyLoadedModuleNames.Add("WindowsNoEditorTargetPlatform");Rules.DynamicallyLoadedModuleNames.Add("WindowsServerTargetPlatform");Rules.DynamicallyLoadedModuleNames.Add("WindowsClientTargetPlatform");Rules.DynamicallyLoadedModuleNames.Add("AllDesktopTargetPlatform");}if (bBuildShaderFormats){Rules.DynamicallyLoadedModuleNames.Add("ShaderFormatD3D");Rules.DynamicallyLoadedModuleNames.Add("ShaderFormatOpenGL");Rules.DynamicallyLoadedModuleNames.Remove("VulkanRHI");Rules.DynamicallyLoadedModuleNames.Add("VulkanShaderFormat");}
}
如果要改动这些内容,则需用先重新编译UBT,然后再编译代码。
实践1:补充模块
1. ShaderPreprocessor模块以及相关模块
TargetPlatform模块
需要ShaderPreprocessor模块
,这个模块的依赖关系比较简单:
PrivateDependencyModuleNames.AddRange(new string[] {"Core","RenderCore",});
AddEngineThirdPartyPrivateStaticDependencies(Target, "MCPP");
Core
和RenderCore
都已经在工程中了,而MCPP
这个第三方模块还没有。
ShaderPreprocessor
看起来是个编译shader的一个重要模块,不过现阶段我想关注的是大体结构,而不是具体细节,因此我选择直接将这两个模块都拷贝。
2. ShaderCompilerCommon模块以及相关模块
ShaderCompilerCommon
被ShaderFormatOpenGL
和ShaderFormatD3D
这种提供shader格式的模块所依赖,它的依赖关系也比较简单:
PrivateDependencyModuleNames.AddRange(new string[] {"Core","RenderCore",});// We only need a header containing definitions
PublicSystemIncludePaths.Add("ThirdParty/hlslcc/hlslcc/src/hlslcc_lib");
hlslcc
也是个第三方模块,应该和HLSL的shader编译有关
2.ShaderFormatD3D相关
对于D3D,还需要有dll,否则之后会报错:
1>UnrealBuildTool : error : Unhandled exception: Source file 'D:\0_WorkSpace\UEYaksueTest\Engine\Binaries\ThirdParty\Windows\DirectX\x64\dxil.dll' does not exist
1> while creating runtime dependencies for module 'ShaderFormatD3D'
因此将\Engine\Binaries\ThirdParty\Windows\DirectX\
拷贝。
3. OpenGL模块以及相关模块
ShaderFormatOpenGL模块
的Build.cs
内容如下:
PrivateIncludePathModuleNames.Add("TargetPlatform");PrivateIncludePaths.Add("Runtime/OpenGLDrv/Private");
PrivateIncludePaths.Add("Runtime/OpenGLDrv/Public");PrivateDependencyModuleNames.AddRange(new string[] {"Core","RenderCore","ShaderCompilerCommon","ShaderPreprocessor","RHI" // @todo platplug: this is caused by the DataDrivenShaderPlatformInfo stuff - maybe it should move to somewhere else, like RenderCore?});AddEngineThirdPartyPrivateStaticDependencies(Target, "OpenGL","HLSLCC");if (Target.IsInPlatformGroup(UnrealPlatformGroup.Linux)){AddEngineThirdPartyPrivateStaticDependencies(Target, "SDL2");}
if (Target.Platform == UnrealTargetPlatform.Mac || Target.Platform == UnrealTargetPlatform.Win64)
{AddEngineThirdPartyPrivateStaticDependencies(Target,"ShaderConductor","SPIRVReflect");
}if (Target.Platform == UnrealTargetPlatform.Win64)
{PublicDelayLoadDLLs.Add("dxcompiler_sc.dll");PublicDelayLoadDLLs.Add("ShaderConductor.dll");
}
其中涉及到的ShaderConductor
和SPIRVReflect
都是第三方模块,(其中SPIRV应该是指Vulkan的 SPIR-V shader格式)。将其拷贝。
另外要注意的是,它还需要include OpenGLDrv
这个模块的头文件,于是我将其拷贝过来,但是暂时先删除头文件之外其他的文件。
此外,还需要拷贝ShaderConductor.lib
文件,不然会有报错:
fatal error LNK1181: 无法打开输入文件“..\Binaries\ThirdParty\ShaderConductor\Win64\ShaderConductor.lib”
4. VulkanShaderFormat模块相关
VulkanShaderFormat
依赖了Vulkan
这个第三方模块。
VulkanShaderFormat
还依赖了 GlsLang
模块,我看这里有个EPIC-Changes.txt
文件,看来他们对里面的内容做了些改变。
5. 其他
DesktopPlatform
和LauncherPlatform
是所依赖的。但他们自己所依赖的模块较少,直接添加进来就没有问题。
实践2: 去掉一些暂时用不到的内容
1.Slate相关
TargetPlatform
需要slate相关的模块是我暂时所不能理解的。我暂时将.Build.cs
中对SlateCore模块
和Slate模块
的依赖给去掉。
随后,我将界面相关的文件SDeviceBrowserDefaultPlatformAddWidget.h/cpp
和DeviceBrowserDefaultPlatformWidgetCreator.h/cpp
给去掉。
我看到了FTargetPlatformBase::GetCustomWidgetCreator
函数用到了上面的内容:
TSharedPtr<IDeviceManagerCustomPlatformWidgetCreator> FTargetPlatformBase::GetCustomWidgetCreator() const
{static TSharedPtr<FDeviceBrowserDefaultPlatformWidgetCreator> DefaultWidgetCreator = MakeShared<FDeviceBrowserDefaultPlatformWidgetCreator>();return DefaultWidgetCreator;
}
于是我暂时将它去掉:
TSharedPtr<IDeviceManagerCustomPlatformWidgetCreator> FTargetPlatformBase::GetCustomWidgetCreator() const
{//static TSharedPtr<FDeviceBrowserDefaultPlatformWidgetCreator> DefaultWidgetCreator = MakeShared<FDeviceBrowserDefaultPlatformWidgetCreator>();//return DefaultWidgetCreator;return nullptr;//yaksuetest
}
2.PHYSX相关
TargetPlatform
模块中的WITH_PHYSX宏
制定了是否编译PHYSX相关的内容。
在UBT中有对这个宏的逻辑:在\Engine\Source\Programs\UnrealBuildTool\Configuration\ModuleRules.cs
中:
// definitions used outside of PhysX/APEX need to be set here, not in PhysX.Build.cs or APEX.Build.cs,
// since we need to make sure we always set it, even to 0 (because these are Private dependencies, the
// defines inside their Build.cs files won't leak out)
if (Target.bCompilePhysX == true)
{PrivateDependencyModuleNames.Add("PhysX");PublicDefinitions.Add("WITH_PHYSX=1");
}
else
{PublicDefinitions.Add("WITH_PHYSX=0");
}
但是,我在编译时遇到的错误是(这些文件都用到了这个宏):
1>D:/0_WorkSpace/UEYaksueTest/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformManagerModule.cpp(24): error C4668: 没有将“WITH_PHYSX”定义为预处理器宏,用“0”替换“#if/#elif”
1>D:/0_WorkSpace/UEYaksueTest/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformManagerModule.cpp(550): error C4668: 没有将“WITH_PHYSX”定义为预处理器宏,用“0”替换“#if/#elif”
1>D:/0_WorkSpace/UEYaksueTest/Engine/Source/Developer/TargetPlatform/Private/TargetPlatformManagerModule.cpp(584): error C4668: 没有将“WITH_PHYSX”定义为预处理器宏,用“0”替换“#if/#elif”
提示的是没有将“WITH_PHYSX”定义为预处理器宏,用“0”替换“#if/#elif”
,这说明这个宏就没有被定义(不管是0还是1),也就是说上面UBT里的逻辑并没有走到。
目前我还不清楚这是为什么,现在我只能在TargetPlatform.Build.cs
中加入这个宏(值是0,暂时不想使用它):
PublicDefinitions.Add("WITH_PHYSX=0");//yaksuetest
我知道这不是引擎原本的方法,希望之后能搞明白这个问题。
3.TextureFormat相关
注释掉相关的模块:
//DynamicallyLoadedModuleNames.Add("TextureFormatDXT");
//DynamicallyLoadedModuleNames.Add("TextureFormatPVR");
//DynamicallyLoadedModuleNames.Add("TextureFormatASTC");//DynamicallyLoadedModuleNames.Add("TextureFormatUncompressed");
4.Audio相关
注释掉相关的模块:
//DynamicallyLoadedModuleNames.Add("AudioFormatOgg");
//DynamicallyLoadedModuleNames.Add("AudioFormatOpus");
//DynamicallyLoadedModuleNames.Add("AudioFormatADPCM");
实践3:确保RenderCore模块中Shader部分可编译
1. Core模块中的TargetPlatform部分
首先,在之前《【UE4源代码观察】观察Core模块》时候,为了保证Core
模块能编译,我将Build.cs
文件中我注释掉了PrivateIncludePathModuleNames中的内容,现在,是时候放出TargetPlatform
了:
PrivateIncludePathModuleNames.AddRange(new string[] {"TargetPlatform",/*"DerivedDataCache","InputDevice","Analytics","RHI"*/});
随后,可以将之前在CoreMisc.cpp
中对于TargetPlatform
的注释去掉:
#include "Interfaces/ITargetPlatformManagerModule.h"
使得下面两个函数可用:
class ITargetPlatformManagerModule* GetTargetPlatformManager()
{static class ITargetPlatformManagerModule* SingletonInterface = NULL;if (!FPlatformProperties::RequiresCookedData()){static bool bInitialized = false;if (!bInitialized){check(IsInGameThread());bInitialized = true;SingletonInterface = FModuleManager::LoadModulePtr<ITargetPlatformManagerModule>("TargetPlatform");}}return SingletonInterface;
}class ITargetPlatformManagerModule& GetTargetPlatformManagerRef()
{class ITargetPlatformManagerModule* SingletonInterface = GetTargetPlatformManager();if (!SingletonInterface){UE_LOG(LogInit, Fatal, TEXT("Target platform manager was requested, but not available."));CA_ASSUME( SingletonInterface != NULL ); // Suppress static analysis warning in unreachable code (fatal error)}return *SingletonInterface;
}
这两个函数被RenderCore
中的代码用到了很多次。
2. RenderCore模块中的TargetPlatform部分
首先,将RenderCore.Build.cs
中对TargetPlatform
的注释去掉。
之后,恢复掉之前TargetPlatform
的注释,具体来说是下面的几个文件:
Engine\Source\Runtime\RenderCore\Private\RenderUtils.cpp
Engine\Source\Runtime\RenderCore\Private\Shader.cpp
Engine\Source\Runtime\RenderCore\Private\ShaderCodeLibrary.cpp
Engine\Source\Runtime\RenderCore\Private\ShaderCore.cpp
随后,编译成功。
总结
这一篇我观察了TargetPlatform模块
的大体结构,并且将之前代码中注释掉的TargetPlatform
部分恢复,使得其Shader相关的部分可以编译。然而,这并不是说Shader相关的部分可以使用了,加断点可以看到:
这一块是CompileGlobalShaderMap
这个函数调用的,而它是Engine
模块的内容。这块想必是很重要的,接下来值得研究。
这篇关于【UE4源代码观察】观察TargetPlatform模块的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!