Bir hareketli grafiği alt piksel artışlarıyla nasıl taşırsınız?


11

Pikseller açık veya kapalı. Bir hareketli grafiği taşıyabileceğiniz minimum miktar tek bir pikseldir. Peki, hareketli grafiğin kare başına 1 pikselden daha yavaş hareket etmesini nasıl sağlıyorsunuz?

Yaptığım yol, bir değişkene hız eklemek ve 1 (veya -1) değerine ulaşıp ulaşmadığını test etmekti. Eğer öyleyse, o zaman sprite taşıyacak ve değişkeni 0'a sıfırlayacağım, şöyle:

update(dt):
    temp_dx += speed * dt
    temp_dy += speed * dt

    if (temp_dx > 1)
        move sprite
        reset temp_dx to 0
    if (tempy_dy > 1)
        move sprite
        reset temp_dy to 0

Bu yaklaşımı sevmedim çünkü aptalca hissediyor ve hareketli grafiğin hareketi çok sarsıntılı görünüyor. Peki alt piksel hareketini ne şekilde uygularsınız?


Yapabileceğiniz tek şey bilinear filtrelemedir.
AturSams

Kare başına 1 pikselden daha az hareket ediyorsanız, nasıl sarsıntılı görünebilir?

Yanıtlar:


17

Bir dizi seçenek var:

  1. Yaptığın gibi yap. Zaten pürüzsüz görünmediğini söylemiştin. Mevcut yönteminizde bazı kusurlar var. Bunun için xaşağıdakileri kullanabilirsiniz:

    tempx += speed * dt
    
    while (tempx > 0.5)
      move sprite to x+1
      tempx -= 1
    while (tempx < -0.5)
      move sprite to x-1
      tempx += 1

    bu daha iyi olmalı. İf ifadelerini 0,5 kullanacak şekilde değiştirdim, 0,5'i geçtiğinizde bir öncekinden bir sonraki değere daha yakınsınız. Her adımda 1 pikselden fazla harekete izin vermek için döngüler kullanırken kullandım (bunu yapmanın en iyi yolu değil, ancak kompakt ve okunabilir kod için yapar). Yavaş hareket eden nesneler için, piksel hizalamanın temel konusunu ele almadığımız için yine de gergin olacak.

  2. Hareketli grafiğiniz için birden fazla grafik bulundurun ve alt piksel ofsetine bağlı olarak farklı bir grafik kullanın. Sadece x yumuşatma altpiksel yapmak için, örneğin, adresinden sprite için bir grafik oluşturabilir x+0.5ve pozisyon arasında ise x+0.25ve x+0.75Orijinalinizdeki yerine bu sprite kullanmak. Daha hassas konumlandırma istiyorsanız, daha fazla alt piksel grafik oluşturun. Bunu yaparsanız xve yrender sayınız, sayıların aralık sayısının karesiyle ölçeklendiği için hızlı bir şekilde balonlanabilir: bir aralık 0.54 render 0.25gerektirir, 16 gerektirir.

  3. Supersample. Bu, alt piksel çözünürlüğünde bir görüntü oluşturmanın tembel (ve potansiyel olarak çok pahalı) bir yoludur. Essental olarak, sahnenizi oluşturduğunuz çözünürlüğü iki katına (veya daha fazlasına), ardından çalışma zamanında ölçeklendirin. Performansın hızlı bir şekilde düşebileceği için burada bakım öneriyorum. Bunu yapmanın daha az agresif bir yolu, sprite'ınızı süper örneklemek ve çalışma zamanında küçültmek olacaktır.

  4. Zehelvion tarafından önerildiği gibi, kullandığınız platform zaten bunu destekliyor olabilir. Tamsayı olmayan x ve y koordinatlarını belirtmenize izin verilirse, doku filtrelemesini değiştirme seçenekleri olabilir. En yakın komşu genellikle varsayılan değerdir ve bu "sarsıntılı" harekete neden olur. Diğer filtreleme (doğrusal / kübik) çok daha pürüzsüz bir etkiye neden olacaktır.

