Intercambia los píxeles MainTex con otras texturas a través de la superficie Shader (Unidad)

La textura principal de mi shader de superficie es un mosaico de imágenes de Google Maps, similar a esto: introduzca la descripción de la imagen aquí .

Quiero replace los píxeles que están cerca de un color específico con el de una textura separada. Lo que está funcionando ahora es el siguiente:

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 networking (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" } 

Este es el primer sombreador que he escrito, y probablemente no sea muy eficaz. Parece contradictorio para mí llamar a tex2D en cada textura por cada píxel para simplemente tirar esos datos, pero no pude pensar en una mejor manera de hacerlo sin if / else (que leí eran malos para las GPU).

Este es un Sombreador de superficie de Unity, y no un sombreador de fragment / vértice. Sé que hay un paso detrás de escena que generará el fragment / sombreador de vértices para mí (añadiendo iluminación, niebla, etc.). Este sombreado se aplica a 100 fichas de map de 256x256px (2560×2560 píxeles en total). Las texturas de césped / carretera / agua son todos 256×256 píxeles también.

Mi pregunta es: ¿hay una manera mejor y más eficaz de lograr lo que estoy haciendo aquí? El juego se ejecuta en Android e iOS.

No soy un especialist en el performance de Shader, pero suponiendo que tienes un número relativamente pequeño de mosaicos fuente que deseas representar en el mismo marco, podría tener más sentido almacenar el resultado del reemploop de píxeles y reutilizarlo.

Como estás diciendo que la image resultante será del mismo tamaño que tu mosaico fuente, solo haz el mosaico fuente con tu sombreador de superficie (sin iluminación, ¡puedes considerar usar un sombreador de píxeles plano simple!) En una RenderTexture una vez y luego use esa RenderTexture como fuente para su rendering mundial. De esta forma, está haciendo el trabajo costoso solo una vez por mosaico fuente y, por lo tanto, ya no es importante si su sombreador está bien optimizado.

Si todas las texturas son estáticas, incluso podría considerar no hacerlo en time de ejecución, pero solo traducirlas una vez en el Editor.