9.0 KiB
9.0 KiB
title, date, excerpt, tags, rating
title | date | excerpt | tags | rating |
---|---|---|---|---|
参考SubsurfaceProfile 模改ToonDataAsset | 2023-02-04 20:38:39 | ⭐⭐ |
原理
PreShader
在材质编译期,将名为 __SubsurfaceProfile 的Uniform表达式塞入材质中。
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结构体
- 从MeshDraw框架的FMeshElementCollector::AddMesh()开始,执行
MeshBatch.MaterialRenderProxy->UpdateUniformExpressionCacheIfNeeded(Views[ViewIndex]->GetFeatureLevel());
,开始更新材质的UniformExpression。 FMaterialRenderProxy::UpdateUniformExpressionCacheIfNeeded()
:取得材质指针之后评估材质表达式。FMaterialRenderProxy::EvaluateUniformExpressions()
:从渲染线程取得材质的ShaderMap,再从ShaderMap取得UniformExpressionSet。FUniformExpressionSet::FillUniformBuffer
:Dump preshader results into buffer.- FEmitContext::EmitPreshaderOrConstant:PreshaderHeader = &UniformExpressionSet.UniformPreshaders.AddDefaulted_GetRef();
将ToonData的ID塞入材质
存在问题,如何将SubsurfaceProfile Asset的ID塞入材质中:
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);
}
将SubsurfaceProfile 塞入 Material
int32 UMaterialExpressionStrataLegacyConversion::Compile(class FMaterialCompiler* Compiler, int32 OutputIndex)
{
}
MaterialRenderProxy
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
uint8 bOverrideSubsurfaceProfile:1;//UE5转移至UMaterialInstance中
TObjectPtr<class USubsurfaceProfile> SubsurfaceProfile;
void UMaterialInterface::UpdateMaterialRenderProxy(FMaterialRenderProxy& Proxy)
//还有所有子类实现 UMaterialInstance、UMaterial
USubsurfaceProfile* UMaterialInterface::GetSubsurfaceProfile_Internal() const
MaterialShared.h
inline bool UseSubsurfaceProfile(FMaterialShadingModelField ShadingModel)
{
return ShadingModel.HasShadingModel(MSM_SubsurfaceProfile) || ShadingModel.HasShadingModel(MSM_Eye);
}
UMaterial
USubsurfaceProfile* UMaterial::GetSubsurfaceProfile_Internal() const
{
checkSlow(IsInGameThread());
return SubsurfaceProfile;
}
UMaterialInstance
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = MaterialInstance)
uint8 bOverrideSubsurfaceProfile:1;