如何为 Mesh3D 正确设置纹理坐标

How to set Texture Coordinates properly for Mesh3D

我是 3D 编程的新手,我很难让我的纹理正确填充我的网格。我已经在墙上正确调整了尺寸,但屋顶上的纹理 运行 有一个角度并且伸展得太远。

我有几种创建网格的方法,但它们最终都被发送到 AddTriangle 方法,在该方法中设置了 TextureCoordinates。

public static void AddTriangle(this MeshGeometry3D mesh, Point3D[] pts)
{
    // Create the points.
    int index = mesh.Positions.Count;
    foreach (Point3D pt in pts)
    {
        mesh.Positions.Add(pt);
        mesh.TriangleIndices.Add(index++);
        mesh.TextureCoordinates.Add(new Point(pt.X + pt.Z, 0 - pt.Y));
    }
}

这是我的 material 的设置方式。

imageBrush.ImageSource = new BitmapImage(new Uri("pack://application:,,,/Textures/shingles1.jpg"));
imageBrush.TileMode = TileMode.Tile;
imageBrush.ViewportUnits = BrushMappingMode.Absolute;
imageBrush.Viewport = new Rect(0, 0, 25, 25);
SidingColor = new DiffuseMaterial(imageBrush);
SidingColor.Color = RGB(89, 94, 100);

我的纹理是这样的:

这是我得到的结果。

经过几个小时的闲逛和谷歌搜索,我能得到的最接近的结果。

哇,这比我预期的要难一些。

这里有一些帮助我找到解决方案的资源。

How to convert a 3D point on a plane to UV coordinates?

从下面的link我意识到上面的公式上面的公式是正确的但是对于右手坐标系。我转换了它,这是最后一步。

http://www.math.tau.ac.il/~dcor/Graphics/cg-slides/geom3d.pdf

如果其他人有此问题,可以使用以下代码。

public static void AddTriangle(this MeshGeometry3D mesh, Point3D[] pts)
{
    if (pts.Count() != 3) return;

    //use the three point of the triangle to calculate the normal (angle of the surface)
    Vector3D normal = CalculateNormal(pts[0], pts[1], pts[2]);
    normal.Normalize();

    //calculate the uv products
    Vector3D u;
    if (normal.X == 0 && normal.Z == 0) u = new Vector3D(normal.Y, -normal.X, 0);
    else u = new Vector3D(normal.X, -normal.Z, 0);

    u.Normalize();
    Vector3D n = new Vector3D(normal.Z, normal.X, normal.Y);
    Vector3D v = Vector3D.CrossProduct(n, u);

    int index = mesh.Positions.Count;
    foreach (Point3D pt in pts)
    {
        //add the points to create the triangle
        mesh.Positions.Add(pt);
        mesh.TriangleIndices.Add(index++);

        //apply the uv texture positions
        double u_coor = Vector3D.DotProduct(u, new Vector3D(pt.Z,pt.X,pt.Y));
        double v_coor = Vector3D.DotProduct(v, new Vector3D(pt.Z, pt.X, pt.Y));
        mesh.TextureCoordinates.Add(new Point(u_coor, v_coor));            
    }
}

private static Vector3D CalculateNormal(Point3D firstPoint, Point3D secondPoint, Point3D thirdPoint)
{
    var u = new Point3D(firstPoint.X - secondPoint.X,
        firstPoint.Y - secondPoint.Y,
        firstPoint.Z - secondPoint.Z);

    var v = new Point3D(secondPoint.X - thirdPoint.X,
        secondPoint.Y - thirdPoint.Y,
        secondPoint.Z - thirdPoint.Z);

    return new Vector3D(u.Y * v.Z - u.Z * v.Y, u.Z * v.X - u.X * v.Z, u.X * v.Y - u.Y * v.X);
}