如何在 WPF 中使用鼠标在 ViewPort3D 中旋转相机?

发布于 2024-12-29 07:47:17 字数 138 浏览 2 评论 0原文

我能够直接在 XAML 中设置放置在 viewport3d 中的透视相机的位置和方向。 但我想知道如何使用鼠标输入旋转相机。 我更喜欢 C# 语言。 我实际上被困在如何使用鼠标输入旋转相机的问题上。 请帮我。 如果有人给我一个示例代码,那将会很有帮助......

I was able to set the position and direction of the perspective camera placed in the viewport3d directly in XAML.
But i would like to know how can i rotate the camera using the mouse input.
I would prefer C# lang.
I was actually stuck at the point how to rotate the camera using the input of the mouse.
Please help me.
It would be helpful if someone gives me a sample code....

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

绅士风度i 2025-01-05 07:47:17

我认为这两个链接可以帮助您很多...

动画 3D 相机的位置WPF
(还有一个示例项目可供尝试!)

旋转带鼠标的相机

我同意 XNA 可能是 3D 情况的最佳解决方案,但本机 3D 支持和硬件加速渲染也是WPF 和 XAML!

正如您所看到的,XAML Viewport3D 的 3D 相机与应用程序完美契合,还使用绑定:

<Viewport3D.Camera>
    <PerspectiveCamera x:Name="camera"
                       UpDirection="0,0,1"
                       LookDirection="{Binding RelativeSource={RelativeSource Self}, Path=Position, Converter={StaticResource lookBackConverter}}"
                       Position="0,0,0" />
</Viewport3D.Camera>

...以及通常的 IValueConverter 实现来让相机移动:

public class LookBackConverter : IValueConverter 
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new Point3D(0,0,0) - (Point3D)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}

I think these two links can help you a lot...

Animating the Position of a 3D Camera in WPF
(there's also a sample project to try!)

Rotating the Camera with the Mouse

I agree that maybe XNA would be the best solution for 3D situations, but native 3D support and hardware-accelerated rendering are also fantastic features of WPF and XAML!

As you can see, a 3D camera for XAML Viewport3D fits perfectly with the application, also using bindings:

<Viewport3D.Camera>
    <PerspectiveCamera x:Name="camera"
                       UpDirection="0,0,1"
                       LookDirection="{Binding RelativeSource={RelativeSource Self}, Path=Position, Converter={StaticResource lookBackConverter}}"
                       Position="0,0,0" />
</Viewport3D.Camera>

...and just the usual IValueConverter implementation to let the camera move:

public class LookBackConverter : IValueConverter 
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return new Point3D(0,0,0) - (Point3D)value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return null;
    }
}
分开我的手 2025-01-05 07:47:17

输入图片这里的描述

以下扩展方法实现了任意方向的自由飞行投影相机旋转到欧几里得 3D 空间。

using System.Windows.Input;
using System.Windows.Media.Media3D;

using static System.Windows.Input.Key;
using static System.Windows.Input.ModifierKeys;

public static class ProjectionCameraExtensions
{
    public static TCamera Move<TCamera>(this TCamera camera, Vector3D axis, double step)
        where TCamera : ProjectionCamera
    {
        camera.Position += axis * step;
        return camera;
    }

    public static TCamera Rotate<TCamera>(this TCamera camera, Vector3D axis, double angle)
        where TCamera : ProjectionCamera
    {
        Matrix3D matrix3D = new();
        matrix3D.RotateAt(new(axis, angle), camera.Position);
        camera.LookDirection *= matrix3D;
        return camera;
    }

    public static Vector3D GetYawAxis(this ProjectionCamera camera) => camera.UpDirection;
    public static Vector3D GetRollAxis(this ProjectionCamera camera) => camera.LookDirection;
    public static Vector3D GetPitchAxis(this ProjectionCamera camera) => Vector3D.CrossProduct(camera.UpDirection, camera.LookDirection);

    public static PerspectiveCamera MoveBy(this PerspectiveCamera camera, Key key) => camera.MoveBy(key, camera.FieldOfView / 180d);
    public static PerspectiveCamera RotateBy(this PerspectiveCamera camera, Key key) => camera.RotateBy(key, camera.FieldOfView / 45d);

    public static TCamera MoveBy<TCamera>(this TCamera camera, Key key, double step) where TCamera : ProjectionCamera => key switch
    {
        W => camera.Move(Keyboard.Modifiers.HasFlag(Shift) ? camera.GetYawAxis() : camera.GetRollAxis(), +step),
        S => camera.Move(Keyboard.Modifiers.HasFlag(Shift) ? camera.GetYawAxis() : camera.GetRollAxis(), -step),
        A => camera.Move(camera.GetPitchAxis(), +step),
        D => camera.Move(camera.GetPitchAxis(), -step),

        _ => camera
    };

