欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

WPF实现平面三角形3D运动效果

程序员文章站 2024-02-21 14:19:04
...

实现效果如下:

WPF实现平面三角形3D运动效果

思路:封装三角形三个顶点和路径的三角形类,图形渲染时同步更新公共顶点三角形的顶点位置。

步骤:

1、三角形类Triangle.cs

        public Point A, B, C;//初始三个顶点
        public Point VA, VB, VC;//运动的三个顶点
        public Path trianglePath;//三角形路径
        public Color triangleColor;//填充
        public double ColorIndex;//颜色深度

        public Triangle(Point a, Point b, Point c, Color co, double z)
        {
            A = VA = a;
            B = VB = b;
            C = VC = c;
            triangleColor = co;
            ColorIndex = z;
            trianglePath = new Path();
            Draw();
        }

        /// <summary>
        /// 绘制三角形
        /// </summary>
        public void Draw()
        {
            var g = new StreamGeometry();
            using (StreamGeometryContext context = g.Open())
            {
                context.BeginFigure(VA, true, true);
                context.LineTo(VB, true, false);
                context.LineTo(VC, true, false);
            }
            trianglePath.Data = g;
            trianglePath.Fill = new SolidColorBrush(triangleColor);
        }

2、 三角形系统类TriangleSystem.cs

    public class TriangleSystem
    {
        /// <summary>
        /// 三角形列表
        /// </summary>
        private List<Triangle> triangles;

        /// <summary>
        /// 点和与其对应三角形字典
        /// </summary>
        public Dictionary<Point, PointClass> pointTriangles;

        /// <summary>
        /// 容器
        /// </summary>
        private Canvas containerCanvas;

        /// <summary>
        /// 三角形宽
        /// </summary>
        private int triangleWidth = 100;

        /// <summary>
        /// 三角形高
        /// </summary>
        private int triangleHeight = 100;

        /// <summary>
        /// 三角形横向数量
        /// </summary>
        private int horizontalCount = 10;

        /// <summary>
        /// 三角形纵向数量
        /// </summary>
        private int verticalCount = 5;

        /// <summary>
        /// X坐标运动范围
        /// </summary>
        private int XRange = 100;

        /// <summary>
        /// Y坐标运动范围
        /// </summary>
        private int YRange = 10;

        /// <summary>
        /// 坐标运动速度
        /// </summary>
        private int speed = 10;

        /// <summary>
        /// 三角形颜色深度
        /// </summary>
        private double zIndex = 10.0;

        /// <summary>
        /// 随机数
        /// </summary>
        private Random random;

        public TriangleSystem(Canvas ca)
        {
            containerCanvas = ca;
            random = new Random();
            triangles = new List<Triangle>();
            pointTriangles = new Dictionary<Point, PointClass>();

            SpawnTriangle();
        }

        /// <summary>
        /// 三角形初始化
        /// </summary>
        private void SpawnTriangle()
        {
            //清空队列
            triangles.Clear();

            for (int i = 0; i < horizontalCount; i++)
            {
                for (int j = 0; j < verticalCount; j++)
                {
                    Point A = new Point(i * triangleWidth, j * triangleHeight);
                    Point B = new Point(i * triangleWidth, (j + 1) * triangleHeight);
                    Point C = new Point((i + 1) * triangleWidth, (j + 1) * triangleHeight);
                    Point D = new Point((i + 1) * triangleWidth, j * triangleHeight);

                    double index = (i * horizontalCount / zIndex + j * verticalCount / zIndex ) / zIndex;
                    index = index > 1 ? 1 : index < 0.1 ? 0.1 : index;
                    Triangle t1 = new Triangle(A, B, C, GetTriangleColor(index), index);
                    Triangle t2 = new Triangle(A, D, C, GetTriangleColor(index - 0.1), index - 0.1);

                    //公共点和三角形集合键值对
                    AddPointTriangles(A, t1, t2);
                    AddPointTriangles(B, t1, t2);
                    AddPointTriangles(C, t1, t2);
                    AddPointTriangles(D, t1, t2);

                    //添加三角形
                    this.containerCanvas.Children.Add(t1.trianglePath);
                    this.containerCanvas.Children.Add(t2.trianglePath);
                    this.triangles.Add(t1);
                    this.triangles.Add(t2);
                }
            }
        }

        /// <summary>
        /// 添加公共点和三角形集合键值对
        /// </summary>
        private void AddPointTriangles(Point p, Triangle t1, Triangle t2)
        {
            if (!this.pointTriangles.Keys.Contains(p))
            {
                List<Triangle> ts = new List<Triangle>();
                ts.Add(t1);
                ts.Add(t2);
                PointClass pc = new PointClass
                {
                    triangles = ts,
                    vector = new Vector(random.Next(-speed, speed) * 0.05, random.Next(-speed, speed) * 0.05),
                };
                this.pointTriangles.Add(p, pc);
            }
            else
            {
                if (!this.pointTriangles[p].triangles.Contains(t1))
                    this.pointTriangles[p].triangles.Add(t1);
                if (!this.pointTriangles[p].triangles.Contains(t2))
                    this.pointTriangles[p].triangles.Add(t2);
            }
        }

        /// <summary>
        /// 获取三角形颜色
        /// </summary>
        private Color GetTriangleColor(double index)
        {
            return Color.FromArgb((byte)(255 * index), 230, 18, 65);
        }

        /// <summary>
        /// 更新三角形
        /// </summary>
        public void Update()
        {
            foreach (var pt in pointTriangles)
            {
                foreach (var t in pt.Value.triangles)
                {
                    if (t.A == pt.Key)
                        t.VA = GetPointValue(t.VA, t.A, ref pt.Value.vector, ref t.triangleColor, ref t.ColorIndex);
                    if (t.B == pt.Key)
                        t.VB = GetPointValue(t.VB, t.B, ref pt.Value.vector, ref t.triangleColor, ref t.ColorIndex);
                    if (t.C == pt.Key)
                        t.VC = GetPointValue(t.VC, t.C, ref pt.Value.vector, ref t.triangleColor, ref t.ColorIndex);
                    t.Draw();
                }
            }
        }

        /// <summary>
        /// 计算顶点值
        /// </summary>
        private Point GetPointValue(Point p1, Point p2, ref Vector v, ref Color c, ref double index)
        {
            Point getPoint = new Point();
            if (p1.X + v.X < p2.X + XRange && p1.X + v.X > p2.X - XRange)
                getPoint.X = p1.X + v.X;
            else
            {
                v.X = -v.X;
                index = index > 1 ? index - 0.01 : index < 0.01 ? index + 0.01 : index - 0.01;
                c = GetTriangleColor(index);
                getPoint.X = p1.X + v.X;
            }
                
            if (p1.Y + v.Y < p2.Y + YRange && p1.Y + v.Y > p2.Y - YRange)
                getPoint.Y = p1.Y + v.Y;
            else
            {
                v.Y = -v.Y;
                getPoint.Y = p1.Y + v.Y;
            }
            return getPoint;
        }
    }

3、PointClass.cs

    public class PointClass
    {
        public List<Triangle> triangles;
        public Vector vector;
    }

 4、主窗体交互逻辑

        private TriangleSystem ts;

        public MainWindow()
        {
            InitializeComponent();
            ts = new TriangleSystem(this.mainCanvas);
            CompositionTarget.Rendering += CompositionTarget_Rendering;
        }

        /// <summary>
        /// 帧渲染事件
        /// </summary>
        private void CompositionTarget_Rendering(object sender, EventArgs e)
        {
            ts.Update();
        }

不足:其中颜色渲染方式不够完善,无法完全模仿3D起伏的效果,有兴趣的可以一起探讨优化。