중간 점 변위 알고리즘


14

MDPMDP

이 문제는 문제를 파악하기 위해 몇 시간을 소비 한 후 주로 절망적 인 상황 에서 나왔습니다.

위 그림을 보시면 저의 중간 변위 알고리즘 알고리즘이 성공적으로 작동하는 것을 볼 수 있습니다. 다소 일관성있는 노이즈 패턴을 생성합니다.

그러나 이미지에 검은 점선 격자가 남고 있으며 이유를 모릅니다. 나는 이것이 수학의 문제라고 생각할 수는 있지만 그것을 볼 수는 없습니다. 이것은 온라인 자원에서 가능한 문제로 지적되지도 않았다. 따라서이 버그를 사냥하는 데 도움이 될 것입니다.

unsigned char** mdp(unsigned char** base, unsigned base_n, unsigned char r) {
    size_t n = (2 * base_n) - 1;

    unsigned char** map = new unsigned char*[n];
    for (unsigned i = 0; i < n; ++i) map[i] = new unsigned char[n];

    // Resize
    // 1 0 1
    // 0 0 0
    // 1 0 1
    for (size_t i = 0; i < n; i += 2) {
        for (size_t j = !(i % 2 == 0); j < n; j += 2) {
            map[i][j] = base[i / 2][j / 2];
        }
    }

    // Diamond algorithm
    // 0 0 0
    // 0 X 0
    // 0 0 0
    for (size_t i = 1; i < n; i += 2) {
        for (size_t j = 1; j < n; j += 2) {
            unsigned char& map_ij = map[i][j];

            unsigned char a = map[i - 1][j - 1];
            unsigned char b = map[i - 1][j + 1];
            unsigned char c = map[i + 1][j - 1];
            unsigned char d = map[i + 1][j + 1];
            map_ij = (a + b + c + d) / 4;

            unsigned char rv = std::rand() % r;
            if (map_ij + r < 255) map_ij += rv; // EDIT: <-- thanks! the bug! `map_ij + rv`, not `r`
            else map_ij = 255;
        }
    }

    // Square algorithm
    // 0 1 0
    // 1 0 1
    // 0 1 0
    for (size_t i = 0; i < n; ++i) {
        for (size_t j = (i % 2 == 0); j < n; j += 2) {
            unsigned char& map_ij = map[i][j];

            // get surrounding values
            unsigned char a = 0, b = a, c = a, d = a;
            if (i != 0) a = map[i - 1][j];
            if (j != 0) b = map[i][j - 1];
            if (j + 1 != n) c = map[i][j + 1];
            if (i + 1 != n) d = map[i + 1][j];

            // average calculation
            if (i == 0) map_ij = (b + c + d) / 3;
            else if (j == 0) map_ij = (a + c + d) / 3;
            else if (j + 1 == n) map_ij = (a + b + d) / 3;
            else if (i + 1 == n) map_ij = (a + b + c) / 3;
            else map_ij = (a + b + c + d) / 4;

            unsigned char rv = std::rand() % r;
            if (map_ij + r < 255) map_ij += rv;
            else map_ij = 255;
        }

    }

    return map;
}

당신이 아닌 다른 조언 자원이있는 경우 http://www.gameprogrammer.com/fractal.html을 하고프랙탈 기반 지형 생성에 대한 http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2 의견으로도 감사합니다.

편집하다:

MDP

이것은 Fabians 제안 (ty)에 따라 새로운 이미지이지만, 여전히 이상한 점이 있습니다. 이곳은 바로 볼 수 있어야합니다 (모든 곳에서 작은 '딤플').

이 이상한 행동을 일으키는 원인은 무엇입니까? 업데이트 된 소스 코드 : http://www.pastie.org/1924223

편집하다:

경계 검사 오류를 발견 한 Fabian 덕분에 관심이있는 사람들을 위해 512x512 png와 같은 현재 솔루션이 있습니다. 그리고 현재 소스 코드 (Fabian에 의해 수정 됨) . MDP

편집 (몇 년 후) : Python 버전 https://gist.github.com/dcousens/5573724#file-mdp-py


그림에서 각 점의 높이가 같은 것 같습니다. 모서리도 같은 높이입니까?
deft_code

1
가치가있는 이미지는 매우 예쁘게 보입니다. :)
ChrisE

scrand () : 나는 내가 이해한다는 것을 완전히 확신하지 못한다. 이것은 간격 (-r / 2, r / 2)에서 부호있는 문자를 반환해야합니까? 인접 지역이 갑자기 검은 색으로 촬영 된 다음 다시 흰색으로 올라가는 것처럼 보입니다. 더 높은 정밀도 (예 : 정수)를 설정 한 다음 값을 [0,256] 또는 [-128,127] 범위로 고정 하시겠습니까?
ChrisE

문제는 아래에서 해결되었습니다. 실제 값이 아닌 임의의 값 범위를 확인하는 경계 때문이었습니다. scrand ()는 임시 '잡음'기능은 이상적으로 복귀시켰다 -128, 127]
deceleratedcaviar

