在C#中校正3D线条图

时间:2010-12-13 07:13:45

标签: c# 3d drawing line

我(在帮助下)创建了一个在3D空间内绘制和绘制一系列块的函数。通常,这是在64x64x64网格化多维数据集中执行的。

这是我的代码:

    internal static int DrawLine(Player theplayer, Byte drawBlock,
                                 int x0, int y0, int z0, int x1, int y1, int z1)
    {
        int blocks = 0;
        bool cannotUndo = false;
        bool detected = false;

        int dx = x1 - x0;
        int dy = y1 - y0;
        int dz = z1 - z0;

        DrawOneBlock(theplayer, drawBlock, x0, y0, z0, ref blocks, ref cannotUndo);
        if (Math.Abs(dx) > Math.Abs(dy) &&
            Math.Abs(dx) > Math.Abs(dz) && 
            detected == false)
        {
            detected = true;
            float my = (float)dy / (float)dx;
            float mz = (float)dz / (float)dx;
            float by = y0 - my * x0;
            float bz = z0 - mz * x0;
            dx = (dx < 0) ? -1 : 1;
            while (x0 != x1)
            {
                x0 += dx;
                DrawOneBlock(theplayer, drawBlock,
                    Convert.ToInt32(x0),
                    Convert.ToInt32(Math.Round(my * x0 + by)),
                    Convert.ToInt32(Math.Round(mz * x0 + bz)),
                    ref blocks, ref cannotUndo);
            }
        }
        if (Math.Abs(dy) > Math.Abs(dz) && 
            Math.Abs(dy) > Math.Abs(dx) &&
            detected == false)
        {
            detected = true;
            float mz = (float)dz / (float)dy;
            float mx = (float)dx / (float)dy;
            float bz = z0 - mz * y0;
            float bx = x0 - mx * y0;
            dy = (dy < 0) ? -1 : 1;
            while (y0 != y1)
            {
                y0 += dy;
                DrawOneBlock(theplayer, drawBlock,
                             Convert.ToInt32(Math.Round(mx * y0 + bx)),
                             Convert.ToInt32(y0),
                             Convert.ToInt32(Math.Round(mz * y0 + bz)),
                             ref blocks, ref cannotUndo);
            }
        }
        if (detected == false)
        {
            detected = true;
            float mx = (float)dx / (float)dz;
            float my = (float)dy / (float)dz;
            float bx = x0 - mx * z0;
            float by = y0 - my * z0;
            dz = (dz < 0) ? -1 : 1;
            while (z0 != z1)
            {
                z0 += dz;
                DrawOneBlock(theplayer, drawBlock,
                             Convert.ToInt32(Math.Round(mx * z0 + bx)),
                             Convert.ToInt32(Math.Round(my * z0 + by)),
                             Convert.ToInt32(z0),
                             ref blocks, ref cannotUndo);
            }
        }
        return blocks;
    }

它应该排队块图并返回它绘制的块数。问题是它没有绘制一条不折不扣的线。在某些情况下,当至少所有块都应通过它们的顶点连接时,它会在块之间留下间隙。

我努力解决的代码中唯一的部分是我计算轴的最大差异并创建斜率常量。我试图做一个完美的对角线时遇到了一个问题。所有的值都是相等的,所以我只是默认为z轴 - 这就是我认为问题存在的地方。

2 个答案:

答案 0 :(得分:8)

也许Bresenham line algorithm被修改为(希望)在3D中工作可能是你的另一种选择?

public static void Swap<T>(ref T x, ref T y)
{
    T tmp = y;
    y = x;
    x = tmp;
}

