uvn 相机

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Graphics.OpenGL;
using OpenTK.Platform.Windows;
using UV_DLP_3D_Printer;

namespace Engine3D
{
    public class GLCamera
    {
        public Matrix4 viewmat;
        public Matrix4 projectmat;

        public Vector3 eye, target, up;
        public Vector3 u, v, n;

        public float minDis = 1;

        enum AnimStep
        {
            StepMove,
            StepDown,
            StepRotate,
            StepNone
        }


        bool isAxis = false;

        float m_bvx, m_bvy, m_bvz;
        float m_bvscalexy, m_bvscaleh;


        public float angle = 30, aspect = 1, zNear = 1f, zFar = 64;

        //float m_animmovex, m_animmovey, m_animmovez, m_animzoom;
        //float m_animdown, m_animrot;
        //int m_animcnt;
        //AnimStep m_animstep;

        public GLCamera()
        {
            viewmat = Matrix4.Identity;

            m_bvscalexy = 4.0f;
            m_bvscaleh = 1.2f;

        }



        public void UpdateBuildVolume(float bx, float by, float bz)
        {
            m_bvx = bx * m_bvscalexy / 2.0f;
            m_bvy = by * m_bvscalexy / 2.0f;
            m_bvz = bz * m_bvscaleh / 2.0f;
        }

        //This functions sets the camera view to the opengl framework
        public void SetViewGL()
        {
            GL.MatrixMode(MatrixMode.Projection);

            GL.LoadMatrix(ref projectmat);

            GL.MatrixMode(MatrixMode.Modelview);
            GL.LoadMatrix(ref viewmat);
        }

        void UpdateView()
        {

            var m = Matrix4.Identity;
            m.M11 = u.X; m.M21 = u.Y; m.M31 = u.Z; m.M41 = -Vector3.Dot(eye, u);
            m.M12 = v.X; m.M22 = v.Y; m.M32 = v.Z; m.M42 = -Vector3.Dot(eye, v); ;
            m.M13 = n.X; m.M23 = n.Y; m.M33 = n.Z; m.M43 = -Vector3.Dot(eye, n);
            m.M14 = 0; m.M24 = 0; m.M34 = 0; m.M44 = 1.0f;
            viewmat = m;
        }




        public void ResetView(float x, float y, float z, float updeg, float righgdeg, float zdeg, float lookz)
        {


            dx = 0;
            dy = 0;
            dz = 0;
            angle = 30;
            SetShape();

            eye = new Vector3(x, y, z);
            target = new Vector3(0, 0, 0);
            up = new Vector3(0, 0, 1);


            Vector3 upvec = new Vector3(up.X - eye.X, up.Y - eye.Y, up.Z - eye.Z);

            /* 计算n、u、v并归一化*/
            n = eye - target;
            u = Vector3.Cross(upvec, n);
            v = Vector3.Cross(n, u);

            u.Normalize();
            v.Normalize();
            n.Normalize();


            UpdateView();
            dy += lookz;
            Slide(0, lookz, 0);
            RotateY(updeg);
            RotateX(righgdeg);


        }

        private float dx = 0;
        private float dy = 0;
        private float dz = 0;

        public void RotateY(float angle)
        {


            Slide(-dx, -dy, 0);

            float d = GetDist();
            int cnt = 100;
            float theta = angle / cnt;
            float slide_d = 2 * d * (float)Math.Sin(theta * 3.14159265 / 360);
            Pitch(theta / 2);
            for (; cnt != 0; --cnt)
            {
                Slide(0, slide_d, 0);
                Pitch(theta);
            }
            Pitch(-theta / 2);

            Slide(dx, dy, dz);
        }


        public void RotateX(float angle)
        {

            Slide(-dx, -dy, dz);

            float d = GetDist();
            int cnt = 100;
            float theta = angle / cnt;
            float slide_d = -2 * d * (float)Math.Sin(theta * 3.14159265 / 360);
            Yaw(theta / 2);
            for (; cnt != 0; --cnt)
            {
                Slide(slide_d, 0, 0);
                Yaw(theta);
            }
            Yaw(-theta / 2);


            Slide(dx, dy, dz);
        }


