Пример #1
0
        private static Rect3D GetChildrenBoundsRecursive(ModelVisual3D visual, Matrix3D tx)
        {
            Rect3D   bounds           = Rect3D.Empty;
            Matrix3D currentTransform = MatrixUtils.Multiply(MatrixUtils.Value(visual.Transform), tx);

            if (visual.Content != null)
            {
                bounds = ModelBounder.CalculateBounds(visual.Content, currentTransform);
            }

            foreach (Visual3D v in visual.Children)
            {
                if (v is ModelVisual3D)
                {
                    bounds.Union(GetChildrenBoundsRecursive((ModelVisual3D)v, currentTransform));
                }
            }

            return(bounds);
        }
Пример #2
0
        private void AdjustCamera(Camera camera, Model3DGroup scene)
        {
            ProjectionCamera pc = camera as ProjectionCamera;

            if (pc == null)
            {
                // Can't adjust MatrixCamera
                return;
            }

            if (double.IsNaN(pc.NearPlaneDistance) ||
                double.IsNaN(pc.FarPlaneDistance) ||
                double.IsPositiveInfinity(pc.NearPlaneDistance) ||
                double.IsNegativeInfinity(pc.FarPlaneDistance) ||
                pc.NearPlaneDistance > pc.FarPlaneDistance)
            {
                // Don't render, and don't use NaN.
                pc.NearPlaneDistance = double.MaxValue;
                pc.FarPlaneDistance  = double.MaxValue;
                return;
            }

            bool adjustNearPlane = double.IsNegativeInfinity(pc.NearPlaneDistance);
            bool adjustFarPlane  = double.IsPositiveInfinity(pc.FarPlaneDistance);

            if (!adjustNearPlane && !adjustFarPlane)
            {
                // Camera is fine.  Leave it alone.
                return;
            }

            Matrix3D view        = MatrixUtils.ViewMatrix(this.camera);
            Rect3D   sceneBounds = ModelBounder.CalculateBounds(scene, view);

            if (sceneBounds.IsEmpty)
            {
                // It doesn't really matter what these are since there's nothing in the scene.
                // But I do like to avoid infinity...
                pc.NearPlaneDistance = double.MaxValue;
                pc.FarPlaneDistance  = double.MaxValue;
            }
            else
            {
                // sceneBounds is aligned to the axes defined by the camera's view matrix,
                //  but it's facing the wrong way!
                //
                //      +-----------+
                //      |sceneBounds|
                //  o---|-----------|---> look direction (-z axis)
                //      |           |
                //      +-----------+
                //      ^           ^
                //   Z+sizeZ        Z
                //
                // o is the camera position (also origin; z == 0)
                // This works regardless of the camera's position relative to the sceneBounds

                double np             = pc.NearPlaneDistance;
                double fp             = pc.FarPlaneDistance;
                double zBufferEpsilon = Math.Pow(2, -10);  // Add a little padding to the scene bounds
                double sceneNearClip  = -(sceneBounds.Z + sceneBounds.SizeZ + zBufferEpsilon);
                double sceneFarClip   = -(sceneBounds.Z - zBufferEpsilon);

                // Shrink the user specified clipping planes to the tightest fit around
                //  the scene without modifying what is visible.
                // Do not expand user's clipping plane values (unless we need a little more zBuffer tolerance)!

                if (adjustFarPlane)
                {
                    pc.FarPlaneDistance = sceneFarClip;
                }
                if (adjustNearPlane)
                {
                    pc.NearPlaneDistance = sceneNearClip;
                }

                if (pc.NearPlaneDistance > pc.FarPlaneDistance)
                {
                    // Don't render.
                    pc.NearPlaneDistance = double.MaxValue;
                    pc.FarPlaneDistance  = double.MaxValue;
                    return;
                }

                if (pc is PerspectiveCamera && pc.NearPlaneDistance <= 0)
                {
                    // We don't currently handle this case correctly.  Just don't crash.
                    pc.NearPlaneDistance = 0.125;
                }

                AdjustCameraTolerance(pc, adjustNearPlane, adjustFarPlane);
            }
        }