Çerçeve arabelleği olmadan bir grafik demosunu nasıl yapabilirim?
Bir mikro denetleyici programlıyorum - yaklaşık 100Mhz - 300Mhz CPU saat hızına ve 64K uygulama RAM'ine (aslında ROM) sahip küçük bir 8 bit bilgisayar, ancak yalnızca çok az miktarda RAM (6K) - bir grafik çerçevesi arabelleği için yeterince yakın değil.
Bu nedenle, bu makinede animasyonlu bir grafik demosu görüntülemek istiyorum. Bir tür animasyonlu grafikleri hesaplamak için yeterli hesaplama gücüne sahip görünüyor.
Animasyonlu grafiklerin görüntülenmesini sağlamak için, bir şekilde, her çağrıldığında, bir görüntü çerçevesinden tek bir piksel satırı döndüren ve ardından görüntülenen bir bilgisayar programına ihtiyacım olacak. Görüntü denetleyici programı, bütün bir çerçeve görüntülenene kadar satır ardına çağırarak bunu yapmaya devam eder, ardından bir sonraki kare için yeniden en üstten başlar.
Açık olmak gerekirse, ekranı kontrol eden programı sormuyorum. Demo programı hakkında soru soruyorum. Grafiklerini her seferinde bir satır veren bir demo programına ihtiyacım var, ekran denetleyicim daha sonra ekrana atacak.
Ne tür bir grafik programının bu şekilde çalışabileceğini hayal etmeye çalışıyorum? Muhtemelen bir tür matematiksel formülün gösterimi.
Bu şekilde çalışan, bir fonksiyonun çağrılabildiği, çerçevenin bir satırını hesaplayan ve döndüren, sadece talep edildiğinde grafik programlama teknikleri önerebilir mi? Bu şekilde çalışan, inceleyebileceğim mevcut programlar var mı?
Umarım soru mantıklıdır. Doğru yöndeki herhangi bir işaret veya ipucu takdir edilecektir.
Yanıtlar
Bu, daha retro donanımların işleyişine bakmanın makul olacağı bir durumdur . Eski donanımların hem bellek hem de işlem gücü açısından güçlü sınırlamaları vardı. 100+ Mhz çipiniz, 80'li yılların ve daha önceki çoğu tüketici sınıfı çiplerinden çok daha hızlıdır. Dolayısıyla, bu CPU'ların render edebilmek için özel grafik yongalarına ihtiyacı olsa da, çok daha hızlı CPU'nuz muhtemelen görevi yeterince yerine getirebilir.
NES'in tilemap ve sprite mimarisi gibi bir şeyle başlamanızı öneririm. Bu mimariler hem bellek açısından verimli (sınırlı depolama alanından çok daha fazlasını elde etmek) hem de satır satır çıktıda hesaplama açısından verimli olacak şekilde tasarlanmıştır, çünkü piksel verileri oluşturup bunu doğrudan görüntüleme cihazına bir CRT.
Genel fikir bu. Bir tilemap iki bölümden oluşur: bir dizi döşeme ve oluşturulmakta olan görüntüyü temsil eden döşeme haritasındaki bir 2B dizin dizisi. Kutucuklar tipik olarak 8x8'dir ve NES'de piksel başına 2 bit ve döşemelerde paletler kullanılmıştır. Ya da daha spesifik olarak, döşeme haritasındaki dizin yalnızca bir döşemenin dizinini değil, aynı zamanda bu döşemeyle kullanılacak paletin dizinini de içerir. Dolayısıyla, bir döşeme doğası gereği bir paletle ilişkilendirilmez; ilişkilendirme kullanım noktasında yapılır (teknik olarak, NES'te, her 2x2 karo bloğunun tümü aynı paleti kullanmak zorunda olduğu için, karo haritası ve palet haritası ayrıdır).
Kaydırmaya izin vermek için, karo haritası görünür ekrandan daha büyüktür ve görünür ekranın sol üst köşesinin tilemap içinde nerede olduğunu temsil eden bir ofset vardır. Bu ofset konumunda olsun Xoff
ve Yoff
.
Bunun satır satır işlemeyi nasıl önemsiz hale getirdiğini görebilirsiniz. Yatay konum için Ypos
(ekran alanında) yatay bir sıra oluşturmak için, başlangıç pikselini tilemap içinde almanız gerekir. Bu, XY konumunu (0, Ypos)
ekran uzayından tilemap uzayına dönüştürmeyi gerektirir . Böylece (Xoff, Yoff)
, `` Xoff, Yoff + Ypos) 'vektörünü oluşturan vektörü eklersiniz.
Ekran uzayından tilemap alanına herhangi bir eşleme yaparken, tilemap boşluğunun hem X hem de Y eksenlerini sarması gerektiğini unutmayın. Dolayısıyla, tilemap alanında yeni bir pikseli her hesapladığınızda, onu tilemap alanının çevresine sarmalısınız.
Şimdi, bu tilemap pikselini iki 2B bileşene ayırmamız gerekiyor: bize bu pikseli veren tilemap içindeki karo indeksi ve bu piksel için almamız gereken karonun içindeki piksel. Döşeme indeksi, yalnızca tilemap alanı piksel tam sayı-bölü döşeme boyutudur. Piksel koordinat integer- tilemap-alan piksel modded karo büyüklüğüne göre. 8x8 karo boyutu verildiğinde, bunu yapıyorsunuz:
ivec2 tilemap_pixel = ...; //Compute the tilemap starting pixel as above.
ivec2 tilemap_tile = ivec2(tilemap_pixel.x & ~0x7, tilemap_pixel.y & ~0x7); //Mask off the lower 3 bits.
ivec2 pixel_in_tile = ivec2(tilemap_pixel.x & 0x7, tilemap_pixel.y & 0x7); //Mask off all but the lower 3 bits.
Bu nedenle tilemap_tile
, şu anda içinde çalıştığımız döşemenin indeksine sahibiz. Ve pixel_in_tile
bize üzerinde çalıştığımız pikseli verir. Böylece, değeri bir palete eşlenerek o pikselin son rengini oluşturmak için o pikseli getirebiliriz. Ya da doğrudan kullanabiliriz.
Bir sonraki pikseli elde etmek oldukça önemsizdir. Sadece pixel_in_tile.x
1 artırıyoruz , karo boyutunu modüle ediyoruz . Artış karo boyutunu tilemap_tile.x
aştıysa , o zaman da 1 artırırız, tilemap boyutunu modulo ederiz . Ve piksel sırasını doldurana kadar devam edersiniz.
Böyle bir algoritmanın performans optimizasyonu için birçok fırsat vardır.
Kutucuklar muhtemelen en büyük veriyi temsil ediyor. 128 elemanlı 8x8 karolu karo seti 2bpp'de bile 2K'dır. Ama mesele şu ki, bunlar ROM'da saklanabilir , çünkü muhtemelen döşemeleri kendileri değiştirmiyorsunuz. Döşeme haritasının boyutu (RAM'de olması gerektiği varsayılarak) istenen çıktı çözünürlüğüne ve döşeme boyutuna bağlıdır. 320x240 boyutunda bir ekranı kaplayabilen 8x8 döşeme için bir döşeme haritası 1.200 bayttır. Tam olarak küçük değil. Düzgün kaydırma için yer istiyorsanız (ve dolayısıyla daha büyük bir döşeme haritası) daha fazla bellek almanız gerekir.
Bununla birlikte, "çıktı boyutunun" görüntü aygıtının gerçek boyutu olması gerekmediğine dikkat etmek de önemlidir . Örneğin, bir 1080p görüntüleme aygıtına çizim yapmayı planlıyorsanız, yine de örneğin, 8 kat daha küçük, 240x135 olan bir dahili çözünürlüğe sahip olabilirsiniz. Bu algoritmayı, aynı piksel değerini arka arkaya 8 kez üretecek şekilde değiştirmek ve aynı satırı 1080p satır başına 8 kez yeniden kullanmak çok kolay. Aslında, bu algoritmanın alt piksel kaydırmaya (135p boşluk değil 1080p alanda kaydırma) ve hatta piksel değerleri arasına bir miktar filtre eklemeye izin vermesi çok zor olmazdı. 240x135 "çıktı boyutu" tilemap, görünür bölge için yalnızca 510 bayt gerektirir, bu nedenle daha büyük bir kaydırma alanı için daha fazla yeriniz olur.