[C#]WPF 3D controls the camera angle with the mouse

Recap

Part of the source code refers to Github, which is the code of a book called WPF-3D. You can buy the physical book if you have conditions.
The source address of this article: WPF3D + mouse control camera perspective + package into a class

Encapsulate the keyboard control into a class

At present, it has been realized to adjust the camera's angle of view through the six keys of up, down, left, and Q and E. Since these functions are relatively concentrated with each other, it is very reasonable to encapsulate them into a class according to the principles of low coupling and high cohesion.

The result of this is that MainWindowthe code in Rang is greatly reduced, leaving only 5 custom functions Window_Loaded, DefineCamera, DefineLights, , DefineModeland . MakeCubeMeshThe original KeyboardControl_KeyDownfunctions will be moved to the camera control class.

The final effect is exactly the same as when it is not encapsulated into a class

insert image description here

Among them, the functions and member variables related to the camera are

private PerspectiveCamera TheCamera = null;

// 相机遥控器,CameraController是自定义了一个类
private CameraController cc = null;
private void DefineCamera(Viewport3D viewport)
{
    
    
    TheCamera = new PerspectiveCamera();
    TheCamera.FieldOfView = 60;
    cc = new CameraController(TheCamera, viewport, this);
}

The next step is to write CameraControllerthis class, and its member variables are as follows

// 每次转换的的最小值
public const double cmDR = 0.1;
public const double cmDTheta = Math.PI / 30;

//相机
public PerspectiveCamera cm = null;
// 传入主窗口的动作
private UIElement mainWindow = null;
// 相机位置和方向
public Point3D cmPosition {
    
     get; set; } = new Point3D(4, 0.5, 5);
public double cmTheta = Math.PI * 1.3;

Among them, the two constants cmDRand cmDTherarepresent the distance and angle of a single movement, respectively. For example, by pressing the left arrow, the current camera angle is decreased cmDTheta.

The constructor is

public CameraController(PerspectiveCamera camera, Viewport3D viewport,UIElement mainWindow)
{
    
    
    cm = camera;
    viewport.Camera = cm;
    this.mainWindow = mainWindow;
    this.mainWindow.PreviewKeyDown += mainWindow_KeyDown;
    PositionCamera();
}

Finally, there is the interaction logic with the buttons. These contents have been written in the previous section and will not be described in detail.

// 将角度转为向量
protected Vector3D AngleToVector(double angle, double length)
{
    
    
    return new Vector3D(
        length * Math.Cos(angle), 0, length * Math.Sin(angle));
}

protected void MoveLR(bool isLeft=true)
{
    
    
    Vector3D v = AngleToVector(cmTheta, cmDR);
    if (isLeft)
        cmPosition += new Vector3D(v.Z, 0, -v.X);
    else
        cmPosition += new Vector3D(-v.Z, 0, v.X);
}

//向上或者向下移动
protected void MoveUD(bool isUp = true)
{
    
    
    Vector3D v = AngleToVector(cmTheta, cmDR);
    if (isUp)
        cmPosition += v;
    else
        cmPosition -= v;
}

// 其中 上、下、Q、E代表平移
// 左右代表旋转
private void mainWindow_KeyDown(object sender, KeyEventArgs e)
{
    
    
    switch (e.Key)
    {
    
    
        case Key.Left: cmTheta -= cmDTheta;break;
        case Key.Right: cmTheta += cmDTheta;break;
        case Key.Up:MoveUD(true);break;
        case Key.Down: MoveUD(false);break;
        case Key.Q: MoveLR(true);break;
        case Key.E: MoveLR(false);break;
    }

    // 更新相机位置
    PositionCamera();
}


// 更新相机的位置
protected virtual void PositionCamera()
{
    
    
    cm.Position = cmPosition;
    cm.LookDirection = AngleToVector(cmTheta, 1);
    cm.UpDirection = new Vector3D(0, 1, 0);
}

Control the viewing angle with the mouse

Only from the structure of the code, there is no difference between controlling with the mouse and controlling with the keyboard, the only difference is that the return values ​​of the two are different.

So the initialization code is highly similar

public CameraController(PerspectiveCamera camera, Viewport3D viewport,
    UIElement mainWindow)
{
    
    
    cm = camera;
    viewport.Camera = cm;
    this.mainWindow = mainWindow;
    //鼠标按下时的动作
    this.mainWindow.MouseLeftButtonDown += mainWindow_LeftDown;
    PositionCameraMouse();
}

The final result is

insert image description here

Among them mainWindow_LeftDownis the key to completing the action. As the name suggests, the trigger condition of this function is to press the left mouse button. The function it implements is that when the left button has been pressed, drag the mouse to change the camera angle of view, so this function is written as

private Point ptLast;
private void mainWindow_LeftDown(object sender, MouseButtonEventArgs e)
{
    
    
    mainWindow.CaptureMouse();
    mainWindow.MouseMove += MainWindow_MouseMove;
    mainWindow.MouseUp += MainWindow_MouseUp;
    ptLast = e.GetPosition(mainWindow);
}

Among them, ptLastis a global variable used to save the position when the mouse is pressed. MainWindow_MouseMoveIt is the action performed when the mouse moves, and the action MainWindow_MouseUpwhen the mouse leaves. Obviously, the latter is easier to implement, and the binding event when the mouse is clicked and the unbinding event when the mouse is released is also a very common way of writing, and it is widely used. , the specific writing is as follows:

private void MainWindow_MouseUp(object sender, MouseButtonEventArgs e)
{
    
    
    mainWindow.ReleaseMouseCapture();
    mainWindow.MouseMove -= MainWindow_MouseMove;
    mainWindow.MouseUp -= MainWindow_MouseUp;
}

MouseMoveWhat is written is the interactive function.

private void MainWindow_MouseMove(object sender, MouseEventArgs e)
{
    
    
    const double xscale = 0.1;
    const double yscale = 0.1;

    Point newPoint = e.GetPosition(mainWindow);
    double dx = newPoint.X - ptLast.X;
    double dy = newPoint.Y - ptLast.Y;

    CameraTheta -= dx * CameraDTheta * xscale;
    CameraPhi -= dy * CameraDPhi * yscale;

    ptLast = newPoint;
    PositionCameraMouse();
}

private void PositionCameraMouse()
{
    
    
    double x, y, z;

    y = CameraR * Math.Cos(CameraPhi);
    double h = CameraR * Math.Sin(CameraPhi);
    x = h * Math.Sin(CameraTheta);
    z = h * Math.Cos(CameraTheta);

    cm.Position = new Point3D(x, y, z);
    cm.LookDirection = new Vector3D(-x, -y, -z);
    cm.UpDirection = new Vector3D(0, 1, 0);
}

Guess you like

Origin blog.csdn.net/m0_37816922/article/details/124196840