2. 3. ve 4. arasındaki seçim, grafiklerinizin nasıl uygulandığına bağlıdır. Bir bitmap stili grafik, ön işleme çok daha iyi uyurken, vektör stili ise sprite süper örneklemesine uygun olabilir. Sisteminiz destekliyorsa, 4. iyi bir yol olabilir.


Tercih 1'de eşiği neden 0,5 ile değiştirelim? İfadeleri neden bir while döngüsüne taşıdığınızı da anlamıyorum. Güncelleme fonksiyonları her adımda bir kez çağrılır.
bzzr

1
Güzel soru - Cevabınızı yorumunuza dayanarak açıkladım.
Jez

Süper örnekleme "tembel" olabilir, ancak çoğu durumda 2x hatta 4x aşırı örneklemenin performans maliyeti, özellikle oluşturmanın diğer yönlerinin basitleştirilmesine izin vermesi durumunda belirli bir sorun olmaz.
supercat

Büyük bütçeli oyunlarda genellikle 3'ü grafik ayarlarında kenar yumuşatma olarak listelenen bir seçenek olarak görüyorum.
Kevin

1
@Kevin: Aslında muhtemelen bilmiyorsun. Çoğu oyun , biraz farklı olan çoklu örnekleme kullanır . Diğer varyantlar da yaygın olarak kullanılır, örneğin değişen kapsama alanı ve derinlik örnekleri. Süper örnekleme neredeyse hiçbir zaman parça gölgelendirici yürütme maliyeti nedeniyle yapılmaz.
imallett

14

Birçok eski skool oyununun bu problemi çözmesinin (veya gizlemesinin) bir yolu, hareketli grafiği canlandırmaktı.

Yani, hareketli grafiğiniz kare başına bir pikselden daha az hareket edecekse (veya özellikle piksel / kare oranı 3 karede 2 piksel gibi tuhaf bir şey olacaksa), bir n bu n karenin üzerinde hareketli grafiği k < n piksel kadar hareket ettiren kare animasyon döngüsü .

Sprite her zaman hamle olarak nokta sürece, yani bazı her çerçevede şekilde, hiçbir zaman herhangi bir tek kare nerede bütün peri olur aniden "pislik" ileri olacaksa oluyor.


(Ben den animasyonlar kazma bazı örneğin düşünüyorum rağmen bu durumu gösteren eski bir video oyun gerçek bir sprite bulamadık Lemmings böyle idi), ancak çıkıyor "planör" dan desen Conway'in Hayat Oyunu bir hale getirir çok güzel illüstrasyon:

resim açıklamasını buraya girin
Animasyon , CC-By-SA 3.0 lisansı altında kullanılan Kieff / Wikimedia Commons tarafından yapılmıştır .

