2010-12-13 71 views
0

J'ai créé (avec aide) une fonction qui trace et dessine une ligne de blocs dans un espace 3D. Généralement, ceci est effectué dans un cube quadrillé 64x64x64.Correction du dessin au trait 3D en C#

C'est le code que j'ai:

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

Il doit faire la queue le dessin de bloc et retourne le nombre de blocs qu'elle a tirées. Le problème est qu'il ne dessine pas une ligne non brisée. Dans certains cas, il laisse des espaces entre les blocs quand au moins tous les blocs devraient être connectés par leurs sommets.

La seule partie du code avec laquelle j'ai lutté est que je calculais la plus grande différence d'axe et que je produisais une constante de pente. J'ai rencontré un problème en essayant de faire une ligne diagonale parfaite. Toutes les valeurs étaient égales donc je suis juste par défaut à l'axe z - c'est là où je crois que le problème existe.

Répondre

8

Peut-être que le Bresenham line algorithm modifié pour (espérons-le) travailler en 3D pourrait être une solution pour vous?

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

Permettra de tester ce code dans quelques heures. – SystemX17

+0

Quelles étaient les valeurs de x0, y0, z0, x1, y1 et z1 qui donnaient la sortie incorrecte? –

+0

désolé, s'il vous plaît noter dans mon code z est répertorié comme la hauteur si j'ai essayé avec juste une surface plane: x0 = 1 y0 = 1 Z0 = 1 x1 = 3 y1 = 3 z1 = 1 Cette tentative échoua à dessiner des résultats. – 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 
    } 

Je ne comprends pas le code, mais d'après la direction Jonas m'a mis dans j'ai pu mettre en œuvre ce test sans faille et.

+0

J'ai haven ' Je l'ai analysé en détail, mais cela ressemble sûrement à une implémentation gonflée de l'algorithme de Bresenham ... –

+0

Je ne suis pas sûr de l'endroit où le 'gras' peut être coupé, donc je pense qu'il devra faire. Mes remerciements pour votre dévouement à répondre à cela pour moi. Sans votre aide j'aurais été fini pour! – SystemX17