    public static TCamera RotateBy<TCamera>(this TCamera camera, Key key, double angle) where TCamera : ProjectionCamera => key switch
    {
        Left => camera.Rotate(camera.GetYawAxis(), +angle),
        Right => camera.Rotate(camera.GetYawAxis(), -angle),
        Down => camera.Rotate(camera.GetPitchAxis(), +angle),
        Up => camera.Rotate(camera.GetPitchAxis(), -angle),

        _ => camera
    };
}

键盘和鼠标输入的处理程序

    private void Window_PreviewKeyDown(object sender, KeyEventArgs e) =>
        Camera.MoveBy(e.Key).RotateBy(e.Key);

    Point from;
    private void Window_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        var till = e.GetPosition(sender as IInputElement);
        double dx = till.X - from.X;
        double dy = till.Y - from.Y;
        from = till;

        var distance = dx * dx + dy * dy;
        if (distance <= 0d)
            return;

        if (e.MouseDevice.LeftButton is MouseButtonState.Pressed)
        {
            var angle = (distance / Camera.FieldOfView) % 45d;
            Camera.Rotate(new(dy, -dx, 0d), angle);
        }
    }

图片来源

enter image description here

Following extension methods implement free flight in any directions & rotations of a projection camera into Euclid 3D space.

using System.Windows.Input;
using System.Windows.Media.Media3D;

using static System.Windows.Input.Key;
using static System.Windows.Input.ModifierKeys;

public static class ProjectionCameraExtensions
{
    public static TCamera Move<TCamera>(this TCamera camera, Vector3D axis, double step)
        where TCamera : ProjectionCamera
    {
        camera.Position += axis * step;
        return camera;
    }

    public static TCamera Rotate<TCamera>(this TCamera camera, Vector3D axis, double angle)
        where TCamera : ProjectionCamera
    {
        Matrix3D matrix3D = new();
        matrix3D.RotateAt(new(axis, angle), camera.Position);
        camera.LookDirection *= matrix3D;
        return camera;
    }

    public static Vector3D GetYawAxis(this ProjectionCamera camera) => camera.UpDirection;
    public static Vector3D GetRollAxis(this ProjectionCamera camera) => camera.LookDirection;
    public static Vector3D GetPitchAxis(this ProjectionCamera camera) => Vector3D.CrossProduct(camera.UpDirection, camera.LookDirection);

    public static PerspectiveCamera MoveBy(this PerspectiveCamera camera, Key key) => camera.MoveBy(key, camera.FieldOfView / 180d);
    public static PerspectiveCamera RotateBy(this PerspectiveCamera camera, Key key) => camera.RotateBy(key, camera.FieldOfView / 45d);

    public static TCamera MoveBy<TCamera>(this TCamera camera, Key key, double step) where TCamera : ProjectionCamera => key switch
    {
        W => camera.Move(Keyboard.Modifiers.HasFlag(Shift) ? camera.GetYawAxis() : camera.GetRollAxis(), +step),
        S => camera.Move(Keyboard.Modifiers.HasFlag(Shift) ? camera.GetYawAxis() : camera.GetRollAxis(), -step),
        A => camera.Move(camera.GetPitchAxis(), +step),
        D => camera.Move(camera.GetPitchAxis(), -step),

        _ => camera
    };

    public static TCamera RotateBy<TCamera>(this TCamera camera, Key key, double angle) where TCamera : ProjectionCamera => key switch
    {
        Left => camera.Rotate(camera.GetYawAxis(), +angle),
        Right => camera.Rotate(camera.GetYawAxis(), -angle),
        Down => camera.Rotate(camera.GetPitchAxis(), +angle),
        Up => camera.Rotate(camera.GetPitchAxis(), -angle),

        _ => camera
    };
}

Handlers for keyboard and mouse input

    private void Window_PreviewKeyDown(object sender, KeyEventArgs e) =>
        Camera.MoveBy(e.Key).RotateBy(e.Key);

    Point from;
    private void Window_PreviewMouseMove(object sender, MouseEventArgs e)
    {
        var till = e.GetPosition(sender as IInputElement);
        double dx = till.X - from.X;
        double dy = till.Y - from.Y;
        from = till;

        var distance = dx * dx + dy * dy;
        if (distance <= 0d)
            return;

        if (e.MouseDevice.LeftButton is MouseButtonState.Pressed)
        {
            var angle = (distance / Camera.FieldOfView) % 45d;
            Camera.Rotate(new(dy, -dx, 0d), angle);
        }
    }

The image source

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文