Burada, aşağı ve sağa sürünen küçük siyah piksel blokları planörlerdir. Eğer dikkatlice bakarsanız, onlar bir piksel çapraz tarama dört animasyon kareleri almak olduğunu göreceksiniz, ancak hareket beri bazı o çerçevelerin her birinde şekilde, hareket, en azından artık değil, iyi (yani sarsıntılı görünmüyor her şeyden daha fazla sarsıntılı.


2
Hız sabitse veya kare başına 1/2 pikselden azsa veya animasyon, hareketteki varyasyonları gizleyecek kadar büyük ve yeterince hızlıysa, bu mükemmel bir yaklaşımdır.
supercat

Bu iyi bir yaklaşımdır, ancak bir kamera hareketli grafiği takip etmek zorunda kalırsa yine de sorunsuz bir şekilde hareket etmeyeceği için sorunlarla karşılaşırsınız.
Elden Abob

6

Hareketli grafiğin konumu bir kayan nokta miktarı olarak tutulmalı ve görüntülenmeden hemen önce bir tam sayıya yuvarlanmalıdır.

Ayrıca hareketli grafiği süper çözünürlükte koruyabilir ve hareketli grafiği görüntülemeden önce örnekleyebilirsiniz. Hareketli grafiği 3x ekran çözünürlüğünde tuttuysanız hareketli hareketli grafiğin alt piksel konumuna bağlı olarak 9 farklı gerçek hareketli karaktere sahip olursunuz.


3

Buradaki tek gerçek çözüm, bilinear filtreleme kullanmaktır. Buradaki fikir, GPU'nun, üst üste binen dört hareketli grafik pikseli temelinde her pikselin değerini hesaplamasına izin vermektir. Bu yaygın ve etkili bir tekniktir. Sprite'ı doku olarak 2d düzlüğüne (bir pano) yerleştirmeniz yeterlidir; daha sonra bu düzlükleri oluşturmak için GPU'yu kullanın. Bu iyi çalışıyor, ancak biraz bulanık sonuçlar almayı ve hedeflediğinizde 8 bit veya 16 bit görünümünü kaybetmeyi umuyoruz.

Artıları:

Zaten uygulanmış, çok hızlı, donanım tabanlı bir çözüm.

Eksileri:

8 bit / 16 bit aslına uygunluk kaybı.


1

Kayan nokta bunu yapmanın normal yoludur, özellikle de sonunda float koordinatlarına sahip gölgeli bir çokgenle donanımın oldukça mutlu olduğu bir GL hedefine render ediyorsanız.

Ancak şu anda yaptığınız işi yapmanın başka bir yolu var ama biraz daha az sarsıntılı: sabit nokta. 32 bit konum değeri, ekranınızın her iki eksende neredeyse kesinlikle 4k pikselden daha az olmasına rağmen, 0 ile 4,294,967,295 arasındaki değerleri temsil edebilir. Bu yüzden ortasına sabit bir "ikili nokta" (ondalık nokta ile benzer şekilde) koyun ve 0-65536'dan başka 16 bit alt piksel çözünürlüğüyle piksel konumlarını temsil edebilirsiniz. Daha sonra normal olarak sayı ekleyebilirsiniz, sadece ekran alanına dönüştürürken veya iki sayıyı birlikte çarptığınızda 16 bit sağa kaydırarak dönüştürmeyi hatırlamanız gerekir.

(Kayan nokta birimi olmayan bir Intel 386'ya sahip olduğum gün içinde 16 bitlik sabit bir noktada bir 3D motor yazdım. Çerçeve başına 200 Phong gölgeli çokgenin körleme hızına ulaştı.)


1

Buradaki diğer cevaplara ek olarak, bir dereceye kadar titreme kullanabilirsiniz. Renk taklidi, bir nesnenin piksellerinin kenarının, daha yumuşak bir kenar elde etmek için arka planla eşleşecek şekilde daha açık / koyu renkte olduğu yerdir. Örneğin, 4 piksel kareniz olduğunu varsayalım:

OO
OO

Eğer bu 1/2 pikseli sağa hareket ettirseydiniz, hiçbir şey gerçekten hareket etmezdi. Ama biraz titreme ile biraz hareket yanılsaması yapabilirsiniz. O'yu siyah, o'yu gri olarak düşünün, böylece şunları yapabilirsiniz:

oOo
oOo

Tek bir çerçevede ve

 OO
 OO

Gelecek. Gri kenarlı gerçek "kare" aslında 3 piksel alır, ancak siyahtan daha açık gri olduklarından daha küçük görünürler. Ancak bunu kodlamak zor olabilir ve şu anda bunu yapan hiçbir şeyin farkında değilim. Dithering'i şeyler için kullanmaya başladıkları zaman, kararlar hızla iyileşti ve görüntü manipülasyonu gibi şeyler dışında çok fazla ihtiyaç yoktu.

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.