아 멋지다! 그것이 지금 작동하는 것을 기쁘게 생각합니다.
ChrisE

답변:


12

알고리즘은 재귀 적으로 값을 추가하지만 값은 양수 또는 음수 일 수 있습니다 (일반적으로 + -1 / (2 ^ octave))

0에서 시작하여 양수 값만 추가하면 올라갈 수 있으므로 정점이 아래로 내려 오는 것을 볼 수 있습니다.

네 모서리에 대해 0이 아닌 127에서 시작하고 부호있는 char을 시도하십시오 (그런 다음 위쪽과 아래쪽 경계를 확인하십시오)

편집하다

따라서 각 옥타브에서 반 효과를 얻기 위해 메인 (64 >> i)에서 두 가지가 더 필요합니다. 또한 출력 함수 (최종 [] [] tp the imgdta []를 매핑하는 함수) 넣어야한다

imgdta [(i * n) + j] = 128 + 최종 [i] [j];

if else 블록보다는

또 다른 이유는 확실하지 않지만 검사를 완전히 제거하면 바운드 검사가 실패합니다 (38 및 65 행). 새로운 어두운 얼룩도 발견되므로 더 큰 유형으로 승격해야 할 수도 있습니다 경계를 수행하기 전에 "64 / i"로 더 시끄러운 그림을 원하는지 확인하십시오.

다른 편집

경계 점검에서 'rv'가 아닌 'r'과 비교하고 있다는 것을 알았습니다. 고정 코드는 다음과 같습니다. http://pastie.org/1927076


이것은 분명히 그것에 대해 갈 수있는 더 좋은 방법 이었으나 아직 시가는 없습니다. 내 이미지에 여전히 '질투'가있는 것처럼 보입니다. 원래 게시물을 업데이트했습니다.
감속

확실하지는 않지만 93 행은 잘못 보입니다. 64 / i는 64 >> i (각 옥타브 효과의 절반으로)이어야합니다.
Richard Fabian

아아 !! 정말 감사합니다. 믿을 수 없습니다. 두 번째 문제에 대해 어리석은 일임을 알았습니다. 임시 TGA 코드가 마음에 들었습니다. 죄송합니다. 문제를 해결하고 헤더를 작성해야합니다.
감속

3

두 가지 중요한 점 :

  1. 고정 소수점 위치에서이 작업을 수행해야 할 강력한 이유가 있습니까? 그 자체로는 아무런 문제가 없으며 그것을 사용하는 데는 많은 이유가 있습니다 (거의 거대한 맵으로 갈 계획이라면 메모리 요구 사항이 가장 중요합니다). 그러나 나는 부동 소수점 버전의 알고리즘으로 시작합니다 작동시킨 후 고정 소수점으로 변환하십시오. 그렇지 않으면 그럴듯한 오류 원인 중 하나를 제거해야합니다 (특히 클램핑으로 인해 문제가 발생할 수 있다고 생각하고 rv를 추가 / 빼기 조건).
  2. 내가 본 코드에서 말하기는 어렵지만 무작위 높이 변위가 레벨에 비례하는 것처럼 보이지 않으며 (1)의 문제와 결합하여 일부 문제가 발생할 수 있습니다. 각 레벨에서 같은 양으로 변위.

아, 그리고 하나의 비 알고리즘 : mdp () 함수에서 할당을하지 않는 것이 좋습니다; 이미 할당 된 두 개의 다른 배열을 전달하고 반복적으로 'in-place'를 수행합니다. 다른 것이 없으면 매번 새 배열을 할당하지 않고 레이어를 수행 할 때 핑퐁을 앞뒤로 할 수 있습니다.


몇 가지 좋은 점은 분명히 알고리즘을 올바르게 얻으려고 노력하는 것입니다. 구현은 이상적이지 않습니다.이 시점에서 메모리를 정리조차하지 않습니다 .P.
감속 캐비어

이 시점에서 패스 오버 스케일링은 64 / i입니다. 나중에 변경 할 것이지만 현재 경험하는 딤플 효과를 실제로 설명하지는 않습니다. : S
감속 캐비어

0

위의 내용 외에도 현재 할당중인 메모리를 삭제하지 않습니다. 이를 해결하려면 104 행을 다음에서 변경하십시오.

for (unsigned i = 1; i < 6; ++i) final = mdp(final, n, 64 / i);

for (unsigned i = 1; i < 6; ++i) {
  signed char** new_final = mdp(final, n, 64 / i);
  for (unsigned i = 0; i < n; ++i)
    delete[] final[i];
  delete[] final;
  final = new_final;
}

tga 파일에 기록 한 후 이것을 추가하십시오 :

for (unsigned i = 0; i < n; ++i)
  delete[] final[i];
delete[] final;

메모리를 정리하는 방법에 대해 잘 알고 있지만 이것이 알고리즘 프로토 타입 일뿐이며 벡터를 사용하도록 다시 작성되는 것으로 보았습니다. 올바른지 확인하고 싶었습니다.
감속
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.