|
使用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 |
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
|