3D вращение куба вокруг осей X и Y - PullRequest
0 голосов
/ 14 декабря 2018

Я пишу приложение WPF, которое использует Viewport 3D для отображения куба, состоящего из 6 различных цветных граней.В конце концов я пытаюсь создать вращающийся кубик Рубика.

Я встроил два метода для вращения камеры вокруг куба, один с помощью клавиш «WASD», а другой - с помощью перетаскивания мыши.

Вращение камеры относительно оси y работает нормально (поэтому «горизонтально»).Однако, при попытке повернуть камеру относительно оси x, она работает правильно только тогда, когда камера еще не повернута горизонтально.Если это так, то кажется, что куб всегда поворачивает одну и ту же грань вверх, независимо от того, где он находится.
В качестве примера, скажем, мы используем стандартный кубик Рубика.Белое лицо будет обращено вверх, а синее лицо будет лицом вперед.Когда камера еще не повернута, и я нажимаю клавишу «W» или перетаскиваю мышь вверх, синее лицо перемещается в направлении белого лица, поэтому куб, кажется, вращается вверх, чего я и хочу.Однако, если я сначала поверну камеру на 180 градусов по горизонтали, чтобы белое лицо все еще было обращено вверх, а переднее лицо теперь стало зеленым, и я использую клавишу «W» или перетаскиваю мышь вверх, вращение все равно будет таким, чтосинего лица, движущегося в сторону белого лица, так что куб, кажется, вращается вниз.

Я предполагаю, что это связано с тем, что ось x остается на том же месте, пока камера вращается, но я не уверен, как это исправить.Любая помощь будет принята с благодарностью.

Это мой код XAML для камеры:

                <Viewport3D.Camera>
                <PerspectiveCamera 
              Position = "2, 2, 5"
              LookDirection = "-2, -2, -5"
              UpDirection = "0, 1, 0"
                NearPlaneDistance="1"
                FarPlaneDistance="20"
              FieldOfView = "80">
                    <PerspectiveCamera.Transform>
                        <Transform3DGroup>
                            <RotateTransform3D>
                                <!--Take care of x rotation of camera-->
                                <RotateTransform3D.Rotation>
                                    <AxisAngleRotation3D x:Name="rotateX" Axis="0 1 0 " Angle="0" />
                                </RotateTransform3D.Rotation>
                            </RotateTransform3D>
                            <RotateTransform3D>
                                <!--Take care of y rotation of camera-->
                                <RotateTransform3D.Rotation>
                                    <AxisAngleRotation3D x:Name="rotateY" Axis="1 0 0 " Angle="0" />
                                </RotateTransform3D.Rotation>
                            </RotateTransform3D>
                        </Transform3DGroup>
                    </PerspectiveCamera.Transform>
                </PerspectiveCamera>
            </Viewport3D.Camera>

Это мой код для поворота камеры при перетаскивании мыши (CanvasCube - это холст, содержащиймой Viewport3D):

        private void Window_MouseDown(object sender, MouseButtonEventArgs e)
    {
        this.Cursor = Cursors.Hand;
        oldMouseX = e.GetPosition(CanvasCube).X;
        oldMouseY = e.GetPosition(CanvasCube).Y;
        mousePressed = true;
    }

    private void Window_MouseMove(object sender, MouseEventArgs e)
    {
        if (mousePressed)
        {

            if(e.GetPosition(CanvasCube).X > oldMouseX)
            {
                rotateX.Angle --;
                oldMouseX = e.GetPosition(CanvasCube).X;
            }
            else if (e.GetPosition(CanvasCube).X < oldMouseX)
            {
                rotateX.Angle ++;
                oldMouseX = e.GetPosition(CanvasCube).X;
            }
           if (e.GetPosition(CanvasCube).Y > oldMouseY)
            {
                rotateY.Angle--;
                oldMouseY = e.GetPosition(CanvasCube).Y;
            }
            else if (e.GetPosition(CanvasCube).Y < oldMouseY)
            {
                rotateY.Angle++;
                oldMouseY = e.GetPosition(CanvasCube).Y;
            }
        }
    }

И это мой код для поворота камеры с помощью клавиш 'WASD':

        private void Window_KeyDown(object sender, KeyEventArgs e)
    {
        switch (e.Key)
        {
            case Key.W:
                angleUp();
                break;
            case Key.S:
                angleDown();
                break;
            case Key.A:
                angleRight();
                break;
            case Key.D:
                angleLeft();
                break;}}
    private void angleUp()
    {
        rotateY.Angle+=2;
    }

    private void angleDown()
    {
        rotateY.Angle-=2;
    }

    private void angleRight()
    {
        rotateX.Angle+=2;
    }

    private void angleLeft()
    {
        rotateX.Angle-=2;
    }

PS Я надеюсь, что проблема ясна таким образом,Мне трудно это объяснить.Если нет, я был бы рад объяснить, чтобы уточнить.

1 Ответ

0 голосов
/ 14 декабря 2018

Мне удалось сделать это с помощью одного RotationTransform, изменив угол преобразования.

<RotateTransform3D >
    <RotateTransform3D.Rotation>
        <AxisAngleRotation3D Axis="{Binding AxisVector}"
                             Angle="{Binding Rotation}"/>
    </RotateTransform3D.Rotation>
</RotateTransform3D>

И затем указав Ось и Угол следующим образом:

private bool dragging;
private Point dragStart;
private Point dragTotal;
private double rotation;
private Vector3D axis;

private void Viewport3DOnPreviewMouseMove(object sender, MouseEventArgs e)
    {
        if (!this.dragging) return;

        var pos = e.GetPosition(this.Viewport3D);

        var x = pos.X - this.dragStart.X;
        var y = pos.Y - this.dragStart.Y;

        this.Rotation =  Math.Sqrt(x * x + y * y);

        this.AxisVector = new Vector3D(y, 0, -x);
    }

    private void Viewport3DOnPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
    {
        this.dragging = true;
        this.dragStart = e.GetPosition(this.Viewport3D);
        this.dragStart.Offset(-this.dragTotal.X, -this.dragTotal.Y);
    }

    private void Viewport3DOnPreviewMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
    {
        this.dragging = false;

        var dragEnd = e.GetPosition(this.Viewport3D);
        this.dragTotal.X = dragEnd.X - this.dragStart.X;
        this.dragTotal.Y = dragEnd.Y - this.dragStart.Y;
    }

Это неКажется, не имеет значения, что Ось имеет переменную длину.

Дайте мне знать, если вам понадобится больше кода.

...