[C#]WPF 3D在很多个正方体中游荡

键盘和鼠标的控制

多个立方体

只有一个立方体无论怎么看都看不出什么花样,所以接下来准备新建多个立方体。那么前提就是将立方体封装成一个函数,从而不必每次都写重复的代码。

而又因涉及到多个图形,所以在cs端写比较便捷,其xaml代码中除了主Window外,只有一个

<Viewport3D Name="mainViewport"/>

最终得到的图形为

在这里插入图片描述

在下面的代码中,w是正方体边长,x,y,z为正方体中心。

private MeshGeometry3D MakeCubeMesh(double x, double y, double z, double w)
{
    
    
    MeshGeometry3D mesh = new MeshGeometry3D();

    // Define the positions.
    w /= 2;
    Point3D[] points =
    {
    
    
        new Point3D(x - w, y - w, z - w),
        new Point3D(x + w, y - w, z - w),
        new Point3D(x + w, y - w, z + w),
        new Point3D(x - w, y - w, z + w),
        new Point3D(x - w, y - w, z + w),
        new Point3D(x + w, y - w, z + w),
        new Point3D(x + w, y + w, z + w),
        new Point3D(x - w, y + w, z + w),
        new Point3D(x + w, y - w, z + w),
        new Point3D(x + w, y - w, z - w),
        new Point3D(x + w, y + w, z - w),
        new Point3D(x + w, y + w, z + w),
        new Point3D(x + w, y + w, z + w),
        new Point3D(x + w, y + w, z - w),
        new Point3D(x - w, y + w, z - w),
        new Point3D(x - w, y + w, z + w),
        new Point3D(x - w, y - w, z + w),
        new Point3D(x - w, y + w, z + w),
        new Point3D(x - w, y + w, z - w),
        new Point3D(x - w, y - w, z - w),
        new Point3D(x - w, y - w, z - w),
        new Point3D(x - w, y + w, z - w),
        new Point3D(x + w, y + w, z - w),
        new Point3D(x + w, y - w, z - w),
    };
    foreach (Point3D point in points) mesh.Positions.Add(point);

    // Define the triangles.
    Tuple<int, int, int>[] triangles = new Tuple<int, int, int>[12];
    for (int i = 0; i < triangles.Length; i++)
    {
    
    
        int tmp = i % 2 == 0 ? 2 : -2;
        triangles[i] = new Tuple<int, int, int>(
            2 * i, 2 * i + 1, 2 * i + tmp);
    }
    foreach (Tuple<int, int, int> tuple in triangles)
    {
    
    
        mesh.TriangleIndices.Add(tuple.Item1);
        mesh.TriangleIndices.Add(tuple.Item2);
        mesh.TriangleIndices.Add(tuple.Item3);
    }

    return mesh;
}

相应地,生成模型的代码也要随之改动,

private void DefineModel(Model3DGroup group)
{
    
    
    // Make the ground.
    MeshGeometry3D groundMesh = new MeshGeometry3D();
    const double wid = 10;
    groundMesh.Positions.Add(new Point3D(-wid, 0, -wid));
    groundMesh.Positions.Add(new Point3D(-wid, 0, +wid));
    groundMesh.Positions.Add(new Point3D(+wid, 0, +wid));
    groundMesh.Positions.Add(new Point3D(+wid, 0, -wid));

    foreach (var i in new int[6] {
    
     0, 1, 2, 0, 2, 3 })
        groundMesh.TriangleIndices.Add(i);

    DiffuseMaterial groundMaterial = new DiffuseMaterial(Brushes.DarkGray);
    GeometryModel3D groundModel = new GeometryModel3D(groundMesh, groundMaterial);
    group.Children.Add(groundModel);

    //为每个正方体染上不同的颜色以做区分
    Func<int, byte> getRGB = (x) => (byte)(128 + x * 50);

    //生成一些立方体.
    for (int x = -2; x <= 2; x += 2)
        for (int z = -2; z <= 2; z += 2)
        {
    
    
            MeshGeometry3D mesh = MakeCubeMesh(x, 0.5, z, 1);
            Color color = Color.FromArgb(255, 
                getRGB(x), getRGB(z), getRGB(x));
            DiffuseMaterial material = new DiffuseMaterial(
                new SolidColorBrush(color));

            GeometryModel3D model = new GeometryModel3D(mesh, material);
            group.Children.Add(model);
        }
}

而摄像机、光线等代码可不做改动,就是上一节的代码

// 窗口加载时执行
private void Window_Loaded(object sender, RoutedEventArgs e)
{
    
    
    // 定义WPF组件
    ModelVisual3D visual3d = new ModelVisual3D();
    Model3DGroup group3d = new Model3DGroup();
    visual3d.Content = group3d; 
    mainViewport.Children.Add(visual3d);

    DefineCamera(mainViewport);
    DefineLights(group3d);
    DefineModel(group3d);
}

// 定义相机
private void DefineCamera(Viewport3D viewport)
{
    
    
    Point3D p = new Point3D(1.5, 2, 3);
    Vector3D lookDirection = new Vector3D(-p.X, -p.Y, -p.Z);
    Vector3D upDirection = new Vector3D(0, 1, 0);
    double fieldOfView = 60;
    //对应PerspectiveCamera的四个参数
    PerspectiveCamera camera = new PerspectiveCamera(
        p, lookDirection, upDirection, fieldOfView);

    viewport.Camera = camera;
}

// 定义光线.
private void DefineLights(Model3DGroup group)
{
    
    
    group.Children.Add(new AmbientLight(Colors.Gray));
    Vector3D direction = new Vector3D(1, -2, -3);
    group.Children.Add(new DirectionalLight(Colors.Gray, direction));
}

添加动作

上面的视角其实并不算好,毕竟只看到了局部。而且由于立方体之间的相互遮挡,就算调整视场角也没法一栏全貌。

所以,如果摄像头可以走动就好了。为了实现这个目的,可以为相机添加一些键盘指令,从而更改视角,就像下面这种

在这里插入图片描述

//和相机有关的全局变量
private PerspectiveCamera TheCamera = null;
public Point3D CameraPosition = new Point3D(4, 0.5, 5);
public double CameraTheta = Math.PI * 1.3;

//相机初始化指令
private void DefineCamera2(Viewport3D viewport)
{
    
    
    TheCamera = new PerspectiveCamera(
        CameraPosition, AngleToVector(CameraTheta, 1), new Vector3D(0, 1, 0), 60);
    viewport.Camera = TheCamera;
    //绑定按键动作
    PreviewKeyDown += KeyboardControl_KeyDown;
}

接下来则是重头戏,关于按键和

private void KeyboardControl_KeyDown(object sender, KeyEventArgs e)
{
    
    
    Vector3D v;
    const double CameraDTheta = Math.PI / 30;
    const double CameraDR = 0.1;

    //将角度a和长度L转为矢量
    Func<double, double, Vector3D> AngleToVector  = (a, L) 
        => new Vector3D(L * Math.Cos(a), 0, L * Math.Sin(a));

    switch (e.Key)
    {
    
    
        case Key.Left:
            CameraTheta -= CameraDTheta;
            break;
        case Key.Right:
            CameraTheta += CameraDTheta;
            break;
        case Key.Up:
            CameraPosition += AngleToVector(CameraTheta, CameraDTheta);
            break;
        case Key.Down:
            CameraPosition += AngleToVector(CameraTheta, -CameraDTheta);
            break;
        case Key.Q:
            v = AngleToVector(CameraTheta, CameraDR);
            CameraPosition += new Vector3D(v.Z, 0, -v.X);
            break;
        case Key.E:
            v = AngleToVector(CameraTheta, CameraDR);
            CameraPosition += new Vector3D(-v.Z, 0, +v.X);
            break;
    }
    TheCamera.Position = CameraPosition;
    TheCamera.LookDirection = AngleToVector(CameraTheta, 1);
    TheCamera.UpDirection = new Vector3D(0, 1, 0);
}

猜你喜欢

转载自blog.csdn.net/m0_37816922/article/details/124155135