Orta Nokta Deplasman Algoritması


14

MDPMDP

Bu soru büyük ölçüde çaresizlikten geldi sorunu anlamaya çalışmak için birkaç saat geçirdikten sonra, çıktı.

Gözlerinizi yukarıdaki resme yönlendirirseniz, orta nokta yer değiştirme algoritması algoritmamın (bir şekilde) başarıyla çalıştığını görmelisiniz; bir şekilde tutarlı bir gürültü paterni üretmede.

Ancak, görüntüde siyah noktalı bir ızgara bırakıyor ve neden olduğu hakkında hiçbir fikrim yok. Bunun matematikte bir sorun olduğunu öngörebilirim, ama göremiyorum; bu da herhangi bir çevrimiçi kaynakta olası bir sorun olarak gösterilmiyordu; bu yüzden bu hatayı avlamak için herhangi bir yardım takdir edilecektir.

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 ve dışında başka ipuçlarınız veya kaynaklarınız varsa veFraktal tabanlı arazi üretimi için http://www.lighthouse3d.com/opengl/terrain/index.php?mpd2 , onları yorum olarak da takdir ediyorum.

Düzenle:

MDP

Bu, Fabians'ın önerisine (ty) göre yeni görüntüdür, ancak yine de hemen görebilmeniz gereken bazı tuhaf tuhaflıklar vardır (her yerde küçük 'çukurlar').

Bu garip davranışa ne sebep olabilir? Güncelleştirilmiş kaynak kodu: http://www.pastie.org/1924223

Düzenle:

İlgililer için sınır kontrol hatasını bulmada Fabian'a çok teşekkürler, 512x512 png olarak mevcut çözüm. Ve mevcut kaynak kodu (Fabian tarafından değiştirildi) . MDP

Düzenleme (yıllar sonra): Python sürümü https://gist.github.com/dcousens/5573724#file-mdp-py


Resimlerde, noktaların her biri aynı yükseklikte gibi görünüyor. Köşeler de aynı yükseklikte mi?
deft_code

1
Değeri ne olursa olsun, resimleriniz çok güzel görünüyor. :)
ChrisE

scrand (): Anladığımdan tam olarak emin değilim - bu işaretli bir karakteri aralıkta (-r / 2, r / 2] döndürmesi gerekiyor mu? Bitişik alanlar aniden siyah ateş ediyor ve sonra tekrar beyaza tırmanıyor gibi görünüyor. daha yüksek hassasiyet (diyelim, tamsayı) ve daha sonra değerleri [0,256] veya [-128,127] aralığına kenetleme?
ChrisE

Sorun aşağıda çözüldü, çünkü gerçek değeri değil, rastgele değer aralığına karşı kontrol ediyordum. Scrand () ideal olarak dönen geçici bir 'gürültü' işleviydi [-128, 127]
yavaşladı

Ah guzel! Şimdi çalıştığını duyduğuma sevindim.
ChrisE

Yanıtlar:


12

Algoritma yinelemeli olarak bir değer ekler, ancak değer pozitif veya negatif olabilir (normalde + -1 / (2 ^ oktav))

Sıfırdan başlar ve yalnızca pozitif değerler eklerseniz, yalnızca yukarı çıkabilirsiniz ve bu yüzden köşelerin aşağı çekildiğini görürsünüz.

dört köşe için sıfır yerine 127'den başlamayı deneyin ve ayrıca imzalı char'ı deneyin (ardından üst ve alt sınırlarınızı kontrol edin)

DÜZENLE

yani, her oktavda yarı etkiyi elde etmek için anada (64 >> i) iki şeyin daha değişmesi gerekir ve ayrıca çıkış işleviniz (son [] [] imgdta [] ile eşleşir, koymalısın

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

if if bloğundan ziyade.

başka bir şey, neden olduğundan emin değilim, ancak kontrolü tamamen kaldırırsanız (bu satır 38 ve 65) tamamen kaldırırsanız, bazı yeni koyu lekeler de fark edersiniz, bu yüzden daha büyük bir türe yükseltmeniz gerekebilir sınırlar yapmadan önce "64 / i" ile olsun daha gürültülü resim istiyorsanız kontrol edin.

BAŞKA BİR DÜZENLEME

sadece ne olduğunu öğrendim, sınır kontrolünde 'rv' ile değil 'r' ile karşılaştırıyorsunuz. Sabit kod şöyledir : http://pastie.org/1927076


Bu kesinlikle bu konuda gitmek için daha iyi bir yol oldu, ama henüz hiçbir puro, benim görüntü hala bazı 'tuhaflıklar' gibi görünüyor, orijinal yazı güncelledim.
yavaşlama

emin değilim ama satır 93 yanlış görünüyor, 64 / i 64 >> i (her oktavın etkisinin yarısı kadar) olabilir
Richard Fabian

Ahhh !! Çok teşekkür ederim, inanamıyorum, o ikinci sorun için aptalca bir şey olacağını biliyordum. Derme çatma TGA kodunu sevdim, özür dilerim, size derdini kurtarmalı ve üstbilgiyi koymalıydım.
yavaşlama

3

Dışarı sıçrayan iki şey:

  1. Bunu sabit noktada yapmak için zorlayıcı bir nedeniniz var mı? Kendi başına yanlış bir şey yok ve bunu kullanmak için birçok neden var (BÜYÜK bir haritaya gitmeyi planlıyorsanız en önemlisi bellek gereksinimleri), ancak kesinlikle algoritmanın kayan noktalı bir sürümü ile başlayacağım ve çalıştıktan sonra sabit noktaya dönüştürmek; başka bir şey yoksa, makul bir hata kaynağını ortadan kaldırmalıdır (özellikle, kelepçenizin sorunlara neden olabileceğinden şüpheleniyorum ve ne zaman / substract rv ekleneceği koşulları).
  2. Gördüğüm koddan söylemek zor olsa da, randomize yükseklik deplasmanınız seviye ile ölçekleniyor gibi görünmüyor ve (1) 'deki sorunla birleştirildiğinde bazı sorunlara neden olabilir - her seviyede aynı miktarda yer değiştirme.

Oh, ve algoritmik olmayan bir şey: mdp () işlevinizde ayırma yapmamanızı şiddetle tavsiye ederim; önceden ayrılmış iki farklı diziye geçin ve birinden diğerine giderek 'yerinde' yinelemesini yapın. Başka bir şey yoksa, her seferinde yeni bir dizi ayırmak yerine katmanları yaptığınızda ileri geri ping-pong yapmanıza izin verir.


Bazı iyi noktalar, açıkçası sadece algoritmayı doğru yapmaya çalışıyorum, uygulama ideal olmaktan uzak, bu noktada belleği bile temizlemiyorum: P.
yavaşlama

Bu noktada, geçişler üzerindeki ölçeklendirme 64 / i'dir, açıkçası bunu daha sonra değiştireceğim, ancak şu anda deneyimlenen çukur etkisini gerçekten açıklamıyor. : S
yavaşladı

0

Yukarıdakilere ek olarak, şu anda ayırdığınız belleği silmiyorsunuz. Bunu düzeltmek için 104. satırı şununla değiştirin:

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

için

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

ve tga dosyasına yazdıktan sonra bunu ekleyin:

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

Belleği nasıl temizleyeceğimin çok farkındayım, ama bunun sadece bir algoritma prototipi olduğunu ve vektörleri kullanmak için yeniden yazılacağını görünce, doğru olduğundan emin olmak istedim.
yavaşlama
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.