Проблемы с SharpDX GetPickRay

Я пытаюсь получить луч выбора из текущего положения / вида камеры, чтобы я мог использовать его для выбора объектов в трехмерном мире. Проблема в том, что когда я перемещаю камеру, луч становится неправильным. Я что-то делаю не так или это проблема точности с плавающей запятой?

ViewportF viewport = new ViewportF();
viewport.Height=307.0
viewport.MaxDepth=1.0
viewport.MinDepth=0.0
viewport.Width=689.0
viewport.X=0.0
viewport.Y=0.0

Matrix viewProjection = new Matrix(new float[] {
    1.075709f, 0, 0, 85067.07f, 
    0, 2.414213f, 0, -146011.6f, 
    0, 0, 1, 14.90265f, 
    0, 0, 1, 15.00265});

Ray ray = Ray.GetPickRay(263, 77, viewport, matrix);

Результат луча:

ray.Position {X:-79080,03 Y:60480,02 Z:-14,90265}
ray.Direction {X:-0,1926253 Y:0,1401343 Z:0,9712146}

И на экране он создает под моей мышью следующую строку:
(вверху слева)

Насколько я понимаю, луч не должен быть виден под моей мышью, не так ли?
Очевидно, он станет видимым, если я перемещу камеру и не изменю луч, который я рисую.

edit: Если я не перемещаю камеру, луч не виден под моей мышью, даже при вращении.
edit2: Кажется, что ray.Position правильное, хотя Ray.Direction кажется неправильным не цитируйте меня по этому поводу.


person ManIkWeet    schedule 09.01.2015    source источник


Ответы (2)


Я хотел предоставить свой собственный пример использования функции Raycasting SharpDX. Вот код, демонстрирующий такое использование:

        private void OnMouseDown(object sender, MouseEventArgs args)
        {
            if (args.Button == MouseButtons.Left)
            {
                // Ray Cast
                List<StaticGeometry> hits = new List<StaticGeometry>();
                Ray rayCast = Ray.GetPickRay(args.X, args.Y,
                    new ViewportF(
                        this.ClientRectangle.X,
                        this.ClientRectangle.Y,
                        this.ClientRectangle.Width,
                        this.ClientRectangle.Height,
                        0,1),
                    Camera.ModelViewProjectionMatrix);

                _rayCastMesh.Dispose();
                _rayCastMesh = new ModelMesh(_device, new Vertex[] {
                    new Vertex() {
                        Location = rayCast.Position },
                    new Vertex() {
                        Location = ( rayCast.Position + rayCast.Direction * Camera.FarZ) } });
                foreach (StaticGeometry geometry in this.StaticGeometry)
                {
                    if (rayCast.Intersects(geometry.BoundingBox.ToBoundingBox()))
                    {
                        hits.Add(geometry);
                    }
                }

                System.Console.WriteLine("Ray Cast Hit Test Results: ");
                System.Console.WriteLine("Count: " + hits.Count);
                foreach (StaticGeometry geometry in hits)
                {
                    System.Console.WriteLine(geometry.Identifier);
                }

            }
            if (args.Button == MouseButtons.Right)
            {
                Cursor.Hide();
                this._mouseLockLocation = new System.Drawing.Point(Cursor.Position.X, Cursor.Position.Y);
                IsMouseLookEnabled = true;
            }
        }

Из которых я получаю матрицу ModelViewProjection из класса Camera, который определен как таковой:

using SharpDX;
using System;
using System.Diagnostics;

namespace VoidwalkerEngine.Framework.DirectX
{
    public enum CameraMode
    {
        FreeLook,
        Orbit
    }

