在编辑器打开时,会从资源包中LoadPackage,我们这里只关心的是材质问题。每一个Obj,都会调用自己的Obj->ConditionalPostLoad()
这里已经是在加载的后端了,在这里面会调用子类的PostLoad()
1
2
3
4
5
6
7
8
9
10
|
for (int32 i = 0; i < ObjLoaded.Num(); i++)
{
UObject* Obj = ObjLoaded[i];
check(Obj);
#if WITH_EDITOR
//一顿操作
#endif
//又一顿操作
Obj->ConditionalPostLoad();
}
|
我们只看 UMaterial::PostLoad,如果调用到这里,也就是说我们加载的是一个材质。这是一个非常长的函数。就不在这里展开了。
这里会调用他父类的PostLoad
,而UMaterial
的父类就是UMaterialInterface
,而他们的区别,和主要的成员分析见Unreal Material类的关系
在UMaterialInterface::PostLoad()
中又会调用UMaterial::CacheResourceShadersForRendering
- Cache resource shaders for rendering.
- If a matching shader map is not found in memory or the DDC, a new one will be compiled.(关于什么是DDC,听过很多次)
- The results will be applied to this FMaterial in the renderer when they are finished compiling.
- Note: This modifies material variables used for rendering and is assumed to be called within a FMaterialUpdateContext!
1
2
3
|
RebuildShadingModelField();//我们首先把ShadingModel重新计算,
FlushResourceShaderMaps();//将我们最终要渲染的MaterialResources,进行卸载
CacheShadersForResources(ShaderPlatform, ResourcesToCache, true);
|
这里是只对我们将渲染到的level进行cache,在cooked build中,没有着色器编译,但这仍然是注册加载的shadermap(啥?)
CacheShadersForResources这是最主要的函数,我们将要进去,看它是如何进行cache,并且看它都cache的什么东西。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
void UMaterial::CacheShadersForResources(……)
{
RebuildExpressionTextureReferences();//就按字面意思理解把
//对每一个将要resource
for (int32 ResourceIndex = 0; ResourceIndex < ResourcesToCache.Num(); ResourceIndex++)
{
FMaterialResource CurrentResource = ResourcesToCache[ResourceIndex];
//最终cache的地方
const bool bSuccess = CurrentResource->CacheShaders(ShaderPlatform, bApplyCompletedShaderMapForRendering);
if (!bSuccess)
{
//如果出现错误的log
}
}
}
|
从上面可以看出,我们最终的cache还是要在回到FMaterialResource身上,这里只是做了保护而已,所以继续往下。
1
2
3
4
5
6
|
bool FMaterial::CacheShaders(……)
{
FMaterialShaderMapId NoStaticParametersId;
GetShaderMapId(Platform, NoStaticParametersId);
return CacheShaders(NoStaticParametersId, Platform, bApplyCompletedShaderMapForRendering);
}
|
这里我们终于来到了一个新的天地,因为我们终于不在Umaterial里面了,而是在FMaterialResource的父类FMaterial里面,
这里主要有两个重要函数
一个是FMaterialResource::GetShaderMapId ,另一个是CacheShaders
FMaterialResource::GetShaderMapId
首先就是调用父类的FMaterial::GetShaderMapId(Platform, OutId);这里最终得到的是FMaterialShaderMapId
关于这个结构体和其他相关结构体的内容可以参见Material相关类
GetShaderMapId:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
if (bLoadedCookedShaderMapId)
{
//开始做的判断是是否已经加载了这个material的shadermap,如果有的话我们还要判断是在哪个线程中就从GameThreadShaderMap获取还是RenderingThreadShaderMap获取。
}
else
{
#if WITH_EDITOR
TArray<FShaderType> ShaderTypes;
TArray<FVertexFactoryType> VFTypes;
TArray<const FShaderPipelineType*> ShaderPipelineTypes;
GetDependentShaderAndVFTypes(Platform, ShaderTypes, ShaderPipelineTypes, VFTypes);
//省略赋值
GetReferencedTexturesHash(Platform, OutId.TextureReferencesHash);
#else
//省略赋值 log
#endif
}
|
最开始做的判断是是否已经加载了这个material的shadermap,如果有的话我们还要判断是在哪个线程中就从GameThreadShaderMap获取还是RenderingThreadShaderMap获取。
GetDependentShaderAndVFTypes
否则的话,我们就需要进行ShaderMap的填充,GetDependentShaderAndVFTypes就是填充的关键。
- 对所有的VertexFactoryType进行判断
- 这个顶点工厂必须是使用在Material里的
- 从每一个FShaderType中得到FMeshMaterialShaderType,如果FMeshMaterialShaderType不是空&&FMeshMaterialShaderType可以cache这个VertexFactoryType,那么我们就允许增加这个AddUnique(ShaderType),并且在最后的时候会增加这个VertexFactoryType
- 从每一个FShaderPipelineType判断是否用于meshmaterial,并且要判断FShaderPipelineType里面所有的shadertype的,如果它里面的所有的shader都通过判断,那么我们就增加这个FShaderPipelineType
- 对所有的FShaderType进行判断
- 和上面的一样,不过判断条件VertexFactoryType改为了null
- 对所有的FShaderPipelineType进行判断
- 同上
其实我们只是对判断依据感兴趣而已。
todo:判断条件是传进来的函数指针,还没有搞清楚来源
这样,我们就讨论完了GetShaderMapId
FMaterialShaderMapId::SetShaderDependencies
下面的函数时FMaterialShaderMapId::SetShaderDependencies,主要就是记录它的hash值,然后记录下来,这里的疑问就出来了。
当我们的FMaterial::GetShaderMapId分析完后,我们就要回到 FMaterialResource::GetShaderMapId里面
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
//这是把所有的材质里使用到的函数,加到OutId.ReferencedFunctions中
Material->AppendReferencedFunctionIdsTo(OutId.ReferencedFunctions);
//这是把所有的材质里使用到的parameter collection,加到OutId.ReferencedParameterCollections中s
Material->AppendReferencedParameterCollectionIdsTo(OutId.ReferencedParameterCollections);
//添加texture的哈希值
Material->GetForceRecompileTextureIdsHash(OutId.TextureReferencesHash);
//如果其有关联的MaterialInstance不为空
if(MaterialInstance)
{
MaterialInstance->GetBasePropertyOverridesHash(OutId.BasePropertyOverridesHash);
FStaticParameterSet CompositedStaticParameters;
MaterialInstance->GetStaticParameterValues(CompositedStaticParameters);
OutId.UpdateParameterSet(CompositedStaticParameters);
}
## FMaterial::CacheShaders
算了
|