2014-02-20 10 views
3

최근에 C#에서 Diamond-Square 절차 생성 알고리즘을 구현했습니다. 그러나, 생성 된 노이즈는 함께 작동하는 "사각형"사이에 매우 뚜렷한 경계가 있습니다. 의사 코드는 알고리즘은 처음에 왼쪽 상단 전체 이미지의 오른쪽 아래 모서리로 시작이다이아몬드 스퀘어 알고리즘은 "부드러운"노이즈를 생성하지 않습니다.

gen() 
{ 
    This takes the two outer corners (upper left and lower right) as parameters (i.e. (0,0) and (4,4)) 

    Change center point of square using average of outer four corners and a random weight change.  

    Change four "diamond point" midpoints of the four sides of the square using the same idea. 

     gen(topRightCorner, centerPoint); 
     gen(topMidpoint,rightMidpoint); 
     gen(leftMidpoint,bottomMidpoint); 
     gen(centerPoint, bottomRightCorner); 
    } 

같은 것을보고, (깊이 우선)를 통해 그것의 방법을 작동합니다.

this article을 사용하여 알고리즘을 설계했습니다. 그들이주는 예는 다음과 같습니다

public class _3DMapGenerator 
{ 
    public _3DMapGenerator(int powerOf2) 
    { 
     sideLength = (int)Math.Pow(2, powerOf2) + 1; 

     for (int x = 0; x < sideLength; x++) 
     { 
      for (int y = 0; y < sideLength; y++) 
      { 
       data.Add(new Point(x, y), 0.5M); 
      } 
     } 

    } 

    int sideLength; 
    Random r = new Random(); 
    public Dictionary<Point, decimal> data = new Dictionary<Point, decimal>(); 

    public void genMap(Point p1 = null,Point p2 = null) 
    { 
     if(p1 == null || p2 == null) 
     { 
      p1 = new Point(0, 0); 
      p2 = new Point(sideLength - 1, sideLength - 1); 
     } 

     Point centerPoint = new Point((p1.x + p2.x)/2, (p1.y + p2.y)/2); 

     if (p2.x - p1.x < 2 || p2.y - p1.y < 2) 
     { 
      return; 
     } 

     decimal swing = ((decimal)(1+p2.x - p1.x))/sideLength; 

     Point p1_2 = new Point(p2.x, p1.y); 
     Point p2_1 = new Point(p1.x, p2.y); 

     Console.WriteLine("Points: " + p1 + " " + p1_2 + " " + p2_1 + " " + p2); 
     //Console.ReadLine(); 
     data[centerPoint] = ((decimal)(data[p1] + data[p2] + data[p1_2] + data[p2_1]))/4 + ((decimal)r.NextDouble() * swing) - (swing/2); 


     Point mP1 = Point.getMidpoint(p1, p1_2); 
     Point mP2 = Point.getMidpoint(p1, p2_1); 
     Point mP3 = Point.getMidpoint(p1_2, p2); 
     Point mP4 = Point.getMidpoint(p2_1, p2); 

     swing /= 2; 
     data[mP1] = ((decimal)(data[p1] + data[p1_2]))/2 + ((decimal)r.NextDouble() * swing) - (swing/2); 
     data[mP2] = ((decimal)(data[p1] + data[p2_1]))/2 + ((decimal)r.NextDouble() * swing) - (swing/2); 
     data[mP3] = ((decimal)(data[p1_2] + data[p2]))/2 + ((decimal)r.NextDouble() * swing) - (swing/2); 
     data[mP4] = ((decimal)(data[p2_1] + data[p2]))/2 + ((decimal)r.NextDouble() * swing) - (swing/2); 

     genMap(p1, centerPoint); 
     genMap(mP1, mP3); 
     genMap(mP2, mP4); 
     genMap(centerPoint, p2); 
    } 

    public void printToImage(string fileName) 
    { 
     Bitmap bmp = DrawFilledRectangle(sideLength,sideLength); 
     foreach(var o in data) 
     { 
      bmp.SetPixel(o.Key.x, o.Key.y, Color.FromArgb((int)(255 * o.Value), (int)(255 * o.Value), (int)(255 * o.Value))); 
     } 
     bmp.Save(fileName); 
    } 

    private static Bitmap DrawFilledRectangle(int x, int y) 
    { 
     Bitmap bmp = new Bitmap(x, y); 
     using (Graphics graph = Graphics.FromImage(bmp)) 
     { 
      Rectangle ImageSize = new Rectangle(0, 0, x, y); 
      graph.FillRectangle(Brushes.White, ImageSize); 
     } 
     return bmp; 
    } 
} 

:

여기

enter image description here

내 전체 코드입니다 :

여기

enter image description here

같이 내 이미지 중 하나가 모습입니다 사각형 사이에 공유되는 중간 점의 값을 평균 한 후에 :

enter image description here

업데이트 반복적 인 코드 : 나는 지금 IDE 권한이 없습니다로

