Unity 模型上绘制贴图融合

    首先功能是在Unity中能在任意的模型上实现类似unity自带的地形系统里的贴图绘制功能。

能够支持最多4张自定义贴图的融合。

源码是在微元素论坛上大佬写的,可以在论坛搜索下E3D MeshPainter这个插件。我稍微改了下并且融合到了自己的Shader中,这里记录下学习的过程。

    主要原理是利用一张贴图(SplatMap)的RGBA通道,分别指定不同的模型区域。一个通道对应一套需要融合的贴图。为了优化效果,一套贴图只有两张图,第一张图的RGB通道存放固有色,A通道存放高度信息,A通道的图是为了在刷地形的过程中能实现先绘制缝隙(高度图黑色区域)的功能。第二张图RG通道存放法线信息,B通道存放粗糙度。金属度用0-1的值控制。


//采样所有贴图
float4 OutPutBaseColor;
half4 OutPutBaseColor0 = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, i.uv * _BaseMap_ST.xy + _BaseMap_ST.zw) * _BaseColor;
half4 OutPutBaseColor1 = SAMPLE_TEXTURE2D(_BaseMap1, sampler_BaseMap1, i.uv * _BaseMap1_ST.xy + _BaseMap1_ST.zw) * _BaseColor1;
half4 OutPutBaseColor2 = SAMPLE_TEXTURE2D(_BaseMap2, sampler_BaseMap2, i.uv * _BaseMap2_ST.xy + _BaseMap2_ST.zw) * _BaseColor2;
half4 OutPutBaseColor3 = SAMPLE_TEXTURE2D(_BaseMap3, sampler_BaseMap3, i.uv * _BaseMap3_ST.xy + _BaseMap3_ST.zw) * _BaseColor3;
half3 normalTangent0 = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, i.uv * _BaseMap_ST.xy + _BaseMap_ST.z).xyz;
half3 normalTangent1 = SAMPLE_TEXTURE2D(_NormalMap1, sampler_NormalMap1, i.uv * _BaseMap1_ST.xy + _BaseMap1_ST.zw).xyz;
half3 normalTangent2 = SAMPLE_TEXTURE2D(_NormalMap2, sampler_NormalMap2, i.uv * _BaseMap2_ST.xy + _BaseMap2_ST.zw).xyz;
half3 normalTangent3 = SAMPLE_TEXTURE2D(_NormalMap3, sampler_NormalMap3, i.uv * _BaseMap3_ST.xy + _BaseMap3_ST.zw).xyz;

half4 var_Control = SAMPLE_TEXTURE2D(_Control, sampler_Control, i.uv * _Control_ST.xy + _Control_ST.zw);
half4 blend = HeightBlendTex(_BlendWeight,OutPutBaseColor0.a,OutPutBaseColor1.a,OutPutBaseColor2.a,OutPutBaseColor3.a,var_Control); 

OutPutBaseColor = (OutPutBaseColor0 * blend.r + OutPutBaseColor1 * blend.g + OutPutBaseColor2 * blend.b + OutPutBaseColor3 * blend.a) * _ColorAll;

half OutPutSpecGloss;
                
 OutPutSpecGloss = blend.r * lerp(0.0,normalTangent0.b,_BlendRoughness.x) 
                + blend.g * lerp(0.0,normalTangent1.b,_BlendRoughness.y) 
                + blend.b * lerp(0.0,normalTangent2.b,_BlendRoughness.z) 
                + blend.a * lerp(0.0,normalTangent3.b,_BlendRoughness.w);
float OutPutRoughness = 1-sqrt(OutPutSpecGloss);

half OutPutMetallicGloss;
OutPutMetallicGloss = _BlendMetallic.r * blend.r + _BlendMetallic.g * blend.g + _BlendMetallic.b * blend.b + _BlendMetallic.a * blend.a;


half3 normal = (float3(normalTangent0.rg,1) * 2 - 0.42) * blend.r;
half3 normal1 = (float3(normalTangent1.rg,1) * 2 - 0.42) * blend.g;
half3 normal2 = (float3(normalTangent2.rg,1) * 2 - 0.42) * blend.b;
half3 normal3 = (float3(normalTangent3.rg,1) * 2 - 0.42) * blend.a;

half3 normalTangent = normalize(normal + normal1 + normal2 + normal3);

half3 normalWorld = normalize(half3(
                dot(i.TtoW0.xyz, normalTangent),
                dot(i.TtoW1.xyz, normalTangent),
                dot(i.TtoW2.xyz, normalTangent)));                

half4 HeightBlendTex(half weight,half depth1,half depth2,half depth3,half depth4,half4 control)
    {
        half4 blend ;
        
        blend.r =depth1 * control.r;
        blend.g =depth2 * control.g;
        blend.b =depth3 * control.b;
        blend.a =depth4 * control.a;
        
        half ma = max(blend.r, max(blend.g, max(blend.b, blend.a)));
        blend = max(blend - ma + weight , 0) * control;
        return blend/(blend.r + blend.g + blend.b + blend.a);
    }

那么现在的问题就是如何在编辑模式下如何实时修改那种控制图。 原理是先使用射线检测得到鼠标点击到的信息,得到UV位置等信息。

Physics.Raycast(terrain, out raycastHit, Mathf.Infinity, 1 << LayerMask.NameToLayer(useLayers[i]))

然后将控制图的颜色信息提取出来。

Color[] terrainBay = MaskTex.GetPixels(x, y, width, height, 0); //得到x,y位置width,height笔刷尺寸的颜色信息

提取出来后将颜色信息和需要绘制的颜色做Lerp。绘制的颜色需要4个颜色,分别是纯的RGBA。

//定义绘制的颜色
Color targetColor = new Color(1f, 0f, 0f, 0f);
switch (selTex) //选择绘制的贴图
{
case 0:
targetColor = new Color(1f, 0f, 0f, 0f);
break;
case 1:
targetColor = new Color(0f, 1f, 0f, 0f);
break;
case 2:
targetColor = new Color(0f, 0f, 1f, 0f);
break;
case 3:
targetColor = new Color(0f, 0f, 0f, 1f);
break;
}


//使用笔刷在原颜色和绘制颜色中Lerp
terrainBay[index] = Color.Lerp(terrainBay[index], targetColor, Stronger);       //设置颜色绘制的颜色 使用Stronger在原图和绘制颜色中做Lerp

最后将新的颜色传回控制图。

MaskTex.SetPixels(x, y, width, height, terrainBay, 0);  //使用terrainBay颜色 绘制x,y位置width,height尺寸的颜色信息

剩下的就是一些UnityEditor的编辑器样式修改。

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值