diff --git a/Runtime/VectorTile.cs b/Runtime/VectorTile.cs
index 1b9f62f411250c853052fbf2dc0784127ff862ed..a4bef7ccfa44050438b6e2cca239e57b0ef721db 100644
--- a/Runtime/VectorTile.cs
+++ b/Runtime/VectorTile.cs
@@ -1,6 +1,8 @@
+using Codice.CM.Client.Differences;
 using Mapbox.Vector.Tile;
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
 using System.Linq;
 using System.Threading.Tasks;
@@ -11,6 +13,14 @@ using static Wander.Easing;
 
 namespace Wander
 {
+    internal class QuadTreeNode
+    {
+        internal Vector2 min, max;
+        internal QuadTreeNode[] children;
+        internal List<(int, int, int)> triangles; // Layer, Feature, Triangle index.
+        internal int depth;
+    }
+
     // Always multiple of 3. Each 3 form a triangle.
     public class TriangulatedPolygon
     {
@@ -30,7 +40,7 @@ namespace Wander
             for ( int i = 0; i < vertices.Count; i += 3 )
             {
                 float minx = float.MaxValue;
-                float miny = float.MaxValue;    
+                float miny = float.MaxValue;
                 if (vertices[i+0].x < minx) minx = vertices[i].x;
                 if (vertices[i+0].y < miny) miny = vertices[i].y;
                 if (vertices[i+1].x < minx) minx = vertices[i+1].x;
@@ -72,12 +82,13 @@ namespace Wander
         private Task parseTileTask;
         private List<VectorTileLayer> layers;
         private List<List<TriangulatedPolygon>> polygonLayers;
+        private QuadTreeNode root;
 
         internal UnityWebRequest request;
 
         public void StartDownload()
         {
-            Debug.Assert(!started);
+            UnityEngine.Debug.Assert(!started);
             request.SendWebRequest();
             started = true;
         }
@@ -175,7 +186,7 @@ namespace Wander
                         //    }
                         //}
                         polygons[polygons.Count-1] = poly;
-                        Debug.Assert( poly.vertices.Count % 3 == 0 );
+                        UnityEngine.Debug.Assert( poly.vertices.Count % 3 == 0 );
                     }
                     catch (Exception)
                     {
@@ -190,9 +201,92 @@ namespace Wander
 
         public void OptimizeForPointIsInsideTriangle()
         {
+            Stopwatch sw = new Stopwatch();
+            sw.Restart();
             for (int i = 0;i < polygonLayers.Count;i++)
+            {
                 for (int j = 0;j < polygonLayers[i].Count;j++)
+                {
                     polygonLayers[i][j].OptimizeForIsPointInTriangle();
+                }
+            }
+
+            // Generate quadtree
+            List<QuadTreeNode> stack = new List<QuadTreeNode>();
+            root = new QuadTreeNode();
+            root.triangles = new List<(int, int, int)>();
+            root.min = new Vector2( 0, 0 );
+            root.max = new Vector2( 4096, 4096 ); // TODO 4096 should be max of all layer extents.
+            for (int l = 0;l < polygonLayers.Count;l++)
+            {
+                var layer = layers[l];
+                for (int f = 0;f < layer.VectorTileFeatures.Count;f++)
+                {
+                    var feature = layer.VectorTileFeatures[f];
+
+                    if (feature.GeometryType != Tile.GeomType.Polygon)
+                        continue;
+
+                    var polygons = polygonLayers[l][f];
+                    if (polygons.vertices.Count == 0)
+                        continue;
+
+                    if (feature.SelectedLayerIdx == 254)
+                        continue;
+
+                    if (feature.RelativeHeight > 0)
+                        continue;
+
+                    var poly = polygonLayers[l][f];
+                    for (int t = 0;t < poly.vertices.Count/3;t++)
+                    {
+                        root.triangles.Add( (l, f, t) );
+                    }
+                }
+            }
+            stack.Add( root );
+            while (stack.Count > 0)
+            {
+                var node = stack[0];
+                stack.RemoveAt( 0 );
+                if (node.triangles.Count < 4)
+                    continue;
+                if (node.depth > 7)
+                    continue;
+                node.children = new QuadTreeNode[4];
+                var hs = (node.max - node.min) / 2;
+                Vector2 [] mins = new [] {
+                    node.min,
+                    new Vector2(node.min.x+hs.x, node.min.y),
+                    new Vector2(node.min.x,      node.min.y+hs.y),
+                    new Vector2(node.min.x+hs.x, node.min.y+hs.y)
+                };
+                for (int i = 0;i < 4;i++)
+                {
+                    var n2   = new QuadTreeNode();
+                    n2.depth = node.depth+1;
+                    n2.min   = mins[i];
+                    n2.max   = n2.min + hs;
+                    n2.triangles = new List<(int, int, int)>();
+                    for ( int t = 0; t < node.triangles.Count; t++ )
+                    {
+                        int l  = node.triangles[t].Item1;
+                        int f  = node.triangles[t].Item2;
+                        int t2 = node.triangles[t].Item3;
+                        var min2 = polygonLayers[l][f].mins[t2];
+                        var max2 = polygonLayers[l][f].maxs[t2];
+                        if ( (min2.x > n2.max.x) || (min2.y > n2.max.y) || (max2.x < n2.min.x) || (max2.y < n2.min.y) )
+                        {
+                            continue;
+                        }
+                        n2.triangles.Add( (l, f, t2) );
+                    }
+                    node.children[i] = n2;
+                    stack.Add( n2 );
+                }   
+                node.triangles = null;
+            }
+            UnityEngine.Debug.Log( "Optimize for raytracing took " + sw.ElapsedMilliseconds );
         }
 
         // Identify feature by specifying a (unique) index based on some criteria. This can very per
@@ -230,103 +324,101 @@ namespace Wander
             int resolution,
             out Dictionary<byte, byte> remappedLayerIndices,     
             out List<Vector3Int> failedPixels,
-            bool? cancelToken )
+            ref bool cancelToken )
         {
-            Debug.Assert( triangulated, "First call Triangulate." );
-            Debug.Assert( layersIdentified, "Identify layers first." );
-            Debug.Assert( resolution > 1, "Must be at least 2." );
+            Stopwatch sw = new Stopwatch();
+            sw.Restart();
+
+            UnityEngine.Debug.Assert( triangulated, "First call Triangulate." );
+            UnityEngine.Debug.Assert( layersIdentified, "Identify layers first." );
+            UnityEngine.Debug.Assert( resolution > 1, "Must be at least 2." );
 
             byte [] texture = new byte[resolution*resolution];
             failedPixels = new List<Vector3Int>();
             remappedLayerIndices = new Dictionary<byte, byte>();
             float oneOverRes = 1.0f / resolution;
+            int cachedTriIdx = 0;
+            float fx = 4096 * oneOverRes; // TODO 4096 may be different in other implementations.
 
-            int cachedTriIdx  = 0;
-            int cachedLyrIdx  = 0;
-            int cachedFtrIdx  = 0;
+            QuadTreeNode node = null;
+            List<QuadTreeNode> stack = new List<QuadTreeNode>();
 
             // For each pixel.
             for (int y = 0;y < resolution ;y++)
             {
-                for (int x = 0;x < resolution && !cancelToken.Value ;x++)
+                for (int x = 0;x < resolution && !cancelToken ;x++)
                 {
                     bool hit  = false;
+                    Vector2 p = new Vector2(fx*x+0.5f, fx*y+0.5f);
 
-                    // For each layer, check triangle intersections.
-                    for (int l = 0;l < layers.Count && !cancelToken.Value;l++)
+                    stack.Add( root );
+                    while (stack.Count > 0)
                     {
-                        var lIdx  = (l+cachedLyrIdx) % layers.Count; // Try last layer/feature/triangle first.
-                        var layer = layers[lIdx];
-                        float fx  = layer.Extent * oneOverRes;
-                        Vector2 p = new Vector2(fx*x+0.5f, fx*y+0.5f);
-
-                        for (int f = 0;f < layer.VectorTileFeatures.Count;f++)
+                        node = stack[0];
+                        stack.RemoveAt( 0 );
+                        if (p.x < node.min.x || p.y < node.min.y || p.x > node.max.x || p.y > node.max.y)
                         {
-                            var ftrIdx  = (f + cachedFtrIdx) % layer.VectorTileFeatures.Count;
-                            var feature = layer.VectorTileFeatures[ftrIdx];
-
-                            if (feature.GeometryType != Tile.GeomType.Polygon)
-                                continue;
-
-                            var polygons = polygonLayers[lIdx][ftrIdx];
-                            if (polygons.vertices.Count == 0)
-                                continue;
-
-                            if (feature.SelectedLayerIdx == 254)
-                                continue;
-
-                            if (feature.RelativeHeight > 0)
-                                continue;
+                            continue;
+                        }
 
-                            var poly     = polygonLayers[lIdx][ftrIdx];
-                            var mins     = poly.mins;
-                            var maxs     = poly.maxs;
-                            var denoms   = poly.denoms;
-                            var vertices = poly.vertices;
-                            var triCount = vertices.Count/3;
-                            for (int t = 0; t < triCount;t++)
+                        if ( node.children != null )
+                        {
+                            for ( int c = 0; c < node.children.Length; c++ )
+                            {
+                                stack.Add( node.children[c] );
+                            }
+                        }
+                        else if (node.triangles != null) // Is leaf
+                        {
+                            for( int t = 0; t < node.triangles.Count; t++ )
                             {
-                                int triIdx = (t+cachedTriIdx) % triCount;
-                                if (p.x < mins[triIdx].x || p.x > maxs[triIdx].x) continue;
-                                if (p.y < mins[triIdx].y || p.y > maxs[triIdx].y) continue;
-                                hit = GeomUtil.PointIsInsideTriangle2( p, vertices[triIdx*3], vertices[triIdx*3+1], vertices[triIdx*3+2], denoms[triIdx] );
+                                int ti = (cachedTriIdx + t)  % node.triangles.Count;
+                                int l  = node.triangles[ti].Item1;
+                                int f  = node.triangles[ti].Item2;
+                                int t2 = node.triangles[ti].Item3;
+                                var min2 = polygonLayers[l][f].mins[t2];
+                                var max2 = polygonLayers[l][f].maxs[t2];
+                                if (p.x < min2.x || p.x > max2.x) continue;
+                                if (p.y < min2.y || p.y > max2.y) continue;
+                                var vertices = polygonLayers[l][f].vertices;
+                                var denoms   = polygonLayers[l][f].denoms;
+                                hit = GeomUtil.PointIsInsideTriangle2( p, vertices[t2*3], vertices[t2*3+1], vertices[t2*3+2], denoms[t2] );
                                 if (hit)
                                 {
-                                    cachedTriIdx = triIdx;
-                                    cachedLyrIdx = lIdx;
-                                    cachedFtrIdx = ftrIdx;
-                                    texture[(resolution - y -1)*resolution+x] = (byte)feature.SelectedLayerIdx;
+                                    // TODO caching the TriIdx doees not work, I have no clue why, it should only function
+                                    // as a hint, as where to start. But using this hint results in massive number of triangles going wrong...
+                                 //   cachedTriIdx = ti; 
+                                    var layerIdx = (byte)layers[l].VectorTileFeatures[f].SelectedLayerIdx;
+                                    texture[(resolution - y -1)*resolution+x] = layerIdx;
                                     break;
                                 }
                             }
-
-                            if (hit) break;
-
-                            cachedTriIdx += 1;
-                            if(cachedTriIdx == triCount) cachedTriIdx = 0;
                         }
 
                         if (hit) break;
 
-                        cachedFtrIdx = 0;
-                    }
+                    } // end while
 
+                    stack.Clear();
                     if (!hit)
                     {
-                        cachedLyrIdx = 0;
                         texture[(resolution - y -1)*resolution+x] = 255;
                         failedPixels.Add( new Vector3Int( x, y, 255 ) );
                     }
+                    else
+                    {
+                        stack.Add( node ); // Add the node that was hit as the next pixel may likely hit this poly again.
+                    }
                 }
             }
 
             // 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.
             byte cachedPixel = 255;
-            int remappedIndexCounter = -1;
+            int  remappedIndexCounter = -1;
             byte remappedPixel = 255;
-            int addr = 0;
-            for (int y = 0;y < resolution && !cancelToken.Value;y++)
+            int  addr = 0;
+            for (int y = 0;y < resolution && !cancelToken;y++)
             {
                 for (int x = 0;x < resolution;x++)
                 {
@@ -353,7 +445,9 @@ namespace Wander
                 }
             }
 
-            Debug.Assert(remappedIndexCounter <= 254, "Exceeded layer count." );
+            UnityEngine.Debug.Assert(remappedIndexCounter <= 254, "Exceeded layer count." );
+
+            UnityEngine.Debug.Log( "Render to texture took " + sw.ElapsedMilliseconds );
             return texture;
         }
     }