Esempio n. 1
0
        internal bool IsInsideClipBoundary(FrustumFace face)
        {
            switch (face)
            {
            case FrustumFace.Left: return(IsInsideLeftClipBoundary);

            case FrustumFace.Right: return(IsInsideRightClipBoundary);

            case FrustumFace.Bottom: return(IsInsideBottomClipBoundary);

            case FrustumFace.Top: return(IsInsideTopClipBoundary);

            case FrustumFace.Near: return(IsInsideNearClipBoundary);

            case FrustumFace.Far: return(IsInsideFarClipBoundary);

            default:
                return(false);
            }
        }
Esempio n. 2
0
        //Clip the edge with a face
        private static UnitProperty ClipEdge(UnitProperty start, UnitProperty end, FrustumFace faceIndex)
        {
            float t = 0;

            //vector = end - start
            var vector = end - start;

            // result = start + (end - start) * t
            switch (faceIndex)
            {
            case FrustumFace.Left:
                // (start.x + vector.x * t) / (start.w + vector.w * t) = -1
                // t = -(start.x + start.w) / (vector.x + vector.w)
                // and (vector.x + vector.w) != 0
                // because there is most one vertex on the face(x = -w), so (vector.x + vector.w) = (end.x - start.x + end.w - start.w) != 0

                t = -(start.PositionTransformed.X + start.PositionTransformed.W) /
                    (vector.PositionTransformed.X + vector.PositionTransformed.W);

                break;

            case FrustumFace.Right:
                // (start.x + vector.x * t) / (start.w + vector.w * t) = 1
                // t = (start.w - start.x) / (vector.x - vector.w)
                // and (vector.x - vector.w) != 0
                // because there is most one vertex on the face(x = w), so (vector.x - vector.w) = (end.x - start.x - end.w + start.w) != 0

                t = (start.PositionTransformed.W - start.PositionTransformed.X) /
                    (vector.PositionTransformed.X - vector.PositionTransformed.W);

                break;

            case FrustumFace.Bottom:
                // (start.y + vector.y * t) / (start.w + vector.w * t) = -1
                // t = (start.y + start.w) / (vector.y + vector.w)
                // and (vector.y + vector.w) != 0
                // because there is most one vertex on the face(y = -w), so (vector.y + vector.w) = (end.y - start.y + end.w - start.w) != 0

                t = -(start.PositionTransformed.Y + start.PositionTransformed.W) /
                    (vector.PositionTransformed.Y + vector.PositionTransformed.W);

                break;

            case FrustumFace.Top:
                // (start.y + vector.y * t) / (start.w + vector.w * t) = 1
                // t = (start.w - start.y) / (vector.y - vector.w)
                // and (vector.y - vector.w) != 0
                // because there is most one vertex on the face(y = w), so (vector.y - vector.w) = (end.y - start.y - end.w + start.w) != 0

                t = (start.PositionTransformed.W - start.PositionTransformed.Y) /
                    (vector.PositionTransformed.Y - vector.PositionTransformed.W);

                break;

            case FrustumFace.Near:
                // (start.z + vector.z * t) / (start.w + vector.w * t) = 0
                // t = - (start.z / vector.z)
                // and vector.z != 0
                // because there is most one vertex on the face(z = 0), so vector.z = (end.z - start.z) != 0

                t = -(start.PositionTransformed.Z / vector.PositionTransformed.Z);

                break;

            case FrustumFace.Far:
                // (start.z + vector.z * t) / (start.w + vector.w * t) = 1
                // t = (start.w - start.z) / (vector.z - vector.w)
                // and (vector.z - vector.w) != 0
                // because there is most one vertex on the face(z = w), so (vector.z - vector.w) = (end.z - start.z - end.w + start.w) != 0

                t = (start.PositionTransformed.W - start.PositionTransformed.Z) /
                    (vector.PositionTransformed.Z - vector.PositionTransformed.W);

                break;

            default:
                break;
            }

            var result = start + vector * t;

            //divide for the new vertex
            result.PositionAfterDivide = result.PositionTransformed / result.PositionTransformed.W;

            return(result);
        }
Esempio n. 3
0
        //Sutherland-Hodgeman algorithm
        private void ClipPrimitives(ref DrawCall drawCall)
        {
            //we enum all primitives in the draw call
            for (int i = 0; i < drawCall.Primitives.Length; i++)
            {
                //create a temp for calculating
                var result = new Primitive(drawCall.Primitives[i].Vertics);

                //for all face of frustum
                for (FrustumFace face = FrustumFace.Left; face <= FrustumFace.Far; face++)
                {
                    var verticesList = new List <UnitProperty>();

                    //enum all edge in edge primitive
                    for (int vertexIndex = 0; vertexIndex < result.Vertics.Length; vertexIndex++)
                    {
                        var currentVertex = result.Vertics[vertexIndex];
                        var nextVertex    = result.Vertics[0];

                        //the last edge
                        if (vertexIndex + 1 != result.Vertics.Length)
                        {
                            nextVertex = result.Vertics[vertexIndex + 1];
                        }


                        //the edge is not inside the clip boundary, so we do not add the vertex to result
                        if (currentVertex.IsInsideClipBoundary(face) is false &&
                            nextVertex.IsInsideClipBoundary(face) is false)
                        {
                            continue;
                        }

                        //the edge is inside the clip boundary, so we add the vertex to result
                        if (currentVertex.IsInsideClipBoundary(face) is true &&
                            nextVertex.IsInsideClipBoundary(face) is true)
                        {
                            //we only add the start vertex
                            verticesList.Add(currentVertex);

                            continue;
                        }

                        //the start is not insided but the end is insided.
                        if (currentVertex.IsInsideClipBoundary(face) is false)
                        {
                            verticesList.Add(ClipEdge(currentVertex, nextVertex, face));

                            continue;
                        }

                        //the start is insided but the end is not insided
                        if (nextVertex.IsInsideClipBoundary(face) is false)
                        {
                            verticesList.Add(currentVertex);
                            verticesList.Add(ClipEdge(currentVertex, nextVertex, face));

                            continue;
                        }
                    }

                    //update the primitive
                    result = new Primitive(verticesList.ToArray());
                }

                //get result
                drawCall.Primitives[i] = result;
            }
        }