2010-12-13 11 views
0

3D空間内にブロック行をプロットして描画する関数を作成しました。一般に、これは、64×64×64の格子状キューブで実行されます。C#での3D線画の修正

これは私が持っているコードです:

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軸をデフォルトにしました。これは問題が存在すると考えているところです。

答えて

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; 
     } 
    } 
} 
+0

数時間でこのコードをテストします。 – SystemX17

+0

誤った出力を出したx0、y0、z0、x1、y1、z1の値は何ですか? –

+0

申し訳ありませんが、私のコードzは、私はちょうど平らな面で試してみましたので、高さとしてリストされているに注意してください。 X0 = 1 Y0 = 1 Z0 = 1 ×1 = 3 Y1 = 3 Z1 = 1 これはに失敗しました結果を引き出す – SystemX17

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 
    } 

私は、コードを理解し、私は欠陥なしでこれとテストを実施することができたにジョナスが私を置く方向に基づいていません。

+0

I haven 'それを詳細に分析したが、確かにBresenhamのラインアルゴリズムの膨大な実装のように見える... –

+0

私はそれが行う必要があると思うので、私は '脂肪'がトリミングすることができるのか分からない。私のためにこれに答えるためにあなたの献身に感謝します。あなたの助けがなければ私はやっただろう! – SystemX17

関連する問題