如何通过鼠标移动进行3D旋转 [英] How to go about 3D rotation by mouse move

查看:143
本文介绍了如何通过鼠标移动进行3D旋转的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直试图解决这个问题好几个月(如果不是一年)。我似乎无法在屏幕上获得相对于3D模型的旋转方向。我可以计算轴方向(作为角度)但不能让鼠标方向绕模型运行(就像Sketchup这样的建模软件)。



I添加了似乎很差的代码,但我尝试了很多不同的方法和它变得如此复杂。所以我把它简化为简单的骨头,开始理解什么是真正控制什么。我想放弃,但我想我需要寻求帮助。



我尝试使用谷歌搜索,但似乎没有什么比较合适或我可以申请。



轮换代码来自使用VB.NET和GDI +旋转实体立方体| codeNtronix [ ^ ]



我尝试过:



I have been try to work this problem out for months (If not a year). I can't seem to get the direction of rotation relative the 3D model on screen. I can work out the axis directions (as angles) but can't get the mouse direction to orbit the model(Just like a modelling software like Sketchup).

I have added code which seems to be poor but I have tried so many different ways & it has got so complex. So I have stripped it down to simple bones to start understanding what is really controlling what. I feel like giving up but I think I need to ask for help.

I have tried googling but nothing seems to quite fit or I can apply to the application.

The rotation code was from Rotating Solid Cube Using VB.NET and GDI+ | codeNtronix[^]

What I have tried:

Dim Distance_Between As Integer = 0 'How much rotation
  
Distance_Between = Math.Sqrt(((e.X - m_PanStartPoint.X) ^ 2) + ((e.Y - m_PanStartPoint.Y) ^ 2))

Dim X_Angle_Diff As Integer = Angle_Axis_X - Angle_Mouse
Dim Y_Angle_Diff As Integer = (Angle_Axis_Y) - Angle_Mouse

If X_Angle_Diff <> 0 Then
   X_Rotate = Orig_X_Rot - (X_Angle_Diff * (Distance_Between / 2000))
End If

If Y_Angle_Diff <> 0 Then
   Y_Rotate = Orig_Y_Rot + (Y_Angle_Diff * (Distance_Between / 2000))
End If





对不清楚感到抱歉。

你说的旋转点没有说明但是它会是正确的(直到我可以锻炼相对于不同旋转点的偏移,即从绘制零点和鼠标旋转的距离)绘制零点。通过Matrix Translate定位绘图零点(此时也完成了刻度)。





Sorry for not being clear.
You are correct the rotation point is not stated but it will be (until I can workout the shift relative to the different rotation point i.e. distance from drawn zero point & mouse rotation) the drawing zero point. The drawing zero point is positioned by Matrix Translate (& Scale is done also at this time).

Dim translateMatrix1 As New Matrix
                translateMatrix1.Scale(Scale_Path, Scale_Path, MatrixOrder.Append)
                translateMatrix1.Translate(Offset_X_Path, Offset_Y_Path, MatrixOrder.Append)
                Temp_Path.Transform(translateMatrix1)







我现在在Ralf Meier的帮助下: -




Where I am now after help from Ralf Meier:-

Dim Correct_Speed_Factor As Decimal = Scale_Path * 0.5 ' set speed of rotation relative to scale

Dim Angle_Mouse As Decimal = Math.Atan2(Orbit_Start.Y - e.Y, Orbit_Start.X - e.X) * 180 / Math.PI

If Angle_Mouse < 0 Then
    Angle_Mouse = 360 + Angle_Mouse
End If


Dim Distance_Between As Decimal = 0 ' To account how much rotation


'Get distance of coord from mousedown to mouse postion
Distance_Between = Math.Sqrt(((e.X - Orbit_Start.X) ^ 2) + ((e.Y - Orbit_Start.Y) ^ 2))


'Get Positive differance between mouse & axis direction
Dim X_Angle_Diff As Decimal = Calc_Angle_dif(Y_Direction_Angle, Angle_Mouse) 'Y_Direction_Angle - Angle_Mouse


