다이아몬드 사각형 지형 생성 문제


11

이 기사에 따라 다이아몬드 사각형 알고리즘을 구현했습니다 : http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2

문제는지도 전체에이 가파른 절벽이 있다는 것입니다. 지형이 재귀 적으로 세분화되면 가장자리에서 발생합니다.

여기에 이미지 설명을 입력하십시오

소스는 다음과 같습니다.

void DiamondSquare(unsigned x1,unsigned y1,unsigned x2,unsigned y2,float range)
    {      
    int c1 = (int)x2 - (int)x1;
    int c2 = (int)y2 - (int)y1;
    unsigned hx = (x2 - x1)/2;
    unsigned hy = (y2 - y1)/2;
    if((c1 <= 1) || (c2 <= 1))
            return;

// Diamond stage
float a = m_heightmap[x1][y1];
float b = m_heightmap[x2][y1];
float c = m_heightmap[x1][y2];
float d = m_heightmap[x2][y2];
float e = (a+b+c+d) / 4 + GetRnd() * range;

m_heightmap[x1 + hx][y1 + hy] = e;

// Square stage
float f = (a + c + e + e) / 4 + GetRnd() * range;
m_heightmap[x1][y1+hy] = f;
float g = (a + b + e + e) / 4 + GetRnd() * range;
m_heightmap[x1+hx][y1] = g;
float h = (b + d + e + e) / 4 + GetRnd() * range;
m_heightmap[x2][y1+hy] = h;
float i = (c + d + e + e) / 4 + GetRnd() * range;
m_heightmap[x1+hx][y2] = i;

DiamondSquare(x1, y1, x1+hx, y1+hy, range / 2.0);   // Upper left
DiamondSquare(x1+hx, y1, x2, y1+hy, range / 2.0);   // Upper right
DiamondSquare(x1, y1+hy, x1+hx, y2, range / 2.0);   // Lower left
DiamondSquare(x1+hx, y1+hy, x2, y2, range / 2.0);       // Lower right

}

매개 변수 : (x1, y1), (x2, y2)-하이트 맵에서 영역을 정의하는 좌표 (기본값 (0,0) (128,128)). 범위-기본적으로 최대 신장. (기본 32)

도움을 주시면 감사하겠습니다.


코드를 자세히 보지 않으면 끝에있는 4 개의 재귀 호출에서 잘못된 호출에 잘못된 모서리가있는 것 같습니다. 지도는 다음 정사각형을 계산하기 전에 각 정사각형이 회전하거나 뒤집힌 것처럼 보이므로 이상한 절벽에서지도를 세분화합니다. 오른쪽 위 사각형의 아래쪽 가장자리는 왼쪽 위 사각형의 오른쪽 가장자리와 일치하는 것처럼 보입니다.
DampeS8N

무슨 말인지 잘 모르겠습니다. 좌표계의 중심은 왼쪽 상단에 있으며 x 축은 오른쪽을 가리키고 y는 아래쪽을 가리 킵니다. 따라서 첫 번째 반복에서 (x1 = 0, y1 = 0), (x2 = 128, y2 = 128) 및 (x1 + hx = 64, y1 + hy = 64)는 사각형의 중심입니다. 따라서 제곱은 ((0,0) (64,64)), ((64,0) (128,64)), ((0,64) (64,128)) 및 ((64, 64) (128,128)). 나에게 잘 보인다 ...
kafka

답변:


12

각 세분화 수준에서 "평방"단계는 "다이아몬드 단계"의 결과에 의존합니다. 그러나 그것은 또한 당신이 설명하지 않은 인접 셀에서 생성 된 다이아몬드 단계의 요인입니다. 현재와 ​​같이 깊이 우선이 아니라 너비 우선을 반복하기 위해 DiamondSquare 함수를 다시 작성했습니다.

