Wdrażam raytracer, a ja jestem w trakcie wdrażania samplerów. Próbnik jest generatorem losowych punktów ponad kwadratem x = 0: 1, y = 0: 1. Każdy próbnik zawiera wiele zestawów "losowych" próbek, a każdy zestaw zawiera określoną liczbę próbek.Zabezpieczanie przetasowania i blokowania NRooków
Teraz jednym z samplerów jest NRooks. Dzieli on powierzchnię w blokach n x n
, wybiera bloki wzdłuż przekątnej, w każdym przekątnym bloku wyodrębnia losowy punkt, a na koniec tasuje najpierw między sobą x
, a następnie y
.
To wszystko jest ładne i czyste. Jednakże, gdy nadszedł czas na wyodrębnienie punktów, książka, którą obserwuję, proponuje te dodatkowe wymagania, aby zerwać korelacje między kolejnymi pikselami i próbkami. Pierwszym wymaganiem jest to, że za każdym razem, gdy zestaw jest wyczerpany, losowo wybierany jest nowy zestaw próbek. Kod wprowadzone do osiągnięcia tego celu jest następująca:
Point2D Sampler::sample_unit_square(void) {
if (count % num_samples == 0) jump = (rand_int() % num_sets) * num_samples;
return (samples[jump + count++ % num_samples]
}
gdzie samples
jest wektorem Point2D wielkości num_samples*num_sets
(jest linearyzowany). Za każdym razem, gdy jeden piksel jest zrobiony (liczba jest podzielna przez num_samples), nowy skok jest wyodrębniany i używany do wskazania liniowej tablicy dla początku nowego zestawu.
Ponieważ używam Python, moja strategia sprawia, że korzystanie z iteratorów:
def __iter__(self):
while True:
for sample_set in random.choice(self._samples_sets):
for sample in sample_set:
yield sample
to jest trywialne, i działa OK.
Drugą potrzebą jest przetasowanie indeksów i tu jest moje pytanie. Książka zmienia kod następująco
Point2D Sampler::sample_unit_square(void) {
if (count % num_samples == 0) jump = (rand_int() % num_sets) * num_samples;
return (samples[jump + shuffled_indices[ jump + count++ % num_samples]]
}
gdzie tasowane indeksów jest tablicą obliczana następująco
void Sampler::setup_shuffled_indices(void) {
shuffled_indices.reserve(num_samples*num_sets);
vector<int> indices;
for (int j=0; j<num_samples; j++) indices.push_back(j);
for (int p=0; p<num_sets; p++) {
random_shuffle(indices.begin(), indices.end());
for (int j=0; j<num_samples; j++) {
shuffled_indices.push_back(indices[j]);
}
}
}
co jest bardzo C++ sposobu podejmowania listę numerów od 1 do n, a ich losowego. Chciałem zaimplementować następujący kod w Pythonie
def __iter__(self):
while True:
sample_set = random.choice(self._samples_sets):
shuffled_set = sample_set[:]
random.shuffle(shuffled_set)
for sample in shuffled_set:
yield sample
mogę również realizować losową iterator że iteracje na planie, oszczędzając liście kopiowania, ale to nie o to chodzi. Moje pytanie wynika z następującej frazy w książce:
... Inną możliwością [usunięcia korelacji] jest użycie ostatecznego shuffle na próbkach każdego zestawu, ale to niszczy warunek n-rooks [. ..]. Najlepszym sposobem jest losowe przetasowanie indeksów używanych w
sample_unit_square
, dla każdego zestawu, ale zagwarantowanie, że wszystkie próbki są używane.
Czego nie rozumiem, to: dlaczego mówi się, że ostateczne przetasowanie na próbkach każdego zestawu łamie n-gawrony? chodzi o to, że używa pośredniego indeksowania do tablicy punktów. Ten indeks pośredni powstaje z przetasowania wszystkich indeksów od 1 do liczby zestawów, ale jest to odpowiednik przetasowania wszystkich próbek w każdym zestawie. Będąc odpowiednikiem IMHO, nie rozumiem, dlaczego pierwsze sformułowanie powinno złamać n-gawrony i dlaczego drugie nie.
Książka, dla przypomnienia, to "Ray śledzący od podstaw" autorstwa Kevina Suffern'a.
Wygląda na to, że autor jest zdezorientowany co do kombinatoryki. Na przykład, przy konstruowaniu układu n-gawronów, dlaczego mieszamy na * obu x i y? Tasowanie na x już dociera do wszystkich n! aranżacje wież; nie powinno też być potrzeby tasowania. –
Czy to możliwe, że autor oznacza przetasowanie całego zestawu, a nie tylko indeksów? tj. z powyższym przykładem 4x4, aby wymieszać wszystkie 16 skrzynek? To by zniszczyło n-gawrony ... – tugs
@tugs: Nie widzę powodu, dla którego powinno. Tasowanie lub użycie indeksu pośredniego, pozwala na wyjście jednego punktu przed drugim. Nie zmienia rozkładu punktów na planszy. –