You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF中如何实现鼠标控制3D物体围绕自身中心旋转(已实现左右旋转)

解决方案:实现立方体的鼠标多轴旋转

你的核心问题在于每次替换AxisAngleRotation3D无法累积多轴旋转,单独修改X/Y轴会导致旋转逻辑冲突。改用Quaternion(四元数)存储总旋转可以自然解决这个问题,它能正确组合多轴旋转且避免万向锁。

以下是修改后的完整代码:

private class MouseButtonInfo
{
    public MouseButtonInfo()
    {
        prevPosition = new Point();
        isDown = false;
    }
    public MouseButtonInfo(Point p, bool b)
    {
        prevPosition = p;
        isDown = b; 
    }
    public Point prevPosition;
    public bool isDown;
}

// 右键状态信息
private MouseButtonInfo rmbInfo = new MouseButtonInfo();

// 用四元数存储总旋转(替代原有的AxisAngleRotation3D)
private Quaternion cubeRotation = Quaternion.Identity;

// 绑定用的旋转属性,将四元数转换为AxisAngleRotation3D
public AxisAngleRotation3D CubeRotation
{ 
    get 
    {
        cubeRotation.ToAxisAngle(out Vector3D axis, out double angle);
        return new AxisAngleRotation3D(axis, angle);
    } 
}

private void viewport3d_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
    this.rmbInfo.isDown = true;
    this.rmbInfo.prevPosition = e.GetPosition(this.viewport3d);
    this.Cursor = Cursors.Hand;
    var el = (UIElement)sender;
    if (!el.CaptureMouse())
    {
        throw new SystemException("Unable to capture the mouse");
    }
}

private void viewport3d_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
{
    this.rmbInfo.isDown = false;
    this.Cursor = null;
    var el = (UIElement)sender;
    el.ReleaseMouseCapture();
}

private void viewport3d_MouseMove(object sender, MouseEventArgs e)
{
    if (this.rmbInfo.isDown)
    {
        Point currentPos = e.GetPosition(this.viewport3d);
        // 计算X/Y方向的鼠标偏移
        double deltaX = currentPos.X - this.rmbInfo.prevPosition.X;
        double deltaY = currentPos.Y - this.rmbInfo.prevPosition.Y;

        // 生成上下旋转(绕X轴)的四元数
        Quaternion xRot = new Quaternion(new Vector3D(1, 0, 0), deltaY * 0.4);
        // 生成左右旋转(绕Y轴)的四元数
        Quaternion yRot = new Quaternion(new Vector3D(0, 1, 0), deltaX * 0.4);

        // 累积旋转:先应用X轴旋转,再应用Y轴旋转(顺序影响最终效果,可根据需求调整)
        cubeRotation = xRot * yRot * cubeRotation;

        // 通知UI更新
        OnPropertyChanged(nameof(CubeRotation));

        this.rmbInfo.prevPosition = currentPos;
    }
}

关键修改说明:

  1. 替换旋转存储方式:用Quaternion替代AxisAngleRotation3D存储总旋转,四元数能正确组合多次旋转,避免单轴旋转的覆盖问题。
  2. 同时处理X/Y偏移:在MouseMove中同时计算水平和垂直方向的鼠标偏移,分别生成对应的旋转四元数。
  3. 累积旋转逻辑:通过四元数乘法组合新旋转与当前旋转,确保每次拖动都基于立方体的当前姿态进行,符合用户直觉。
  4. 保持绑定兼容性:CubeRotation属性将四元数转换为AxisAngleRotation3D,无需修改原有的UI绑定逻辑。

内容的提问来源于stack exchange,提问作者michuu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 18:23:27