|
可以的,稍微修改一点引擎代码。主要要解决编译的入口函数和如何在shader中使用材质参数。
1 自定义入口函数
首先写一个自己的 Custom 节点类,我是继承 UE 原有的 Custom 节点。这个类主要用于设置shader文件并判断该材质是否使用自定义的 shader。- UCLASS()
- class UMaterialExpressionMyCustom : public UMaterialExpressionCustom
- {
- GENERATED_UCLASS_BODY()
-
- // shader文件
- UPROPERTY(EditAnywhere, Category=MaterialExpressionCustom)
- FString ShaderFilePath;
- public:
- const FString &GetShaderFilePath() const;
- };
复制代码 然后在 FMeshMaterialShaderType::BeginCompileShader 和 FMaterialShaderType::BeginCompileShader 中修改入口函数名。- const TCHAR *shaderEntryFuncName = GetFunctionName();
- const TCHAR *shaderFilename = GetShaderFilename();
- // 在 FMaterial 中定义的函数,判断是否有 MyCustom 节点
- if (Material->IsUseMyCustomShader())
- {
- UMaterialExpressionMYCustom *myCustomExrpession = Material->GetFirstUMaterialExpressionMyCustom();
-
- // 这个地方要有一个机制判断当前的 Pass 是否使用自定义的 shader
- // 我是通过文件名判断的,比如 /Engine/Private/BasePassPixelShader.usf
- if (IsCustomShaderSupport(shaderFilename))
- {
- if (this->GetFrequency() == SF_Pixel)
- {
- shaderEntryFuncName = TEXT("MyMainPS");
- ShaderEnvironment.SetDefine(TEXT("MY_PIXEL_SHADER"), TEXT("1"));
- }
- }
-
- }
复制代码 之后要在合适的地方 include 到自己的 shader 文件。在 FMaterial::BeginCompileShaderMap 中,完成材质翻译之后,将自己的 shader 文件添加到 include path 中。- if (this->IsUseMyCustomShader())
- {
- // #include "/Engine/Generated/MyCustomMaterial.ush" 被写在 .usf 最后,见 Engine\Shaders\Private\BasePassPixelShader.usf
- UMaterialExpressionMyCustom *myCustomExrpession = this->GetFirstUMaterialExpressionMyCustom();
- const FString &shaderFilename = *myCustomExrpession->GetShaderFilePath();
- // 生成参数定义代码
- FString paramcode = MaterialTranslator.MyGetMaterialParametersCode();
-
- MaterialEnvironment->IncludeVirtualPathToContentsMap.Add(TEXT("/Engine/Generated/MyCustomMaterial.ush")
- , FString::Printf(TEXT("%s \n #include \"%s\" "), *paramcode, *shaderFilename));
- }
复制代码 上面的代码把自己的 shader 文件在 /Engine/Generated/MyCustomMaterial.ush 中 include 了。之后需要在想要支持自定义 shader 的 pass 中 include MyCustomMaterial.ush。比如要支持 basepass 的 ps,则在 Engine\Shaders\Private\BasePassPixelShader.usf 文件最后 #include "/Engine/Generated/MyCustomMaterial.ush"。
上面做完后,就可以写自己的 shader 了。下面是一个 BasePass 的 PS,函数签名和 PixelShaderOutputCommon.ush 中一致。- void MyMainPS(
- #if PIXELSHADEROUTPUT_INTERPOLANTS || PIXELSHADEROUTPUT_BASEPASS
- FVertexFactoryInterpolantsVSToPS Interpolants,
- #endif
- #if PIXELSHADEROUTPUT_BASEPASS
- FBasePassInterpolantsVSToPS BasePassInterpolants,
- #elif PIXELSHADEROUTPUT_MESHDECALPASS
- FMeshDecalInterpolants MeshDecalInterpolants,
- #endif
- in INPUT_POSITION_QUALIFIERS float4 SvPosition : SV_Position // after all interpolators
- OPTIONAL_IsFrontFace
- , out float4 OutTarget0 : SV_Target0
- )
- {
- OutTarget0 = float4(1, 0, 0, 1);
- }
复制代码 2 使用材质参数
在 FHLSLMaterialTranslator 定义一个函数 MyGetMaterialParametersCode,遍历其中的参数节点,将每个参数通过宏定义的方式构造一段代码。下面代码中获取了 Vector 参数,其他类型的参数也可以用类似方法取出。- FString MyGetMaterialParametersCode() const
- {
- const FUniformExpressionSet &uniformSet = MaterialCompilationOutput.UniformExpressionSet;
- TArray<FString> paramCode;
- for(int i=0; i<uniformSet.UniformVectorExpressions.Num(); ++i)
- {
- const FMaterialUniformExpression *e = uniformSet.UniformVectorExpressions[i];
- if (e == nullptr || e->GetType() != &FMaterialUniformExpressionVectorParameter::StaticType)
- {
- continue;
- }
- const FMaterialUniformExpressionVectorParameter *ee = (const FMaterialUniformExpressionVectorParameter*)e;
- FString vname = ee->GetParameterInfo().Name.ToString();
- FString code = FString::Printf(TEXT(&#34;#define MyParam_%s Material.VectorExpressions[%d]&#34;), *vname, i);
- paramCode.Add(code);
- }
-
- // result
- FString ret;
- for (const FString &code : paramCode)
- {
- ret += code + &#34;\n&#34;;
- }
- return ret;
- }
复制代码 在编译的时候,从材质中翻译出代码后,调用以上函数获得参数定义代码,写到 /Engine/Generated/MyCustomMaterial.ush 中,即可在自己的 shader 中使用这些参数了。- void MyMainPS(
- #if PIXELSHADEROUTPUT_INTERPOLANTS || PIXELSHADEROUTPUT_BASEPASS
- FVertexFactoryInterpolantsVSToPS Interpolants,
- #endif
- #if PIXELSHADEROUTPUT_BASEPASS
- FBasePassInterpolantsVSToPS BasePassInterpolants,
- #elif PIXELSHADEROUTPUT_MESHDECALPASS
- FMeshDecalInterpolants MeshDecalInterpolants,
- #endif
- in INPUT_POSITION_QUALIFIERS float4 SvPosition : SV_Position // after all interpolators
- OPTIONAL_IsFrontFace
- , out float4 OutTarget0 : SV_Target0
- )
- {
- OutTarget0 = float4(MyParam_Color1.xyz, 1);
- }
复制代码 需要注意的是,参数必须要最终连到输出节点上才能被收入 UniformExpressionSet。 |
|