    public class Camera
    {
        /// <summary>
        /// The name of this camera
        /// </summary>
        public string Name { get; set; }
        /// <summary>
        /// The eye location of this camera
        /// </summary>
        public Vector3 Location { get; set; }
        /// <summary>
        /// The Pitch of this Camera, as Radians
        /// </summary>
        public float Pitch { get; set; }
        /// <summary>
        /// The Yaw of this Camera, as Radians
        /// </summary>
        public float Yaw { get; set; }
        /// <summary>
        /// The Roll of this Camera, as Radians
        /// </summary>
        public float Roll { get; set; }
        /// <summary>
        /// The NearZ of this Camera
        /// </summary>
        public float NearZ { get; set; }
        /// <summary>
        /// The FarZ of this Camera
        /// </summary>
        public float FarZ { get; set; }
        /// <summary>
        /// The Field of View of this Camera, value should be
        /// between 0.70 and 1.20
        /// </summary>
        public float FieldOfView { get; set; }
        public float AspectRatio { get; set; }
        public float LookSpeed { get; set; }
        public float MoveSpeed { get; set; }
        /// <summary>
        /// Determines if this Camera is currently accelerating.
        /// </summary>
        public bool IsAccelerating { get; set; }
        /// <summary>
        /// The acceleration speed multiplier of this Camera.
        /// </summary>
        public float AccelerationMultiplier { get; set; }
        public CameraMode Mode { get; set; }
        public float ViewportWidth;
        public float ViewportHeight;
        public float SoftBoundsRadius { get; set; } = 16f;
        public float HardBoundsRadius { get; set; } = 2f;
        public float CollisionDistance { get; set; } = 128f;
        public bool IsCollisionEnabled { get; set; } = true;

        /// <summary>
        /// The BoundingSphere of this Camera
        /// </summary>
        public BoundingSphere SoftBounds
        {
            get
            {
                return new BoundingSphere()
                {
                    Center = this.Location,
                    Radius = SoftBoundsRadius
                };
            }
        }

        /// <summary>
        /// The BoundingSphere of this Camera
        /// </summary>
        public BoundingSphere HardBounds
        {
            get
            {
                return new BoundingSphere()
                {
                    Center = this.Location,
                    Radius = HardBoundsRadius
                };
            }
        }

        /// <summary>
        /// The Target Vector of this Camera
        /// </summary>
        public Vector3 Target
        {
            get
            {
                return new Vector3(
                    (float)Math.Sin(this.Yaw),
                    (float)Math.Tan(this.Pitch),
                    (float)Math.Cos(this.Yaw));
            }
        }

        /// <summary>
        /// The Frustum of this Camera
        /// </summary>
        public BoundingFrustum Frustum
        {
            get
            {
                return new BoundingFrustum(this.ModelViewProjectionMatrix);
            }
        }

        public Matrix ModelViewMatrix
        {
            get
            {
                return Matrix.LookAtLH(this.Location, Location + Target, Up);
            }
        }

        public Matrix ProjectionMatrix
        {
            get
            {
                return Matrix.PerspectiveFovRH(FieldOfView, AspectRatio, NearZ, FarZ);
            }
        }

        public Matrix ModelViewProjectionMatrix
        {
            get
            {
                return ModelViewMatrix * ProjectionMatrix;
            }
        }

        //public CardinalDirectionType Direction
        //{
        //    get
        //    {
        //        return VoidwalkerMath.GetCardinalDirection(VoidwalkerMath.ToDegrees(Yaw));
        //    }
        //}

        public Vector3 Forward
        {
            get
            {
                return new Vector3((float)Math.Cos(Pitch), 0, (float)Math.Sin(Pitch));
            }
        }

        public Vector3 Right
        {
            get
            {
                return new Vector3(Forward.Z, 0, -Forward.Z);
            }
        }

        public Vector3 Up
        {
            get
            {
                return new Vector3(-(float)Math.Sin(Roll), (float)Math.Cos(Roll), 0);
            }
        }

        public Camera()
        {

        }

        public Camera(string name)
            : this()
        {
            this.Name = name;
            this.Location = new Vector3();
        }

        public void ToOrigin()
        {
            Transform(Vector3.Zero, 0, 0, 0);
        }

        public void Transform(Vector3 location, float pitch, float yaw, float roll)
        {
            this.Location = location;
            this.Pitch = pitch;
            this.Yaw = yaw;
            this.Roll = roll;
        }

        public float GetCurrentMoveSpeed()
        {
            if (IsAccelerating)
            {
                return this.MoveSpeed * this.AccelerationMultiplier;
            }
            return this.MoveSpeed;
        }

        public void TranslateLeft(float deltaTime)
        {
            float moveSpeed = GetCurrentMoveSpeed();
            this.Location = new Vector3(
                Location.X - (float)Math.Sin(Yaw + MathUtil.PiOverTwo) * moveSpeed * deltaTime,
                Location.Y,
                Location.Z - (float)Math.Cos(Yaw + MathUtil.PiOverTwo) * moveSpeed * deltaTime);
        }