        public Point3d TrasformPoint(Point3d point)
        {

            int[] data = new int[4];
            GL.GetInteger(GetPName.Viewport, data);

            int w = (int)data[2];
            int h = (int)data[3];
            Vector4 vector4 = new Vector4(point.x, point.y, point.z, 1.0f);

            Vector4 v1, v2;
            var m = viewmat;
            m.Transpose();
            Vector4.Transform(ref m, ref vector4, out v1); ;
            m = projectmat;
            m.Transpose();
            Vector4.Transform(ref projectmat, ref v1, out v2);
            v2.W = v1.Z;

            v2.W = 1.0f / v2.W;
            v2.X *= v2.W;
            v2.Y *= v2.W;
            v2.Z *= v2.W;


            var p = new Point3d((v2.X + 1) * data[2] / 2, data[3] - (v2.Y + 1) * data[3] / 2, 0);
            return p;
        }


        public void GetPoint(float X, float Y, out Point3d origin, out Vector3d dir)
        {
            int[] data = new int[4];
            GL.GetInteger(GetPName.Viewport, data);

            int w = (int)data[2];
            int h = (int)data[3];
            //  mess += "Screen Width/Height = " + w.ToString() + "," + h.ToString() + "\r\n";
            float aspect = ((float)w) / ((float)h);
            //mess += "Screen Aspect = " + aspect.ToString() + "\r\n";

            float window_y = (h - Y) - h / 2;
            double norm_y = (double)(window_y) / (double)(h / 2);
            float window_x = X - w / 2;
            double norm_x = (double)(window_x) / (double)(w / 2);
            //float near_height = .2825f; // no detectable error
            float near_height = 1 * (float)Math.Tan(angle * 3.14159265 / 360); // no detectable error
            float y = (float)(near_height * norm_y);
            float x = (float)(near_height * aspect * norm_x);


            Vector4 ray_pnt = new Vector4(0.0f, 0.0f, 0.0f, 1.0f);

            Vector4 ray_vec = new Vector4((float)x, (float)y, -1f, 0);
            ray_vec.Normalize();



            Matrix4 viewInv = (viewmat).Inverted();

            Vector4 t_ray_pnt = new Vector4();
            Vector4 t_ray_vec = new Vector4();

            Vector4.Transform(ref ray_vec, ref viewInv, out t_ray_vec);
            Vector4.Transform(ref ray_pnt, ref viewInv, out t_ray_pnt);
            //mess += "World Pick Vec =  (" + String.Format("{0:0.00}", t_ray_vec.X) + ", " + String.Format("{0:0.00}", t_ray_vec.Y) + "," + String.Format("{0:0.00}", t_ray_vec.Z) + ")\r\n";
            //mess += "World Pick Pnt =  (" + String.Format("{0:0.00}", t_ray_pnt.X) + ", " + String.Format("{0:0.00}", t_ray_pnt.Y) + "," + String.Format("{0:0.00}", t_ray_pnt.Z) + ")\r\n";

            origin = new Point3d();
            dir = new Engine3D.Vector3d();

            origin.Set(t_ray_pnt.X, t_ray_pnt.Y, t_ray_pnt.Z);
            dir.Set(t_ray_vec.X, t_ray_vec.Y, t_ray_vec.Z);

        }

        public Point3d GetPoint(float X, float Y, float Z = 0)
        {


            Point3d origin = new Point3d();
            Engine3D.Vector3d dir = new Engine3D.Vector3d();

            GetPoint(X, Y, out origin, out dir);

            var t = (Z - origin.z) / dir.z;
            if (float.IsNaN(t))
            {
                origin.z = 0f;
                return origin;
            }
            var p = new Point3d(origin.x + dir.x * t, origin.y + dir.y * t, origin.z + dir.z * t);

            return p;
        }




        public void SetShape(float viewAngle, float aspect, float Near, float Far)
        {
            angle = viewAngle;
            this.aspect = aspect;
            zNear = Near;
            zFar = Far;

            SetShape();
        }





        public void Roll(float angle)
        {
            float cs = (float)Math.Cos(angle * 3.14159265 / 180);
            float sn = (float)Math.Sin(angle * 3.14159265 / 180);
            Vector3 t = new Vector3(u);
            Vector3 s = new Vector3(v);
            u = new Vector3(cs * t.X - sn * s.X, cs * t.Y - sn * s.Y, cs * t.Z - sn * s.Z);
            v = new Vector3(sn * t.X + cs * s.X, sn * t.Y + cs * s.Y, sn * t.Z + cs * s.Z);

            UpdateView();          //每次计算完坐标轴变化后调用此函数更新视点矩阵  
        }
        public void Pitch(float angle)
        {
            float cs = (float)Math.Cos(angle * 3.14159265 / 180);
            float sn = (float)Math.Sin(angle * 3.14159265 / 180);
            Vector3 t = new Vector3(v);
            Vector3 s = new Vector3(n);
            v = new Vector3(cs * t.X - sn * s.X, cs * t.Y - sn * s.Y, cs * t.Z - sn * s.Z);
            n = new Vector3(sn * t.X + cs * s.X, sn * t.Y + cs * s.Y, sn * t.Z + cs * s.Z);

            UpdateView();          //每次计算完坐标轴变化后调用此函数更新视点矩阵  
        }
        public void Yaw(float angle)
        {
            float cs = (float)Math.Cos(angle * 3.14159265 / 180);
            float sn = (float)Math.Sin(angle * 3.14159265 / 180);
            Vector3 t = new Vector3(n);
            Vector3 s = new Vector3(u);
            n = new Vector3(cs * t.X - sn * s.X, cs * t.Y - sn * s.Y, cs * t.Z - sn * s.Z);
            u = new Vector3(sn * t.X + cs * s.X, sn * t.Y + cs * s.Y, sn * t.Z + cs * s.Z);

            UpdateView();          //每次计算完坐标轴变化后调用此函数更新视点矩阵  
        }
        public void Slide(float du, float dv, float dn)
        {
            eye.X += du * u.X + dv * v.X + dn * n.X;
            eye.Y += du * u.Y + dv * v.Y + dn * n.Y;
            eye.Z += du * u.Z + dv * v.Z + dn * n.Z;
            target.X += du * u.X + dv * v.X + dn * n.X;
            target.Y += du * u.Y + dv * v.Y + dn * n.Y;
            target.Z += du * u.Z + dv * v.Z + dn * n.Z;

            UpdateView();
        }

        //public void Move(float x, float y, float z)
        //{

        //    Vector3 v1 = new Vector3(-x, -y, -z);

        //    float du = -Vector3.Dot(u, v1);
        //    float dv = -Vector3.Dot(v, v1);
        //    float dn = -Vector3.Dot(n, v1);

        //    dx += du;
        //    dy += dv;
        //    dz += dn;

        //    Slide(du, dv, dn);
        //}



        public void Move(float x, float y)
        {

            //var transltion = Matrix4.CreateTranslation(-x, -y, 0);
            //Vector4 v = new Vector4(x, y, 0, 1);
            //var m = viewmat;
            //m.Transpose();

            Vector3 v1 = new Vector3(-x, -y, 0);

            Vector3 vector = Vector3.Cross(v1, n);
           

            float du = -Vector3.Dot(u, v1);
            float dv = -Vector3.Dot(v, v1);
            float dn = -Vector3.Dot(n, v1);

 
            dx += du;
            dy += dv;
            Slide(du, dv, dn);

        }





        public float GetDist()
        {
            double dist = Math.Pow(eye.X, 2) + Math.Pow(eye.Y, 2) + Math.Pow(eye.Z, 2);
            return (float)Math.Pow(dist, 0.5);
        }


        public void MoveForward(float d, float x, float y)
        {
            int[] data = new int[4];
            GL.GetInteger(GetPName.Viewport, data);

            int w = (int)data[2];
            int h = (int)data[3];

            var pHit = TestHitTest((float)x, (float)y);

            minDis = Vector3.Dot(new Vector3(pHit.x, pHit.y, pHit.z), n);

            if (minDis < 0)
            {
                minDis = 0;
            }
            minDis += 10;


            //Point3d origin1 , origin2;
            //Engine3D.Vector3d dir1, dir2;
            // GetPoint((float)p.X, (float)p.Y, out origin1, out dir1);
            // GetPoint((float)data[2] / 2, (float)data[3] / 2,out origin2, out dir2);
            //var t = (pHit.z - origin1.z) / dir1.z;
            //if (float.IsNaN(t))
            //{
            //    t = 0f;
            //}
            //var p1 = new Point3d(origin1.x + dir1.x * t, origin1.y + dir1.y * t, origin1.z + dir1.z * t);
            //var center = new Point3d(origin2.x + dir2.x * t, origin2.y + dir2.y * t, origin2.z + dir2.z * t);


            bool isAngleChange = false;
            float factor = (eye - target).Length / 500f;
            if (factor < 0.03)
                factor = 0.03f;
            d = d * factor;


            Action<Action> moveAction = (action) =>
            {
                var p1 = GetPoint(x, y, pHit.z);
                action();

                var p2 = GetPoint(x, y, pHit.z);
                if (Math.Abs(n.Z) > 0.01)
                {
                    Move(-p2.x + p1.x, -p2.y + p1.y);
                }

            };


            if (angle != 30)
            {
                isAngleChange = true;
            }
            else
            {

                moveAction(() => Slide(0, 0, d));

                var dis = Vector3.Dot(eye, n);


                if (dis < minDis)
                {
                    isAngleChange = true;
                    moveAction(() => Slide(0, 0, -d));
                }
            }

            if (isAngleChange)
            {
                moveAction(() => MoveAngle(d));
            }



            minDis = 0;
        }


        private void MoveAngle(float d)
        {
            var da = 1f;

            if (angle < 1)
            {
                da /= 10; ;
            }

            if (d < 0)
            {
                da = -da;
            }

            angle += da;
            if (angle > 30)
            {
                angle = 30;
            }
            if (angle < 0.1f)
            {
                angle = 0.1f;
            }
            SetShape();

        }

  

        private void SetShape()
        {
            if (isAxis)
            {
                return;
            }
            projectmat = Matrix4.CreatePerspectiveFieldOfView(angle * 3.14159265f / 180,  aspect, zNear, zFar);

        }


        public void SetShape(float left, float right,float bottom, float top, float zNear, float zFar)
        {
            projectmat  = Matrix4.CreatePerspectiveOffCenter(left, right, bottom, top, zNear, zFar);
            isAxis = true;
        }


        public Point3d TestHitTest(float X, float Y)
        {


            int[] data = new int[4];
            GL.GetInteger(GetPName.Viewport, data);

            int w = (int)data[2];
            int h = (int)data[3];
            //  mess += "Screen Width/Height = " + w.ToString() + "," + h.ToString() + "\r\n";
            float aspect = ((float)w) / ((float)h);
            //mess += "Screen Aspect = " + aspect.ToString() + "\r\n";

            float window_y = (h - Y) - h / 2;
            double norm_y = (double)(window_y) / (double)(h / 2);
            float window_x = X - w / 2;
            double norm_x = (double)(window_x) / (double)(w / 2);
            //float near_height = .2825f; // no detectable error
            float near_height = 1 * (float)Math.Tan(angle * 3.14159265 / 360); // no detectable error
            float y = (float)(near_height * norm_y);
            float x = (float)(near_height * aspect * norm_x);


            /*
            To transform this eye coordinate pick ray into object coordinates, multiply it by the inverse of the ModelView matrix in use 
            when the scene was rendered. When performing this multiplication, remember that the pick ray is made up of a vector and a point, 
            and that vectors and points transform differently. You can translate and rotate points, but vectors only rotate. 
            The way to guarantee that this is working correctly is to define your point and vector as four-element arrays, 
            as the following pseudo-code shows:

            float ray_pnt[4] = {0.f, 0.f, 0.f, 1.f};
            float ray_vec[4] = {x, y, -near_distance, 0.f};
            The one and zero in the last element determines whether an array transforms as a point or a vector when multiplied by the 
            inverse of the ModelView matrix.*/
            Vector4 ray_pnt = new Vector4(0.0f, 0.0f, 0.0f, 1.0f);
            //Vector4 ray_vec = new Vector4((float)norm_x, (float)norm_y, -1.0f, 0);
            Vector4 ray_vec = new Vector4((float)x, (float)y, -1f, 0);
            ray_vec.Normalize();

            //mess += "Eye Pick Vec =  (" + String.Format("{0:0.00}", ray_vec.X) + ", " + String.Format("{0:0.00}", ray_vec.Y) + "," + String.Format("{0:0.00}", ray_vec.Z) + ")\r\n";

      
            Matrix4 viewInv = Matrix4.Invert(viewmat);

            Vector4 t_ray_pnt = new Vector4();
            Vector4 t_ray_vec = new Vector4();

            Vector4.Transform(ref ray_vec, ref viewInv, out t_ray_vec);
            Vector4.Transform(ref ray_pnt, ref viewInv, out t_ray_pnt);
            //mess += "World Pick Vec =  (" + String.Format("{0:0.00}", t_ray_vec.X) + ", " + String.Format("{0:0.00}", t_ray_vec.Y) + "," + String.Format("{0:0.00}", t_ray_vec.Z) + ")\r\n";
            //mess += "World Pick Pnt =  (" + String.Format("{0:0.00}", t_ray_pnt.X) + ", " + String.Format("{0:0.00}", t_ray_pnt.Y) + "," + String.Format("{0:0.00}", t_ray_pnt.Z) + ")\r\n";

            Point3d origin = new Point3d();
            Point3d intersect = new Point3d();
            Engine3D.Vector3d dir = new Engine3D.Vector3d();

            origin.Set(t_ray_pnt.X, t_ray_pnt.Y, t_ray_pnt.Z);
            dir.Set(t_ray_vec.X, t_ray_vec.Y, t_ray_vec.Z); // should this be scaled?

            var obj = UVDLPApp.Instance().Engine3D.m_objects;
            List<ISectData> isects = UV_DLP_3D_Printer._3DEngine.RTUtils.IntersectObjects(dir, origin, UVDLPApp.Instance().Engine3D.m_objects, true);
            if (isects.Count > 0)
            {

                foreach (ISectData isect in isects)
                {
                    if (!float.IsNaN(isect.intersect.x)) // check for NaN
                    {
                        return isect.intersect;

   
                    }
                }

                //ISectData isect = (ISectData)isects[0]; // get the first
                // check for NaN

            }

            return new Point3d() ;
        }



        //public void ResetViewAnim(float x, float y, float z, float updeg, float lookz)
        //{
        //    m_animcnt = 10;
        //    // move
        //    m_animstep = AnimStep.StepMove;
        //    m_animmovex = -m_dx / m_animcnt;
        //    m_animmovey = -m_dy / m_animcnt;
        //    m_animmovez = (lookz - m_dz) / m_animcnt;

        //    // zoom
        //    Vector3d diff = (m_eye - m_lookat);
        //    float len = Vector3d.length(diff) - Vector3d.length(new Vector3d(x, y, z));
        //    m_animzoom = len / m_animcnt;

        //    // down
        //    len = (float)Math.Sqrt(m_eye.x * m_eye.x + m_eye.y * m_eye.y);
        //    float deg = (float)Math.Atan2(m_eye.z, len) / deg2rad;
        //    if (m_up.z < 0)
        //        deg = 180 - deg;
        //    if (((deg > 85) && (deg < 95)) || ((deg < -85) && (deg > -95)))
        //    {
        //        RotateUp(-deg / 10);
        //        deg -= deg / 10;
        //    }
        //    m_animdown = (updeg - deg) / m_animcnt;

        //    // rotate
        //    deg = (float)Math.Atan2(m_eye.x, -m_eye.y) / deg2rad;
        //    if (m_up.z < 0)
        //        deg += 180;
        //    if (deg > 360)
        //        deg -= 360;
        //    m_animrot = deg / m_animcnt;
        //}

        //public bool AnimTick()
        //{
        //    switch (m_animstep)
        //    {
        //        case AnimStep.StepMove:
        //            m_dx += m_animmovex;
        //            m_dy += m_animmovey;
        //            m_dz += m_animmovez;
        //            MoveForward(m_animzoom, 1);
        //            RotateUp(m_animdown);
        //            RotateRightFlat(m_animrot, 1);
        //            m_animcnt--;
        //            if (m_animcnt == 0)
        //            {
        //                m_animstep = AnimStep.StepNone;
        //                return false;
        //            }
        //            return true;

        //        case AnimStep.StepRotate:
        //            RotateRightFlat(m_animrot);
        //            m_animcnt--;
        //            if (m_animcnt == 0)
        //            {
        //                m_animstep = AnimStep.StepNone;
        //                return false;
        //            }
        //            return true;

        //    }
        //    return false;
        //}
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值