Dim Y_Angle_Diff As Decimal = Calc_Angle_dif(X_Direction_Angle, Angle_Mouse)
Dim Z_Angle_Diff As Decimal = (Calc_Angle_dif(X_Direction_Angle, Angle_Mouse) + Calc_Angle_dif(Y_Direction_Angle, Angle_Mouse)) / 2

  X_Rotate = Orig_X_Rot - ((Distance_Between * ((X_Angle_Diff - 90) / 90)) / Correct_Speed_Factor)

    Y_Rotate = Orig_Y_Rot - ((Distance_Between * ((Y_Angle_Diff - 90) / 90)) / Correct_Speed_Factor)
        Z_Rotate = Orig_Z_Rot - ((Distance_Between * ((Z_Angle_Diff - 90) / 90)) / Correct_Speed_Factor)

        'Then redraw





带功能



With function

Private Function Calc_Angle_dif(ByVal firstAngle As Single, ByVal secondAngle As Single) As Decimal
     Dim difference As Decimal = secondAngle - firstAngle
     Select Case difference
         Case Is < -180
             difference += 360
         Case Is > 180
             difference -= 360
     End Select
     If secondAngle = firstAngle Then
         Return 0
     Else
         Return (Math.Abs(difference))
     End If
     End
 End Function





这很有效但我似乎X&时的旋转锁定Y在同一架飞机上。另一个问题是一段时间(并非总是颠倒过来)滚动方向反转。



很奇怪&我不太确定是什么原因。欢迎任何帮助,因为我的数学变得非常紧张。



我想我可能找到了错误的原因。 3D旋转公式在X旋转中工作但Y& Z处于屏幕旋转状态。这是矩阵计算,对我的数学专家来说可能有点远。也许需要一些帮助找到原因。




This works quite well but I seem to a rotation lock when the X & Y are on the same plane. The other problem is some time(not always when upside down) the roll direction is reversed.

Weird & I am not quite sure what is the cause. Any help is welcome as my math are getting very much stretched.

I think I may of found the reason for the errors. the 3D rotation formula works in X rotation but Y & Z are in screen rotation. This is matrices calculation which maybe a bit to far for my math expertices. Maybe need some help finding the reason.

Public Function RotateX(ByVal angle As Integer) As Point3D
        Dim rad As Double, cosa As Double, sina As Double, yn As Double, zn As Double
 
        rad = angle * Math.PI / 180
        cosa = Math.Cos(rad)
        sina = Math.Sin(rad)
        yn = Me.Y * cosa - Me.Z * sina
        zn = Me.Y * sina + Me.Z * cosa
        Return New Point3D(Me.X, yn, zn)
    End Function
 
    Public Function RotateY(ByVal angle As Integer) As Point3D
        Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Zn As Double
 
        rad = angle * Math.PI / 180
        cosa = Math.Cos(rad)
        sina = Math.Sin(rad)
        Zn = Me.Z * cosa - Me.X * sina
        Xn = Me.Z * sina + Me.X * cosa
 
        Return New Point3D(Xn, Me.Y, Zn)
    End Function
 
    Public Function RotateZ(ByVal angle As Integer) As Point3D
        Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Yn As Double
 
        rad = angle * Math.PI / 180
        cosa = Math.Cos(rad)
        sina = Math.Sin(rad)
        Xn = Me.X * cosa - Me.Y * sina
        Yn = Me.X * sina + Me.Y * cosa
        Return New Point3D(Xn, Yn, Me.Z)
    End Function







使用来自Ralf Meier的解决方案2



这是我通过捕捉点更改旋转点时遇到的问题。

更新在Ralf Meier评论之后。




Using Solution 2 from Ralf Meier

Here is the problem I am having with changing rotation point by snap point.
Updated after Ralf Meier comments.

Imports System.Drawing.Graphics

Public Class Form2
    'Inherits Control

    Protected m_vertices(8) As Point3D
    Protected m_faces(6, 4) As Integer
    Protected m_colors(6) As Color
    Protected m_brushes(6) As Brush


    Dim Offset_X As Integer
    Dim Offset_Y As Integer
    Dim Scale As Integer = 100

    Sub New()
        ' Enable double-buffering to eliminate flickering.
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)

        ' Create the cube vertices.

        m_vertices = New Point3D() {
                     New Point3D(-1, 1, -1),
                     New Point3D(1, 1, -1),
                     New Point3D(1, -1, -1),
                     New Point3D(-1, -1, -1),
                     New Point3D(-1, 1, 1),
                     New Point3D(1, 1, 1),
                     New Point3D(1, -1, 1),
                     New Point3D(-1, -1, 1)}

        ' Create an array representing the 6 faces of a cube. Each face is composed by indices to the vertex array
        ' above.
        m_faces = New Integer(,) {{0, 1, 2, 3}, {1, 5, 6, 2}, {5, 4, 7, 6}, {4, 0, 3, 7}, {0, 4, 5, 1}, {3, 2, 6, 7}}

        ' Define the colors of each face.
        m_colors = New Color() {Color.BlueViolet, Color.Cyan, Color.Green, Color.Yellow, Color.Violet, Color.LightSkyBlue}

        ' Create the brushes to draw each face. Brushes are used to draw filled polygons.
        For i = 0 To 5
            m_brushes(i) = New SolidBrush(m_colors(i))
        Next




    End Sub

    Property xAngle As Integer
        Get
            Return my_xAngle
        End Get
        Set(value As Integer)
            my_xAngle = (value + 360) Mod 360
            Me.Invalidate()
        End Set
    End Property

    Private my_xAngle As Integer

    Property yAngle As Integer
        Get
            Return my_yAngle
        End Get
        Set(value As Integer)
            my_yAngle = (value + 360) Mod 360
            Me.Invalidate()
        End Set
    End Property
    Private my_yAngle As Integer

    Property zAngle As Integer
        Get
            Return my_zAngle
        End Get
        Set(value As Integer)
            my_zAngle = (value + 360) Mod 360
            Me.Invalidate()
        End Set
    End Property

    Private my_zAngle As Integer

    Dim Shift_X As Integer 'Shift in X Pivot point
    Dim Shift_Y As Integer 'Shift in Y Pivot point
    Dim Shift_Z As Integer 'Shift in Z Pivot point

    ' Used for Panning
    Dim Orig_X_Shift As Integer
    Dim Orig_Y_Shift As Integer


    Dim X_Zero_Track As Integer 'Track Origin point in X
    Dim Y_Zero_Track As Integer 'Track Origin point in Y

    Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)

        If e.Button = Windows.Forms.MouseButtons.Left Then
            MousePress = True
            MousePosLast = e.Location
        End If


        'Pan
        If e.Button = Windows.Forms.MouseButtons.Middle Then
            MousePosLast = e.Location
            Orig_X_Shift = Offset_X
            Orig_Y_Shift = Offset_Y
        End If



        MyBase.OnMouseDown(e)
    End Sub
    Private MousePress As Boolean = False
    Protected Overrides Sub OnMouseUp(e As System.Windows.Forms.MouseEventArgs)
        MousePress = False

        'Reset it back to position of Origin on No Snap
        snap = False
        Offset_X = X_Zero_Track
        Offset_Y = Y_Zero_Track
        Shift_X = 0 ' Zero Pivot point X
        Shift_Y = 0 ' Zero Pivot point Y
        Shift_Z = 0  'Zero Pivot point Z

        MyBase.OnMouseUp(e)
    End Sub



    Private snap As Boolean = False


    Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)

        'Orbit
        If MousePress Then

            MouseMoveHorizontal = MousePosLast.X - e.X
            MouseMoveVertical = MousePosLast.Y - e.Y
            MousePosLast = e.Location

            Dim Speed_Reducer As Integer = 5

            Dim xxAngle As Integer = (xAngle + 360) Mod 180
            Dim yyAngle As Integer = (yAngle + 360) Mod 180

            If (yyAngle > 135) Or (yyAngle <= 45) Then
                yAngle += MouseMoveHorizontal / Speed_Reducer
                xAngle -= MouseMoveVertical / Speed_Reducer
            Else
                xxAngle = (xAngle + 360) Mod 180
                If (xxAngle > 135) Or (xxAngle <= 45) Then
                    yAngle += MouseMoveHorizontal / Speed_Reducer
                    xAngle -= MouseMoveVertical / Speed_Reducer
                Else
                    xAngle += MouseMoveHorizontal / Speed_Reducer
                    yAngle -= MouseMoveVertical / Speed_Reducer
                End If
            End If

            Me.Invalidate()
        End If




        'Pan
        If e.Button = Windows.Forms.MouseButtons.Middle Then
            Offset_X = Orig_X_Shift + (e.X - MousePosLast.X)
            Offset_Y = Orig_Y_Shift + (e.Y - MousePosLast.Y)
            Me.Invalidate()
        End If

        MyBase.OnMouseMove(e)
    End Sub
    Private MouseMoveVertical As Integer = 0
    Private MouseMoveHorizontal As Integer = 0
    Private MousePosLast As Point




    Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
        Dim t(8) As Point3D
        Dim f(4) As Integer
        Dim v As Point3D
        Dim avgZ(6) As Double
        Dim order(6) As Integer
        Dim tmp As Double
        Dim iMax As Integer

        ' Clear the window
        e.Graphics.Clear(Color.LightBlue)

        'Save to the original offset to set it back later
        Dim Zero_Offset_X As Integer = Offset_X
        Dim Zero_Offset_y As Integer = Offset_Y



        'Reset offset (point of orgin) realitive to pivot point
        Dim Pivot_Point As Point3D
        Pivot_Point = New Point3D(Shift_X, Shift_Y, Shift_Z)
        Pivot_Point = Pivot_Point.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
        Offset_X -= ((Pivot_Point.X) * Scale)
        Offset_Y -= ((Pivot_Point.Y) * Scale)


        Dim Stringf As String = "SNAP ---- X" & Shift_X & " ------ Y" & Shift_X & " ------ Z" & Shift_Z
        e.Graphics.DrawString(Stringf, New Font("Ariel", 12), New SolidBrush(Color.Black), 10, 10)





        ' Transform all the points and store them on the "t" array.
        For i = 0 To 7
            Dim b As Brush = New SolidBrush(Color.White)
            v = m_vertices(i)
            t(i) = v.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
            't(i) = t(i).Project(Me.ClientSize.Width, Me.ClientSize.Height, 256, 10) 'Not Used



            'Would do this as Transform Matrix to Graphicspath
            'Scale
            t(i).X *= Scale
            t(i).Y *= Scale

            'Shift Pivot Point for view
            t(i).X += Offset_X
            t(i).Y += Offset_Y
        Next

        ' Compute the average Z value of each face.
        For i = 0 To 5
            avgZ(i) = (t(m_faces(i, 0)).Z + t(m_faces(i, 1)).Z + t(m_faces(i, 2)).Z + t(m_faces(i, 3)).Z) / 4.0
            order(i) = i
        Next

        ' Next we sort the faces in descending order based on the Z value.
        ' The objective is to draw distant faces first. This is called 
        ' the PAINTERS ALGORITHM. So, the visible faces will hide the invisible ones.
        ' The sorting algorithm used is the SELECTION SORT.
        For i = 0 To 4
            iMax = i
            For j = i + 1 To 5
                If avgZ(j) > avgZ(iMax) Then
                    iMax = j
                End If
            Next
            If iMax <> i Then
                tmp = avgZ(i)
                avgZ(i) = avgZ(iMax)
                avgZ(iMax) = tmp

                tmp = order(i)
                order(i) = order(iMax)
                order(iMax) = tmp
            End If
        Next

        ' Draw the faces using the PAINTERS ALGORITHM (distant faces first, closer faces last).
        For i = 0 To 5
            Dim points() As Point
            Dim index As Integer = order(i)
            points = New Point() {
                New Point(CInt(t(m_faces(index, 0)).X), CInt(t(m_faces(index, 0)).Y)),
                New Point(CInt(t(m_faces(index, 1)).X), CInt(t(m_faces(index, 1)).Y)),
                New Point(CInt(t(m_faces(index, 2)).X), CInt(t(m_faces(index, 2)).Y)),
                New Point(CInt(t(m_faces(index, 3)).X), CInt(t(m_faces(index, 3)).Y))
            }
            e.Graphics.FillPolygon(m_brushes(index), points)
        Next


        'Draw active pivot point
        Pivot_Point = New Point3D(Shift_X, Shift_Y, Shift_Z)
        Pivot_Point = Pivot_Point.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
        e.Graphics.DrawString("X", New Font("Ariel", 12, FontStyle.Bold), New SolidBrush(Color.Red), ((Pivot_Point.X * Scale) + Offset_X) - 10, ((Pivot_Point.Y * Scale) + Offset_Y) - 10)



        'Draw Orgin point
        e.Graphics.DrawString("O", New Font("Ariel", 10), New SolidBrush(Color.Black), Offset_X - 8, Offset_Y - 8)

        'Track Last place of Origin
        X_Zero_Track = Offset_X ' (Zero.X * Scale) + Offset_X
        Y_Zero_Track = Offset_Y ' (Zero.X * Scale) + Offset_X


        'Reset Offset adjustments
        Offset_X = Zero_Offset_X
        Offset_Y = Zero_Offset_y




        MyBase.OnPaint(e)
    End Sub

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        Me.WindowState = FormWindowState.Maximized

        'Set Offsets
        Offset_X = Me.Width / 2
        Offset_Y = Me.Height / 2

        'Set Scale/Size
        Scale = 100


    End Sub

    Private Sub Form2_MouseWheel(sender As Object, e As MouseEventArgs) Handles Me.MouseWheel


        Dim scale_Factor As Decimal = 1.1


        'Zoom
        If e.Delta > 0 Then 'Zoom In
            Scale *= scale_Factor

        Else 'Zoom Out
            If Scale / scale_Factor <= 0 Then 'Zoom to Small
                Exit Sub
            Else
                Scale /= scale_Factor
            End If

        End If

        Me.Invalidate()
    End Sub



    Private Sub Form2_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp

        isKeyDown = False

        'Reset it back to position of Origin on No Snap
        snap = False
        Offset_X = X_Zero_Track
        Offset_Y = Y_Zero_Track
        Shift_X = 0 ' Zero Pivot point X
        Shift_Y = 0 ' Zero Pivot point Y
        Shift_Z = 0  'Zero Pivot point Z


        Me.Invalidate()
    End Sub



    Dim isKeyDown As Boolean = False

    Private Sub Form2_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown

        'Makesure there is only fire
        If isKeyDown = True Then
            Exit Sub
        End If

        Select Case e.KeyCode
            Case Keys.NumPad1
                snap = True
                'Shift pivot to 1st point
                Shift_X = m_vertices(0).X 'Shift in X Pivot point
                Shift_Y = m_vertices(0).Y  'Shift in Y Pivot point
                Shift_Z = m_vertices(0).Z  'Shift in Z Pivot point.

            Case Keys.NumPad2
                snap = True
                'Shift pivot to 2nd point
                Shift_X = m_vertices(1).X 'Shift in X Pivot point
                Shift_Y = m_vertices(1).Y  'Shift in Y Pivot point
                Shift_Z = m_vertices(1).Z  'Shift in Z Pivot point

            Case Keys.NumPad3
                snap = True
                'Shift pivot to one 3rd point
                Shift_X = m_vertices(2).X 'Shift in X Pivot point
                Shift_Y = m_vertices(2).Y  'Shift in Y Pivot point
                Shift_Z = m_vertices(2).Z  'Shift in Z Pivot point

            Case Keys.NumPad4
                snap = True
                'Shift pivot to 4th point
                Shift_X = m_vertices(3).X 'Shift in X Pivot point
                Shift_Y = m_vertices(3).Y  'Shift in Y Pivot point
                Shift_Z = m_vertices(3).Z  'Shift in Z Pivot point

            Case Keys.NumPad5
                snap = True
                'Shift pivot to 5th point
                Shift_X = m_vertices(4).X 'Shift in X Pivot point
                Shift_Y = m_vertices(4).Y  'Shift in Y Pivot point
                Shift_Z = m_vertices(4).Z  'Shift in Z Pivot point

            Case Keys.NumPad6
                snap = True
                'Shift pivot to  6th point
                Shift_X = m_vertices(5).X 'Shift in X Pivot point
                Shift_Y = m_vertices(5).Y  'Shift in Y Pivot point
                Shift_Z = m_vertices(5).Z  'Shift in Z Pivot point

            Case Keys.NumPad7
                snap = True
                'Shift pivot to 7th point
                Shift_X = m_vertices(6).X 'Shift in X Pivot point
                Shift_Y = m_vertices(6).Y  'Shift in Y Pivot point
                Shift_Z = m_vertices(6).Z  'Shift in Z Pivot point

            Case Keys.NumPad8
                snap = True
                'Shift pivot to 8th point
                Shift_X = m_vertices(7).X 'Shift in X Pivot point
                Shift_Y = m_vertices(7).Y  'Shift in Y Pivot point
                Shift_Z = m_vertices(7).Z  'Shift in Z Pivot point

            Case Else
                snap = False
                'Shift point back to Zero/Origin
                Shift_X = 0 ' Zero Pivot point X
                Shift_Y = 0 ' Zero Pivot point Y
                Shift_Z = 0  'Zero Pivot point Z

        End Select


        'Make adjustments offsets to compensate for new pivot point. Only once fire
        Dim Pivot_Point As Point3D = New Point3D(Shift_X, Shift_Y, Shift_Z)
        Pivot_Point = Pivot_Point.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
        Offset_X += ((Pivot_Point.X) * Scale)
        Offset_Y += ((Pivot_Point.Y) * Scale)

        isKeyDown = True

        Me.Invalidate()
    End Sub
End Class

推荐答案

我请求道歉...但我忘记了我们所说的话关于...

根据我的建议,我修改了你所引用链接的代码。

这是我的解决方案:我构建一个具有行为的控件允许用/通过鼠标移动旋转立方体。



I beg for apologize ... but I have forgotten what we have spoken about ...
According to my suggestion I modified the code from the Link you are refering to.
Here is my Solution : I build a Control which has the Behaviour that allows to rotate a cube with/by the Mouse-Movement.

Imports System.Drawing.Graphics

Public Class RotatingCube
    Inherits Control

    Protected m_vertices(8) As Point3D
    Protected m_faces(6, 4) As Integer
    Protected m_colors(6) As Color
    Protected m_brushes(6) As Brush

    Sub New()
        ' Enable double-buffering to eliminate flickering.
        Me.SetStyle(ControlStyles.AllPaintingInWmPaint, True)
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer, True)

        ' Create the cube vertices.
        m_vertices = New Point3D() {
                     New Point3D(-1, 1, -1),
                     New Point3D(1, 1, -1),
                     New Point3D(1, -1, -1),
                     New Point3D(-1, -1, -1),
                     New Point3D(-1, 1, 1),
                     New Point3D(1, 1, 1),
                     New Point3D(1, -1, 1),
                     New Point3D(-1, -1, 1)}

        ' Create an array representing the 6 faces of a cube. Each face is composed by indices to the vertex array
        ' above.
        m_faces = New Integer(,) {{0, 1, 2, 3}, {1, 5, 6, 2}, {5, 4, 7, 6}, {4, 0, 3, 7}, {0, 4, 5, 1}, {3, 2, 6, 7}}

        ' Define the colors of each face.
        m_colors = New Color() {Color.BlueViolet, Color.Cyan, Color.Green, Color.Yellow, Color.Violet, Color.LightSkyBlue}

        ' Create the brushes to draw each face. Brushes are used to draw filled polygons.
        For i = 0 To 5
            m_brushes(i) = New SolidBrush(m_colors(i))
        Next
    End Sub

    Property xAngle As Integer
        Get
            Return my_xAngle
        End Get
        Set(value As Integer)
            my_xAngle = (value + 360) Mod 360
            Me.Invalidate()
        End Set
    End Property
    Private my_xAngle As Integer

    Property yAngle As Integer
        Get
            Return my_yAngle
        End Get
        Set(value As Integer)
            my_yAngle = (value + 360) Mod 360
            Me.Invalidate()
        End Set
    End Property
    Private my_yAngle As Integer

    Property zAngle As Integer
        Get
            Return my_zAngle
        End Get
        Set(value As Integer)
            my_zAngle = (value + 360) Mod 360
            Me.Invalidate()
        End Set
    End Property
    Private my_zAngle As Integer



    Protected Overrides Sub OnMouseDown(e As System.Windows.Forms.MouseEventArgs)
        If e.Button = Windows.Forms.MouseButtons.Left Then
            MousePress = True
            MousePosLast = e.Location
        End If
        MyBase.OnMouseDown(e)
    End Sub
    Private MousePress As Boolean = False
    Protected Overrides Sub OnMouseUp(e As System.Windows.Forms.MouseEventArgs)
        MousePress = False
        MyBase.OnMouseUp(e)
    End Sub

    Protected Overrides Sub OnMouseMove(e As System.Windows.Forms.MouseEventArgs)
        If MousePress Then
            MouseMoveHorizontal = MousePosLast.X - e.X
            MouseMoveVertical = MousePosLast.Y - e.Y
            MousePosLast = e.Location

            Dim xxAngle As Integer = (xAngle + 360) Mod 180
            Dim yyAngle As Integer = (yAngle + 360) Mod 180

            If (yyAngle > 135) Or (yyAngle <= 45) Then
                yAngle += MouseMoveHorizontal
                xAngle -= MouseMoveVertical
            Else
                xxAngle = (xAngle + 360) Mod 180
                If (xxAngle > 135) Or (xxAngle <= 45) Then
                    yAngle += MouseMoveHorizontal
                    xAngle -= MouseMoveVertical
                Else
                    xAngle += MouseMoveHorizontal
                    yAngle -= MouseMoveVertical
                End If
            End If

            Me.Invalidate()
        End If

        MyBase.OnMouseMove(e)
    End Sub
    Private MouseMoveVertical As Integer = 0
    Private MouseMoveHorizontal As Integer = 0
    Private MousePosLast As Point

    Protected Overrides Sub OnPaint(e As System.Windows.Forms.PaintEventArgs)
        Dim t(8) As Point3D
        Dim f(4) As Integer
        Dim v As Point3D
        Dim avgZ(6) As Double
        Dim order(6) As Integer
        Dim tmp As Double
        Dim iMax As Integer

        ' Clear the window
        e.Graphics.Clear(Color.LightBlue)

        ' Transform all the points and store them on the "t" array.
        For i = 0 To 7
            Dim b As Brush = New SolidBrush(Color.White)
            v = m_vertices(i)
            t(i) = v.RotateX(xAngle).RotateY(yAngle).RotateZ(zAngle)
            t(i) = t(i).Project(Me.ClientSize.Width, Me.ClientSize.Height, 256, 4)
        Next

        ' Compute the average Z value of each face.
        For i = 0 To 5
            avgZ(i) = (t(m_faces(i, 0)).Z + t(m_faces(i, 1)).Z + t(m_faces(i, 2)).Z + t(m_faces(i, 3)).Z) / 4.0
            order(i) = i
        Next

        ' Next we sort the faces in descending order based on the Z value.
        ' The objective is to draw distant faces first. This is called 
        ' the PAINTERS ALGORITHM. So, the visible faces will hide the invisible ones.
        ' The sorting algorithm used is the SELECTION SORT.
        For i = 0 To 4
            iMax = i
            For j = i + 1 To 5
                If avgZ(j) > avgZ(iMax) Then
                    iMax = j
                End If
            Next
            If iMax <> i Then
                tmp = avgZ(i)
                avgZ(i) = avgZ(iMax)
                avgZ(iMax) = tmp

                tmp = order(i)
                order(i) = order(iMax)
                order(iMax) = tmp
            End If
        Next

        ' Draw the faces using the PAINTERS ALGORITHM (distant faces first, closer faces last).
        For i = 0 To 5
            Dim points() As Point
            Dim index As Integer = order(i)
            points = New Point() {
                New Point(CInt(t(m_faces(index, 0)).X), CInt(t(m_faces(index, 0)).Y)),
                New Point(CInt(t(m_faces(index, 1)).X), CInt(t(m_faces(index, 1)).Y)),
                New Point(CInt(t(m_faces(index, 2)).X), CInt(t(m_faces(index, 2)).Y)),
                New Point(CInt(t(m_faces(index, 3)).X), CInt(t(m_faces(index, 3)).Y))
            }
            e.Graphics.FillPolygon(m_brushes(index), points)
        Next

        MyBase.OnPaint(e)
    End Sub