public Dictionary<Point, List<decimal>> data = new Dictionary<Point, List<decimal>>(); 

    static Random r = new Random(); 

    public int sideLength; 

    public void genMap() 
    { 
     for (int sideLen = sideLength; sideLen >= 3; sideLen = sideLen/2 + 1) 
     { 
      for (int yOff = 0; yOff + sideLen < sideLength + 1; yOff += sideLen - 1) 
      { 
       for (int xOff = 0; xOff + sideLen < sideLength + 1; xOff += sideLen - 1) 
       { 

        Point upL = new Point(xOff, yOff); 
        Point upR = new Point(xOff + sideLen - 1, yOff); 
        Point lowL = new Point(xOff, yOff + sideLen - 1); 
        Point lowR = new Point(xOff + sideLen - 1, yOff + sideLen - 1); 

        Point centerPoint = new Point((upL.x + lowR.x)/2, (upL.y + lowR.y)/2); 

        Point mPTop = Point.getMidpoint(upL, upR); 
        Point mPLeft = Point.getMidpoint(upL, lowL); 
        Point mPRight = Point.getMidpoint(upR, lowR); 
        Point mPBottom = Point.getMidpoint(lowL, lowR); 

        decimal swing = ((decimal)(1 + sideLen))/(2 * sideLength); 


        set(mPTop, ((decimal)(get(upL) + get(upR)))/2 + ((decimal)r.NextDouble() * swing) - (swing/2)); 
        set(mPLeft, ((decimal)(get(upL) + get(lowL)))/2 + ((decimal)r.NextDouble() * swing) - (swing/2)); 
        set(mPRight, ((decimal)(get(upR) + get(lowR)))/2 + ((decimal)r.NextDouble() * swing) - (swing/2)); 
        set(mPBottom, ((decimal)(get(lowL) + get(lowR)))/2 + ((decimal)r.NextDouble() * swing) - (swing/2)); 


        swing *= 2; 
        set(centerPoint, ((decimal)(get(upL) + get(upR) + get(lowL) + get(lowR)))/4 + ((decimal)r.NextDouble() * swing) - (swing/2)); 
       } 
      } 
     } 



    } 

    void set(int x, int y, decimal d) 
    { 
     set(new Point(x, y), d); 
    } 

    void set(Point p, decimal d) 
    { 
     data[p].Add(d); 
    } 

    Decimal get(int x, int y) 
    { 
     return get(new Point(x, y)); 
    } 
    Decimal get(Point p) 
    { 
     if (data[p].Count == 0) 
     { 
      Console.WriteLine("No elements."); 
      return 0; 
     } 
     return data[p].Average(); 
    } 
+0

크기가 5 인 정사각형의 0,0 및 5,5 좌표는 어떻게됩니까? –

+0

죄송합니다. 의미는 (0,0)과 (4,4)입니다. – Wilson

+0

주어진 답이 맞다고 생각하지 않습니다. 어느 포인트를 두 번 설정해서는 안됩니다. ** 네 개의 이웃 점이 모두 계산 될 때까지 점을 설정하지 마십시오 **. –

답변

0

여기에 내 생각이다.

data[mP1] = ((decimal)(data[p1] + data[p1_2]))/2 + ((decimal)r.NextDouble() * swing) - (swing/2); 
    data[mP2] = ((decimal)(data[p1] + data[p2_1]))/2 + ((decimal)r.NextDouble() * swing) - (swing/2); 
    data[mP3] = ((decimal)(data[p1_2] + data[p2]))/2 + ((decimal)r.NextDouble() * swing) - (swing/2); 
    data[mP4] = ((decimal)(data[p2_1] + data[p2]))/2 + ((decimal)r.NextDouble() * swing) - (swing/2); 

그 중간 점은 여러 가지 사각형 사이에서 공유되고, 메소드를 호출 할 수있는 마지막 재설정해서는 안, 대신 평균 :

는 현재 새로운 사각형 사이의 지점에 값을 다시 작성합니다.

+0

그래서'data'의 값을'List '으로 변경했습니다. 값을 설정할 때마다 새 값이 목록에 추가됩니다. 마지막에는 목록의 평균을 사용하여 이미지를 출력합니다. 원래 결과물에 새로운 이미지가 추가 된 것을 보여주는 새 이미지를 추가했습니다. 도움이되었지만 국경은 여전히 ​​분명합니다. – Wilson

0

나는 오래 전에 비슷한 문제가 없었고 실제로 해결책은 매우 간단했습니다. 실수는 주변의 전체 "다이아몬드"를 평균화하는 대신 중간 점을 둘러싸는 코너 만 평균화하는 것입니다. 그러므로 사각형의 인공물을 남겨 두므로 단순한 해법은 이미 평균을 구한 두 구석의 평균과 왼쪽과 오른쪽의 사각형의 중심을 구하는 것입니다. 평균 또는 난수를 추가하거나 추가 할 수 있습니다. 또한 genMap을 네 번 호출하여 노드의 맨 아래에 도달 한 다음 다음 노드로 계속 진행할 수 있습니다. 현재는 문제가 아니지만 일단 전체를 구현하면 다이아몬드 단계는 당신이 한 번에 한 번씩 각 수준을 계산하지 않는 왼쪽 또는 오른쪽 감각에 결코 이웃이 아님을 알게 될 것입니다. 이 문제를 해결하려면 함수를 한 번 호출하고 for 루프에 특정 크기의 각 "섹터"를 지정하십시오.