/// <summary> /// Returns i,j pixel coordinates of this ViewVector within 1D rep of pixelGrid /// of height, width spanning across FOV /// </summary> public int Map <T>(T[] grid, int height, int width, ViewVector FOV, Vector2 FOVReduction) { int i = (int)(width / 2 + width * (Theta / (FOV.Theta / FOVReduction.x))); int j = (int)(height / 2 + height * (Phi / (FOV.Phi / FOVReduction.y))); // ensure in grid if (i < 0) { throw new ArgumentOutOfRangeException("i", "less than zero"); } if (i > width) { throw new ArgumentOutOfRangeException("i", "greater than width"); } if (j < 0) { throw new ArgumentOutOfRangeException("j", "less than zero"); } if (j > height) { throw new ArgumentOutOfRangeException("j", "greater than height"); } int index = j * width + i; if (index > grid.Length) { throw new ArgumentOutOfRangeException("index", "greater than grid length"); } return(index); }
/// <summary> /// Returns list of all points in viewField using oc for occlusion approximation. /// Will update occluded and notInView to lists of vertices in those categories. /// NOTE: clearing lists, resetting metadata must be done BEFORE calling method. /// </summary> public List <CachedVertex> AllInView(List <SurfacePoints> extras, List <bool> meshGuide, Frustum viewField, Occlusion oc) { for (int i = 0; i < extras.Count; i++) { // check visibility if (meshGuide[i]) { for (int j = 0; j < extras[i].Wvertices.Count; j++) { Vector3 pt = extras[i].Wvertices[j]; Vector3 Pvec = Vector(viewField.Transform.position, pt); ViewVector vv = viewField.ViewVec(pt); if (viewField.FOV.Contains(vv)) { Vector2 coords = vv.Map <Occlusion.OcclusionCell>(oc.grid, viewField.FOV); CachedVertex cv = new CachedVertex(pt, i, j); if (oc.grid[(int)coords.x, (int)coords.y].nullCell || Pvec.magnitude < oc.grid[(int)coords.x, (int)coords.y].distance) { oc.grid[(int)coords.x, (int)coords.y].closest = cv; oc.grid[(int)coords.x, (int)coords.y].distance = Pvec.magnitude; oc.grid[(int)coords.x, (int)coords.y].nullCell = false; NonOccludedVertices++; } VerticesInView++; } CheckedVertices++; } } } return(oc.Points()); }
/// <summary> /// Projects raster values onto passed list of points from frustum viewField. /// Also updates mesh colors of meshes and points defined by meshList, meshIndices, pointIndices /// according to color1 to color2, value1 to value2 scale. /// </summary> private List <PointValue <byte> > Project(List <CachedVertex> points, Frustum viewField, byte[,] raster, float closest, float furthest, Vector3 curPos) { List <PointValue <byte> > result = new List <PointValue <byte> >(); for (int i = 0; i < points.Count; i++) { Vector3 pt = points[i].point; ViewVector vv = viewField.ViewVec(pt); if (!viewField.FOV.Contains(vv)) { throw new ArgumentOutOfRangeException("pt", "not contained in viewField.FOV"); } /* Usual path - use sensor pixelmap * Vector2 coords = vv.Map<byte>(raster, viewField.FOV); * PointValue<byte> pv = new PointValue<byte>(pt, raster[(int)coords.x, (int)coords.y]); */ // proximity path - use vertex coordinates Vector3 Vpos = Vector(curPos, pt); float distVal = (Vpos.magnitude - closest) / (furthest - closest); distVal = Mathf.Clamp01(distVal); byte scaledVal = (byte)(distVal * 255f); PointValue <byte> pv = new PointValue <byte>(pt, scaledVal); // add pv to return result.Add(pv); } return(result); }
/// <summary> /// Returns i,j pixel coordinates of this ViewVector within pixelGrid spanning across FOV /// </summary> public Vector2 Map <T>(T[,] grid, ViewVector FOV) { Vector2 result = new Vector2(); result.x = (int)(grid.GetLength(0) / 2 + grid.GetLength(0) * (Theta / FOV.Theta)); result.y = (int)(grid.GetLength(1) / 2 + grid.GetLength(1) * (Phi / FOV.Phi)); return(result); }
public Occlusion(int i, int j, ViewVector myFOV) { FOV = myFOV; objSize = -1f; objDistance = -1f; grid = new OcclusionCell[i, j]; Reset(); }
public void Update(Vector3 position) { base.Update(); ViewVector = Vector3.Transform(Target - position, Matrix.CreateRotationY(0)); ViewVector.Normalize(); Forward.Normalize(); View = Matrix.CreateLookAt(position, position + Forward, Vector3.Up); }
/// <summary> /// Determines the required grid size given hard-coded parameters for occlusion approximation via closest in grid. /// </summary> public static Vector2 GridSize(ViewVector FOV) { float totalViewSizeX = 2.0f * ObjDistance * (float)Math.Tan(DegToRad(FOV.Theta) / 2.0); float totalViewSizeY = 2.0f * ObjDistance * (float)Math.Tan(DegToRad(FOV.Phi) / 2.0); Vector2 dims = new Vector2(); dims.x = (int)Math.Round(totalViewSizeX / ObjSize); dims.y = (int)Math.Round(totalViewSizeY / ObjSize); return(dims); }
/// <summary> /// Projects raster values onto passed list of points from frustum viewField. /// Also updates mesh colors of meshes and points defined by meshList, meshIndices, pointIndices /// according to color1 to color2, value1 to value2 scale. /// </summary> private List <PointValue <byte> > Project(List <CachedVertex> points, Frustum viewField, byte[,] raster, ReadOnlyCollection <SpatialMappingSource.SurfaceObject> meshList, Color32 color1, Color32 color2, Color32 defaultColor, byte value1, byte value2) { List <PointValue <byte> > result = new List <PointValue <byte> >(); // setup coloring List <List <Color32> > newColoring = new List <List <Color32> >(); List <int> colorIndices = new List <int>(); for (int i = 0; i < points.Count; i++) { // setup coloring if (!colorIndices.Contains(points[i].meshIndex)) { int numVerts = meshList[points[i].meshIndex].Filter.sharedMesh.vertexCount; List <Color32> newColors = new List <Color32>(); // fill in default color for (int j = 0; j < numVerts; j++) { newColors.Add(defaultColor); } newColoring.Add(newColors); colorIndices.Add(points[i].meshIndex); } Vector3 pt = points[i].point; ViewVector vv = viewField.ViewVec(pt); if (!viewField.FOV.Contains(vv)) { throw new ArgumentOutOfRangeException("pt", "not contained in viewField.FOV"); } Vector2 coords = vv.Map <byte>(raster, viewField.FOV); PointValue <byte> pv = new PointValue <byte>(pt, raster[(int)coords.x, (int)coords.y]); // add pv to return result.Add(pv); // update mesh color float scaleVal = (float)(pv.Value - value1) / (float)(value2 - value1); int ColorIndex = colorIndices.FindIndex(x => x == points[i].meshIndex); newColoring[ColorIndex][points[i].pointIndex] = Color32.Lerp(color1, color2, scaleVal); } for (int i = 0; i < colorIndices.Count; i++) { meshList[colorIndices[i]].Filter.sharedMesh.SetColors(newColoring[i]); } return(result); }
/// <inheritdoc /> public override void Update(GameTime gameTime) { CameraPosition = Distance * new Vector3((float)Math.Sin(Angle), 0, (float)Math.Cos(Angle)); ViewVector = Vector3.Transform(CameraTarget - CameraPosition, Matrix.CreateRotationY(0)); ViewVector.Normalize(); Angle += 0.002f; View = Matrix.CreateLookAt(CameraPosition, CameraTarget, Vector3.UnitY); base.Update(gameTime); }
// Use this for initialization void Start() { // finish setup FOV = new ViewVector(TargetFOV.x, TargetFOV.y); ViewField = new Frustum(Camera.main.transform, FOV); CubeMin = new Vector3(CubeCenter.x - CubeSize / 2f, CubeCenter.y - CubeSize / 2f, CubeCenter.z - CubeSize / 2f); CubeMax = new Vector3(CubeCenter.x + CubeSize / 2f, CubeCenter.y + CubeSize / 2f, CubeCenter.z + CubeSize / 2f); for (int i = 0; i < Vertices; i++) { Points.Add(RandomPoint(CubeMin, CubeMax, Rand)); } Scale = new Vector3(VertexSize, VertexSize, VertexSize); Inter = Intersector.Instance; // create point markers Parent = new GameObject(); Parent.name = "VertexMarkers"; for (int i = 0; i < Vertices; i++) { GameObject Child = GameObject.CreatePrimitive(PrimitiveType.Sphere); Child.AddComponent <MeshFilter>(); Child.AddComponent <MeshRenderer>(); Child.AddComponent <SphereCollider>(); Child.name = "Marker" + i.ToString(); Child.transform.parent = Parent.transform; Child.transform.position = Points[i]; Child.transform.localScale = Scale; Child.GetComponent <MeshRenderer>().material = OutViewMaterial; if (ViewVectorLabels) { GameObject VVLabelT = Instantiate(VVLabelText); VVLabelT.transform.parent = Parent.transform; VVLabelT.name = "Text" + i.ToString(); VVLabelT.transform.position = Points[i] + VVLabelOffset; GameObject VVLabelB = Instantiate(VVLabelBackground); VVLabelB.transform.parent = Parent.transform; VVLabelB.name = "Background" + i.ToString(); VVLabelB.transform.position = Points[i] + VVLabelOffset + new Vector3(0, 0, 0.01f); } } // draw bounds box GameObject BoxParent = new GameObject(); BoxParent.name = "BoxParent"; DrawBox(CubeMin, CubeMax, BoxParent, LineSize, LineMaterial); }
/// <summary> /// Determines the required grid size given hard-coded parameters for occlusion approximation via closest in grid. /// </summary> public Dictionary <string, int> RequiredGrid(ViewVector FOV) { double size = 0.10; // minimum object size to not be considered occluded (m) double angle = 45.0; // maximum surface angle with line-of-sight normal to not be considered occluded (deg) double distance = 3.0; // maximum object distance from sensor to not be considered occluded (m) double apparentSize = size * Math.Cos(DegToRad(angle)); double totalViewSizeX = 2.0 * distance * Math.Tan(DegToRad(FOV.Theta) / 2.0); double totalViewSizeY = 2.0 * distance * Math.Tan(DegToRad(FOV.Phi) / 2.0); Dictionary <string, int> pixels = new Dictionary <string, int>(); pixels.Add("i", (int)Math.Round(totalViewSizeX / apparentSize)); pixels.Add("j", (int)Math.Round(totalViewSizeY / apparentSize)); return(pixels); }
/// <summary> /// Returns list of PointValues representing raster values projected onto points from viewField. /// </summary> private List <PointValue <T> > Project <T>(List <Vector3> points, Frustum viewField, T[,] raster) { List <PointValue <T> > result = new List <PointValue <T> >(); foreach (Vector3 pt in points) { ViewVector vv = viewField.ViewVec(pt); if (!viewField.FOV.Contains(vv)) { throw new ArgumentOutOfRangeException("pt", "not contained in viewField.FOV"); } Vector2 coords = vv.Map <T>(raster, viewField.FOV); result.Add(new PointValue <T>(pt, raster[(int)coords.x, (int)coords.y])); } return(result); }
public Occlusion(float myObjSize, float myObjDistance, ViewVector myFOV) { // set data objSize = myObjSize; objDistance = myObjDistance; FOV = myFOV; // calculate necessary pixel counts float totalViewSizeX = 2.0f * objDistance * (float)Math.Tan(DegToRad(FOV.Theta) / 2.0); float totalViewSizeY = 2.0f * objDistance * (float)Math.Tan(DegToRad(FOV.Phi) / 2.0); Vector2 dims = new Vector2(); dims.x = (int)Math.Round(totalViewSizeX / objSize); dims.y = (int)Math.Round(totalViewSizeY / objSize); // create grid grid = new OcclusionCell[(int)dims.x, (int)dims.y]; Reset(); }
/* OLD INTERSECTION VERSION * /// <summary> * /// Calculates resultant PointValues when 2D Raster (img) is projected along Frustum at Mesh (vertices). * /// Mesh represented by list of vertices. * /// NOTE 1: does not currently account for occlusion. * /// NOTE 2: projection's FOV should be full FOV angles, not half-angles. * /// NOTE 3: Attempted to make generic. See note at begining of file. * /// </summary> * public List<PointValue<byte>> Intersection(Frustum projection, byte[,] img, List<Vector3> vertices) * { * /// setup * ImgPCi = img.GetLength(0); * ImgPCj = img.GetLength(1); * VerticesInView = 0; * * /// update occlusion grid * /// Cannot predeclare OcPixels because cannot add Dictionary components in declaration. * Dictionary<string, int> OcPixels = RequiredGrid(projection.FOV); * // Predeclaration of ocGrid has no benefit due to array type an dynamic size. * OcclusionCell<byte>[,] ocGrid = new OcclusionCell<byte>[OcPixels["i"], OcPixels["j"]]; * for (i = 0; i < OcPixels["i"]; i++) * { * for (j = 0; j < OcPixels["j"]; j++) * { * ocGrid[i, j].nullCell = true; * } * } * * /// try each vertex * for (i = 0; i < vertices.Count; i++) * { * /// calculate position vector (world space) * Vector(projection.Transform.position, vertices[i], ref Pworld); * * /// convert position vector (world space) to position vector (Frustum space) * Plocal = projection.Transform.InverseTransformVector(Pworld); * * /// convert position vector (Frustum space) to view vector (Frustum space) * Vlocal.Update(Plocal); * * /// check if view vector is within Frustum FOV * if (Math.Abs(Vlocal.Theta) < projection.FOV.Theta / 2.0 && * Math.Abs(Vlocal.Phi) < projection.FOV.Phi / 2.0) * { * VerticesInView++; * * /// map view vector to occlusion grid * iOc = (int)(OcPixels["i"] / 2 + OcPixels["i"] * (Vlocal.Theta / projection.FOV.Theta)); * jOc = (int)(OcPixels["j"] / 2 + OcPixels["j"] * (Vlocal.Phi / projection.FOV.Phi)); * * /// add to occlusion grid as new PointValue if not occluded * * if (ocGrid[iOc, jOc].nullCell || Pworld.magnitude < ocGrid[iOc, jOc].distance) * { * /// map view vector to img pixel grid * iImg = (int)(ImgPCi / 2 + ImgPCi * (Vlocal.Theta / projection.FOV.Theta)); * jImg = (int)(ImgPCj / 2 + ImgPCj * (Vlocal.Phi / projection.FOV.Phi)); * * /// update occlusion grid * ocGrid[iOc, jOc].pv.Update(vertices[i], img[iImg, jImg]); * ocGrid[iOc, jOc].distance = Pworld.magnitude; * ocGrid[iOc, jOc].nullCell = false; * } * } * } * * /// Alteratively could prevent reallocating using Result.Clear(), however is slow * Result = new List<PointValue<byte>>(); * for (i = 0; i < ocGrid.GetLength(0); i++) * { * for (j = 0; j < ocGrid.GetLength(1); j++) * { * if (!ocGrid[i, j].nullCell) * Result.Add(ocGrid[i, j].pv); * } * } * NonOccludedVertices = Result.Count; * return Result; * } */ // new Intersection /// <summary> /// Calculates resultant PointValues when 2D Raster (img) is projected along Frustum at Mesh (vertices). /// Mesh represented by list of vertices. /// NOTE 1: does not currently account for occlusion. /// NOTE 2: projection's FOV should be full FOV angles, not half-angles. /// NOTE 3: Attempted to make generic. See note at begining of file. /// </summary> public void Intersection(Frustum projection, List <Vector3> vertices, out List <Vector3> InView, out List <Vector3> OutView, out List <ViewVector> VV, out List <Vector3> PVecs) { /// setup VerticesInView = 0; InView = new List <Vector3>(); OutView = new List <Vector3>(); VV = new List <ViewVector>(); PVecs = new List <Vector3>(); /// try each vertex for (i = 0; i < vertices.Count; i++) { /// calculate position vector (world space) Pworld = Vector(projection.Transform.position, vertices[i]); /// convert position vector (world space) to position vector (Frustum space) Plocal = projection.Transform.InverseTransformVector(Pworld); PVecs.Add(Plocal); /// convert position vector (Frustum space) to view vector (Frustum space) ViewVector Vlocal = new ViewVector(Plocal); VV.Add(Vlocal); /// check if view vector is within Frustum FOV if (Math.Abs(Vlocal.Theta) < projection.FOV.Theta / 2.0 && Math.Abs(Vlocal.Phi) < projection.FOV.Phi / 2.0) { VerticesInView++; InView.Add(vertices[i]); } else { OutView.Add(vertices[i]); } } InViewCount = InView.Count; OutViewCount = OutView.Count; }
/// <summary> /// Projects raster values onto passed list of points from frustum viewField. /// Also updates mesh colors of meshes and points defined by meshList, meshIndices, pointIndices /// according to color1 to color2, value1 to value2 scale. /// </summary> private List <PointValue <byte> > Project(List <CachedVertex> points, Frustum viewField, byte[,] raster) { List <PointValue <byte> > result = new List <PointValue <byte> >(); for (int i = 0; i < points.Count; i++) { Vector3 pt = points[i].point; ViewVector vv = viewField.ViewVec(pt); if (!viewField.FOV.Contains(vv)) { throw new ArgumentOutOfRangeException("pt", "not contained in viewField.FOV"); } Vector2 coords = vv.Map <byte>(raster, viewField.FOV); PointValue <byte> pv = new PointValue <byte>(pt, raster[(int)coords.x, (int)coords.y]); // add pv to return result.Add(pv); } return(result); }
public Occlusion(float myObjSize, float myObjDistance, ViewVector myFOV) { // control // Converts real size myObjSize to apparent size for up to this angle from plane perpindicular to line of sight float ObjAngleOffset = 30; // deg // set data objSize = myObjSize * (float)Math.Cos(DegToRad(ObjAngleOffset)); objDistance = myObjDistance; FOV = myFOV; // calculate necessary pixel counts float totalViewSizeX = 2.0f * objDistance * (float)Math.Tan(DegToRad(FOV.Theta) / 2.0); float totalViewSizeY = 2.0f * objDistance * (float)Math.Tan(DegToRad(FOV.Phi) / 2.0); Vector2 dims = new Vector2(); dims.x = (int)Math.Round(totalViewSizeX / objSize); dims.y = (int)Math.Round(totalViewSizeY / objSize); // create grid grid = new OcclusionCell[(int)dims.x, (int)dims.y]; Reset(); }
/// <summary> /// Projects raster values onto passed list of points from frustum viewField. /// Also updates mesh colors of meshes and points defined by meshList, meshIndices, pointIndices /// according to color1 to color2, value1 to value2 scale. /// </summary> private List <PointValue <byte> > Project(List <CachedVertex> points, Frustum viewField, byte[] raster, int height, int width, float closest, float furthest, Vector3 curPos, Vector2 FOVReduction, bool proxConfig) { List <PointValue <byte> > result = new List <PointValue <byte> >(); for (int i = 0; i < points.Count; i++) { Vector3 pt = points[i].point; ViewVector vv = viewField.ViewVec(pt); if (!viewField.FOV.Contains(vv)) { throw new ArgumentOutOfRangeException("pt", "not contained in viewField.FOV"); } PointValue <byte> pv; if (!proxConfig) { // external sensor configuration int index = vv.Map <byte>(raster, height, width, viewField.FOV, FOVReduction); pv = new PointValue <byte>(pt, raster[index]); } else { // proximity sensor configuration byte colorVal = (byte)Mathf.Clamp(255f * (Vector(curPos, pt).magnitude - closest) / (furthest - closest), 0, 255); pv = new PointValue <byte>(pt, colorVal); } // add pv to return result.Add(pv); } return(result); }
static string viewVectorToStr(ViewVector vector) { return(String.Format("(Theta: {0}, Phi: {1})", vector.Theta, vector.Phi)); }
/// <summary> /// Calculates resultant PointValues when 2D Raster (img) is projected along Frustum at Mesh (vertices). /// Mesh represented by list of vertices. /// NOTE 1: does not currently account for occlusion. /// NOTE 2: projection's FOV should be full FOV angles, not half-angles. /// </summary> public List <PointValue <T> > Intersection <T>(Frustum projection, T[,] img, List <Vector3> vertices) { /// setup int imgPCi = img.GetLength(0); int imgPCj = img.GetLength(1); List <PointValue <T> > result = new List <PointValue <T> >(); VerticesInView = 0; /// create occlusion grid Dictionary <string, int> ocPixels = RequiredGrid(projection.FOV); int ocPCi = ocPixels["i"]; int ocPCj = ocPixels["j"]; OcclusionCell <T>[,] ocGrid = new OcclusionCell <T> [ocPCi, ocPCj]; for (int i = 0; i < ocGrid.GetLength(0); i++) { for (int j = 0; j < ocGrid.GetLength(1); j++) { ocGrid[i, j].nullCell = true; } } /// try each vertex foreach (Vector3 vertex in vertices) { /// calculate position vector (world space) Vector3 Pworld = Vector(projection.Transform.position, vertex); /// convert position vector (world space) to position vector (Frustum space) Vector3 Plocal = projection.Transform.InverseTransformVector(Pworld); /// convert position vector (Frustum space) to view vector (Frustum space) ViewVector Vlocal = new ViewVector(Plocal); /// check if view vector is within Frustum FOV if (Math.Abs(Vlocal.Theta) < projection.FOV.Theta / 2.0 && Math.Abs(Vlocal.Phi) < projection.FOV.Phi / 2.0) { VerticesInView++; /// map view vector to occlusion grid int ioc = (int)(ocPCi / 2 + ocPCi * (Vlocal.Theta / projection.FOV.Theta)); int joc = (int)(ocPCj / 2 + ocPCj * (Vlocal.Phi / projection.FOV.Phi)); /// add to occlusion grid as new PointValue if not occluded if (ocGrid[ioc, joc].nullCell || Pworld.magnitude < ocGrid[ioc, joc].distance) { /// map view vector to img pixel grid int iImg = (int)(imgPCi / 2 + imgPCi * (Vlocal.Theta / projection.FOV.Theta)); int jImg = (int)(imgPCj / 2 + imgPCj * (Vlocal.Phi / projection.FOV.Phi)); /// update occlusion grid ocGrid[ioc, joc].pv = new PointValue <T>(vertex, img[iImg, jImg]); ocGrid[ioc, joc].distance = Pworld.magnitude; ocGrid[ioc, joc].nullCell = false; } } } for (int i = 0; i < ocGrid.GetLength(0); i++) { for (int j = 0; j < ocGrid.GetLength(1); j++) { if (!ocGrid[i, j].nullCell) { result.Add(ocGrid[i, j].pv); } } } nonOccludedVertices = result.Count; return(result); }
/// <summary> /// True if vv is contained within FOV defined by this obj. /// </summary> public bool Contains(ViewVector vv) { return(Math.Abs(vv.Theta) < Theta / 2.0 && Math.Abs(vv.Phi) < Phi / 2.0); }
/// <summary> /// Returns true if any of points are within ViewField, or a pair span it. /// Spanning referes to a pair of points located in front of the sensor and in diagonal ViewVector quandrants. /// DOES NOT update metadata. /// </summary> public bool AnyInView(List <Vector3> points, Frustum viewField) { bool topRight = false; bool topLeft = false; bool botLeft = false; bool botRight = false; bool left = false; bool right = false; bool top = false; bool bot = false; foreach (Vector3 pt in points) { ViewVector vv = viewField.ViewVec(pt); // check in in FOV if (viewField.FOV.Contains(vv)) { return(true); } // check if elligible for span if (Math.Abs(vv.Theta) < 90) { // check corners if (vv.Theta > 0 && vv.Phi > 0) { topRight = true; } else if (vv.Theta > 0) { botRight = true; } else if (vv.Phi > 0) { topLeft = true; } else { botLeft = true; } // check edges if (vv.Theta > 0 && Math.Abs(vv.Phi) < viewField.FOV.Phi / 2) { right = true; } else if (vv.Theta < 0 && Math.Abs(vv.Phi) < viewField.FOV.Phi / 2) { left = true; } else if (vv.Phi > 0 && Math.Abs(vv.Theta) < viewField.FOV.Theta / 2) { top = true; } else if (vv.Phi < 0 && Math.Abs(vv.Theta) < viewField.FOV.Theta / 2) { bot = true; } } } // check for spanning if ((topRight && botLeft) || (topLeft && botRight)) { return(true); } if ((left && right) || (top & bot)) { return(true); } return(false); }
/* OLD INTERSECTION VERSION * /// <summary> * /// Calculates resultant PointValues when 2D Raster (img) is projected along Frustum at Mesh (vertices). * /// Mesh represented by list of vertices. * /// NOTE 1: does not currently account for occlusion. * /// NOTE 2: projection's FOV should be full FOV angles, not half-angles. * /// NOTE 3: Attempted to make generic. See note at begining of file. * /// </summary> * public List<PointValue<byte>> Intersection(Frustum projection, byte[,] img, List<Vector3> vertices) * { * /// setup * ImgPCi = img.GetLength(0); * ImgPCj = img.GetLength(1); * VerticesInView = 0; * * /// update occlusion grid * /// Cannot predeclare OcPixels because cannot add Dictionary components in declaration. * Dictionary<string, int> OcPixels = RequiredGrid(projection.FOV); * // Predeclaration of ocGrid has no benefit due to array type an dynamic size. * OcclusionCell<byte>[,] ocGrid = new OcclusionCell<byte>[OcPixels["i"], OcPixels["j"]]; * for (i = 0; i < OcPixels["i"]; i++) * { * for (j = 0; j < OcPixels["j"]; j++) * { * ocGrid[i, j].nullCell = true; * } * } * * /// try each vertex * for (i = 0; i < vertices.Count; i++) * { * /// calculate position vector (world space) * Vector(projection.Transform.position, vertices[i], ref Pworld); * * /// convert position vector (world space) to position vector (Frustum space) * Plocal = projection.Transform.InverseTransformVector(Pworld); * * /// convert position vector (Frustum space) to view vector (Frustum space) * Vlocal.Update(Plocal); * * /// check if view vector is within Frustum FOV * if (Math.Abs(Vlocal.Theta) < projection.FOV.Theta / 2.0 && * Math.Abs(Vlocal.Phi) < projection.FOV.Phi / 2.0) * { * VerticesInView++; * * /// map view vector to occlusion grid * iOc = (int)(OcPixels["i"] / 2 + OcPixels["i"] * (Vlocal.Theta / projection.FOV.Theta)); * jOc = (int)(OcPixels["j"] / 2 + OcPixels["j"] * (Vlocal.Phi / projection.FOV.Phi)); * * /// add to occlusion grid as new PointValue if not occluded * * if (ocGrid[iOc, jOc].nullCell || Pworld.magnitude < ocGrid[iOc, jOc].distance) * { * /// map view vector to img pixel grid * iImg = (int)(ImgPCi / 2 + ImgPCi * (Vlocal.Theta / projection.FOV.Theta)); * jImg = (int)(ImgPCj / 2 + ImgPCj * (Vlocal.Phi / projection.FOV.Phi)); * * /// update occlusion grid * ocGrid[iOc, jOc].pv.Update(vertices[i], img[iImg, jImg]); * ocGrid[iOc, jOc].distance = Pworld.magnitude; * ocGrid[iOc, jOc].nullCell = false; * } * } * } * * /// Alteratively could prevent reallocating using Result.Clear(), however is slow * Result = new List<PointValue<byte>>(); * for (i = 0; i < ocGrid.GetLength(0); i++) * { * for (j = 0; j < ocGrid.GetLength(1); j++) * { * if (!ocGrid[i, j].nullCell) * Result.Add(ocGrid[i, j].pv); * } * } * NonOccludedVertices = Result.Count; * return Result; * } */ // new Intersection /// <summary> /// Calculates resultant PointValues when 2D Raster (img) is projected along Frustum at Mesh (vertices). /// Mesh represented by list of vertices. /// NOTE 1: does not currently account for occlusion. /// NOTE 2: projection's FOV should be full FOV angles, not half-angles. /// NOTE 3: Attempted to make generic. See note at begining of file. /// </summary> public void Intersection(Frustum projection, List <Vector3> vertices, out List <Vector3> InView, out List <Vector3> OutView, out List <Vector3> Occluded, out List <ViewVector> VV, out List <Vector3> PVecs) { /// setup InView = new List <Vector3>(); OutView = new List <Vector3>(); Occluded = new List <Vector3>(); VV = new List <ViewVector>(); PVecs = new List <Vector3>(); // Predeclaration of ocGrid has no benefit due to array type an dynamic size. OcclusionCell <byte>[,] ocGrid = new OcclusionCell <byte> [(int)OccGridSize.x, (int)OccGridSize.y]; for (i = 0; i < OccGridSize.x; i++) { for (j = 0; j < OccGridSize.y; j++) { ocGrid[i, j].nullCell = true; ocGrid[i, j].occluded = new List <Vector3>(); } } /// try each vertex for (i = 0; i < vertices.Count; i++) { /// calculate position vector (world space) Pworld = Vector(projection.Transform.position, vertices[i]); /// convert position vector (world space) to position vector (Frustum space) Plocal = projection.Transform.InverseTransformVector(Pworld); PVecs.Add(Plocal); /// convert position vector (Frustum space) to view vector (Frustum space) ViewVector Vlocal = new ViewVector(Plocal); VV.Add(Vlocal); /// check if view vector is within Frustum FOV if (Math.Abs(Vlocal.Theta) < projection.FOV.Theta / 2.0 && Math.Abs(Vlocal.Phi) < projection.FOV.Phi / 2.0) { /// map view vector to occlusion grid iOc = (int)(OccGridSize.x / 2 + OccGridSize.x * (Vlocal.Theta / projection.FOV.Theta)); jOc = (int)(OccGridSize.y / 2 + OccGridSize.y * (Vlocal.Phi / projection.FOV.Phi)); if (ocGrid[iOc, jOc].nullCell) { ocGrid[iOc, jOc].closest = vertices[i]; ocGrid[iOc, jOc].distance = Pworld.magnitude; ocGrid[iOc, jOc].nullCell = false; } else if (Pworld.magnitude < ocGrid[iOc, jOc].distance) { ocGrid[iOc, jOc].occluded.Add(ocGrid[iOc, jOc].closest); ocGrid[iOc, jOc].closest = vertices[i]; ocGrid[iOc, jOc].distance = Pworld.magnitude; } else { ocGrid[iOc, jOc].occluded.Add(vertices[i]); } } else { OutView.Add(vertices[i]); } } // add vertices in occluded grid for (i = 0; i < OccGridSize.x; i++) { for (j = 0; j < OccGridSize.y; j++) { InView.Add(ocGrid[i, j].closest); Occluded.AddRange(ocGrid[i, j].occluded); } } InViewCount = InView.Count; OutViewCount = OutView.Count; OccludedCount = Occluded.Count; }
public Frustum(UnityEngine.Transform myTransform, ViewVector myFOV) { Transform = myTransform; FOV = myFOV; }
// new Intersection /// <summary> /// Calculates resultant PointValues when 2D Raster (img) is projected along Frustum at Mesh (vertices). /// Mesh represented by list of vertices. /// NOTE: projection's FOV should be full FOV angles, not half-angles. /// </summary> public List <PointValue <byte> > Intersection(Frustum projection, ref List <Vector3> vertices, ref byte[,] raster) { /// setup List <PointValue <byte> > Results = new List <PointValue <byte> >(); VerticesInView = 0; Vector2 ImgSize = new Vector2(); ImgSize.x = raster.GetLength(0); ImgSize.y = raster.GetLength(1); Vector2 OcGridSize = GridSize(projection.FOV); OcclusionCell <byte>[,] ocGrid = OcclusionCell <byte> .OcGrid(OcGridSize); /// try each vertex for (i = 0; i < vertices.Count; i++) { /// calculate position vector (world space) Vector3 Pworld = Vector(projection.Transform.position, vertices[i]); /// convert position vector (world space) to position vector (Frustum space) Vector3 Plocal = projection.Transform.InverseTransformVector(Pworld); /// convert position vector (Frustum space) to view vector (Frustum space) ViewVector Vlocal = new ViewVector(Plocal); /// check if view vector is within Frustum FOV if (Math.Abs(Vlocal.Theta) < projection.FOV.Theta / 2.0 && Math.Abs(Vlocal.Phi) < projection.FOV.Phi / 2.0) { VerticesInView++; /// map view vector to occlusion grid iOc = (int)(OcGridSize.x / 2 + OcGridSize.x * (Vlocal.Theta / projection.FOV.Theta)); jOc = (int)(OcGridSize.y / 2 + OcGridSize.y * (Vlocal.Phi / projection.FOV.Phi)); if (ocGrid[iOc, jOc].nullCell || Pworld.magnitude < ocGrid[iOc, jOc].distance) { /// map view vector to Img grid iImg = (int)(ImgSize.x / 2 + ImgSize.x * (Vlocal.Theta / projection.FOV.Theta)); jImg = (int)(ImgSize.y / 2 + ImgSize.y * (Vlocal.Phi / projection.FOV.Phi)); ocGrid[iOc, jOc].closest = vertices[i]; ocGrid[iOc, jOc].distance = Pworld.magnitude; ocGrid[iOc, jOc].value = raster[iImg, jImg]; ocGrid[iOc, jOc].nullCell = false; } } } // add vertices in occluded grid for (i = 0; i < OcGridSize.x; i++) { for (j = 0; j < OcGridSize.y; j++) { if (!ocGrid[i, j].nullCell) { Results.Add(new PointValue <byte>(ocGrid[i, j].closest, ocGrid[i, j].value)); } } } CheckedVertices = vertices.Count; NonOccludedVertices = Results.Count; return(Results); }
public Frustum(Transform myTransform, ViewVector myFOV) { Transform = myTransform; FOV = myFOV; }
// Tests Intersector class // Currently tests: // Vector (T1) // InverseTransformVector (T2 - not implemented) // ViewVector alt. constructor (T3) // Intersection (small scale) (T4 - not implemented) // Intersection (large scale) (T5 - not implemented) static string TestIntersector(Intersector IntersectorObj) { string output = "\n<size=144>Testing Intersector...</size>\n\n"; // Test 1: Vector from two points output += "<b>Test 1</b>\n"; Vector3 p1 = new Vector3(0, 0, 0); Vector3 p2 = new Vector3(2, 2, 2); output += String.Format("Vector from two points: {0} to {1}\n", pointToStr(p1), pointToStr(p2)); Vector3 result = new Vector3(); IntersectorObj.Vector(p1, p2, ref result); output += String.Format("Resultant vector: {0}\n\n", pointToStr(result)); // Cannot test Unity Library outside of Unity... // Test 2: InverseTransformVector output += "<b>Test 2</b>\n"; GameObject view2 = new GameObject(); view2.name = "ViewFieldTest2"; view2.transform.Rotate(new Vector3(90, 90, 0)); output += String.Format("InverseTransformVector... view-field position: {0}, view-field euler angles: {1}\n", pointToStr(view2.transform.position), pointToStr(view2.transform.eulerAngles)); Vector3[] unitVectors = unitVectorsArray(); for (int i = 0; i < 8; i++) { output += String.Format("Vector{0}: World Space: {1}, View-Field Local Space: {2}\n", i + 1, pointToStr(unitVectors[i]), pointToStr(view2.transform.InverseTransformVector(unitVectors[i]))); } output += "\n"; // */ // Test 3: View Vector alt. constructor output += "<b>Test 3</b>\n"; output += String.Format("ViewVector creation from position vector (in local space)... 2D cross-sectional plane is XY plane.\n"); Vector3 forward = new Vector3(0, 0, 1); for (int i = 0; i < 8; i++) { output += String.Format("Vector{0} {1}: ViewVector{0} (deg): {2}\n", i + 1, pointToStr(unitVectors[i]), viewVectorToStr(new ViewVector(unitVectors[i]))); } output += String.Format("Vector {0}: ViewVector (deg): {1}\n", pointToStr(forward), viewVectorToStr(new ViewVector(forward))); output += "\n"; // Cannot test Unity Library outside of Unity... // Test 4: Intersection (small scale) output += "<b>Test 4</b>\n"; List <Vector3> unitVectorList = new List <Vector3>(); for (int i = 0; i < 8; i++) { unitVectorList.Add(unitVectors[i]); } GameObject view4 = new GameObject(); view4.name = "ViewFieldTest4"; ViewVector FOV4 = new ViewVector(170, 170); Frustum projection4 = new Frustum(view4.transform, FOV4); byte[,] raster4 = new byte[100, 100]; output += String.Format("Intersection... Raster: ({0}x{1}), Frustum FOV: ({2}x{3}), " + "Frustum Pos: {4}, Frustum EA's: {5}\n" + "Tested all 8 unit vectors, found intersection points...\n", raster4.GetLength(0), raster4.GetLength(1), FOV4.Theta, FOV4.Phi, pointToStr(projection4.Transform.position), pointToStr(projection4.Transform.eulerAngles)); List <PointValue <byte> > intersect = Intersector.Instance.Intersection(projection4, raster4, unitVectorList); foreach (PointValue <byte> pv in intersect) { output += String.Format("Point: {0}, ViewVector: {1}\n", pointToStr(pv.Point), viewVectorToStr(new ViewVector(pv.Point))); } output += "\n"; // Cannot test Unity Library outside of Unity... // Test 5: Intersection (large scale) output += "<b>Test 5</b>\n"; System.Random rand = new System.Random(); GameObject view5 = new GameObject(); view5.name = "ViewFieldTest5"; ViewVector FOV5 = new ViewVector(179, 179); Frustum projection5 = new Frustum(view5.transform, FOV5); byte[,] raster5 = new byte[100, 100]; int iterations = 100; Stopwatch stopWatch = new Stopwatch(); Vector3 boundsMin = new Vector3(-5, -5, -5); Vector3 boundsMax = new Vector3(5, 5, 5); List <Vector3> randVectors = new List <Vector3>(); for (int i = 0; i < iterations; i++) { randVectors.Add(randomPoint(boundsMin, boundsMax, rand)); } output += String.Format("Intersection... Raster: ({0}x{1}), Frustum FOV: ({2}x{3}). {4} Iterations...\n", raster5.GetLength(0), raster5.GetLength(1), FOV5.Theta, FOV5.Phi, randVectors.Count); Intersector tmp = Intersector.Instance; stopWatch.Reset(); stopWatch.Start(); List <PointValue <byte> > result5 = tmp.Intersection(projection5, raster5, randVectors); stopWatch.Stop(); long ms = (long)1000 * stopWatch.ElapsedTicks / Stopwatch.Frequency; output += String.Format("Took {0} ms ({1} us / op)... {2} vectors in view\n", ms, ms / (double)iterations * 1000.0, result5.Count); output += "\n"; // Test 6: RequiredGrid output += "<b>Test 6</b>\n"; ViewVector FOV6 = new ViewVector(60, 60); output += String.Format("Testing RequiredGrid... FOV: {0}\n", viewVectorToStr(FOV6)); Dictionary <string, int> pixels = Intersector.Instance.RequiredGrid(FOV6); output += String.Format("i: {0}, j: {1}\n", pixels["i"], pixels["j"]); output += "\n"; /// Test 7: Occlusion (basic) output += "<b>Test 7</b>\n"; GameObject view7 = new GameObject(); view7.name = "ViewFieldTest7"; ViewVector FOV7 = new ViewVector(170, 170); Frustum projection7 = new Frustum(view7.transform, FOV7); byte[,] raster7 = new byte[100, 100]; for (int i = 0; i < raster7.GetLength(0); i++) { for (int j = 0; j < raster7.GetLength(1); j++) { raster7[i, j] = (byte)(i + j); } } output += String.Format("Created Frustum: pos: {0}, EA's {1}, FOV: {2}\n", pointToStr(projection7.Transform.position), pointToStr(projection7.Transform.eulerAngles), viewVectorToStr(projection7.FOV)); output += String.Format("Created Raster: {0}x{1}\n", raster7.GetLength(0), raster7.GetLength(1)); Vector3 v1 = new Vector3(1, 1, 1); Vector3 v2 = new Vector3(2, 2, 2); Vector3 v3 = new Vector3(0, 0, 1); List <Vector3> vertices7 = new List <Vector3>(); vertices7.Add(v2); vertices7.Add(v1); vertices7.Add(v2); vertices7.Add(v3); output += String.Format("Trying vertices: v1: {0}, v2: {1}, v3: {2}. Intersection return...\n", pointToStr(v1), pointToStr(v2), pointToStr(v3)); List <PointValue <byte> > intersectRet = Intersector.Instance.Intersection(projection7, raster7, vertices7); for (int i = 0; i < intersectRet.Count; i++) { output += String.Format("Point: {0}, Value: {1}\n", pointToStr(intersectRet[i].Point), intersectRet[i].Value); } output += "\n"; // Test 8: Occlusion (large scale) output += "<b>Test 8</b>\n"; GameObject view8 = new GameObject(); view8.name = "ViewFieldTest8"; ViewVector FOV8 = new ViewVector(170, 170); Frustum projection8 = new Frustum(view8.transform, FOV8); byte[,] raster8 = new byte[100, 100]; output += String.Format("Created Frustum: pos: {0}, EA's {1}, FOV: {2}\n", pointToStr(projection8.Transform.position), pointToStr(projection8.Transform.eulerAngles), viewVectorToStr(projection8.FOV)); output += String.Format("Created Raster: {0}x{1}\n", raster8.GetLength(0), raster8.GetLength(1)); // create 'wall' vertices double wallSize = 4.0; double wallRes = 0.05; double wallDistance = 3.0; float wallWiggle = 0.001f; int wallPixels = (int)(wallSize / wallRes); double wallBotLeft = -(wallSize / 2.0); int wallValue = 0; int wallCount = (int)Math.Pow(wallPixels, 2); List <Vector3> vertices = new List <Vector3>(); for (int i = 0; i < wallPixels; i++) { for (int j = 0; j < wallPixels; j++) { float vertX = (float)(i * wallRes + wallBotLeft); float vertY = (float)(j * wallRes + wallBotLeft); float vertZ = (float)wallDistance; Vector3 vert = new Vector3(vertX, vertY, vertZ); vertices.Add(wiggleVert(vert, wallWiggle, rand)); } } // create 'box' vertices float boxSize = 1f; Vector3 boxMin = new Vector3(-boxSize / 2, -boxSize / 2, (float)(wallDistance + 1)); Vector3 boxMax = new Vector3(boxSize / 2, boxSize / 2, (float)(wallDistance + 1 + boxSize)); int boxCount = 10000; for (int i = 0; i < boxCount; i++) { vertices.Add(randomPoint(boxMin, boxMax, rand)); } // report progress output += String.Format("Created wall... ({0},{0}) to ({1},{1}), z: {2}, wiggle: {3}, " + "vertices: {4}, resolution (m): {5}\n", wallBotLeft, wallBotLeft + wallSize, wallDistance, wallWiggle, wallCount, wallRes); output += String.Format("Created box: {0} to {1}, vertices: {2}\n", pointToStr(boxMin), pointToStr(boxMax), boxCount); // run intersection List <PointValue <byte> > intersectRet8 = Intersector.Instance.Intersection(projection8, raster8, vertices); int wallCountRet = 0; int boxCountRet = 0; for (int i = 0; i < intersectRet8.Count; i++) { Vector3 point = intersectRet8[i].Point; if (within(point, boxMin, boxMax)) { boxCountRet++; } else { wallCountRet++; } } output += String.Format("Intersection Return... wall vertices: {0}/{1}, box vertices: {2}/{3}", wallCountRet, wallCount, boxCountRet, boxCount); return(output); }
private static string viewVectorToStr(ViewVector vector) { return(String.Format("(Theta: {0}, Phi: {1})", Math.Round(vector.Theta, 0), Math.Round(vector.Phi, 0))); }