BlueRoseNote/03-UnrealEngine/Rendering/RenderingPipeline/参考SubsurfaceProfile 模改ToonDataAsset.md

215 lines
9.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 参考SubsurfaceProfile 模改ToonDataAsset
date: 2023-02-04 20:38:39
excerpt:
tags:
rating: ⭐⭐
---
# 原理
## PreShader
在材质编译期,将名为 **__SubsurfaceProfile** 的Uniform表达式塞入材质中。
```c++
int32 FHLSLMaterialTranslator::NumericParameter(EMaterialParameterType ParameterType, FName ParameterName, const UE::Shader::FValue& InDefaultValue)
{
const UE::Shader::EValueType ValueType = GetShaderValueType(ParameterType);
check(InDefaultValue.GetType() == ValueType);
UE::Shader::FValue DefaultValue(InDefaultValue);
// If we're compiling a function, give the function a chance to override the default parameter value
FMaterialParameterMetadata Meta;
if (GetParameterOverrideValueForCurrentFunction(ParameterType, ParameterName, Meta))
{
DefaultValue = Meta.Value.AsShaderValue();
check(DefaultValue.GetType() == ValueType);
}
const uint32* PrevDefaultOffset = DefaultUniformValues.Find(DefaultValue);
uint32 DefaultOffset;
if (PrevDefaultOffset)
{
DefaultOffset = *PrevDefaultOffset;
}
else
{
DefaultOffset = MaterialCompilationOutput.UniformExpressionSet.AddDefaultParameterValue(DefaultValue);
DefaultUniformValues.Add(DefaultValue, DefaultOffset);
}
FMaterialParameterInfo ParameterInfo = GetParameterAssociationInfo();
ParameterInfo.Name = ParameterName;
const int32 ParameterIndex = MaterialCompilationOutput.UniformExpressionSet.FindOrAddNumericParameter(ParameterType, ParameterInfo, DefaultOffset);
return AddUniformExpression(new FMaterialUniformExpressionNumericParameter(ParameterInfo, ParameterIndex), GetMaterialValueType(ParameterType), TEXT(""));
}
```
`const int32 ParameterIndex = MaterialCompilationOutput.UniformExpressionSet.FindOrAddNumericParameter(ParameterType, ParameterInfo, DefaultOffset);`
`return AddUniformExpression(new FMaterialUniformExpressionNumericParameter(ParameterInfo, ParameterIndex), GetMaterialValueType(ParameterType), TEXT(""));`
之后在`Chunk[MP_SubsurfaceColor] = AppendVector(SubsurfaceColor, CodeSubsurfaceProfile);`将结果编译成`MaterialFloat4(MaterialFloat3(1.00000000,1.00000000,1.00000000),Material.PreshaderBuffer[2].x)`
## 填充PreShader结构体
1. 从MeshDraw框架的FMeshElementCollector::AddMesh()开始,执行`MeshBatch.MaterialRenderProxy->UpdateUniformExpressionCacheIfNeeded(Views[ViewIndex]->GetFeatureLevel());`开始更新材质的UniformExpression。
2. `FMaterialRenderProxy::UpdateUniformExpressionCacheIfNeeded()`:取得材质指针之后评估材质表达式。
3. `FMaterialRenderProxy::EvaluateUniformExpressions()`从渲染线程取得材质的ShaderMap再从ShaderMap取得UniformExpressionSet。
4. `FUniformExpressionSet::FillUniformBuffer`Dump preshader results into buffer.
1. FEmitContext::EmitPreshaderOrConstantPreshaderHeader = &UniformExpressionSet.UniformPreshaders.AddDefaulted_GetRef();
# 将ToonData的ID塞入材质
存在问题如何将SubsurfaceProfile Asset的ID塞入材质中
```c++
int32 FMaterialCompiler::ScalarParameter(FName ParameterName, float DefaultValue)
{
return NumericParameter(EMaterialParameterType::Scalar, ParameterName, DefaultValue);
}
int32 FHLSLMaterialTranslator::NumericParameter(EMaterialParameterType ParameterType, FName ParameterName, const UE::Shader::FValue& InDefaultValue)
{
const UE::Shader::EValueType ValueType = GetShaderValueType(ParameterType);
check(InDefaultValue.GetType() == ValueType);
UE::Shader::FValue DefaultValue(InDefaultValue);
// If we're compiling a function, give the function a chance to override the default parameter value
FMaterialParameterMetadata Meta;
if (GetParameterOverrideValueForCurrentFunction(ParameterType, ParameterName, Meta))
{ DefaultValue = Meta.Value.AsShaderValue();
check(DefaultValue.GetType() == ValueType);
}
const uint32* PrevDefaultOffset = DefaultUniformValues.Find(DefaultValue);
uint32 DefaultOffset;
if (PrevDefaultOffset)
{
DefaultOffset = *PrevDefaultOffset;
}else
{
DefaultOffset = MaterialCompilationOutput.UniformExpressionSet.AddDefaultParameterValue(DefaultValue);
DefaultUniformValues.Add(DefaultValue, DefaultOffset);
}
FMaterialParameterInfo ParameterInfo = GetParameterAssociationInfo();
ParameterInfo.Name = ParameterName;
const int32 ParameterIndex = MaterialCompilationOutput.UniformExpressionSet.FindOrAddNumericParameter(ParameterType, ParameterInfo, DefaultOffset);
return AddUniformExpression(new FMaterialUniformExpressionNumericParameter(ParameterInfo, ParameterIndex), GetMaterialValueType(ParameterType), TEXT(""));
}
bool FMaterialHLSLGenerator::GetParameterOverrideValueForCurrentFunction(EMaterialParameterType ParameterType, FName ParameterName, FMaterialParameterMetadata& OutResult) const
{
bool bResult = false;
if (!ParameterName.IsNone())
{ // Give every function in the callstack on opportunity to override the parameter value
// Parameters in outer functions take priority // For example, if a layer instance calls a function instance that includes an overriden parameter, we want to use the value from the layer instance rather than the function instance for (const FFunctionCallEntry* FunctionEntry : FunctionCallStack)
{ const UMaterialFunctionInterface* CurrentFunction = FunctionEntry->MaterialFunction;
if (CurrentFunction)
{
if (CurrentFunction->GetParameterOverrideValue(ParameterType, ParameterName, OutResult))
{ bResult = true;
break;
}
}
}
}
return bResult;
}
// Finds a parameter by name from the game thread, traversing the chain up to the BaseMaterial.
FScalarParameterValue* GameThread_GetScalarParameterValue(UMaterialInstance* MaterialInstance, FName Name)
{
UMaterialInterface* It = 0;
FMaterialParameterInfo ParameterInfo(Name); // @TODO: This will only work for non-layered parameters
while(MaterialInstance)
{
if(FScalarParameterValue* Ret = GameThread_FindParameterByName(MaterialInstance->ScalarParameterValues, ParameterInfo))
{
return Ret;
}
It = MaterialInstance->Parent;
MaterialInstance = Cast<UMaterialInstance>(It);
}
return 0;
}
template <typename ParameterType>
ParameterType* GameThread_FindParameterByName(TArray<ParameterType>& Parameters, const FHashedMaterialParameterInfo& ParameterInfo)
{
for (int32 ParameterIndex = 0; ParameterIndex < Parameters.Num(); ParameterIndex++)
{
ParameterType* Parameter = &Parameters[ParameterIndex];
if (Parameter->ParameterInfo == ParameterInfo)
{
return Parameter;
}
}
return NULL;
}
void UMaterialFunctionInstance::OverrideMaterialInstanceParameterValues(UMaterialInstance* Instance)
{
// Dynamic parameters
Instance->ScalarParameterValues = ScalarParameterValues;
Instance->VectorParameterValues = VectorParameterValues;
Instance->DoubleVectorParameterValues = DoubleVectorParameterValues;
Instance->TextureParameterValues = TextureParameterValues;
Instance->RuntimeVirtualTextureParameterValues = RuntimeVirtualTextureParameterValues;
Instance->FontParameterValues = FontParameterValues;
// Static parameters
FStaticParameterSet StaticParametersOverride = Instance->GetStaticParameters();
StaticParametersOverride.EditorOnly.StaticSwitchParameters = StaticSwitchParameterValues;
StaticParametersOverride.EditorOnly.StaticComponentMaskParameters = StaticComponentMaskParameterValues;
Instance->UpdateStaticPermutation(StaticParametersOverride);
}
```
和UMaterialExpressionStrataLegacyConversion::Compile()无关。
GetSubsurfaceProfileParameterName()
__SubsurfaceProfile
1. 在FHLSLMaterialTranslator::Translate() => NumericParameter()会往MaterialCompilationOutput.UniformExpressionSet以及DefaultUniformValues添加默认值以及Offset。最终会调用AddUniformExpression()
## MaterialRenderProxy
```c++
void SetSubsurfaceProfileRT(const USubsurfaceProfile* Ptr) { SubsurfaceProfileRT = Ptr; }
const USubsurfaceProfile* GetSubsurfaceProfileRT() const { return SubsurfaceProfileRT; }
/** 0 if not set, game thread pointer, do not dereference, only for comparison */
const USubsurfaceProfile* SubsurfaceProfileRT;
```
## UMaterialInterface
```c++
uint8 bOverrideSubsurfaceProfile:1;//UE5转移至UMaterialInstance中
TObjectPtr<class USubsurfaceProfile> SubsurfaceProfile;
void UMaterialInterface::UpdateMaterialRenderProxy(FMaterialRenderProxy& Proxy)
//还有所有子类实现 UMaterialInstance、UMaterial
USubsurfaceProfile* UMaterialInterface::GetSubsurfaceProfile_Internal() const
```
## MaterialShared.h
```c++
inline bool UseSubsurfaceProfile(FMaterialShadingModelField ShadingModel)
{
return ShadingModel.HasShadingModel(MSM_SubsurfaceProfile) || ShadingModel.HasShadingModel(MSM_Eye);
}
```
## UMaterial
```c++
USubsurfaceProfile* UMaterial::GetSubsurfaceProfile_Internal() const
{
checkSlow(IsInGameThread());
return SubsurfaceProfile;
}
```
## UMaterialInstance
```c++
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = MaterialInstance)
uint8 bOverrideSubsurfaceProfile:1;
```