private static int OccluderComparison(OccluderVector v1, OccluderVector v2) { if (v1.angle == v2.angle) { return(0); } if (v1.angle > v2.angle) { return(1); } return(-1); }
private static int OccluderComparison(OccluderVector v1, OccluderVector v2) { if(v1.angle == v2.angle) { // If the angles are equivalent, sort on their distance from the camera if( v1.vec.sqrMagnitude > v2.vec.sqrMagnitude) { return 1; } else if( v2.vec.sqrMagnitude < v1.vec.sqrMagnitude) { return -1; } return 0; } if(v1.angle > v2.angle) { return 1; } return -1; }
void OnEnable() { m_viewCollider = GetComponent <BoxCollider>(); //validVerts.Capacity = m_maxOccluderVerts; extentsVals.Clear(); // Bung four values into the extents to set the initial capacity extentsVals.Add(Vector3.zero); extentsVals.Add(Vector3.zero); extentsVals.Add(Vector3.zero); extentsVals.Add(Vector3.zero); for (int occluderID = 0; occluderID < m_maxOccluderVerts; occluderID++) { vertices[occluderID] = new Vector3(); uvs[occluderID] = new Vector2(); normals[occluderID] = new Vector3(0.0f, -1.0f, 0.0f); colors[occluderID] = new Color(1.0f, 1.0f, 1.0f, 1.0f); m_occluders[occluderID] = new OccluderVector(); } vertices[0] = new Vector3(0.0f, 0.0f, 0.0f); uvs[0] = new Vector2(0.5f, 0.5f); m_occluders[m_maxOccluderVerts] = new OccluderVector(); float extentsVal = Mathf.Abs(m_viewCollider.size.x * Mathf.Cos(Mathf.PI / 4)); m_fixedExtents[0] = new Vector3(-extentsVal, 0.0f, extentsVal); m_fixedExtents[1] = new Vector3(-extentsVal, 0.0f, -extentsVal); m_fixedExtents[2] = new Vector3(extentsVal, 0.0f, extentsVal); m_fixedExtents[3] = new Vector3(extentsVal, 0.0f, -extentsVal); }
/// <summary> /// Gets a list of all vertices that occlude the view area. /// The OccluderVector structure contains the hit-points of each collision, as well as the angle of the hit-point from the left extent. /// </summary> /// <returns> /// The occluder list, sorted around increasing angle from the left extent. /// </returns> private List<OccluderVector> GetOccluders() { Vector3 cameraDirection = m_camera.transform.rotation * Vector3.up; List<VectorOffsetPair> verts = new List<VectorOffsetPair>(); // Loop through each collider and add its vertices to the list foreach(Collider viewCollider in m_collidersInView) { MeshFilter meshFilter = viewCollider.GetComponent<MeshFilter>(); foreach(Vector3 vert in meshFilter.mesh.vertices) { Vector3 vertexWorldPos = viewCollider.transform.TransformPoint(vert); // This can be replaced with an addition of the transform position if everything is grid-aligned. Vector3 cameraToVertex = vertexWorldPos - transform.position; Debug.DrawRay (this.transform.position + new Vector3(0.0f, 0.0f, -4.0f), cameraToVertex , Color.magenta); // This works out the magnitude of the vector if it were to reach the max range. // TODO: This could be removed if the camera area was a correct sweep rather than a triangle. The magnitude of the vector would just be // tested against the range. The difficulty is the lateral sweep becomes harder over a curve. float cameraDirVertexDot = Vector3.Dot(cameraDirection, Vector3.Normalize(cameraToVertex)); float angle = Mathf.Acos(cameraDirVertexDot); float mag = (cameraToVertex).magnitude; float thing = mag * cameraDirVertexDot; if(thing < m_camera.range && angle <= Mathf.Deg2Rad * (m_camera.fov_degrees ) / 2.0f) { VectorOffsetPair newPair = new VectorOffsetPair(); newPair.vec = vertexWorldPos; Vector3 offsetDirection = newPair.vec - (meshFilter.mesh.bounds.center + meshFilter.gameObject.transform.position); newPair.offsetVec = newPair.vec + (offsetDirection * m_nudgeMagnitude); newPair.offsetVec.z = newPair.vec.z; verts.Add(newPair); } } } List<Vector3> validVerts = new List<Vector3>(); validVerts.Clear(); RaycastHit hitInfo; // Manually cast the edges Vector3 right = Quaternion.Euler(0.0f, 0.0f, -((m_camera.fov_degrees / 2.0f))) * cameraDirection; Vector3 left = Quaternion.Euler(0.0f, 0.0f, ((m_camera.fov_degrees / 2.0f))) * cameraDirection; Vector3 leftDirection = left; float edgeCosTheta = Vector3.Dot(cameraDirection, Vector3.Normalize(right)); float edgeMaxMagnitude = m_camera.range / edgeCosTheta; right = Vector3.Normalize(right) * edgeMaxMagnitude; left = Vector3.Normalize(left) * edgeMaxMagnitude; List<OccluderVector> occluders = new List<OccluderVector>(); if(!Physics.Raycast(this.transform.position, right, out hitInfo, edgeMaxMagnitude, collisionLayer)) { validVerts.Add(transform.position + right); } else { validVerts.Add(hitInfo.point); } if(!Physics.Raycast(this.transform.position, left, out hitInfo, edgeMaxMagnitude, collisionLayer)) { validVerts.Add(transform.position + left); } else { validVerts.Add(hitInfo.point); } right += transform.position; left += transform.position; // Iterate through the initial verts and add both valid verts and projected offset vert intersections foreach(VectorOffsetPair vert in verts) { Vector3 directionToVert = vert.vec - this.transform.position; directionToVert = vert.offsetVec - this.transform.position; float magnitude = directionToVert.magnitude * 0.98f; // Check to see if the original vertex is occluded if (!Physics.Raycast (this.transform.position, directionToVert, out hitInfo, magnitude, collisionLayer)) { // Not occluded. The vert itself is fine. Next we check the projected ray... validVerts.Add(vert.vec); float cosTheta = Vector3.Dot(cameraDirection, Vector3.Normalize(directionToVert)); float maxMagnitude = m_camera.range / cosTheta; Vector3 maxPosition = transform.position + (Vector3.Normalize(directionToVert) * maxMagnitude); Vector3 newDirection = Vector3.Normalize(directionToVert) * maxMagnitude ; if(!Physics.Raycast(this.transform.position, newDirection, out hitInfo, newDirection.magnitude, collisionLayer)) { validVerts.Add(maxPosition); } else { validVerts.Add (hitInfo.point); } } } // Ray-cast along the extent of the wedge RaycastHit[] hits; RaycastHit[] hitsReverse; Vector3 direction = right - left; hits = Physics.RaycastAll(left, direction, direction.magnitude, collisionLayer); hitsReverse = Physics.RaycastAll(right, -direction, direction.magnitude, collisionLayer); RaycastHit[] allHits = new RaycastHit[hits.Length + hitsReverse.Length]; hits.CopyTo(allHits, 0); hitsReverse.CopyTo(allHits, hits.Length); foreach(RaycastHit hit in allHits) { Vector3 directionToVert = hit.point - this.transform.position; if (!Physics.Raycast (this.transform.position, directionToVert, out hitInfo, directionToVert.magnitude * 0.99f, collisionLayer)) { validVerts.Add(hit.point); } } // Output all results foreach(Vector3 vert in validVerts) { Vector3 directionToVert = vert - this.transform.position; OccluderVector newOccluder = new OccluderVector(); newOccluder.vec = vert; Vector3 normalDirection = Vector3.Normalize(directionToVert); float angle = Mathf.Acos(Vector3.Dot(Vector3.Normalize(leftDirection), normalDirection)); if(Vector3.Normalize(leftDirection) == normalDirection) { angle = 0.0f; } newOccluder.angle = angle; occluders.Add(newOccluder); } occluders.Sort(OccluderComparison); foreach(OccluderVector vert in occluders) { Debug.DrawRay (this.transform.position + new Vector3(0.0f, 0.0f, -5.0f), vert.vec - this.transform.position , Color.green); } return occluders; }