End Class







Public Class Point3D
    Protected m_x As Double, m_y As Double, m_z As Double

    Public Sub New(ByVal x As Double, ByVal y As Double, ByVal z As Double)
        Me.X = x
        Me.Y = y
        Me.Z = z
    End Sub

    Public Property X() As Double
        Get
            Return m_x
        End Get
        Set(ByVal value As Double)
            m_x = value
        End Set
    End Property

    Public Property Y() As Double
        Get
            Return m_y
        End Get
        Set(ByVal value As Double)
            m_y = value
        End Set
    End Property

    Public Property Z() As Double
        Get
            Return m_z
        End Get
        Set(ByVal value As Double)
            m_z = value
        End Set
    End Property

    Public Function RotateX(ByVal angle As Integer) As Point3D
        Dim rad As Double, cosa As Double, sina As Double, yn As Double, zn As Double

        rad = angle * Math.PI / 180
        cosa = Math.Cos(rad)
        sina = Math.Sin(rad)
        yn = Me.Y * cosa - Me.Z * sina
        zn = Me.Y * sina + Me.Z * cosa
        Return New Point3D(Me.X, yn, zn)
    End Function

    Public Function RotateY(ByVal angle As Integer) As Point3D
        Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Zn As Double

        rad = angle * Math.PI / 180
        cosa = Math.Cos(rad)
        sina = Math.Sin(rad)
        Zn = Me.Z * cosa - Me.X * sina
        Xn = Me.Z * sina + Me.X * cosa

        Return New Point3D(Xn, Me.Y, Zn)
    End Function

    Public Function RotateZ(ByVal angle As Integer) As Point3D
        Dim rad As Double, cosa As Double, sina As Double, Xn As Double, Yn As Double

        rad = angle * Math.PI / 180
        cosa = Math.Cos(rad)
        sina = Math.Sin(rad)
        Xn = Me.X * cosa - Me.Y * sina
        Yn = Me.X * sina + Me.Y * cosa
        Return New Point3D(Xn, Yn, Me.Z)
    End Function

    Public Function Project(ByVal viewWidth, ByVal viewHeight, ByVal fov, ByVal viewDistance)
        Dim factor As Double, Xn As Double, Yn As Double
        factor = fov / (viewDistance + Me.Z)
        Xn = Me.X * factor + viewWidth / 2
        Yn = Me.Y * factor + viewHeight / 2
        Return New Point3D(Xn, Yn, Me.Z)
    End Function
End Class


Sorry for not being clear.
You are correct the rotation point is not stated but it will be (until I can workout the shift relative to the different rotation point i.e. distance from drawn zero point & mouse rotation) the drawing zero point. The drawing zero point is positioned by Matrix Translate (& Scale is done also at this time).

<pre lang="vb">Dim translateMatrix1 As New Matrix
                translateMatrix1.Scale(Scale_Path, Scale_Path, MatrixOrder.Append)
                translateMatrix1.Translate(Offset_X_Path, Offset_Y_Path, MatrixOrder.Append)
                Temp_Path.Transform(translateMatrix1)





I need to have the orbital roll relative to mouse move/gesture.



I need to have the orbital roll relative to mouse move/gesture.


这篇关于如何通过鼠标移动进行3D旋转的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