Z-buffer için derinlik enterpolasyonu, tarama çizgisi ile


10

Kendi yazılım 3d rasterizer yazmak zorundayım ve şimdiye kadar üçgenlerden oluşan 3d modelimi 2d uzaya yansıtabiliyorum:

Her üçgenin 2d uzayı temsil etmesi için puanlarımı döndürür, tercüme eder ve yansıtırım. Sonra 3 üçgen noktasını alıyorum ve üçgenlerin kenarları (sol ve sağ) boyunca tüm noktaları [x] [y] bulmak için tarama çizgisi algoritmasını (doğrusal enterpolasyon kullanarak) uyguluyorum, böylece üçgeni yatay olarak tarayabiliyorum, satır satır ve piksel ile doldurun.

Bu çalışıyor. Dışında z tamponlama uygulamak zorundayım. Bu, üçgenin 3 köşesinin döndürülmüş ve çevrilmiş z koordinatlarını bilerek, tarama çizgisi algoritmamla bulduğum diğer tüm noktalar için z koordinatını enterpolasyonlamak zorunda olduğum anlamına gelir.

Kavram yeterince açık görünüyor, önce bu hesaplamalarla Za ve Zb'yi buluyorum:

var Z_Slope = (bottom_point_z - top_point_z) / (bottom_point_y - top_point_y);
var Za = top_point_z + ((current_point_y - top_point_y) * Z_Slope);

Sonra her Zp için aynı enterpolasyonu yatay olarak yaparım:

var Z_Slope = (right_z - left_z) / (right_x - left_x);
var Zp = left_z + ((current_point_x - left_x) * Z_Slope);

resim açıklamasını buraya girin

Ve eğer geçerli z izleyiciye bu dizindeki önceki z'den daha yakınsa, rengi renk arabelleğine yazın VE yeni z'yi z arabelleğine yazın. (koordinat sistemim x: sol -> sağ; y: üst -> alt; z: yüzünüz -> bilgisayar ekranı;)

Sorun şu ki, haywire gidiyor. Proje burada ve "Z-Buffered" radyo düğmesini seçerseniz, sonuçları göreceksiniz ... ( "Z-Buffered" modunda ressamın algoritmasını (sadece tel kafes çizmek için) kullandığımı unutmayın) hata ayıklama amacıyla )

PS: Burada , z = 1/zenterpolasyon yapmadan önce z'leri karşılıklarına (yani ) çevirmeniz gerektiğini okudum . Bunu denedim ve görünüşe göre bir değişiklik yok. Neyi kaçırıyorum? (Herkes tam olarak z'yi 1 / z'ye nereye çevirmeniz gerektiği ve nerede (eğer) geri çevirmeniz gerektiği konusunda netleştirebilir mi?)

[EDIT] Hangi maksimum ve minimum z değerlerini aldığımla ilgili bazı veriler:

    max z: 1;                  min z: -1;                 //<-- obvious, original z of the vertices of the triangles
    max z: 7.197753398761272;  min z: 3.791703256899924;   //<-- z of the points that were drawn to screen (you know, after rotation, translation), by the scanline with zbuffer, gotten with interpolation but not 1/z.
    max z: 0.2649908532179404; min z: 0.13849507306889008;//<-- same as above except I interpolated 1/z instead of z.
//yes, I am aware that changing z to 1/z means flipping the comparison in the zBuffer check. otherwise nothing gets drawn.

Özenli hata ayıklamaya başlamadan önce, birisi şimdiye kadar kavramımın doğru olduğunu onaylayabilir mi?

[EDIT2]

Z-tamponlamayı çözdüm. Anlaşıldığı gibi, çizim sırası hiç bozulmadı. Z koordinatları doğru hesaplanıyordu.

Sorun, kare hızımı artırmak için, ekrandaki gerçek pikseller yerine her 4 pikselde 4 piksel / 4 piksel kutu çiziyordum. Bu yüzden piksel başına 16 piksel çiziyordum, ancak bunlardan yalnızca biri için z arabelleğini kontrol ediyordum. Ben böyle bir boobum.

TL / DR: Soru hala duruyor: Z yerine Z'nin (1 / z'de olduğu gibi) karşılığını nasıl / neden / ne zaman kullanmalısınız? Çünkü şu anda her şey her iki şekilde de çalışıyor. (fark edilir bir fark yoktur).


Ynt: "Ve tabii ki, z geçerli izleyiciye bu dizindeki önceki değerden daha yakınsa, zBuffer'a eklerim." Bu, ne demek istediğinizi ifade ettiğinizi ancak ne demek istediğinizin olduğundan emin olmak istediğinizi açık değil ", geçerli z izleyiciye o dizinde önceki z'den daha yakınsa, renk arabelleğine renk yazın VE "z tamponunun amacı, o pikseldeki bir renk zaten kamera gözüne daha yakın yazılmışsa, renk yazmalarını engellemektir.
Alturis

Bu doğru. Üzgünüm, sorumu ifade ettiğimde gecikti. Ben gözden geçireceğim.
Spectraljump

Yanıtlar:


5

Hızlı cevap: Z (X ', Y') 'nin doğrusal bir fonksiyonu değildir, fakat 1 / Z'dir. Doğrusal olarak enterpolasyon yaptığınızdan, 1 / Z için doğru sonuçları alırsınız, ancak Z için değil.

