【问题标题】:Swap out MainTex pixels with other textures' via surface Shader (Unity)通过表面着色器(Unity)用其他纹理交换 MainTex 像素
【发布时间】:2017-06-08 19:35:51
【问题描述】:

我的表面着色器的主要纹理是一个谷歌地图图像瓦片,类似于这样: .

我想用单独纹理中的像素替换接近指定颜色的像素。现在的工作如下:

Shader "MyShader"
{
    Properties
    {
        _MainTex("Base (RGB) Trans (A)", 2D) = "white" {}

        _GrassTexture("Grass Texture", 2D) = "white" {}
        _RoadTexture("Road Texture", 2D) = "white" {}
        _WaterTexture("Water Texture", 2D) = "white" {}
    }

    SubShader
    {
        Tags{ "Queue" = "Transparent-1" "IgnoreProjector" = "True" "ForceNoShadowCasting" = "True" "RenderType" = "Opaque" }
        LOD 200

        CGPROGRAM
        #pragma surface surf Lambert alpha approxview halfasview noforwardadd nometa 

        uniform sampler2D _MainTex;
        uniform sampler2D _GrassTexture;
        uniform sampler2D _RoadTexture;
        uniform sampler2D _WaterTexture;

        struct Input
        {
            float2 uv_MainTex;
        };

        void surf(Input IN, inout SurfaceOutput o)
        {
            fixed4 ct = tex2D(_MainTex, IN.uv_MainTex);

            // if the red (or blue) channel of the pixel is within a 
            // specific range, get either a 1 or a 0 (true/false).
            int grassCond = int(ct.r >= 0.45) * int(0.46 >= ct.r);
            int waterCond = int(ct.r >= 0.14) * int(0.15 >= ct.r);
            int roadCond = int(ct.b >= 0.23) * int(0.24 >= ct.b);

            // if none of the above conditions is a 1, then we want to keep our
            // current pixel's color:
            half defaultCond = 1 - grassCond - waterCond - roadCond;

            // get the pixel from each texture, multiple by their check condition
            // to get:
            //    fixed4(0,0,0,0) if this isn't the right texture for this pixel
            //    or fixed4(r,g,b,1) from the texture if it is the right pixel
            fixed4 grass = grassCond * tex2D(_GrassTexture, IN.uv_MainTex);
            fixed4 water = waterCond * tex2D(_WaterTexture, IN.uv_MainTex);
            fixed4 road = roadCond * tex2D(_RoadTexture, IN.uv_MainTex);
            fixed4 def = defaultCond * ct; // just used the MainTex pixel

            // then use the found pixels as the Albedo
            o.Albedo = (grass + road + water + def).rgb;
            o.Alpha = 1;
        }
        ENDCG
    }

    Fallback "None"
}

这是我编写的第一个着色器,它的性能可能不是很好。对我来说,在每个纹理上为每个像素调用 tex2D 以丢弃这些数据似乎违反直觉,但如果没有 if/else(我读到这对 GPU 不利),我想不出更好的方法来做到这一点。

这是一个 Unity 表面着色器,而不是片段/顶点着色器。我知道幕后有一个步骤会为我生成片段/顶点着色器(添加场景的照明、雾等)。此着色器应用于 100 个 256x256 像素的地图图块(总共 2560x2560 像素)。草/道路/水的纹理也都是 256x256 像素。

我的问题是:有没有更好、更高效的方式来完成我在这里所做的事情?该游戏可在 Android 和 iOS 上运行。

【问题讨论】:

  • 您是将 256x256 源图块转换为 256x256 目标图块,还是结果应该很大?
  • 结果为 256x256

标签: android ios unity3d opengl-es shader


【解决方案1】:

我不是着色器性能方面的专家,但假设您希望在同一帧中渲染的源图块数量相对较少,那么存储像素替换的结果并重复使用它可能更有意义。

正如您所说,生成的图像将与源图块大小相同,只需使用表面着色器渲染源图块(尽管没有任何照明,您可能需要考虑使用简单的平面像素着色器!) 进入 RenderTexture 一次,然后使用该 RenderTexture 作为世界渲染的源。这样一来,每个源图块只需执行一次昂贵的工作,因此着色器是否经过良好优化不再重要。

如果所有纹理都是静态的,您甚至可以考虑在运行时不这样做,而只需在编辑器中翻译一次即可。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-11-03
    • 1970-01-01
    • 2022-01-27
    • 1970-01-01
    • 1970-01-01
    • 2014-11-26
    • 1970-01-01
    • 2017-08-29
    相关资源
    最近更新 更多