첫 번째 문제는 사각형 모서리를 두 번 다시 계산하기 때문에 인접한 중심점의 기여를 무시한다는 것입니다. 예를 들어 참조하는 기사에서

P = (J + G + K + E)/4 + RAND(d)

그러나 코드는 효과적으로

P = (J + G + J + E)/4 + RAND(d)

즉 , 인접한 중심점이 아닌 현재 중심점을 두 번 고려합니다 . 그렇기 때문에 이전 중심점을 계산할 수 있도록 너비를 넓혀야합니다.

내 코드와 출력은 다음과 같습니다.

void DiamondSquare(unsigned x1, unsigned y1, unsigned x2, unsigned y2, float range, unsigned level) {
    if (level < 1) return;

    // diamonds
    for (unsigned i = x1 + level; i < x2; i += level)
        for (unsigned j = y1 + level; j < y2; j += level) {
            float a = m_heightmap[i - level][j - level];
            float b = m_heightmap[i][j - level];
            float c = m_heightmap[i - level][j];
            float d = m_heightmap[i][j];
            float e = m_heightmap[i - level / 2][j - level / 2] = (a + b + c + d) / 4 + GetRnd() * range;
        }

    // squares
    for (unsigned i = x1 + 2 * level; i < x2; i += level)
        for (unsigned j = y1 + 2 * level; j < y2; j += level) {
            float a = m_heightmap[i - level][j - level];
            float b = m_heightmap[i][j - level];
            float c = m_heightmap[i - level][j];
            float d = m_heightmap[i][j];
            float e = m_heightmap[i - level / 2][j - level / 2];

            float f = m_heightmap[i - level][j - level / 2] = (a + c + e + m_heightmap[i - 3 * level / 2][j - level / 2]) / 4 + GetRnd() * range;
            float g = m_heightmap[i - level / 2][j - level] = (a + b + e + m_heightmap[i - level / 2][j - 3 * level / 2]) / 4 + GetRnd() * range;
        }

    DiamondSquare(x1, y1, x2, y2, range / 2, level / 2);
}

http://i.imgur.com/laBhN.png


예, 또한 폭 우선 접근 방식을 따라 생각하고있었습니다. 이 프랙탈은 항상 문제를 일으 킵니다. Perlin 노이즈 및 L 시스템과 동일했습니다. 당신은 굉장합니다.
kafka

3

한 가지 가능성은 링크 된 페이지의 알고리즘이하지 않는 구현으로 바로 가기를 취하는 것입니다.

정사각형 스테이지의 경우 점의 높이를 계산합니다.

float f = (a + c + e + e) / 4 + GetRnd() * range;
m_heightmap[x1][y1+hy] = f;

맵을 래핑 할 때 페이지 알고리즘에서 사용하도록 표시합니다. 이렇게하면 "다음 정사각형"의 높이 값을 사용하여이 값을 계산할 수 있습니다. 가장 간단한 첫 번째 경우, 중심점 (높이 'e')이 왼쪽과 오른쪽에 모두 사용되어 f를 계산합니다.

그러나 참조하는 알고리즘에서는 다른 사각형 / 다이아몬드의 실제 값을 사용하여이 사각형 점의 높이 값을 계산하는 데 도움이됩니다. 알고리즘에서 두 번째 레벨 포인트는 다음 공식으로 계산됩니다.

N = (K + A + J + F)/4 + RAND(d)

거기에 가치의 중복이 없다는 것을 알 수 있습니까?

나는 당신이 주어진 비 랩핑 버전의 수식을 사용하려고 시도 할 수도 있다고 생각합니다.

F = (A + C + E)/3 + ...
    instead of
F = (A + C + E + E)/4 + ...

고마워, 그것은 유용한 관찰이었다. 방정식을 볼 때 코딩으로 직접 이동하지 않는 병변을 배웠다고 생각합니다.
kafka

천만에요 나도 많은 시간을 할애 해 ... "봐, 내가 코딩 할 수있는 것.
fnord
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.