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

标签 c# wpf directx texture-mapping sharpdx

我是 3D 编程新手,在让纹理正确填充网格方面遇到了困难。我已经在墙上正确调整了尺寸,但屋顶上的纹理以一定角度运行并且拉伸(stretch)得太远。

我有几种方法来创建网格,但它们最终都会发送到 AddTriangle 方法,在该方法中设置纹理坐标。

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);

我的纹理看起来像这样:

shingle1.jpg

这是我得到的结果。

Texture Problem.jpg

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

最佳答案

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

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

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

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

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);
}

关于c# - 如何为 Mesh3D 正确设置纹理坐标,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49592970/

相关文章:

c# - 从数据库登录

c# - 将 ListView 滚动到顶部 ItemsSource Changed 被意外调用

c# - 在 Graphsharp 中向边缘添加自定义样式

wpf - 用于关闭 View 的 ViewModel 命令的 Cinch 版本

c++ - 制作模型加载器 : What to do after reading the vertices and texture?

c++ - 将 SpriteBatch 与 Direct3D 和 XAML 结合使用

c# - MVC 中的 AJAX JSON 调用来过滤 View 中的列表

c# - 使用 linq 删除列表中的重复项

c# - Lambda 表达式的性能优势

c++ - HLSL 法线贴图矩阵乘法