diff --git a/Runtime/VectorTile.cs b/Runtime/VectorTile.cs
index b28dae785c9d688fb4fce27d115ebff655bef7a3..35f49bc137f77a3f0ae08ccb64491857dc9b209c 100644
--- a/Runtime/VectorTile.cs
+++ b/Runtime/VectorTile.cs
@@ -67,6 +67,7 @@ namespace Wander
         private bool valid;
         private bool finished;
         private bool triangulated;
+        private bool layersIdentified;
         private Task parseTileTask;
         private List<VectorTileLayer> layers;
         private List<List<TriangulatedPolygon>> polygonLayers;
@@ -178,94 +179,68 @@ namespace Wander
                     polygonLayers[i][j].OptimizeForIsPointInTriangle();
         }
 
-        // Calls callback(x, y, channel) for each raster position (256 channels) where each value represents a single channel.
-        // If no polygon was hit, 255 is called.
-        // If polygon was hit, but no feature was matched, 254 is called.
-        // Returns a list of failed to match pixels. This can be due to geometry not exactly matching or a layer not being found.
-        public List<Vector3Int> RenderToTextureSingle(
-            int width, int height, 
-            List<string> matchingAttribKeys, 
-            List<List<string>> layerNamesList, 
-            Func<int, int, byte, bool> callback )
+        // Identify feature by specifying a (unique) index based on some criteria. This can very per
+        // vector tile provider. 
+        public void IdentifyLayers( Func<VectorTileLayer, List<KeyValuePair<string, object>>, int> selectionCallback )
         {
             Debug.Assert( triangulated, "First call Triangulate." );
-            Debug.Assert( layerNamesList.Count < 254, "254 and 255 are reserved for no hit or no match." );
 
-            // First match layers to layer names.
-            bool cancel = false;
-            List<Vector3Int> failedPixels = new List<Vector3Int>();
-            for (int l = 0;l < layers.Count && !cancel;l++)
+            for (int l = 0;l < layers.Count;l++)
             {
                 var layer  = layers[l];
-                for (int f = 0;f < layer.VectorTileFeatures.Count && !cancel;f++)
+                for (int f = 0;f < layer.VectorTileFeatures.Count;f++)
                 {
                     var feature = layer.VectorTileFeatures[f];
                     feature.SelectedLayerIdx = 254;
 
-                    if (feature.GeometryType != Tile.GeomType.Polygon)
-                        continue;
-
-                    if (feature.Attributes == null)
-                        continue;
-
-                    // Find matching layer.
-                    bool matchingLayerFound = false;
-                    for (int a = 0;a < feature.Attributes.Count && !matchingLayerFound;a++)
+                    int uniqueId = selectionCallback( layer, feature.Attributes );
+                    if (uniqueId > -1)
                     {
-                        for (int m = 0;m < matchingAttribKeys.Count && !matchingLayerFound;m++)
+                        if ( uniqueId == 8 )
                         {
-                            if (feature.Attributes[a].Key != matchingAttribKeys[m])
-                                continue;
-
-                            string function = feature.Attributes[a].Value as string;
-                            for (int layerIdx = 0;layerIdx < layerNamesList.Count && !matchingLayerFound;layerIdx++)
-                            {
-                                for (int layerNameIdx = 0;layerNameIdx < layerNamesList[layerIdx].Count;layerNameIdx++)
-                                {
-                                    if (function.Contains( layerNamesList[layerIdx][layerNameIdx] ))
-                                    {
-                                        feature.SelectedLayerIdx = layerIdx;
-                                        matchingLayerFound = true;
-                                        break;
-                                    }
-                                }
-                            }
-                        }
-                    }
-
-                    // try Layer.name
-                    if (!matchingLayerFound)
-                    {
-                        for (int layerIdx = 0;layerIdx < layerNamesList.Count && !matchingLayerFound;layerIdx++)
-                        {
-                            for (int layerNameIdx = 0;layerNameIdx < layerNamesList[layerIdx].Count;layerNameIdx++)
-                            {
-                                if (layer.Name.Contains( layerNamesList[layerIdx][layerNameIdx] ))
-                                {
-                                    feature.SelectedLayerIdx = layerIdx;
-                                    matchingLayerFound = true;
-                                    break;
-                                }
-                            }
+                            int jt = 0;
                         }
+                        feature.SelectedLayerIdx = uniqueId;
+                        break; // Done with this feature.
                     }
                 }
             }
 
-            Debug.Assert( width == height, "Must be square images." );
+            layersIdentified = true;
+        }
 
