找回密码
 立即注册
查看: 443|回复: 0

Unreal向shader传入材质贴图

[复制链接]
发表于 2020-12-5 19:39 | 显示全部楼层 |阅读模式
使用Unreal制作非PBR的效果真的是头疼,就拿卡通效果来说,一个描边效果就费死劲
然而,如果要使用ramp贴图制作如下效果。
只能通过法线和灯光方向算出脸颊那侧的光感,像脖子下边自阴影如果也想通过ramp来取色的话,就没办法了,因为在Unreal的材质蓝图中是没办法取到阴影信息的,也就是说我们要想取这张图就必须要在shader中能获取贴图。
普通ramp
  float difLight = dot(WorldNormal, lightDir);
  float hLambert = difLight * 0.5 + 0.5;
  float3 ramp = tex2D(_RampTex, float2(hLambert, hLambert)).rgb;
带阴影和AO的ramp
  float difLight = dot(WorldNormal, lightDir);
  float hLambert = difLight * 0.5 + 0.5;
  hLambert = hLambert * ao * shadow;
  float3 ramp = tex2D(_RampTex, float2(hLambert, hLambert)).rgb;前两章,有讲过如何使用全局贴图
但是这里可能不同角色或者不同材质,比如衣服和皮肤使用的ramp可能是不一样的,那么问题就变成了本文的标题,如何向shader中传入一张材质贴图呢?
首先,我们要知道,通过材质蓝图向shader中传递只能传递数值类型,前文也有讲如何添加自定义数据。
其次,我们再来回顾一下材质蓝图编译成shader的原理,材质蓝图会编译成一个个函数,对于移动平台来讲,会通过统一的模板MobileBasePassVertexShader和MobileBasePassPixelShader来调用这些函数,然后使用获得的值来进行计算。
通过上面的知识,我们可以做一个这样的构想,我们在编译材质蓝图的时候能否生成一个函数,传入uv坐标,返回出贴图对应的颜色,这样,我们可以保证贴图能在材质上编辑,跟材质蓝图的其他贴图参数没有区别,然后还能提供给shader使用。
顺着这个思路,我们可以修改材质蓝图的模板MaterialTemplate.ush,增加一个我们需要的函数模板
这个模板对应在HLSL翻译器是在HLSLMaterialTranslator.h中,GetMaterialShaderCode这个方法中
注意需要按照严格的顺序来。
我们可以参考CustomData这个函数,看看他构建的代码是什么。
half GetMaterialCustomData0(FMaterialPixelParameters Parameters)
{
    MaterialFloat4 Local0 = ProcessMaterialColorTextureLookup(Texture2DSampleBias(Material.Texture2D_0, Material.Texture2D_0Sampler,Parameters.TexCoords[0].xy,View.MaterialTextureMipBias));
    MaterialFloat4 Local1 = ProcessMaterialColorTextureLookup(Texture2DSampleBias(Material.Texture2D_1, Material.Texture2D_1Sampler,Parameters.TexCoords[0].xy,View.MaterialTextureMipBias));
    MaterialFloat4 Local2 = ProcessMaterialColorTextureLookup(Texture2DSampleBias(Material.Texture2D_2, Material.Textre2D_2Sampler,Parameters.TexCoords[0].xy,View.MaterialTextureMipBias));
    return Local0.rgb;;
}这里,unreal似乎处理得比较粗糙,他把所有的定义都放在这,可能通过代码裁剪来把不需要的代码过滤。
我们也可以创建一个自定义变量,参考前面文章
然后生成自己的代码段这样连接
再把我们需要的代码变成如下:
half3 GetLutColor(float2 uv)
{
    MaterialFloat4 Local0 = ProcessMaterialColorTextureLookup(Texture2DSampleBias(Material.Texture2D_0, Material.Texture2D_0Sampler,uv,View.MaterialTextureMipBias));
    return Local0.rgb;;
}这就是一个字符串的匹配问题了。
可以参考一下我的代码
//lut tex
FMaterialShadingModelField MaterialShadingModels = Material->GetShadingModels();
FString lutTexCode = FString::Printf(TEXT("return 1"));
if (MaterialShadingModels.HasShadingModel(MSM_ColorRamp))
{
        FString lutCode = TranslatedCodeChunkDefinitions[MP_FKLutMap];
        FString returnCode = TranslatedCodeChunks[MP_FKLutMap];
        int startIndex = returnCode.Find(".rgb");
        if (startIndex != INDEX_NONE)
        {
                returnCode = returnCode.Left(startIndex);
                FString containCode = "MaterialFloat4 " + returnCode + " = ProcessMaterialColorTextureLookup";
                FString leftStr;
                FString rightStr;
                while (lutCode.Split(";", &leftStr, &rightStr))
                {
                        if (leftStr.Contains(returnCode))
                        {
                                int len = lutCode.Len();
                                startIndex = leftStr.Find("Parameters.TexCoords[");
                                if (startIndex != INDEX_NONE)
                                {
                                        leftStr = lutCode.Left(startIndex);
                                        rightStr = lutCode.Right(len - startIndex);
                                        startIndex = rightStr.Find(".xy");
                                        if (startIndex != INDEX_NONE)
                                        {
                                                rightStr = rightStr.Right(rightStr.Len() - startIndex - 3);
                                                startIndex = rightStr.Find(";");
                                                if (startIndex != INDEX_NONE)
                                                {
                                                        rightStr = rightStr.Left(startIndex) + ";\r\n";
                                                }
                                                lutCode = leftStr + "uv" + rightStr;
                                                lutTexCode = lutCode + "        return " + TranslatedCodeChunks[MP_FKLutMap];
                                        }

                                        break;
                                }
                        }

                        lutCode = rightStr;
                }
        }
}
LazyPrintf.PushParam(*lutTexCode);这里我做了ShaderModel的判断,大家可以按照自己的需求来。
做完了上面这些,就可以在Shader中使用了。写个例子把lutColor输出出来。
效果图:




最后还是把本文修改的完整代码Patch贴一下,以便参考链接:https://pan.baidu.com/s/1Gs8kDj50Wu4NZThEwiUxZQ
提取码:k7ts

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-11-24 12:06 , Processed in 0.089456 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表