簡體   English   中英

通過表面着色器(Unity)將MainTex像素與其他紋理交換掉

[英]Swap out MainTex pixels with other textures' via surface Shader (Unity)

我的表面着色器的主要紋理是Google Maps圖像圖塊,類似於: 在此輸入圖像描述

我想用一個單獨的紋理替換接近指定顏色的像素。 現在正在做的是以下內容:

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 Surface Shader,而不是片段/頂點着色器。 我知道幕后會有一個步驟會為我生成片段/頂點着色器(添加場景的光照,霧等)。 此着色器應用於100個256x256px地圖圖塊(總共2560x2560像素)。 草/道路/水紋理也都是256x256像素。

我的問題是:是否有一種更好,更高效的方式來完成我在這里所做的事情? 該游戲在Android和iOS上運行。

我不是Shader性能方面的專家,但假設您希望在同一幀中呈現相對較少數量的源圖塊,那么存儲像素替換的結果並重用它可能更有意義。

當您聲明生成的圖像將與源圖塊的大小相同時,只需使用表面着色器渲染源圖塊(盡管沒有任何光照,您可能需要考慮使用簡單的平面像素着色器!) RenderTexture一次,然后使用RenderTexture作為世界渲染的源。 這樣你每個源瓷磚只做一次昂貴的工作,因此你的着色器是否得到了很好的優化甚至不再重要。

如果所有紋理都是靜態的,您甚至可以考慮不在運行時執行此操作,而只需在編輯器中將它們翻譯一次。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM