1

我正在努力在 wpf 中正确映射纹理。首先 3d 不是我的强项,但我有一些示例代码和下面的输出图像。我正在取一个多边形,执行三角剖分,然后尝试在输出上映射一个矩形纹理。我遇到的问题是我无法将纹理映射为平滑地跟随曲线。一个纹理贴图使用了 3dtools.dll 库,效果很好,但生成的纹理贴图在左侧产生了输出。它不会像我想要的那样倾斜。右边的结果图像是我尝试手动将纹理坐标映射到图像。我理解为什么它看起来确实如此,但我不确定如何纠正它?

 private void simpleButtonClick(object sender, RoutedEventArgs e)
        {
            ClearViewport();
            SetCamera();

            PathGeometry FlatPath;

            Geometry Geo = Geometry.Parse("M 0,0 L 0,10 C 4,4 6,6 10,10 V 0 C 6,-4 4,-6 0,0");
            var GeoText = FormattedText.BuildGeometry(new Point(0, 0));

            FlatPath =
                Geo.GetFlattenedPathGeometry(.01,
                                             ToleranceType.
                                                 Absolute);
            var vertices = new List<Vertex>();
            foreach (PathFigure Figure in FlatPath.Figures)
            {
                List<Point> PointList = DumpFigureToList(Figure);
                vertices.AddRange(PointList.Select(p=>new Vertex((float)p.X,(float)p.Y)));
            }

            // Write out the data set we're actually going to triangulate
            var angulator = new Triangulator();

            List<Triad> triangles = angulator.Triangulation(vertices, true);

            var Bounds = FlatPath.Bounds;

            var mesh = new MeshGeometry3D();
            var cube = new Model3DGroup();
            var Count = 0;
            foreach (var Tri in triangles)
            {
                Tri.MakeCounterClockwise(vertices);
                if (FlatPath.FillContains(new Point(Tri.circumcircleX, Tri.circumcircleY)))
                {
                    var p0 = new Point3D(vertices[Tri.a].x, vertices[Tri.a].y, 0);
                    var p1 = new Point3D(vertices[Tri.b].x, vertices[Tri.b].y, 0);
                    var p2 = new Point3D(vertices[Tri.c].x, vertices[Tri.c].y, 0);


                    mesh.Positions.Add(p0);
                    mesh.Positions.Add(p1);
                    mesh.Positions.Add(p2);
                    mesh.TriangleIndices.Add(Count);
                    Count++;
                    mesh.TriangleIndices.Add(Count);
                    Count++;
                    mesh.TriangleIndices.Add(Count);
                    Count++;
                    Vector3D normal = CalculateNormal(p0, p1, p2);
                    mesh.Normals.Add(normal);
                    mesh.Normals.Add(normal);
                    mesh.Normals.Add(normal);



                    mesh.TextureCoordinates.Add(new Point((Bounds.Left - vertices[Tri.a].x) / Bounds.Width, vertices[Tri.a].y > 0 ? 1 : 0));
                    mesh.TextureCoordinates.Add(new Point((Bounds.Left - vertices[Tri.b].x) / Bounds.Width, vertices[Tri.b].y > 0 ? 1 : 0));
                    mesh.TextureCoordinates.Add(new Point((Bounds.Left - vertices[Tri.c].x) / Bounds.Width, vertices[Tri.c].y > 0 ? 1 : 0));

                    if (wireframeCheckBox.IsChecked == true)
                    {
                        var wireframe = new ScreenSpaceLines3D();
                        wireframe.Points.Add(p0);
                        wireframe.Points.Add(p1);
                        wireframe.Points.Add(p2);
                        wireframe.Points.Add(p0);
                        wireframe.Color = Colors.LightBlue;
                        wireframe.Thickness = 2;

                        this.mainViewport.Children.Add(wireframe);
                    }
                }
            }


            //mesh.TextureCoordinates = _3DTools.MeshUtils.GeneratePlanarTextureCoordinates(mesh, new Vector3D(0, 0, 1));

            var myBrush = new ImageBrush();
            myBrush.ImageSource =
                new BitmapImage(new Uri(@"curvedown.png", UriKind.Absolute));
            Material material = new DiffuseMaterial(myBrush);
            var model = new GeometryModel3D(mesh, material);
            var group = new Model3DGroup();
            group.Children.Add(model);

            PointLight light = new PointLight(Colors.White, new Point3D(10,10,10));
            group.Children.Add(light);


            var Model = new ModelVisual3D();
            Model.Content = group;
            this.mainViewport.Children.Add(Model);

        }

这是上面带有线框的输出。我正在使用注释掉的纹理坐标代码。右侧是手动代码(未注释)。 输出图像

4

1 回答 1

4

使用您拥有的三角测量,它永远不会像您期望的那样正确弯曲。要实现这种弯曲,您必须手动生成细条纹。就像是

    ++++++++
    ||||||||
    ||||||||
    ++++++++

-- 其中每个 + 是一个顶点 -- 但不是使其笔直,而是沿着来自公共点(虚拟圆)的不同线映射它,沿着半径的特定偏移量。

在伪代码中:

    对于从 0 到 nStripes 的每个 i
      让角度 = 开始 + (结束-开始) * i / nStripes
      让 p1 = 点
        X = 内半径 * cos(角度)
        Y = 内半径 * sin(角度)
      让 p2 = 点
        X = 外半径 * cos(角度)
        Y = 外半径 * sin(角度)
      在 p1 处添加顶点
      在 p2 处添加顶点

然后成对连接先前生成的边,因此 (0,1)+(2,3) 将形成一个四边形,(2,3)+(4,5) 另一个,依此类推...

您将不得不决定哪些条纹数量足够好。永远记住,三角形内的纹理映射总是通过线性插值完成,而不是曲线,所以你不能指望曲线或梯形之类的东西神奇地看起来正确。

于 2012-12-27T14:05:11.723 回答