Hi there, I used this tutorial as a reference guide for building Plane based terrains using a Biome splat map with simple RGB colours. https://gamedevacademy.org/complete-guide-to-procedural-level-generation-in-unity-part-2/ I then found a Shader which would allow me to take the biome splat map and use the RGBA values to apply textures at the vertex locations with a nice side-effect being the blend effect where the 'terrain' textures blend based on the generated biome texture (see attached images from different game runs). However this approach only allows for 4 terrain textures based on the RGBA values from the biome texture, what I would like is to change to the Shader to support 2DArray's so I can use 16 textures and not be restricted to RGBA colours. The Shader below works nicely with 4 textures, and the C# snippet works fine as well, however the TextureArray is not being used in the shader code below at the moment Also, the resultant material doesn't receive shadows! Not sure how to fix that either... Code (CSharp): Shader "Custom/Biome Tilemap" { Properties { // Biome splat map for texturing _MainTex ("Biome Splat Map", 2D) = "white" {} // Want to use this 2DArray that will have 16 textures... _TerrainTextures ("Terrain Textures", 2DArray) = "white" {} // As opposed to 4 specific textures [NoScaleOffset] _Texture1 ("Texture 1", 2D) = "white" {} [NoScaleOffset] _Texture2 ("Texture 2", 2D) = "white" {} [NoScaleOffset] _Texture3 ("Texture 3", 2D) = "white" {} [NoScaleOffset] _Texture4 ("Texture 4", 2D) = "white" {} } SubShader { Tags{ "RenderType"="Opaque" "Queue"="Geometry"} LOD 150 Pass { CGPROGRAM // Doesn't receive shadows, creating a surface program and method "surf" (excluded) // results in the following error messages: // // "Shader error in 'TileMaps': CGPROGRAM cannot contain #pragma surface // as well as other programs at line 25". // // "Shader error in 'TileMaps': Parse error: syntax error, unexpected TOK_PASS, // expecting TOK_SETTEXTURE or '}' at line 26". //#pragma surface surf Standard fullforwardshadows #pragma vertex vert #pragma fragment frag // to use texture arrays we need to target DX10/OpenGLES3 which // is shader model 3.5 minimum #pragma target 3.5 #include "UnityCG.cginc" sampler2D _MainTex; float4 _MainTex_ST; // How to use 2DArray instead?! sampler2D _Texture1, _Texture2, _Texture3, _Texture4; UNITY_DECLARE_TEX2DARRAY(_TerrainTextures); struct VertexData { float4 position : POSITION; float2 uv : TEXCOORD0; }; struct Interpolators { float4 position : SV_POSITION; float2 uv : TEXCOORD0; float2 uvSplat : TEXCOORD1; }; Interpolators vert (VertexData v) { Interpolators i; i.position = UnityObjectToClipPos(v.position); i.uv = TRANSFORM_TEX(v.uv, _MainTex); i.uvSplat = v.uv; return i; } float4 frag (Interpolators i) : SV_TARGET { // Apply using 2DArray based on colours from Biome texture (_MainTex), // I want to be able to use 16 textures and apply based on biome colours float4 splat = tex2D(_MainTex, i.uvSplat); return tex2D(_Texture1, i.uv) * splat.r + tex2D(_Texture2, i.uv) * splat.g + tex2D(_Texture3, i.uv) * splat.b + tex2D(_Texture4, i.uv) * (1 - splat.r - splat.g - splat.b); } ENDCG } } } The C# code that configures the shader and textures: Code (CSharp): // Load textures, create Texture2D[] etc. // Set the textures to a material tileRenderer.material.SetTexture("_MainTex", biomeProfileTexture); tileRenderer.material.SetTexture("_TerrainTextures", texture2DArray); tileRenderer.material.SetTexture("_Texture1", grassTexture8); tileRenderer.material.SetTexture("_Texture2", grassTexture5); tileRenderer.material.SetTexture("_Texture3", waterTexture1); tileRenderer.material.SetTexture("_Texture4", grassTexture11);
What do you mean you don't want to be restricted to RGBA? And why don't you want to use 4 seperate textures?
Probably worded that wrong! To be clear, my splat map produces 16 colours, for each of those 16 colours I want to assign a texture at that UV coordinate, I figured that using a texture 2DArray would be the cleanest way to achieve that, but I am unsure how to do it. With my Shader code above, I am only using 4 textures and assigning them based on the R, G , B, A values from the splat map UV's. For example, _Texture1 is assigned for "Red" UV cords: Code (CSharp): tex2D(_Texture1, i.uv) * splat.r Essentially, I want to be able to combine 16 textures from a 2DArray based on different shades of Green for example. With my shader, _Texture2 is assigned for green "splat.g". How can I assign for light green, green and dark green? Then apply the same concept for red, purple etc.
Hi tmcthee, See attached for an example of part of my splat map. I have complete control over the colours that are generated. The algorithm that I have used to generate the splat map can be found here: https://gamedevacademy.org/complete-guide-to-procedural-level-generation-in-unity-part-2/ However, I was thinking that I would use shades of Green for Grass textures, Blue for Water, Red for Rock textures and Yellow for other. The area that I am really stuck on is how to combine them all (16 textures) into a single texture in the frag method, as stated, my example works with 4 textures and uses R, G, B and A for texture assignment at UV coords. I need it for a 2DArray or something similar that will support 16 colours to textures using say, different shades of green: Code (CSharp): float4 frag (vertOutput i) : SV_TARGET { // Get splat map float4 splat = tex2D(_MainTex, i.uvSplat); // How to combine 16 textures from 2DArray based on RGBA variations // and return as a single texture? (This does 4 textures) return tex2D(_Texture1, i.uv) * splat.r + tex2D(_Texture2, i.uv) * splat.g + tex2D(_Texture3, i.uv) * splat.b + tex2D(_Texture4, i.uv) * (1 - splat.r - splat.g - splat.b); }