Farketmezsiniz çünkü Z1 ve Z2 arasındaki karşılaştırma doğru olduğu sürece, her iki değer yanlış olsa bile zbuffer doğru olanı yapar. Doku eşlemesi eklediğinizde kesinlikle fark edeceksiniz (ve daha sonra sahip olacağınız soruyu cevaplamak için: 1 / Z, U / Z ve V / Z'yi enterpolat edin ve U ve V'yi şu değerlerden yeniden oluşturun: U = (U / Z) / (1 / Z), V = (V / Z) / (1 / Z). Daha sonra bana teşekkür edeceksin)

Bir örnek. Bir parça kağıt al. Yukarıdan aşağıya görünüm, bu yüzden Y koordinatını unutun. X yatay eksendir, Z dikey eksendir, kamera (0, 0) konumundadır, yansıtma düzlemi z = 1'dir.

A (-2, 2) ve B (2, 4) noktalarını düşünün. AB segmentinin orta noktası M (0, 3) 'tür. Çok uzak çok iyi.

A'yı A ': X' = X / Z = -1 olarak yansıtırsınız, böylece A '(-1, 1) olur. Benzer şekilde, B '(0.5, 1)' dir. Ancak M'nin izdüşümünün (0, 1) olduğuna dikkat edin, ki bu A'B'nin orta noktası DEĞİLDİR. Neden? Segmentin sağ yarısı kameradan sol yarısından daha uzak olduğu için daha küçük görünüyor.

Öyleyse M 'nin Z' sini doğrusal enterpolasyon kullanarak hesaplamaya çalışırsanız ne olur? dx = (0.5 - -1) = 1.5, dz = (4 - 2) = 2, bu nedenle X '= 0 olan M' için doğrusal olarak enterpolasyonlu Z, zA + (dz / dx) (x - xA) = 2'dir + (2 / 1,5) (0 - -1) = 2 + 1,333 = 3,3333 - 3 DEĞİL!

Neden? Çünkü X 'yönündeki her adım için, Z yönünde aynı miktarı hareket ettiremezsiniz (veya başka bir deyişle Z, X' in doğrusal bir fonksiyonu değildir). Neden? Çünkü ne kadar fazla sağa giderseniz, segment kameradan o kadar uzakta olur, bu nedenle bir piksel uzayda daha uzun bir mesafeyi temsil eder.

Son olarak, 1 / Z yerine enterpolasyon uygularsanız ne olur? İlk önce A ve B'de 1 / Z hesaplayın: sırasıyla 0.5 ve 0.25. Sonra enterpolate edersiniz: dx = (0.5 - -1) = 1.5, dz = (0.25 - 0.5) = -0.25, böylece X '= 0'da 1 / Z = 0.5 + (-0.25 / 1.5) * (0 - -1) = 0.3333. Ama bu 1 / Z, yani Z'nin değeri ... tam olarak, 3. Olması gerektiği gibi.

Evet, matematik harika.


1
Oh, ve "ne zaman" ile ilgili olarak: üçgeni rasterleştirmeye başlamadan önce 1 / Z değerlerini hesaplayın (örn. Dikey döngüden hemen önce), böylece tarama çizgisinin solunda ve sağında enterpolasyonlu 1 / Z elde edersiniz. Bunları doğrusal olarak enterpole edin (tekrar 1 / Z YAPMAYIN - enterpolasyonlu değerler zaten 1 / Z!) Ve zbuffer'ı kontrol etmeden hemen önce dönüşümü geri alın.
ggambett

1
Ve son olarak, neden. Bir düzlem (üçgenin gömülü olduğu yerde) Ax + By + Cz + D = 0'dır. Z (x, y) 'nin açıkça doğrusal fonksiyonudur. X '= x / z ve y' = y / z olacak şekilde yansıtıyorsunuz. Oradan, x = x'z ve y = y'z. Bunları orijinal denklemde değiştirirseniz, Ax'in + By'x + Cz + D = 0 elde edersiniz. Şimdi z = -D / (Ax '+ By' + C), burada z doğrusal bir işlev değildir (x ', y'). Ancak 1 / z bu nedenle (Ax '+ By' + C) / -D'dir (bu, (x ', y') 'nin doğrusal bir fonksiyonudur.
ggambett

1
Biliyorsunuz, birkaç makale ve kurs okudum ve hiçbiri cevabınız kadar net değildi. Posterity için, "U" ve "V" harflerinin 2B dokunun eksenlerini gösterdiğini, çünkü "X", "Y" ve "Z" modellerinin 3B nesnesinin eksenlerini belirtmek için kullanıldığını da not edeceğim. UV doku, 3B bir nesneyi oluşturan çokgenlerin bir görüntüdeki renkle boyanmasına izin verir. " - Wikipedia - UV Haritalama
Spectraljump

Bunu duyduğuma sevindim. Aslında, önceki bir bilgisayarda Bilgisayar Grafikleri
öğrettim

Çok teşekkürler - bunu her zaman merak ettim - ve daha iyi bir cevap bulabilir miyim bilmiyorum! +1
Kodlayıcı
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.