중간 점 변위 알고리즘


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.