Поменяйте пиксели MainTex с помощью других текстур с помощью поверхностного шейдера (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 для каждой текстуры для каждого пикселя, чтобы просто выбросить эти данные, но я не мог придумать, как лучше это сделать, если / else (который я читал плохо для графических процессоров).

Это шейдер Unity Surface Shader, а не шейдер фрагмента / вершины. Я знаю, что есть шаг, который происходит за кулисами, которые будут генерировать фрагмент / вершинный шейдер для меня (добавление в освещение сцены, туман и т. Д.). Этот шейдер применяется к 100 256x256px картам (всего 2560×2560 пикселей). Текстуры травы / дороги / воды также имеют 256×256 пикселей.

Мой вопрос: есть ли более эффективный способ выполнения того, что я здесь делаю? Игра работает на Android и iOS.

Я не специалист по производительности Shader, но, предполагая, что у вас относительно небольшое количество исходных фрагментов, которые вы хотите отобразить в одном и том же фрейме, может возникнуть больше смысла хранить результат замены пикселя и повторно использовать его.

Поскольку вы заявляете, что результирующее изображение будет иметь тот же размер, что и исходный фрагмент, просто отрисуйте исходную плиту с помощью вашего шейдера поверхности (без какого-либо освещения, хотя вы можете рассмотреть возможность использования простого плоского пиксельного шейдера!) В RenderTexture один раз, а затем использовать этот RenderTexture в качестве источника для вашего рендеринга в мире. Таким образом, вы выполняете дорогостоящую работу только один раз на исходную плиту, и, следовательно, даже не важно, будет ли ваш шейдер хорошо оптимизирован.

Если все текстуры являются статическими, вы можете даже подумать об этом не во время выполнения, а просто перевести их один раз в Редактор.