使用 WPF 和 C# 绘制覆盖有阴影高度图的 3D 表面

时间:2024-12-16 21:42:24

此示例使用 C# 和 XAML 绘制覆盖有阴影高度图的 3D 表面。示例释了如何在三维表面上覆盖图像。此示例执行的操作类似。但是,它不是简单地使用包含网格的现有图像,而是生成一个阴影图像以显示表面的高度。

下面的CreateAltitudeMap方法生成纹理位图。

该方法首先计算所绘制区域的表面函数值。它计算将要创建的图像中每个像素的值,在本例中为 512×512 像素图像。然后,代码使用 LINQ MinMax方法获取数组中的最大值和最小值。

然后,代码会创建一个BitmapPixelMaker对象。它会循环遍历图像中的像素,并使用相应的函数值来确定像素的颜色。代码使用MapRainbowColor方法(稍后介绍)将每个函数值映射到适当的颜色。

该方法最后调用BitmapPixelMaker对象的MakeBitmap方法来创建WriteableBitmap,然后使用位图的Save扩展方法将结果保存到文件中。

MapRainbowColor 方法使用以下代码将给定边界之间的值映射到颜色。

// Map a value to a rainbow color.
private void MapRainbowColor(double value,
    double min_value, double max_value,
    out byte red, out byte green, out byte blue)
{
    // Convert into a value between 0 and 1023.
    int int_value = (int)(1023 * (value - min_value) /
        (max_value - min_value));

    // Map different color bands.
    if (int_value < 256)
    {
        // Red to yellow. (255, 0, 0) to (255, 255, 0).
        red = 255;
        green = (byte)int_value;
        blue = 0;
    }
    else if (int_value < 512)
    {
        // Yellow to green. (255, 255, 0) to (0, 255, 0).
        int_value -= 256;
        red = (byte)(255 - int_value);
        green = 255;
        blue = 0;
    }
    else if (int_value < 768)
    {
        // Green to aqua. (0, 255, 0) to (0, 255, 255).
        int_value -= 512;
        red = 0;
        green = 255;
        blue = (byte)int_value;
    }
    else
    {
        // Aqua to blue. (0, 255, 255) to (0, 0, 255).
        int_value -= 768;
        red = 0;
        green = (byte)(255 - int_value);
        blue = 255;
    }
}

代码首先缩放该值,使其范围从 0 到 1023。根据值是 0 - 255、256 - 511、512 - 767 还是 768 - 1023 范围,代码将颜色转换为彩虹的不同部分。

将网格映射到表面上的程序 类似。以下代码显示了此示例如何使用CreateAltitudeMap方法保存的纹理图像来创建表面的材质。

// Create the altitude map texture bitmap.
private void CreateAltitudeMap()
{
    // Calculate the function's value over the area.
    const int xwidth = 512;
    const int zwidth = 512;
    const double dx = (xmax - xmin) / xwidth;
    const double dz = (zmax - zmin) / zwidth;
    double[,] values = new double[xwidth, zwidth];
    for (int ix = 0; ix < xwidth; ix++)
    {
        double x = xmin + ix * dx;
        for (int iz = 0; iz < zwidth; iz++)
        {
            double z = zmin + iz * dz;
            values[ix, iz] = F(x, z);
        }
    }

    // Get the upper and lower bounds on the values.
    var get_values =
        from double value in values
        select value;
    double ymin = get_values.Min();
    double ymax = get_values.Max();

    // Make the BitmapPixelMaker.
    BitmapPixelMaker bm_maker =
        new BitmapPixelMaker(xwidth, zwidth);

    // Set the pixel colors.
    for (int ix = 0; ix < xwidth; ix++)
    {
        for (int iz = 0; iz < zwidth; iz++)
        {
            byte red, green, blue;
            MapRainbowColor(values[ix, iz], ymin, ymax,
                out red, out green, out blue);
            bm_maker.SetPixel(ix, iz, red, green, blue, 255);
        }
    }

    // Convert the BitmapPixelMaker into a WriteableBitmap.
    WriteableBitmap wbitmap = bm_maker.MakeBitmap(96, 96);

    // Save the bitmap into a file.
    wbitmap.Save("Texture.png");
}
// Make the surface's material using an image brush.
ImageBrush texture_brush = new ImageBrush();
texture_brush.ImageSource =
    new BitmapImage(new Uri("Texture.png", UriKind.Relative));
DiffuseMaterial surface_material =
    new DiffuseMaterial(texture_brush);

源码:

https://download.****.net/download/ljygood2/90120994