Skip to content
Snippets Groups Projects
Commit b72ce56a authored by Knuiman, Bart's avatar Knuiman, Bart
Browse files

Now correctly handles two pixels per byte. So 4 bits per pixel (16 channels of...

Now correctly handles two pixels per byte. So 4 bits per pixel (16 channels of which the last one is reserved for not valid).
parent 322ce668
No related branches found
No related tags found
No related merge requests found
...@@ -7,33 +7,33 @@ using System.Threading.Tasks; ...@@ -7,33 +7,33 @@ using System.Threading.Tasks;
using UnityEngine; using UnityEngine;
using UnityEngine.Networking; using UnityEngine.Networking;
namespace Wander namespace Wander
{ {
internal class QuadTreeNode internal class QuadTreeNode
{ {
internal Vector2 min, max; internal Vector2 min, max;
internal QuadTreeNode[] children; internal QuadTreeNode[] children;
internal List<(int, int, int)> triangles; // Layer, Feature, Triangle index. internal List<(int, int, int)> triangles; // Layer, Feature, Triangle index.
internal int depth; internal int depth;
} }
// Always multiple of 3. Each 3 form a triangle. // Always multiple of 3. Each 3 form a triangle.
public class TriangulatedPolygon public class TriangulatedPolygon
{ {
public List<Vector2> vertices; public List<Vector2> vertices;
public List<Vector2> mins; public List<Vector2> mins;
public List<Vector2> maxs; public List<Vector2> maxs;
public List<float> denoms; public List<float> denoms;
public void OptimizeForIsPointInTriangle() public void OptimizeForIsPointInTriangle()
{ {
if ( vertices == null ) return; // Non poly layers have this. if (vertices == null) return; // Non poly layers have this.
mins = new List<Vector2>( vertices.Count / 3 ); mins = new List<Vector2>( vertices.Count / 3 );
maxs = new List<Vector2>( vertices.Count / 3 ); maxs = new List<Vector2>( vertices.Count / 3 );
denoms = new List<float>( vertices.Count / 3 ); denoms = new List<float>( vertices.Count / 3 );
for ( int i = 0; i < vertices.Count; i += 3 ) for (int i = 0;i < vertices.Count;i += 3)
{ {
float minx = float.MaxValue; float minx = float.MaxValue;
float miny = float.MaxValue; float miny = float.MaxValue;
...@@ -61,8 +61,8 @@ namespace Wander ...@@ -61,8 +61,8 @@ namespace Wander
denoms.Add( denominator ); denoms.Add( denominator );
} }
} }
} }
public class VectorTile public class VectorTile
{ {
public bool DownloadStarted => started; public bool DownloadStarted => started;
...@@ -84,7 +84,7 @@ namespace Wander ...@@ -84,7 +84,7 @@ namespace Wander
public void StartDownload() public void StartDownload()
{ {
UnityEngine.Debug.Assert(!started); UnityEngine.Debug.Assert( !started );
request.SendWebRequest(); request.SendWebRequest();
started = true; started = true;
} }
...@@ -122,17 +122,17 @@ namespace Wander ...@@ -122,17 +122,17 @@ namespace Wander
// Number of failed polys to triangulate are returned. // Number of failed polys to triangulate are returned.
public int Triangulate() public int Triangulate()
{ {
if (triangulated ) if (triangulated)
return 0; return 0;
int numFailedPolys = 0; int numFailedPolys = 0;
polygonLayers = new List<List<TriangulatedPolygon>>(); polygonLayers = new List<List<TriangulatedPolygon>>();
List<double> vertices = new List<double>(); List<double> vertices = new List<double>();
List<int> holeIndices = new List<int>(); List<int> holeIndices = new List<int>();
for ( int i =0; i < layers.Count; i++ ) for (int i = 0;i < layers.Count;i++)
{ {
var features = layers[i].VectorTileFeatures; var features = layers[i].VectorTileFeatures;
var polygons = new List<TriangulatedPolygon>(); var polygons = new List<TriangulatedPolygon>();
for (int j = 0; j< features.Count; j++) for (int j = 0;j< features.Count;j++)
{ {
polygons.Add( new TriangulatedPolygon() ); // Add empty to ensure list(layer) of lists(features) match. polygons.Add( new TriangulatedPolygon() ); // Add empty to ensure list(layer) of lists(features) match.
if (features[j].GeometryType != Tile.GeomType.Polygon) if (features[j].GeometryType != Tile.GeomType.Polygon)
...@@ -160,7 +160,7 @@ namespace Wander ...@@ -160,7 +160,7 @@ namespace Wander
var indices = EarcutNet.Earcut.Tessellate( vertices, holeIndices ); var indices = EarcutNet.Earcut.Tessellate( vertices, holeIndices );
TriangulatedPolygon poly = new TriangulatedPolygon(); TriangulatedPolygon poly = new TriangulatedPolygon();
poly.vertices = new List<Vector2>( indices.Count ); poly.vertices = new List<Vector2>( indices.Count );
for (int k = 0;k < indices.Count; k++) for (int k = 0;k < indices.Count;k++)
{ {
double x = vertices[indices[k]*2]; double x = vertices[indices[k]*2];
double y = vertices[indices[k]*2+1]; double y = vertices[indices[k]*2+1];
...@@ -273,7 +273,7 @@ namespace Wander ...@@ -273,7 +273,7 @@ namespace Wander
} }
UnityEngine.Debug.Log( "Optimize for raytracing took " + sw.ElapsedMilliseconds ); UnityEngine.Debug.Log( "Optimize for raytracing took " + sw.ElapsedMilliseconds );
} }
catch ( Exception e ) catch (Exception e)
{ {
UnityEngine.Debug.LogException( e ); UnityEngine.Debug.LogException( e );
} }
...@@ -304,15 +304,15 @@ namespace Wander ...@@ -304,15 +304,15 @@ namespace Wander
layersIdentified = true; layersIdentified = true;
} }
// Generates a raster for each position (pixel) (256 channels) where each value represents a single channel. // Generates a raster for each position (pixel). 2 pixels are pushed in 1 (each 16 bit).
// If no polygon was hit, 255 is encoded. // If no polygon was hit, 15 is encoded (reserved).
// If polygon was hit, but no feature was matched, 254 is encoded. // If polygon was hit, but no feature was matched, also 15 is encoded.
// Returns a list of failed to match pixels. This can be due to geometry not exactly matching or a layer not being found. // Returns a list of failed to match pixels. This can be due to geometry not exactly matching or a layer not being found.
// Also outputs a remap of layer indices. For instance for a specific tile, only layerIdx 1, 6 and 3 are used. // Also outputs a remap of layer indices. For instance for a specific tile, only layerIdx 1, 6 and 3 are used.
// Then it applies a remapping of 1->0, 6->1, 3->2. So that in the shader only 3 textures are needed starting from 0, 1.. etc. // Then it applies 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( public byte[] RenderToTextureSingle(
int resolution, int resolution,
out Dictionary<byte, byte> remappedLayerIndices, out Dictionary<byte, byte> remappedLayerIndices,
out List<Vector3Int> failedPixels, out List<Vector3Int> failedPixels,
ref bool cancelToken ) ref bool cancelToken )
{ {
...@@ -323,7 +323,7 @@ namespace Wander ...@@ -323,7 +323,7 @@ namespace Wander
UnityEngine.Debug.Assert( layersIdentified, "Identify layers first." ); UnityEngine.Debug.Assert( layersIdentified, "Identify layers first." );
UnityEngine.Debug.Assert( resolution > 1, "Must be at least 2." ); UnityEngine.Debug.Assert( resolution > 1, "Must be at least 2." );
byte [] texture = new byte[resolution*resolution]; byte [] texture = new byte[resolution*resolution/2];
failedPixels = new List<Vector3Int>(); failedPixels = new List<Vector3Int>();
remappedLayerIndices = new Dictionary<byte, byte>(); remappedLayerIndices = new Dictionary<byte, byte>();
float oneOverRes = 1.0f / resolution; float oneOverRes = 1.0f / resolution;
...@@ -336,7 +336,7 @@ namespace Wander ...@@ -336,7 +336,7 @@ namespace Wander
// For each pixel. // For each pixel.
for (int y = 0;y < resolution && !cancelToken;y++) for (int y = 0;y < resolution && !cancelToken;y++)
{ {
for (int x = 0;x < resolution && !cancelToken ;x++) for (int x = 0;x < resolution && !cancelToken;x++)
{ {
bool hit = false; bool hit = false;
Vector2 p = new Vector2(fx*x+0.5f, fx*y+0.5f); Vector2 p = new Vector2(fx*x+0.5f, fx*y+0.5f);
...@@ -351,16 +351,16 @@ namespace Wander ...@@ -351,16 +351,16 @@ namespace Wander
continue; continue;
} }
if ( node.children != null ) if (node.children != null)
{ {
for ( int c = 0; c < node.children.Length; c++ ) for (int c = 0;c < node.children.Length;c++)
{ {
stack.Add( node.children[c] ); stack.Add( node.children[c] );
} }
} }
else if (node.triangles != null) // Is leaf else if (node.triangles != null) // Is leaf
{ {
for( int t = 0; t < node.triangles.Count; t++ ) for (int t = 0;t < node.triangles.Count;t++)
{ {
int ti = (cachedTriIdx + t) % node.triangles.Count; // Continue searching where we left off int ti = (cachedTriIdx + t) % node.triangles.Count; // Continue searching where we left off
int l = node.triangles[ti].Item1; int l = node.triangles[ti].Item1;
...@@ -375,9 +375,13 @@ namespace Wander ...@@ -375,9 +375,13 @@ namespace Wander
hit = GeomUtil.PointIsInsideTriangle2( p, vertices[t2*3], vertices[t2*3+1], vertices[t2*3+2], denoms[t2] ); hit = GeomUtil.PointIsInsideTriangle2( p, vertices[t2*3], vertices[t2*3+1], vertices[t2*3+2], denoms[t2] );
if (hit) if (hit)
{ {
cachedTriIdx = ti; cachedTriIdx = ti;
var layerIdx = (byte)layers[l].VectorTileFeatures[f].SelectedLayerIdx; var layerIdx = (byte)layers[l].VectorTileFeatures[f].SelectedLayerIdx;
texture[(resolution - y -1)*resolution+x] = layerIdx; //var addr2 = y*resolution+x;
var addr2 = (resolution - y -1)*resolution+x;
if (layerIdx > 15) layerIdx = 15; // max layers 15 (15 is reserved, nothing was hit).
var shift = (addr2&1) << 2;
texture[addr2>>1] |= (byte)(layerIdx << shift);
break; break;
} }
} }
...@@ -390,8 +394,10 @@ namespace Wander ...@@ -390,8 +394,10 @@ namespace Wander
stack.Clear(); stack.Clear();
if (!hit) if (!hit)
{ {
texture[(resolution - y -1)*resolution+x] = 255; var addr2 = (resolution - y -1)*resolution+x;
failedPixels.Add( new Vector3Int( x, y, 255 ) ); var shift = (addr2&1) << 2;
texture[addr2>>1] |= (byte)(15 << shift);
failedPixels.Add( new Vector3Int( x, y, 15 ) );
} }
else else
{ {
...@@ -402,47 +408,61 @@ namespace Wander ...@@ -402,47 +408,61 @@ namespace Wander
// Determine number of different layers. For instance, if only layer 3, 8, 14 and 15 are used, we select // 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. // a material that only uses 4 textures and put 3 -> Albedo_0 -> 8 to Albedo_1, etc. in the shader.
byte cachedPixel = 255; byte cachedPixel = 15;
int remappedIndexCounter = -1; int remappedIndexCounter = -1;
byte remappedPixel = 255; byte remappedPixel = 15;
int addr = 0; uint addr = 0;
byte pixel = 0;
for (int y = 0;y < resolution && !cancelToken;y++) for (int y = 0;y < resolution && !cancelToken;y++)
{ {
for (int x = 0;x < resolution;x++) for (int x = 0;x < resolution && !cancelToken;x++)
{ {
byte pixel = texture[addr]; if ((x&1) == 0)
if (pixel < 254) pixel = texture[addr>>1];
byte shift = (byte)((addr&1));
byte pixel2 = (byte)((pixel >> (shift<<2)) & 15);
if (pixel2 != 15)
{ {
if (pixel != cachedPixel) if (pixel2 != cachedPixel)
{ {
if (!remappedLayerIndices.TryGetValue( pixel, out remappedPixel )) if (!remappedLayerIndices.TryGetValue( pixel2, out remappedPixel ))
{ {
if (remappedIndexCounter < 253) // 254 is reserved for no layer match, 255 is ray hit with triangle. if (remappedIndexCounter < 13) // 15 is reserved for not found, so 0-14 are valid.
{ {
remappedIndexCounter++; remappedIndexCounter++;
remappedPixel = (byte)remappedIndexCounter; remappedPixel = (byte)remappedIndexCounter;
remappedLayerIndices.Add( pixel, remappedPixel ); remappedLayerIndices.Add( pixel2, remappedPixel );
} }
else remappedPixel = 0; else remappedPixel = 15; // Reserved for invalid.
} }
cachedPixel = pixel; cachedPixel = pixel2;
} }
texture[addr] = remappedPixel; UnityEngine.Debug.Assert( remappedPixel < 15 );
} // leave unfound or unhit pixels on their original value. }
else
{
remappedPixel = 15;
cachedPixel = 15;
}
// Data in texture is not zero anymore, so must check if is even, then just set, otherwise OR-add it.
if (shift==0)
texture[addr>>1] = remappedPixel;
else
texture[addr>>1] |= (byte)(remappedPixel << 4);
addr++; addr++;
} }
} }
UnityEngine.Debug.Assert(remappedIndexCounter <= 254, "Exceeded layer count." ); UnityEngine.Debug.Assert( remappedIndexCounter <= 15, "Exceeded layer count." ); // Invalid pixel is not added to map, so max must be 15, not 16.
UnityEngine.Debug.Log( "Render to texture took " + sw.ElapsedMilliseconds ); UnityEngine.Debug.Log( "Render to texture took " + sw.ElapsedMilliseconds );
return texture; return texture;
} }
} }
public static class VectorTileLoader public static class VectorTileLoader
{ {
public static VectorTile LoadFromUrl( string url, bool autoStart=true ) public static VectorTile LoadFromUrl( string url, bool autoStart = true )
{ {
VectorTile tile = new VectorTile(); VectorTile tile = new VectorTile();
tile.request = UnityWebRequest.Get( url ); tile.request = UnityWebRequest.Get( url );
...@@ -452,5 +472,5 @@ namespace Wander ...@@ -452,5 +472,5 @@ namespace Wander
} }
return tile; return tile;
} }
} }
} }
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment