Autor Wątek: Gimbal lock ?  (Przeczytany 934 razy)

Offline KrissM

  • Użytkownik

# Czerwiec 21, 2010, 12:42:01
Witam. Na wstępie chcę się przywitać (pierwszy raz na tym forum)

Mam pytanie napisałem programik, który obroca kamerą (po sferze) względem układu wspólrzędnych. No i działa tak sobie, siędzę nad problemem kilka dni i nic nie mogę wymyśleć. Pod tym linkiem jest filmik z działania programu http://www.youtube.com/watch?v=jcHsTvo3uX4 kiedy obracam kamerę na początku działania programu góra-dół wszystko wydaje się ok kiedy poruszam prawo-lewo też wszystko wydaje się ok ale kiedy tylko pozycja kamery lewo-prawo sie zmieni to ruch góra dół jest nieprawidłowy. Czy to jest gimbal lock? Od niedawna programuję w 3D i osobiście tego jeszcze nie doświadczyłem.
Piszę w c# wpf i kod obrotu wygląda mniej więcej tak.

            RotateTransform3D cameraRotateY = new RotateTransform3D();
            RotateTransform3D cameraRotateX = new RotateTransform3D();
  cameraRotateY = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), cameraYaw));
  cameraRotateX = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), cameraPitch));

Matrix3D mat = new Matrix3D();
mat = Matrix3D.Multiply(cameraRotateX.Value,cameraRotateY.Value);
 _positionCamera = Point3D.Multiply(_positionCamera, mat);
 _lookAtCamera = Vector3D.Multiply(_lookAtCamera,mat);

[/code


To są najważniejsze linijki z metody aktualizującej ruch kamery.
Przyczym cameraYaw i cameraPitch to jest kąt o jaki obraza się kamera ( w tym filmie przyrost kątu ustawiony jest o 1)

_positionCamera - położenie kamery
_lookAtCamera - vektor "patrzenia kamery"

Pewnie ktoś z forumowiczów zna problem i może pomóc.

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline BrutalComputer

  • Użytkownik

# Czerwiec 21, 2010, 13:48:44
Ja u siebie trzymam:
- punkt na który kamera się patrzy
- promień okręgu
- kąt w poziomie
- kąt w pionie

Pozycję kamery obliczam prosto z funkcji trygonometrycznych z kątów i promienia, a punkt patrzenia za pomocą LookAt.
Możesz spróbować zamiast RotateTransform3D obliczyć pozycję kamery na piechotę. Jestem na 100% pewien, że po prostu nakładają się na siebie obroty.
Powinieneś za każdą zmianą pozycji kamery obliczać jej pozycję od nowa, inaczej błędy będą się nakładać.

Nie jest to gimbal lock.
« Ostatnia zmiana: Czerwiec 21, 2010, 13:51:48 wysłana przez BrutalComputer »

Offline KrissM

  • Użytkownik

# Czerwiec 24, 2010, 23:28:13
Ja u siebie trzymam:
- punkt na który kamera się patrzy
- promień okręgu
- kąt w poziomie
- kąt w pionie
Nie jest to gimbal lock.

Dzięki za sugestie, w między czasie próbowałem coś za pomocą standardowych macierzy obrotu ale z marnym skutkiem. Poszperałem trochę na wikipedi, znalazłem kilka wzorów popróbowałem i działa tak jak chciałem tzn obór kamery po sferze względem jakiegoś punktu i do tego zoom.

Poniżej moje wypociny, może komuś się przyda (C#, WPF)


    class CameraClass
    {

        #region Pola klasy     
        PerspectiveCamera _cameraObject;
        Point3D _positionCamera;
        Vector3D _lookAtCamera;
        public RotateCameraStruct CurrentRotation;
        public Point3D centerRotateCamera = new Point3D(0, 0, 0); //punkt wokół którego obraca się kamera - środek
        float rho = 12; //promień

        public float cameraYaw=0;//kąt obrotu
        public float cameraPitch=90; //kąt obrotu
        double cameraPitchRadian;//kąt w radianach
        double cameraYawRadian;//kąt w radianach
        float speedRotate = 1f; //kąt - wartość zmiany kąta przy obrocie

        //zmienne pomocnicze
        const double radiansTemp = Math.PI / 180;
        double CosYawRadian;
        double SinYawRadian;
        double CosPitchRadian;
        double SinPitchRadian;
       
        #endregion


        #region Właściwości

        public Point3D PositionCamera
        {
            get
            {
                return this._positionCamera;
            }
            set
            {
                this._positionCamera = value;
                _cameraObject.Position = this._positionCamera;

            }
        }

        public Vector3D LookAtCamera
        {
            get
            {
                return this._lookAtCamera;
            }
            set
            {
                this._lookAtCamera = value;
                this._cameraObject.LookDirection = this._lookAtCamera;
            }
        }

        public PerspectiveCamera CameraObject
        {
            get
            {
                return this._cameraObject;
            }
        }

        public float Zoom
        {
            get
            {
                return rho;
            }
            set
            {
               
                rho = value;
                if (rho < 0.2f)
                    rho = 0.5f;
                else
                    if (rho > 500)
                        rho = 500;
            }
        }
       
        #endregion





        #region Kontruktory klasy

        public CameraClass()
        {
            _cameraObject = new PerspectiveCamera();
            this.PositionCamera = new Point3D(0, 0, 5);
            CurrentRotation = new RotateCameraStruct();

            //trygonometria - pomocnicze do pozycji kamery
            CosYawRadian = Math.Cos(cameraYawRadian);
            SinYawRadian = Math.Sin(cameraYawRadian);
            CosPitchRadian = Math.Cos(cameraPitchRadian);
            SinPitchRadian = Math.Sin(cameraPitchRadian);
                     
        }

        #endregion



        public void UpdateCamera()
        {
           
            if (CurrentRotation.RotateY != RotateDirectionEnum.None)
            {
                if (CurrentRotation.RotateY == RotateDirectionEnum.Left)
                {
                    cameraPitch += speedRotate;
                }
                else
                    cameraPitch -= speedRotate;


                if (cameraPitch > 360) cameraPitch = cameraPitch - 360;

                if (cameraPitch < 0) cameraPitch = cameraPitch + 360;


                cameraPitchRadian = radiansTemp * cameraPitch;

                CosPitchRadian = Math.Cos(cameraPitchRadian);
                SinPitchRadian = Math.Sin(cameraPitchRadian);

             }


            if (CurrentRotation.RotateX != RotateDirectionEnum.None)
            {
                if (CurrentRotation.RotateX == RotateDirectionEnum.Up)
                {
                    cameraYaw += speedRotate;
                }
                else
                    cameraYaw -= speedRotate;

                if (cameraYaw > 360) cameraYaw = cameraYaw - 360;

                if (cameraYaw < 0) cameraYaw = cameraYaw + 360;

                if (cameraYaw >= 90 || cameraYaw<270) CameraObject.UpDirection = new Vector3D(0, -1, 0);
                if (cameraYaw >= 270 || cameraYaw<90) CameraObject.UpDirection = new Vector3D(0, 1, 0);

                cameraYawRadian = radiansTemp * cameraYaw;
                CosYawRadian = Math.Cos(cameraYawRadian);
                SinYawRadian = Math.Sin(cameraYawRadian);

             }



            //właściwe wyliczanie pozycji kamery przy obrocie
            _positionCamera.X = this.centerRotateCamera.X + rho * CosPitchRadian * CosYawRadian;
            _positionCamera.Y = this.centerRotateCamera.Y + rho * SinYawRadian;
            _positionCamera.Z = this.centerRotateCamera.Z + rho * CosYawRadian * SinPitchRadian;



            _lookAtCamera = -(Vector3D)_positionCamera;
            _cameraObject.Position = _positionCamera;
            _cameraObject.LookDirection = _lookAtCamera ;
           
            //zerowanie
            CurrentRotation = new RotateCameraStruct();
           
        }

    }

« Ostatnia zmiana: Czerwiec 25, 2010, 09:07:17 wysłana przez KrissM »