private void Draw3DLine(int x0, int y0, int z0, int x1, int y1, int z1)
{
    bool steepXY = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
    if (steepXY) { Swap(ref x0, ref y0); Swap(ref x1, ref y1); }

    bool steepXZ = Math.Abs(z1 - z0) > Math.Abs(x1 - x0);
    if (steepXZ) { Swap(ref x0, ref z0); Swap(ref x1, ref z1); }

    int deltaX = Math.Abs(x1 - x0);
    int deltaY = Math.Abs(y1 - y0);
    int deltaZ = Math.Abs(z1 - z0);

    int errorXY = deltaX / 2, errorXZ = deltaX / 2;

    int stepX = (x0 > x1) ? -1 : 1;  
    int stepY = (y0 > y1) ? -1 : 1;
    int stepZ = (z0 > z1) ? -1 : 1;

    int y=y0, z=z0;

    // Check if the end of the line hasn't been reached.
    for(int x = x0; x!=x1; x+=stepX) 
    {
        int xCopy=x, yCopy=y, zCopy=z;

        if (steepXZ) Swap(ref xCopy, ref zCopy);
        if (steepXY) Swap(ref xCopy, ref yCopy);

        // Replace the WriteLine with your call to DrawOneBlock
        Console.WriteLine("[" + xCopy + ", " + yCopy + ", " + zCopy + "], ");

        errorXY -= deltaY;
        errorXZ -= deltaZ;

        if (errorXY < 0) 
        {
            y += stepY;
            errorXY += deltaX;
        }

        if (errorXZ < 0) 
        {
            z += stepZ;
            errorXZ += deltaX;
        }
    }
}

答案 1 :(得分:0)

internal static void LineCallback(Player player, Position[] marks, object tag) //MODIFIED//
    {
        byte drawBlock = (byte)tag;
        if (drawBlock == (byte)Block.Undefined)
        {
            drawBlock = (byte)player.lastUsedBlockType;
        }

        player.undoBuffer.Clear();

        int blocks = 0;
        bool cannotUndo = false;

        // LINE CODE

        int x1 = marks[0].x, y1 = marks[0].y, z1 = marks[0].h, x2 = marks[1].x, y2 = marks[1].y, z2 = marks[1].h;
        int i, dx, dy, dz, l, m, n, x_inc, y_inc, z_inc, err_1, err_2, dx2, dy2, dz2;
        int[] pixel = new int[3];
        pixel[0] = x1;
        pixel[1] = y1;
        pixel[2] = z1;
        dx = x2 - x1;
        dy = y2 - y1;
        dz = z2 - z1;
        x_inc = (dx < 0) ? -1 : 1;
        l = Math.Abs(dx);
        y_inc = (dy < 0) ? -1 : 1;
        m = Math.Abs(dy);
        z_inc = (dz < 0) ? -1 : 1;
        n = Math.Abs(dz);
        dx2 = l << 1;
        dy2 = m << 1;
        dz2 = n << 1;

        DrawOneBlock(player, drawBlock, x2, y2, z2, ref blocks, ref cannotUndo);
        DrawOneBlock(player, drawBlock, x2, y2, z2, ref blocks, ref cannotUndo);

        if ((l >= m) && (l >= n)) {

            err_1 = dy2 - l;
            err_2 = dz2 - l;
            for (i = 0; i < l; i++) {
                DrawOneBlock(player, drawBlock, pixel[0], pixel[1], pixel[2], ref blocks, ref cannotUndo);
                if (err_1 > 0) {
                    pixel[1] += y_inc;
                    err_1 -= dx2;
                }
                if (err_2 > 0) {
                    pixel[2] += z_inc;
                    err_2 -= dx2;
                }
                err_1 += dy2;
                err_2 += dz2;
                pixel[0] += x_inc;
            }
        } else if ((m >= l) && (m >= n)) {
            err_1 = dx2 - m;
            err_2 = dz2 - m;
            for (i = 0; i < m; i++) {
                DrawOneBlock(player, drawBlock, pixel[0], pixel[1], pixel[2], ref blocks, ref cannotUndo);
                if (err_1 > 0) {
                    pixel[0] += x_inc;
                    err_1 -= dy2;
                }
                if (err_2 > 0) {
                    pixel[2] += z_inc;
                    err_2 -= dy2;
                }
                err_1 += dx2;
                err_2 += dz2;
                pixel[1] += y_inc;
            }
        } else {
            err_1 = dy2 - n;
            err_2 = dx2 - n;
            for (i = 0; i < n; i++) {
                DrawOneBlock(player, drawBlock, pixel[0], pixel[1], pixel[2], ref blocks, ref cannotUndo);
                if (err_1 > 0) {
                    pixel[1] += y_inc;
                    err_1 -= dz2;
                }
                if (err_2 > 0) {
                    pixel[0] += x_inc;
                    err_2 -= dz2;
                }
                err_1 += dy2;
                err_2 += dx2;
                pixel[2] += z_inc;
            }
        }

        // END LINE CODE
    }

我不明白代码,但根据Jonas给我的方向,我能够实现这个并且没有缺陷进行测试。