        public void TranslateRight(float deltaTime)
        {
            float moveSpeed = GetCurrentMoveSpeed();
            this.Location = new Vector3(
                Location.X + (float)Math.Sin(Yaw + MathUtil.PiOverTwo) * moveSpeed * deltaTime,
                Location.Y,
                Location.Z + (float)Math.Cos(Yaw + MathUtil.PiOverTwo) * moveSpeed * deltaTime);
        }

        public void TranslateForward(float deltaTime)
        {
            float degreesX = MathUtil.RadiansToDegrees(Pitch) * 0.01745329F; // X rotation
            float degreesY = MathUtil.RadiansToDegrees(Yaw) * 0.01745329F; // Y rotation
            float moveSpeed = GetCurrentMoveSpeed();
            this.Location = new Vector3(
                this.Location.X - (float)(moveSpeed * Math.Sin(degreesY) * Math.Cos(degreesX)) * deltaTime,
                this.Location.Y - (float)(moveSpeed * Math.Sin(degreesX)) * deltaTime,
                this.Location.Z - (float)(moveSpeed * Math.Cos(degreesY) * Math.Cos(degreesX)) * deltaTime);
        }

        public void TranslateBackward(float deltaTime)
        {

            float degreesX = MathUtil.RadiansToDegrees(Pitch) * 0.01745329F; // X rotation
            float degreesY = MathUtil.RadiansToDegrees(Yaw) * 0.01745329F; // Y rotation
            float moveSpeed = GetCurrentMoveSpeed();
            this.Location = new Vector3(
                this.Location.X + (float)(moveSpeed * Math.Sin(degreesY) * Math.Cos(degreesX)) * deltaTime,
                this.Location.Y + (float)(moveSpeed * Math.Sin(degreesX)) * deltaTime,
                this.Location.Z + (float)(moveSpeed * Math.Cos(degreesY) * Math.Cos(degreesX)) * deltaTime);
        }

        public void TransformYawPitch(float dx, float dy)
        {
            Yaw -= dx * LookSpeed;
            Pitch += dy * LookSpeed;
            const float pitchClamp = 1.56f;
            if (Pitch <= -pitchClamp)
            {
                Pitch = -pitchClamp;
            }
            if (Pitch >= pitchClamp)
            {
                Pitch = pitchClamp;
            }
        }

        public void TranslateUp(float deltaTime)
        {
            this.Location = new Vector3(
                this.Location.X,
                this.Location.Y + GetCurrentMoveSpeed() * deltaTime,
                this.Location.Z);
        }

        public void TranslateDown(float deltaTime)
        {
            this.Location = new Vector3(
                this.Location.X,
                this.Location.Y - GetCurrentMoveSpeed() * deltaTime,
                this.Location.Z);
        }

        public void LookAt(Vector3 location, float pitch, float yaw, float roll)
        {
            this.Location = location;
            this.Pitch = pitch;
            this.Yaw = yaw;
            this.Roll = roll;
        }

        public void SetAspectRatio(int width, int height)
        {
            this.ViewportWidth = width;
            this.ViewportHeight = height;
            this.AspectRatio = width / (float)height;
        }
    }
}

И, наконец, вот видео, наглядно демонстрирующее совместную работу вышеприведенного кода. https://www.youtube.com/watch?v=q5KFGdLtceo

person Krythic    schedule 04.08.2020

В конце концов, это не было чем-то большим, чем следующий фрагмент кода:

public Ray GetPickRay(float mouseX, float mouseY)
{
    return Ray.GetPickRay((int)mouseX, (int)mouseY, new ViewportF(0, 0, ViewportWidth, ViewportHeight), ViewProjectionMatrix);
}
person ManIkWeet    schedule 09.01.2015
comment
Ваша ссылка 404, поэтому мы не ссылаемся на внешние веб-сайты. Не могли бы вы обновить свой ответ? До тех пор я голосую против. - person Krythic; 02.08.2020
comment
@Krythic Я не помню, что изначально было на веб-сайте в качестве контента, но я добавил небольшую правку. - person ManIkWeet; 03.08.2020
comment
Я уже узнал, как это сделать. Вот мои результаты: youtube.com/watch?v=q5KFGdLtceo - person Krythic; 03.08.2020
comment
Право жалуется на то, что я публикую ссылку в моем ответе, и продолжает делать что-то подобное (да, YouTube может не отключиться, но вы можете удалить видео / аккаунт через 5 лет) - person ManIkWeet; 04.08.2020