抛砖引玉之Silverlight53D体验:摄像机

本文介绍了一个3D相机类的设计与实现,包括平移、缩放和旋转等功能,并提出了在特定视角下出现的闪烁问题,寻求解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

由于原来从未做过3D方面的开发,所以在这方面吃了不少苦头!只有借助网络力量,搜罗一番改进如下:

public class Camera
    {
        public enum RotateType
        {
            AboutCamera,
            AboutTarget
        }

        public Camera()
        {
            this.aspectRatio = (float)4.0f / 3.0f;
            this.fieldOfView = MathHelper.PiOver4;
            this.m_Target = Vector3.Zero;
            this.nearPlane = 0.1f;
            this.farPlane = 1000f;
        }

        private void ReCreateViewMatrix()
        {
            Vector3 dir = Vector3.Normalize(m_Target - m_Position);
            float dp = Vector3.Dot(dir, Vector3.UnitZ);
            if (Math.Abs(dp) < 0.9999f)
                viewMatrix = Matrix.CreateLookAt(m_Position, m_Target, Vector3.UnitZ);
            else
                viewMatrix = Matrix.CreateLookAt(m_Position, m_Target, -Vector3.UnitY);
            viewMatrixDirty = false;
        }

        private void ReCreateProjectionMatrix() 
        {
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(fieldOfView, aspectRatio, nearPlane, farPlane); 
            projectionMatrixDirty = false; 
        }

        public void SetAspectRatio(float aspectRatio)
        {
            this.AspectRatio = aspectRatio;
        }
           
        public void Zoom(float d)
        {
            float newDistance = CurrentDistance - d;
            if (newDistance < 1.0f)
                newDistance = 1.0f;

            Vector3 dir = Vector3.Normalize(m_Position - m_Target);
            Position = m_Target + (dir * newDistance);
        }

        public void Move(Vector3 csOffset)
        {
            csOffset *= Math.Max(1.0f, CurrentDistance / 10.0f);

            Vector3 dir = Vector3.Normalize(m_Target - m_Position);
            float dp = Vector3.Dot(dir, Vector3.UnitZ);
            Vector3 up;
            if (Math.Abs(dp) < 0.9999f)
                up = Vector3.UnitZ;
            else
                up = -Vector3.UnitY;
            Vector3 right = Vector3.Cross(dir, up);
            right.Normalize();
            up = Vector3.Cross(right, dir);
            up.Normalize();

            Vector3 offset = (dir * csOffset.Z) +
                             (right * csOffset.X) +
                             (up * csOffset.Y);
            Position += offset;
            Target += offset;
        }

        public void Rotate(RotateType type, float azimuth, float inclination)
        {
            if (type == RotateType.AboutTarget)
            {
                //移动相机位置
                Quaternion rotLocal = Quaternion.CreateFromYawPitchRoll(azimuth, inclination, 0);
                Quaternion rotWorld = Quaternion.CreateFromRotationMatrix(ViewMatrix);
                Quaternion rotInvWorld = Quaternion.Inverse(rotWorld);

                Quaternion rot = Quaternion.Multiply(rotInvWorld, Quaternion.Multiply(rotLocal, rotWorld));

                Vector3 offset = m_Position - m_Target;
                Vector3 rotatedOffset = Vector3.Transform(offset, rot);
                Position = m_Target + new Vector3(rotatedOffset.X, rotatedOffset.Y, rotatedOffset.Z);
            }
            else if (type == RotateType.AboutCamera)
            {
                //移动目标
                Quaternion rotLocal = Quaternion.CreateFromYawPitchRoll(azimuth, inclination, 0);
                Quaternion rotWorld = Quaternion.CreateFromRotationMatrix(ViewMatrix);
                Quaternion rotInvWorld = Quaternion.Inverse(rotWorld);

                Quaternion rot = Quaternion.Multiply(rotInvWorld, Quaternion.Multiply(rotLocal, rotWorld));

                Vector3 offset = m_Target - m_Position;
                Vector3 rotatedOffset = Vector3.Transform(offset, rot);
                Target = m_Position + new Vector3(rotatedOffset.X, rotatedOffset.Y, rotatedOffset.Z);
            }
        }

        private bool viewMatrixDirty = true;//是否需要更新视图矩阵
        private bool projectionMatrixDirty = true;//是否需要更新投影矩阵

        /// <summary>
        /// 获取当前相机的位置与目标的距离
        /// </summary>
        public float CurrentDistance
        {
            get { return (m_Position - m_Target).Length(); }
        }

        private float fieldOfView;
        /// <summary>
        /// 获取或设置相机的可视区域弧度
        /// </summary>
        public float FieldOfView
        {
            get { return fieldOfView; }
            set
            {
                if (fieldOfView != value)
                {
                    projectionMatrixDirty = true;
                    fieldOfView = value;
                }
            }
        }

        private float aspectRatio;
        /// <summary>
        /// 获取或设置相机的长宽比(通常为[float]屏幕宽度除以[float]屏幕高度)
        /// </summary>
        public float AspectRatio
        {
            get { return aspectRatio; }
            set
            {
                if (aspectRatio != value)
                {
                    projectionMatrixDirty = true;
                    aspectRatio = value;
                }
            }
        }

        private float nearPlane;
        /// <summary>
        /// 获取或设置相机近裁面
        /// </summary>
        public float NearPlane
        {
            get { return nearPlane; }
            set
            {
                if (nearPlane != value)
                {
                    projectionMatrixDirty = true;
                    nearPlane = value;
                }
            }
        }

        private float farPlane;
        /// <summary>
        /// 获取或设置相机的远裁面
        /// </summary>
        public float FarPlane
        {
            get { return farPlane; }
            set
            {
                if (farPlane != value)
                {
                    projectionMatrixDirty = true;
                    farPlane = value;
                }
            }
        }

        private Vector3 m_Position;
        /// <summary>
        /// 获取或设置当前相机的位置
        /// </summary>
        public Vector3 Position
        {
            get { return m_Position; }
            set
            {
                if (m_Position != value)
                {
                    viewMatrixDirty = true;
                    m_Position = value;
                }
            }
        }

        private Vector3 m_Target;
        /// <summary>
        /// 获取或设置当前相机观察的目标
        /// </summary>
        public Vector3 Target
        {
            get { return m_Target; }
            set
            {
                if (m_Target != value)
                {
                    m_Target = value;
                    viewMatrixDirty = true;
                }
            }
        }

        /// <summary>
        /// 获取视图矩阵与投影矩阵的乘积
        /// </summary>
        public Matrix ViewProjectionMatrix 
        { 
            get { return ViewMatrix * ProjectionMatrix; } 
        } 

        private Matrix viewMatrix;
        /// <summary>
        /// 获取当前相机的视图矩阵
        /// </summary>
        public Matrix ViewMatrix 
        { 
            get 
            { 
                if (viewMatrixDirty)
                    ReCreateViewMatrix(); 
                return viewMatrix; 
            } 
        }

        private Matrix projectionMatrix;
        /// <summary>
        /// 获取当前相机的投影矩阵
        /// </summary>
        public Matrix ProjectionMatrix 
        { 
            get 
            { 
                if (projectionMatrixDirty)
                    ReCreateProjectionMatrix(); 
                return projectionMatrix; 
            } 
        }
    }

 操作:左键平移相机、鼠标滚轮缩放相机、右键旋转相机。

 目前存在的问题:当相机进行俯仰查看顶部或底部时(且角度与屏幕垂直时)会出现闪烁的问题。杯具的人啊。。。不知道如何控制俯仰的范围。。。

期待各位高手能不吝赐教,谢谢!

代码链接

转载于:https://www.cnblogs.com/dfxj/archive/2012/04/26/2471334.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值