-            // For each layer, for each pixel, now check triangle intersections.
-            for (int l = 0;l < layers.Count && !cancel;l++)
+        // Calls callback(x, y, channel) for each raster position (256 channels) where each value represents a single channel.
+        // If no polygon was hit, 255 is called.
+        // If polygon was hit, but no feature was matched, 254 is called.
+        // Returns a list of failed to match pixels. This can be due to geometry not exactly matching or a layer not being found.
+        // Also out puts a remap of layer indices. For instance for a specific tile, only layerIdx 1, 6 and 3 are used.
+        // Then this a remapping of 1->0, 6->1, 3->2. So that in the shader only 3 textures are needed starting from 0, 1.. etc.
+        public byte[] RenderToTextureSingle(
+            int resolution,
+            out Dictionary<byte, byte> remappedLayerIndices,     
+            out List<Vector3Int> failedPixels,
+            bool? cancelToken)
+        {
+            Debug.Assert( triangulated, "First call Triangulate." );
+            Debug.Assert( layersIdentified, "Identify layers first." );
+            Debug.Assert( resolution > 1, "Must be at least 2." );
+
+            byte [] texture = new byte[resolution*resolution];
+            failedPixels = new List<Vector3Int>();
+            remappedLayerIndices = new Dictionary<byte, byte>();
+            byte cachedPixel = 0;
+
+            // For each layer, for each pixel, check triangle intersections.
+            for (int l = 0;l < layers.Count && !cancelToken.Value;l++)
             {
                 var layer = layers[l];
-                float fx  = (float)layer.Extent / width;
+                float fx  = (float)layer.Extent / resolution;
                 TriangulatedPolygon cachedPoly = default;
                 int cachedVtxIdx  = -1;
                 int cachedTriIdx  = -1;
-                byte cachedPixel  = 0;
-                for (int y = 0;y < height && !cancel;y++)
+                for (int y = 0;y < resolution && !cancelToken.Value;y++)
                 {
-                    for (int x = 0;x < width && !cancel;x++)
+                    for (int x = 0; x < resolution; x++)
                     {
                         Vector2 p = new Vector2(fx*x+0.5f*fx, fx*y+0.5f*fx);
                         bool hit  = false;
@@ -283,7 +258,7 @@ namespace Wander
                                 hit = GeomUtil.PointIsInsideTriangle2( p, vertices[cachedVtxIdx], vertices[cachedVtxIdx+1], vertices[cachedVtxIdx+2], denoms[cachedTriIdx] );
                                 if (hit)
                                 {
-                                    cancel = callback( x, y, cachedPixel ); // If SelectedLayerIdx did not match, it was set to 254.
+                                    texture[(resolution - y -1)*resolution+x] = cachedPixel;
                                     continue; // Pass from cache, continue to next pixel.
                                 }
                             }
@@ -317,7 +292,11 @@ namespace Wander
                                     cachedTriIdx = triIdx;
                                     cachedVtxIdx = vIdx;
                                     cachedPixel  = (byte)feature.SelectedLayerIdx;
-                                    cancel = callback( x, y, cachedPixel );
+                                    if ( cachedPixel == 8 )
+                                    {
+                                        int jt = 0;
+                                    }
+                                    texture[(resolution - y -1)*resolution+x] = cachedPixel;
                                     break;
                                 }
                             }
@@ -327,13 +306,49 @@ namespace Wander
 
                         if ( !hit )
                         {
+                         //   texture[(resolution - y -1)*resolution+x] = 255;
                             failedPixels.Add( new Vector3Int( x, y, 255 ) );
                         }
                     }
                 }
             }
 
-            return failedPixels;
+            // Determine number of different layers. For instance, if only layer 3, 8, 14 and 15 are used, we select
+            // a material that only uses 4 textures and put 3 -> Albedo_0 -> 8 to Albedo_1, etc. in the shader.
+            cachedPixel = 255;
+            int remappedIndexCounter = -1;
+            byte remappedPixel = 255;
+            int addr = 0;
+            for (int y = 0;y < resolution && !cancelToken.Value;y++)
+            {
+                for (int x = 0;x < resolution;x++)
+                {
+                    byte pixel = texture[addr];
+                    if  (pixel == 8 )
+                    {
+                        int jt = 0;
+                    }
+                    if ( pixel != cachedPixel && pixel != 254 /*used for not matched layer*/ )
+                    {
+                        if (!remappedLayerIndices.TryGetValue( pixel, out remappedPixel ))
+                        {
+                            if (remappedIndexCounter < 253) // 254 is reserved for no layer match, 255 is ray hit with triangle.
+                            {
+                                remappedIndexCounter++;
+                                remappedPixel = (byte)remappedIndexCounter;
+                                remappedLayerIndices.Add( pixel, remappedPixel );
+                            }
+                            else remappedPixel = 0;
+                        }
+                        cachedPixel = pixel;
+                    }
+                    texture[addr] = remappedPixel;
+                    addr++;
+                }
+            }
+
+            Debug.Assert(remappedIndexCounter <= 254, "Exceeded layer count." );
+            return texture;
         }
     }