Example #1
0
        /// <summary>
        /// Calculates the normal for a connected triangle edge, assumes the edge is part of a complete triangle and there are 3 triangle edges
        /// </summary>
        public bool ComputeTriangleNormal(XbimTriangleEdge[] edges)
        {
            var p1 = _vertices[edges[0].StartVertexIndex].Position;
            var p2 = _vertices[edges[0].NextEdge.StartVertexIndex].Position;
            var p3 = _vertices[edges[0].NextEdge.NextEdge.StartVertexIndex].Position;

            var ax = p1.X; var bx = p2.X; var cx = p3.X;
            var ay = p1.Y; var by = p2.Y; var cy = p3.Y;
            var az = p1.Z; var bz = p2.Z; var cz = p3.Z;
            // calculate normal of a triangle
            var v = new Vec3(
                (by - ay) * (cz - az) - (bz - az) * (cy - ay),
                (bz - az) * (cx - ax) - (bx - ax) * (cz - az),
                (bx - ax) * (cy - ay) - (by - ay) * (cx - ax)
                );

            if (Vec3.Normalize(ref v))
            {
                edges[0].Normal = v;
                edges[1].Normal = v;
                edges[2].Normal = v;
                return(true);
            }
            return(false);
        }
Example #2
0
        public static void ComputeNewellsNormal(ContourVertex[] vertices, ref Vec3 normal)
        {
            float         x = 0, y = 0, z = 0;
            ContourVertex current;
            var           previous = new ContourVertex();
            int           count    = 0;
            int           total    = vertices.Length;

            for (var i = 0; i <= total; i++)
            {
                if (i < total)
                {
                    current = vertices[i];
                }
                else
                {
                    current = vertices[0];
                }
                if (count > 0)
                {
                    float xn  = previous.Position.X;
                    float yn  = previous.Position.Y;
                    float zn  = previous.Position.Z;
                    float xn1 = current.Position.X;
                    float yn1 = current.Position.Y;
                    float zn1 = current.Position.Z;
                    x += (yn - yn1) * (zn + zn1);
                    y += (xn + xn1) * (zn - zn1);
                    z += (xn - xn1) * (yn + yn1);
                }
                previous = current;
                count++;
            }
            normal.X = x;
            normal.Y = y;
            normal.Z = z;
            Vec3.Normalize(ref normal);
        }
Example #3
0
        public void BalanceNormals()
        {
            const double minAngle = Math.PI / 5;

            //set up the base normals
            foreach (var faceGroup in Faces)
            {
                foreach (var triangle in faceGroup.Value)
                {
                    ComputeTriangleNormal(triangle);
                }
            }


            var edgesAtVertex = _faces.Values.SelectMany(el => el).SelectMany(e => e).Where(e => e != null).GroupBy(k => k.StartVertexIndex);

            foreach (var edges in edgesAtVertex)
            {
                //create a set of faces to divide the point into a set of connected faces
                var faceSet = new List <List <XbimTriangleEdge> >();//the first face set at this point

                //find an unconnected edge if one exists
                var unconnectedEdges = edges.Where(e => e.AdjacentEdge == null);
                var freeEdges        = unconnectedEdges as IList <XbimTriangleEdge> ?? unconnectedEdges.ToList();

                if (!freeEdges.Any())
                //they are all connected to each other so find the first sharp edge or the any one if none sharp, this stops a face being split
                {
                    XbimTriangleEdge nextConnectedEdge = edges.First();
                    freeEdges = new List <XbimTriangleEdge>(1)
                    {
                        edges.First()
                    };                                                           //take the first if we don't find a sharp edge
                    //now look for any connected edges
                    var visited = new HashSet <long>();
                    do
                    {
                        visited.Add(nextConnectedEdge.EdgeId);
                        nextConnectedEdge = nextConnectedEdge.NextEdge.NextEdge.AdjacentEdge;
                        if (nextConnectedEdge != null)
                        {
                            if (visited.Contains(nextConnectedEdge.EdgeId)) //we have been here before
                            {
                                break;                                      //we are looping or at the start
                            }
                            //if the edge is sharp and the triangle is not colinear, start here
                            var nextAngle = nextConnectedEdge.Angle;
                            if (nextAngle > minAngle && nextConnectedEdge.Normal.IsValid)
                            {
                                freeEdges = new List <XbimTriangleEdge>(1)
                                {
                                    nextConnectedEdge
                                };
                                break;
                            }
                        }
                    } while (nextConnectedEdge != null);
                }

                foreach (var edge in freeEdges)
                {
                    var face = new List <XbimTriangleEdge> {
                        edge
                    };
                    faceSet.Add(face);
                    XbimTriangleEdge nextConnectedEdge = edge;
                    //now look for any connected edges
                    var visited = new HashSet <long>();
                    do
                    {
                        visited.Add(nextConnectedEdge.EdgeId);
                        var nextConnectedEdgeCandidate = nextConnectedEdge.NextEdge.NextEdge.AdjacentEdge;
                        while (nextConnectedEdgeCandidate != null && !visited.Contains(nextConnectedEdgeCandidate.EdgeId) && !nextConnectedEdgeCandidate.Normal.IsValid) //skip colinear triangles
                        {
                            //set the colinear triangle to have the same normals as the current edge
                            nextConnectedEdgeCandidate.Normal                   = nextConnectedEdge.Normal;
                            nextConnectedEdgeCandidate.NextEdge.Normal          = nextConnectedEdge.Normal;
                            nextConnectedEdgeCandidate.NextEdge.NextEdge.Normal = nextConnectedEdge.Normal;
                            visited.Add(nextConnectedEdgeCandidate.EdgeId);
                            nextConnectedEdgeCandidate = nextConnectedEdgeCandidate.NextEdge.NextEdge.AdjacentEdge;
                        }

                        nextConnectedEdge = nextConnectedEdgeCandidate;
                        if (nextConnectedEdge != null)
                        {
                            if (visited.Contains(nextConnectedEdge.EdgeId))
                            {
                                break; //we are looping or at the start
                            }
                            //if the edge is sharp start a new face
                            var angle = nextConnectedEdge.Angle;
                            if (angle > minAngle && nextConnectedEdge.Normal.IsValid)
                            {
                                face = new List <XbimTriangleEdge>();
                                faceSet.Add(face);
                            }
                            face.Add(nextConnectedEdge);
                        }
                    } while (nextConnectedEdge != null);
                    //move on to next face
                }

                //we have our smoothing groups
                foreach (var vertexEdges in faceSet.Where(f => f.Count > 1))
                {
                    var vertexNormal = Vec3.Zero;
                    foreach (var edge in vertexEdges)
                    {
                        if (edge.Normal.IsValid)
                        {
                            Vec3.AddTo(ref vertexNormal, ref edge.Normal);
                        }
                    }

                    Vec3.Normalize(ref vertexNormal);
                    foreach (var edge in vertexEdges)
                    {
                        edge.Normal = vertexNormal;
                    }
                }
            }

            //now regroup faces
            _faces = _faces.Values.SelectMany(v => v).GroupBy(t => ComputeTrianglePackedNormalInt(t)).ToDictionary(k => k.Key, v => v.ToList());
        }