En Son Eklenenler

8 Bit Cihazlarda Hızlı Çizgi Çizdirme

Uzun bir aradan sonra yeni bir yazı ile karşınızdayım. Bu yazı biraz talep üzerine gerçekleşti diyebilirim. Birden fazla arkadaşım 8-bit cihazlarda hızlı çizgi çizdirme konusunda çalışmaya başladılar. Ben de bu konuda bir makale yazmaya karar verdim.

Commodore 64 için hazırladığım örneği aşağıdaki linkten indirebilirsiniz:

Multicolor Line

WASD ile (x1, y1) posizyonunu, UHJK ile de (x2, y2) pozisyonunu değiştirebilirsiniz. SPACE tuşu bağlangıç ve bitiş noktalarında parıldayan spriteları gizler. Çerçevede yer alan renk bloğu rutinin ne kadar CPU yediğini, bloğun rengi ise rutinin tipini göstermektedir. Mavi: az eğimli açılar, Mor: çok eğimli, her Y’ye tek piksel denk gelen açılar anlamına gelmektedir. Bu programda dik açılar için fazla optimizasyon yapılmamış, az eğimli açılara odaklanılmıştır. Nedenini yazının ilerleyen kısımlarında göreceksiniz.

Bu kodu derlemek için ihtiyacınız olan Assembly Editörü’nü aşağıdaki linkten indirebilirsiniz:

Kick Assembler

Sonucu PC üzerinde görmek isterseniz de;

Vice

işinizi görecektir. Kodu her platformda derleyebilirsiniz. Gerekli parametreleri “compile.bat” dosyasında göreceksiniz. Windows kullanıyorsanız doğrudan “compile.bat” dosyasının içerisinde yer alan;

  • KICKASM_PATH
  • VICE_PATH

değişkenlerini kendi bilgisayarınızda bulunan dosya yolları ile değiştirecek olursanız, “compile.bat” dosyasını çalıştırdığınızda program otomatik olarak derlenip, Vice’ın içerisinde çalışmaya başlayacaktır.

Şimdi bu kadar giriş yaptıktan sonra biraz açıklamalara geçelim.

Bilgisayarda Çizgi Nasıl Çizdirilir?

Bu konuya eski makalelerimde (Ekran Kartlarının Geleceği) değinmiştim ama teknik detayına girmemiştim.

Hemen bir grafik üzerinden hızlı bir giriş yapalım;

Bu örnekte (1,3) – (12,10) koordinatları arasına bir çizgi çekmek istiyoruz. Başlangıç noktamız (1,3)’den itibaren ne kadar sağa, ne kadar aşağı ilerlememiz gerekiyor? Bunu deltaX ve deltaY değerleri olarak (kısaca dx ve dy) hızlıca son ve baş noktalar arasındaki farkı alarak hesaplıyoruz. Sonra da dx/dy ile eğimi hesaplayabiliyoruz. Artık elimide bir eğim değeri var. Bunu nasıl kullanabiliriz?

Elimizde eğim değeri olmasaydı da oran orantı ile bulunduğumuz x’e karşılık gelen y’yi bulabilirdik.

Mesela x=8 için y kaçtır?

y = y1+(x-x1)/dx*dy

y = 3+(8-1)/11*7 = 7.45

olarak bulduk. 7.45’i yuvaladığımızda 7 elde ediyoruz. Demek ki x: 8 için y: 7 olması gerekiyormuş.

Şimdi buradaki “/dx*dy”yi “*m” olarak değiştirebiliriz. Böylece bölmeden kurtulur ve tek bir çarpma ile sonucu bulabiliriz.

y = y1+(x-x1)*m

y = 3+(8-1)*0.6363 = 7.45, aynı sonucu elde ettik.

Bu şekilde ilerleyerek çizgiyi çizebiliriz. Yani;

dx = x2 - x1
dy = y2 - y1
m = dy / dx
for(x = x1; x <= x2; x++) {
  y = y1 + (x - x1) * m
  plot(x, y)
}


Bu kod yukarıdaki çizgiyi çizmemizi sağlayacaktır.

Bu kadar, bir sonraki makalede görüşmek üzere… Keşke 8 Bit cihazlar için iş bu kadar kolay olsaydı. İlk olarak çarpma / bölme işlemlerinden kurtulmamız gerekiyor. Bu da Bresenham ve türevleri olan algoritmalar ile mümkün. Bu algoritmaları bir çok yerde benzer formüllerle bulabilirsiniz. Kişisel tercihim şu formüldür (sadece yukarıdaki dx > dy ihtimaline özel olarak çalışacak rutin).

dx = x2 - x1
dy = y2 - y1
stepCounter = dx / 2
x = x1
y = y1
do {
  plot(x, y)
  stepCounter += dy
  if(stepCounter >= dx) {
    stepCounter -= dx
    y++
  }
  x++
} while(x <= x2)


Burada dikkat ederseniz çarpma / bölme kullanmıyoruz. Baştaki “/ 2” 8 bir bilgisayarlarda “sağa bir bit kaydırma” işlemi çeklinde gerçekleştirilebiliyor, diğer bir ifade ile “dx >> 1” olarak düşünebilirsiniz. “stepCounter” ismini verdiğimiz sayaç 0’dan değil “dx / 2″den başlıyor. Bunun nedeni çizginin her y satırındaki parçasının başına ve sonuna eşit dağıtılması, simetrik ve düzgün bir çizgi oluşturmamızı sağlaması. Yani ilk parçanın ortasından çizmeye başlıyoruz.

Bresenham’ın bulduğu ilginç fikir şu. Elimizde dx = 11 ve dy = 7 varsa, biz 7/11 ya da 11/7 şeklinde küsüratlı sayılar bulup, bunları kullanmak yerine;

  • Sayaca 7 ekle, 11’i geçti mi?
  • Geçmediyse pixeli koy ama aynı satırda kal, geçtiyse alt satıra geç ve sayaçtan 11 çıkar, küsürat sayaçta kalsın.

fikrini ortaya atmış olmasıdır. Bu sayacın dy değerlerini ekleye ekleye gidip, dx sınırını geçip geçmediği kontrol etmesi, geçmediği sürece aynı satırda kalması ve geçtiği noktada alt satıra inip sayacı sıfırlamak yerine, sayaçtan sınır değerini (dx) çıkarmak bizi küsüratlı sayılarla çalışmaktan kurtarıyor.

Evet, ve işte makalenin sonuna… yine gelemedik. Belki PC’de eski DOS günlerinde olsaydık ve 13h mode’unda 320×200 ekran açmış olsaydık makaleyi burada (en azından yukarıdaki çizgiyi çektirme ihtimali için) sonlandırabilirdik. Çünkü ekrandaki her bir pixel bir byte’a denk geliyor 13h modunda. Ama Commodore 64, ZX Spectrum, Amstrad CPC, Atari 800 XL ve onlarca benzeri 8 bit cihaz ele alındığında grafik modlarında çoğunlukla bir byte’a birden fazla pixel denk gelir. Mesela 320×200 tek renk modunda çizim yapmak isterseniz bir byte’ın her bir biti bir pixele denk gelecektir. Sizin o byte’a tek tek “plot(x, y)” yapmanız demek aynı işlemi bir byte için 8 kere tekrar ettirmeniz demektir ki asıl kabus burada başlıyor. Daha da kötüsü önceki yazdığınız değerlerin silinmemesi için byte’a doğrudan değer yazmanız mümkün değil, bitleri ORlamak durumundasınız. Commodore 64 Assembly (6502/6510) diliyle ifade etmek gerekirse;

lda bitMask
ora plotAddress
sta plotAddress
...
lda bitMask
ora plotAddress
sta plotAddress
...


şeklinde 8 kere tekrar eden bir kod çıkıyor ortaya. Ama biz yukarıdaki örnekte ilk satırda iki pixel, ikinci satırda tek pixel, üçünsü satırda yine iki pixel şeklinde çizim yaptırmamız gerektiğini biliyoruz. Yani aslında şu kod işimizi görüyor (bu defa adres değerine y index’ini de ekleyip daha gerçekçi bir kod oluşturalım)

ldy y1
lda #%11000000
ora (plotAddress),y
sta (plotAddress),y
iny
lda #%00100000
ora (plotAddress),y
sta (plotAddress),y
iny
lda #%00011000
ora (plotAddress),y
sta (plotAddress),y


İşte ulaşmak isteyeceğimiz ideal kod budur. Ama tüm (x1, y1) – (x2, y2) olasılıkları için böyle bir açık (unrolled) kod oluşturmak ağırlıklı olarak 16k – 128k arasında belleklere sahip 8 bit makineler için imkansıza yakındır ya da çok sınırlı bir alana çizim yapabilmenizi sağlayacaktır. Peki nasıl bir çözüm bulabiliriz?

En tepede paylaştığım Commodore 64 örneğinde kaynak kodları, özellikle “line.asm” dosyasını incelediğinizde şöyle bir çözümle karşılaşacaksınız. Bu benim bulduğum büyük bir inovasyon değil, scenerlar yıllardır bu yöntemin çeşitli varyasyonlarını kullanıyorlar. Örneğin Codebase64 sitesinde şu şekilde paylaşılmış bir örnek mevcut.

Lines by Bitbreaker / Oxyron ^ Arsenic ^ Nuance

Benim burada hazırladığım rutin Commodore 64’ün multicolor çözünürlüğüne özel. Çözünürlük 160×200 ve her bir karakter bloğu 4×8 çözünürlükte. Yani çizgi çizmeye başlama ihtimali olan pozisyonlar sadece 4 ihtimale düşüyor. Bu da bize çok daha az ihtimalde (4+3+2+1 = 10 ihtimal) hızlı bir açık rutin yazabilmemizi sağlıyor. Ancak bu durumda da karşımıza her pixelin iki bitten oluşması ve 3 farklı renk için üç farklı bit patternine özel kod yazılması gereksinimi ortaya çıkıyor. Burada makrolar yardımımıza koşuyor. Kodu bir defa yazıp, makroları farklı parametrelerle çağırarak farklı renkler için gerekli kodları üretebiliyoruz.

İlk olarak nereden başlamamız gerekiyor? İlk iş kaç karakter bloğu uzunluğunda çizim yapacağımızı bulmak

	lda x1
	and #3
	sec
	adc dx
	lsr
	lsr
	sta charBlock


Bu rutin x1’in karakter içinde kaçıncı pixele denk geldiğini alıp (0-3 aralığı), buna dx’i yani çizginin yataydaki genişliğini ekleyip, sonucu 4’e bölerek toplam karakter sayısını buluyor. Artık kaç bytelık alanda ilerlememiz gerektiğini biliyoruz.

Özel olarak değerlendirmemiz gereken 3 durum var;

  1. Tek karakter bloğu: Çizimin aynı karakter kolonu içerisinde başlayıp yine aynı karakter kolonu içinde bitmesi ihtimali. Bunu özel olarak ele almalıyız. İlk bu ihtimal değineceğiz.
  2. Normal karakter blokları: Bunlar arada kalan bloklar. Sadece çizginin ilk başlangıç noktası için giriş bölümünde ufak bir değişiklik yapmak gerekiyor ama hem başlangıç, hem de arada kalan karakter blokları aynı kod ile çizdirilebiliyor. Normal karakter bloklarının özelliği hangi pikselden başlarsa başlasın karakterin sonuna kadar ilerlemesi.
  3. Son karakter bloğu: Çizginin sona erdiği noktada hangi pikselde duracağımızı iyi değerlendirmemiz gerekiyor. Burada da ihtimaller çok fazla değil. O nedenle normal karakter bloklarında olduğu gibi açık rutinlerle tüm ihtimaller hızlı bir biçimde çizdirilebiliyor ve doğru noktada çizim sonlandırılabiliyor.

Şimdi tek tek ele alalım.

Tek Karakter Bloğu

“charBlock” değerinde özel olarak ele almamız gereken bir durum değerin 0 olması. Yani bu ne demek? Aynı karakter bloğu (kolonu) içinde başlayıp, yine aynı karakter bloğu içinde çizimi bitireceğiz demek. Y’de ilerleyebiliriz, ama X’de aynı karakter kolonunda başlayıp bitiriyoruz çizimi. Çizim 4 pixel genişliğinde olduğu durumda diğer karakter bloğuna çizim yapmasak da ulaşmış oluyoruz, yani karakterin sonuna eriştiğimiz noktada charBlock değeri 0 değil 1 oluyor. Bizim burada özel olarak ele almamız gereken;

  • Sadece 1. piksel (1000)
  • 1. pikselden 2. piksele (1100)
  • 1. pikselden 3. piksele (1110)
  • Sadece 2. piksel (0100)
  • 2. pikselden 3. piksele (0110)
  • Sadece 3. piksel (0010)

şeklinde 6 çizilme ihtimali çıkıyor. Elbette ki bu arada yine eğime göre Y’de ilerlemeyi hesaplamamız gerekiyor. Kodun içerisinde “singleCharBlock” olarak geçen bölümde bunun nasıl ele alındığını görebilirsiniz, kendiniz de bu ihtimalleri daha hızlı çalışacak biçimde ele alabilirsiniz. Sadece en fazla 3 plotla sınırlı kaldığı için ben bu kısmı hafızada az yer kaplayacak şekilde kodlamayı tercih ettim. Rekor kırmak gibi bir niyetiniz varsa örnektekinden daha iyisini kodlamanızı öneririm.

	stx temp // X'de bulunan o noktadaki değer stepCounter
	ldx x1
	jmp singleCharBlock
...
singleCharBlockNext:
	lda temp
	sec
	sbc dy
	bcs !+
	adc dx
	stepY(dir)
!:	sta temp
	inx
singleCharBlock:
	lda mask,x
	ora (plotAddress),y
	sta (plotAddress),y
	cpx x2
	bcc singleCharBlockNext
	rts


Örnek kod bu biçimde, “singleCharBlock”dan rutine giriyoruz ve loop ile çizim yapıyoruz, aynı adrese de birden fazla kez yazma durumumuz söz konusu, yani bahsetmiş olduğum optimizasyonlar burada kullanılmıyor.

Gelelim geriye kalan iki farklı çizim rutinine.

Normal Karakter Blokları

Burada yine ihtimalleri göz önüne almamız lazım. İhtimaller şunlar.

  • Bloğun 1. pikselinden çizmeye başlamak (b_1000)
  • Bloğun 2. pikselinden çizmeye başlamak (b_0100)
  • Bloğun 3. pikselinden çizmeye başlamak (b_0010)
  • Bloğun 4. pikselinden çizmeye başlamak (b_0001)

Kodun içinde parantez içinde verilen etiketleri inceleyebilirsiniz. Öncelikle b_1000 ihtimalini ele almak istiyorum.

b_1000:
	txa
	sbc dy
	bcc d_1000
	sbc dy
	bcc d_1100
	sbc dy
	bcc d_1110
	sbc dy
	bcc d_1111

	tax
	lda #(%11111111 & colorMask)
	jmp b_1000_plotAddress+2


Kodun içinde İngilizce olarak yorumlar yazmış durumdayım. Burada yorumlar sildim. Tek tek ne olup bittiğini açıklayacağım. Burada yaptığımız şey şu. “sbc dy” satırları önceden bahsettiğim piksel piksel ilerlerken “stepCounter” değişkeni üzerinde ilerlememizle aynı şey. Ancak burada pozitif değil, negatif yönde ilerliyoruz. Aksi taktirde dx’den büyük mü diye sorgulamak için fazladan bir compare (cmp) komutu kullanmak zorunda kalırdık. dx’den geriye doğru ilerleyip, değer sıfırdan küçük olunca dx ekliyoruz diye düşünebilirsiniz. Asıl dikkat edilmesi gereken şey şu, dx’de ilerliyoruz ama sıfıra ulaşmadığı sürece çizim yapmıyoruz. İşte bu rutinin kilit noktası bu. ne zaman ki sıfıra ulaşıyoruz, oradaki ihtimallerden biri gerçekleşiyor. Diyelim “bcc d_1110” noktasında değer sıfırın altına düştü. Doğrudan “1110” şeklinde tek solukta pikselleri yazıyoruz. Daha sonra bir alt ya da üst (çizginin yönüne göre) satıra geçip, çizime kaldığımız noktadan devam ediyoruz. Şimdi örnek icabı “d_1110″ı inceleyelim.

d_1110:
	tax
	lda #(%11111100 & colorMask)
	jmp b_0001_plotAddress

b_0001_plotAddress:
	ora (plotAddress),y
	sta (plotAddress),y
	iny

b_0001:
	txa
	adc dxMinusDy
...


Çizim noktasına ulaştığımızda ilk iş olarak accumulatordeki “stepCounter” değerimizi x’e aktararak korunmasını sağlıyoruz. Sonra doğrudan accumulator’e %11111100 şeklinde yazmamız gereken değeri yazıyoruz (1110 ihtimalindeyiz, hatırlatırım). Her bir piksel iki bit ile ifade edildiği için durum bu şekilde. Ancak burada farklı renkler kullanmak isteseydik yazmamız gereken değerler %10101000 ve %01010100 olacaktı. Bunu da makromuza geçtiğimiz “colorMask” değişkeni ile AND’leyerek sağlıyoruz. colorMask %11111111 olduğu durumda birebir aynı sonucu alırız ama %10101010, %01010101 gibi değerler vererek diğer 2 rengi, %10011001 gibi değerlerle dithering için gereken değerleri elde edebiliriz.

Değer elimizde hazır. Peki değeri nasıl yazdıracağız? Burada “nasıl?”dan daha önemli olan sorun “nerede?”. Çizdirdiğimiz patern neydi? “1110”. Bu durumda alt satırda 4. pikselden devam etmemiz lazım, öyle değil mi? Yani gitmemiz gereken rutin “0001”. Rutinlerin öncesinde plot rutinleri de yer alıyor. Yani “b_0001″in hemen üstünde “b_0001_plotAddress” bulunuyor. Burada doğrudan “ora/sta” ile değer yazıldıktan sonra “iny” ile bir alttaki satıra ulaşılıyor. Kodu inceleyecek olursanız “iny” yerine “stepY(dir)” şeklinde bir makro göreceksiniz. Aşağı değil yukarı ilerlediğimiz durumda “dey” kullanmamız gerektiği için bu noktalarda bu şekilde kullanımlar var. Ancak en başta ele aldığımız grafikteki çizgiyi çektirmek için gereken ihtimal yukarıda verdiğim kod parçasıyla uyuşuyor.

Şimdi son dikkat çekilmesi gereken yere geldik. “b_1000” rutinimiz “sbc dy” ile başlamıştı. Ancak burada “adc dxMinusDy” bulunuyor. Bunun sebebi burada aslında yapmamız gerekenin şu olması;

	adc dx
	sbc dy


Neden? Çünkü sayacımız sıfırın altına düştü de buraya ulaştık, önce sayacı dx ekleyerek pozitif noktaya getirmemiz, sonra bir sonraki adım için yine dy’yi çıkarmamız gerkiyor. Bunun için bu rutinlere ulaşmadan önce çizgi rutinimizin başlarında;

	lda dx
	sec
        sbc dy
	sta dxMinusDy


şeklinde tek bir değer hesaplıyoruz. Sonra “adc dxMinusDy” ile tek opcode’da sayacı ihtiyacımız olan değere getiriyoruz.

Evet, biraz uzun ve çok fazla dallanan bir kod yapısı ama sabredin, sonlarına geldik. En hızlı yol genellikle en kolay ve okunaklı yol değildir.

Son olarak şöyle bir durumla karşılaşıyoruz. Bu “txa” ve “adc dxMinusDy” ile giren rutinler sadece alt satıra geçilmişse bu şekilde başlamalı. Ya çizginin başlangıç noktası 2., 3., 4. piksellere denk gelirse ne olacak? Evet, o ihtimaller için de başı “txa” ve “sbc dy” ile başlayan versiyonları üretmek lazım ama sırf şu kadarcık iş için o kadar büyük kopyalar oluşturmak istemeyerek, hızdan az bir ödün vererek bu ihtimaller için şu rutinleri oluşturdum.

b_0100_s:
	txa
	sbc dy
	jmp b_0100+3

b_0010_s:
	txa
	sbc dy
	jmp b_0010+3

b_0001_s:
	txa
	sbc dy
	jmp b_0001+3


Yani dy’yi çıkardıktan sonra diğer rutinlerin ilk 3 byte’ını es geçerek yoluna devam et. İlk 3 byte “txa” ve “adc dxMinusDy” komutlarının toplamı (1+2).

Bu rutinleri çağıran ilk girişteki kod da şu şekilde.

	lda x1
	and #%00000011
	beq b_1000

	cmp #1
	beq b_0100_s

	cmp #2
	beq b_0010_s

	jmp b_0001_s


Yani x1’in alt 2 bitine bak (0-3 aralığı bir değer çıkacaktır). Sıfır ise “b_1000″e git, en baştan temiz temiz çizmeye başla. 1 ise “b_0100_s”e git, 2 ise “b_0010_s”e git, son ihtimalde de “b_0001_s”e git ve çizim rutinlerine düzgün noktadan giriş yap.

En karışık ihtimal buydu ve bunu noktalamış olduk. Gelelim son ihtimale.

Son Karakter Bloğu

Bir karakter bloğunu bitirdiğimiz zaman blok sayacımızı (charBlock) bir azaltıyoruz ve bunun son blok olup olmadığına bakıyoruz. Son blok değilse bir sonraki kolona göre bazı ayarlamalar yapıp (plotAddress’e 128 ekleyip) sonra yine karakterin başından çizim yapacak rutine sıçrıyoruz. Bunu yaptığımız kod kısmı şurası.

b_1000_plotAddress:
	ora (plotAddress),y
	sta (plotAddress),y
	tya
	eor #$80
	tay
	bmi !+
	inc plotAddress+1
!:
	dec charBlock
	bne b_1000


128 ($80) eklemek için adc/sbc yerine eor kullanımı carry flag ile uğraşmamak için, yoksa amaç sadece toplama yapmak, 128 hariç hiç bir değer için de bu şekilde kullanamazdık, byte’ın tam yarısına denk gelmesinin avantajı. 16×16 karakterlik bir alana çizim yaptığımızdan 16*8 = 128 olduğu için güzel denk gelen bir durum bu.

Burada son bölüme dikkat edelim. “charBlock” bir azaltılıyor. 0’dan başka bir değerse “b_1000″e gidiliyor, tanıdık bir rutin, bloğun başından çizim yapılmaya devam ediliyor. Peki sıfıra ulaşmışsak ne olacak?

	lda x2
	clc
	adc #1
	and #3
	beq !out+
	cmp #2
	beq l_1100
	cmp #3
	beq l_1110

l_1000:
	lda #(%11000000 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
!out:
	rts


Arada atlanılan “l_1100” ve “l_1110” harici oldukça kısa ve açık bir rutin. x2’ye bir eklememizin nedeni x2’ye kadar değil x2 de dahil çizim yapmak istememiz. Aslında XOR (C64’de bilinen ismiyle EOR) filler tarzı kodlarda bir önceki pikselde bitirmek daha doğru oluyor (ki ben de şu anda bu rutini kendi kodlarımda x2 hariç çizecek şekilde kullanıyorum). Ama burada size tam düzgün bir rutin göstermek istediğim için bir ekledim.

Eğer çizecek bir şey kalmamışsa çıkışa git, kalmışsa kaç piksel kalmış? 1 piksel kalmışsa zaten bas pikseli çık (l_1000), başka derdimiz yok. Ama 2 ya da 3 piksel kalmışsa ne olacak?

İki piksel kalmışsa (l_1100)

l_1100:
	txa
	sbc dy
	bcs !+

	lda #(%11000000 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	stepY(dir)
	lda #(%00110000 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	rts
!:
	lda #(%11110000 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	rts


Arada diğer satıra geçmek gerekiyor mu gerekmiyor mu? Gerekiyorsa bu satıra 1000 yaz, diğer satıra geç ve 0100 yaz ve bitir. Eğer geçmek gerekmiyorsa doğrudan bu satıra 1100 yaz ve çık.

Üç piksel kalmışsa (l_1110)

l_1110:
	txa
	sbc dy
	bcs !+

	tax
	lda #(%11000000 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	stepY(dir)
	
	txa
	adc dxMinusDy
	bcs !next+

	lda #(%00110000 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	stepY(dir)
	lda #(%00001100 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	rts
!next:
	lda #(%00111100 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	rts
!:
	sbc dy
	bcs !+

	lda #(%11110000 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	stepY(dir)
	lda #(%00001100 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y
	rts
!:
	lda #(%11111100 & colorMask)
	ora (plotAddress),y
	sta (plotAddress),y

	rts


İhtimaller artınca kod iyice uzuyor. Ama unutmayın, kod uzuyor ama çalışan kod bunun tamamı değil. Ya 1000 0100 0010 şeklinde üç satıra üç tane byte set edecek, ya 1100 0010 / 1000 0110 gibi iki byte ya da son ihtimalde doğrudan bulunduğu yere 1110 yazıp çıkıp gidecek.

Beklediğinizden daha karmaşık çıkmış olabilir. Ama en hızlıyı hedeflediğinizde yol böyle rutinlerden geçiyor. Bu arada elbette ki bunun en hızlı rutin olması gibi bir iddiam da yok, büyük ihtimalle üzerinde bir kaç saat daha çalışsam önemli derecede hızlandırabilirim rutinleri. Ama daha ilk optimizasyonları yapmaya başladığım gibi (bazı jmp’lardan kurtulmak için rutinlerin sıralarını değiştirdim) kod daha da anlaşılmaz bir hal almaya başladı. Biraz daha devam edecek olsaydım bu dökümanı hazırlamak, sizin kodları inceleyip anlamanız çok daha zor bir duruma gelecekti. O yüzden optimizasyonları henüz kod okunabilir durumdayken kesme kararı aldım.

Örnek sadece tek renk çizgi çekiyor. Diğer renkleri çizdirmek isterseniz ne yapmanız gerekiyor? Bu örneğin dışında uyarladığım yerlerde bu değişiklikleri yaptım. Kodun içinde;

// This needs to be changed for different colors


Şeklinde işaretlenmiş kısımlar var. Line rutinini çağırmadan önce bu kısımları ilgili renk seçeneğini oluşturacak tablolara ya da rutinlere yönlendirecek şekilde modifiye etmeniz gerekiyor.

Örneğin; drawLine11down, drawLine10down, drawLine01down, drawLine11up, drawLine10up, drawLine01up rutinlerinin başına “.align $100” koyarak 256 bytelık blokların başına gelecek şekilde yerleştirdim kendi örneklerimde. Bu sayede sadece high byte’larını değiştirerek istediğim rutine yönlendirebiliyorum. Eğer bu dediklerimi anlamamışsanız yazının buraya kadar geçen bölümünü de anlamış olma ihtimaliniz olmadığından gönül rahatlığıyla açıklamaları bu noktada kesiyorum.

Başka söylenebilecek neler var? x1’in x2’den büyük, y1’in y2’den büyük olması gibi ihtimaller sorun yaratır. Bunlar kodun için bazen sıralanarak yani (x1,y1) – (x2,y2) çiflerinin yerlerini değiştirerek, bazen farklı yöntemlerle çözülmüş durumda. Dik açılarda çizimden hemen hiç bahsetmedik, çünkü bu rutinin asıl amacı bit bit değil byte byte çizim yaptırmaya yönelik örnek oluşturmaktı. Dik açılardan zaten her byte’a 1 pixel denk geliyor, bu optimizasyonların hiç biri işe yaramıyor. Dik açıları çok basit ve yavaş sayılabilecek bir loop olarak bıraktım. Kendi örneklerimde bu line rutinini XOR fill ile kullandığım için zaten dik açıların sadece en üst piksellerini çizdiriyorum.

Mevcut örnekte geçmediği için bu kod parçasının örneğini de vereyim burada. Bu kod dik açılardan her bir piksel kolonunun sadece en üst pikselini çizer. XOR fill için gerekli olan çizim tekniği bu olduğu için böyle yapıyoruz. Ekranda sadece çizgi olarak gözükecek objelerde bu tekniği kullanmıyoruz.

narrowLine:
// do {
//   setPixel(px, py);
//   stepCounter += dy;
//   while(stepCounter >= dx) {
//     stepCounter -= dx;
//     py++;
//   }
//   px++;
// } while(px < x2);
!narrowLoop1:
	lda offsetXLo,x
	sta plotAddress
.label offsetHiAddress1 = *+2
	lda offsetX1Hi,x
	sta plotAddress+1

ob1:	lda orBitMask1,x
	ora (plotAddress),y
	sta (plotAddress),y

	lda stepCounter
	clc
	adc dy
!narrowLoop2:
	cmp dx
	bcc !+
	sbc dx
.label stepY2 = *
	iny
	bne !narrowLoop2-
!:
	sta stepCounter

	inx
	cpx x2
	bcc !narrowLoop1-
	rts


128×128 Piksellik Alandan Daha Geniş Alanlara Çizim Yapılması

Bu rutinin en büyük dayanaklarından biri “Y” indeksiyle kolonlarda düzgün bir biçimde ilerleyebilmek. Ancak ne Commodore 64’ün ne de diğer 8 bit bilgisayar platformlarının normal grafik modları bu şekilde lineer ilerlemezler. Bunun için karakterleri kolonlarda alt alta dizip, kendimiz böyle bir çizim modu oluşturuyoruz. Doğrudan bitmap ekrana çizim yapmak istesek bu rutine bir çok yük bindirecek şeyi aralara eklememiz gerekir. Ama temel prensip değişmez. Ben size temel prensibi anlatmak için böyle bir örnek geliştirdim.

Bir diğer yöntem ise yine karakter seti üzerine çizim yapmak ama birden fazla karakter seti kullanmak. Peki bu nasıl oluyor, örnekleri var mıdır?

Örneğin “Snapshot / Glance” demosunda geçen bu robot kol efektimde 16×16 yerine 32×16’lık bir alana çizim yaptırmıştım. 32×16 = 512 karakter ediyor ve bir karakter seti 256 karakter ile sınırlı. Bu nedenle alt alta 2 tane 32×8’lik alan koyup, arada tarama yakalatarak karakter setlerini değiştiriyordum. Bu durumda kolon yükseklikleri yine 128 olsa da 64’ü geçip geçmediğini kontrol etmek, buna göre diğer karakter setine çizim yaptırmak gerekiyordu ama bunun ekstra maliyeti o kadar da yüksek değildir. Yani y’de ilerleme işleminde 64’e kadar ve 64’den sonra şeklinde kontroller koyarak bu rutini 256×128’lik bir alana çizim yapacak hale getirebilir. 3. 4. karakter setlerini de kullanarak tam ekran efektler de yapabiliriz. Ama kompleksitenin çok artmaması için size önerim 256’dan daha geniş alanlara bu şekilde çizim yaptırmaktan kaçınmanız yönünde olacaktır. 128 yerine bir karakter seti daha ekleyerek 192’lik alana çizim yaptıracak olursanız Atari 800 XL’de tüm ekran yüksekliğini kapladınız, C64’de ise 8 piksel boşluk kaldı demektir.

Diğer 8-Bit Cihazlar

Yazımızın başlığı “8 Bit Cihazlarda Hızlı Çizgi Çizdirme” ancak sadece Commodore 64 üzerinden örneklerle gittik. Sebebi elbette ki şahsen 8 bit cihazlar arasında en hakim olduğum cihazın Commodore 64, en hakim olduğum işlemci çipinin 6502 tabanlı işlemciler olması. Ancak şu günlerde z80 cihazlarla da flört eder durumdayım. Dolayısıyla ilerleyen dönemlerde farklı platformlara adaptasyonlarını paylaşabilirim sizinle. Bu olsun ya da olmasın, bu yazının temel amacı bu konudaki ana prensibi irdelemekti. Aslında bu yazıda anlatılan konular sadece çizgi çizdirme ile sınırlı da değil. 8 bit cihazlarda bütün (hatırı sayılır) demo efektleri bu şekilde planlanıp kodlanıyor. Tabii efektten efekte mücadeleler, yapılan optimizasyonlar, CPU ve hafıza arasında verilen savaşlar değişiyor. Ama prensip her zaman bir efektin mümkün olan en az cycle’ı harcayarak ekrana çizdirilmesi ve tabii hafızaya sığacak şekilde tasarlanması.

Kodlardaki yorumlar neden İngilizce de bu yazı Türkçe? Amacım kodları indiren bir yabancının da faydalanabilmesi idi. Nasılsa bu yazıda detayları Türkçe olarak da açıkladım. Talep gelirse Türkçe yorum satırları olan bir kaynak kod örneği de hazırlayabilirim.

Bol çizgili, nice 2 boyutlu, 3 boyutlu vektör efektlerine vesile olması dileklerimle, sonraki yazılarımda görüşmek üzere.

6502 Yeniden Üretimde (W65C02S6PG-14)

Açıkçası benim açımdan inanılmaz heyecan verici bir durum yok. Çünkü ne yazık ki bu yeni üretilen çip 6510’un, yani Commodore 64’ün içindeki çipin yerini alabilecek birşey değil. Ancak yine de 6502 uyumlu ve 6502’nin 1 MHZ’lik hızının yanısıra 14 MHZ hızında üretilmiş olması çok güzel bir gelişme.

6502 uyumlu W65C02S6PG-14

6502 uyumlu W65C02S6PG-14

WDC (Western Design Center) firması tarafından 40 pin olarak üretilen çip £4.90 fiyatından satışa sunulacakmış. Ayrıca firma FPGA’ler için 65C02 isimli bir de sanal versiyon yayınlayacağını duyurmuş. Yani modern donanımlarda 14 MHZ’lik 6502 kullanarak ilginç retro projelere imza atılabilir ve elimizdeki 30+ senelik 6502 tabanlı kod birikimiyle hızlıca bu yeni cihazlar için çeşitli yazılımlar, demolar, oyunlar geliştirebiliriz.

“Commodore 64” 30 Yaşında!

Benden az daha genç olan Commodore 64 ilk kez Commodore International firması bünyesinde yer alan Commodore Business Machines ya da yaygın kullanılan kısaltmasıyla CBM tarafından 1982 yılının Ocak ayında tanıtılmıştı. Aynı yılın bahar aylarında üretime giren ünlü cihaz, Ağustos ayında 595 dolarlık fiyatıyla elektronik/bilgisayar marketlerin raflarında yerini almıştı.

 

Commodore Logosu

Commodore 64, sık sık C64 ya da Commodore’un sol tarafta gördüğünüz ünlü logosu yüzünden C=64 şeklinde kısaltmalarla kullanılmıştır.

 

 

 

Commodore 64’ün donanımsal özellikleri şu şekilde özetlenebilir.

İşlemci Çipi: MOS Teknoloji 6510 – ~1 Mhz (PAL: 0.985 Mhz, NTSC: 1.023 Mhz)
Bellek: 64 KB RAM + 20 KB ROM
Görüntü Çipi: VIC-II (320×200 tek renk ya da 160×200 16 renk grafik modu ve 8 donanımsal yaratık desteği)
Ses Çipi: SID (8 bit 3 kanal, eski modellerde 6581, yeni modellerde 8580 kullanılmıştır)
Bağlantı Noktaları: Güç ünitesi, 2 x joystick (ya da mouse/paddle v.b.), kartuş, anten bağlantısı (RF), eski component A/V çıkışı (luma, chroma, mono audio), disk drive, teyp ve RS-232

Commodore 64 Modelleri:

Aslında detaya girildiğinde daha fazla model olduğu görülse de özellikle dış görünüş ve SID çipleri birbirinden farklı olan 2 ana model aşağıdaki gibi kategorilendirilebilir.

Eski kasa (ilk üretim):

Commodore 64 (Eski Kasa)

Yeni kasa:

Commodore 64 (Yeni Kasa)

30 Yılda Neler Değişti?

 

Bu konuda uzun uzun çok şey yazılabilir ancak şu şekilde açıklanabilir sanırım.

Yie Ar Kung-Fu (Orjinal 1985)

Yie Ar Kung-Fu (By Veto 2010)

Bu grafiklerdeki ilerlemeye basit bir örnek. Üretildiği tarihlerde kesinlikle mümkün olmayan ve yaklaşık olarak 90’ların başından günümüze kadar kademe kademe gelişen yeni grafik modlarının kalitede en son ulaştığı seviye diyebileceğim NUFLI modundan başka örnekler verecek olursak;

NUFLI 1

NUFLI 2

İşte 80’lerdeki o basit görünüşlü oyun ve demolardan görsel kalite açısından gelinen nokta budur.

Geçen 30 Yıl İçersinde Donanımın Sınırlarındaki Değişim

 

Değişim elbette ki sadece grafik tarafında olmadı. Aslında ilk üretilen Commodore 64’den hiçbir farkı olmayan cihazların donanım sınırları zamanla genişledi. Yani eskiden donanımın yapabileceği öngörülmeyen şeyler, günümüzde oldukça sıradan bir biçimde yapılabiliyor. Örneğin Commodore 64’de 320×200 çözünürlükteki iç ekranın dışında kalan çerçeve (border), daha 80’li yıllarda açılarak bu alana yaratıklardan (sprite) oluşan grafikler basılmaya başlandı. Önce alt/üst, sonrasında da iki yandaki çerçeveler bazı donanım aldatmacalarıyla açılabildi. İlginçtir ki bu o dönemde birbirinden tamamen bağımsız olarak üretilmiş birçok bilgisayarda benzer yöntemlerle yapılabiliyordu.

Yıllar ilerledikçe başlangıçta kullanılması tavsiye edilmeyen illegal opcodelar yani kullanımı onaylanmayan ve dökümante edilmemiş işlemci komutları (Commodore 64’ün Programcı’nın El Kitabı’nda bu özellikle belirtilmiştir), yıllar ilerledikçe hemen her Commodore 64 programcısının başı sıkıştığında baş vurduğu yöntemler haline geldi.

Commodore 64 her ne kadar donanımsal grafik kaydırma özelliğini desteklemese de, yine VIC-II çipini kandırmak suretiyle çok az işlemci gücü harcayarak grafikleri ekranda dilediğimiz gibi kaydırmak mümkün oldu. Bu da özellikle 80 sonu, 90 başlarında çok kaliteli ve çok renkli grafikleri olan platform oyunları, shoot’em up’lar olarak bize geri döndü.

Elbette ki Commodore 64’ün limitlerini zorlama konusunda en çok çaba sarfeden ve sonuç alanlar Commodore 64 scenerları oldu. Demoscene dünyasındaki rekabet her geçen gün birbirinden üstün demoların yayınlanmasına ve “Commodore 64’de yapılması olanaksız” denen birçok efektin yapılabilmesine neden oldu.

Örnek Demolar:

[youtube_sc url=”yFdjWSaDlIo” title=”Edge%20Of%20Disgrace%20-%20Part%201″ width=”384″]

[youtube_sc url=”0b4uGv-9xpw” title=”Edge%20Of%20Disgrace%20-%20Part%202″ width=”384″]

[youtube_sc url=”Z8trliwndrU” title=”Snapshot%20-%20Part%201″ width=”384″]

[youtube_sc url=”PEmf4FBakBE” title=”Snapshot%20-%20Part%202″ width=”384″]

Commodore 64 hakkında daha yazılacak çok şey var ancak bu seferlik

30. yaş günün kutlu olsun eski dostum ve çocukluk arkadaşım

demekle yetineceğim. Belki ilerleyen süreçte Commodore 64 üzerine daha detaylı blog yazıları da yayınlayabilirim, kim bilir.

Haydar Rock Bar 10 Sene Aradan Sonra Bizlerle!

Haydar Rock Bar

Haydar Rock Bar

Herkese aynı şeyi ifade etmesi imkansız, ancak hayatımı en “yaşadığım” dönemlerde çok sağlam izlere sahip olan bir bardır Haydar. 1999 yılında kapanan ve kapandığında Homer Simpson’ın Moe’nun Tavernası kapandığında hissedeceği hisleri yaşamış biri olarak bugün epey bir sevinçliyim. İşin en güzel tarafı da Muarrem Abi’yi bıraktığım gibi bulmuş olmam. Adam hiç değişmemiş, yaşlanmamış, her zamanki gibi işinin başında.

* Ağırlıklı olarak 70’lerin rock gruplarını sevenlerdenseniz,
* Ben 2.5 TL’ye 50’lik bira içmek istiyorum diyorsanız,
* Gittiğim yerde tanıdık kimse olmasa oturup barmenle sohbet ederek geceyi geçirebileyim diye içinizden geçiriyorsanız,
* İstiklal’de kendinize bir sığınak arıyorsanız

size Haydar’ı tavsiye ediyorum. Haydar, Büyükparmakkapı sokakta (Mojo’nun, Katarsis’in bulunduğu sokak) sokağın girişinden 30 metre sonra bir bakkalın sağından girilen binanın 3. katında. Daha (yeniden) açılalı 25 gün falan olmuş. Esnaf da çok iyi bilmiyordu, bulana kadar zorlandım. Ancak sonra çevredeki bakkallara v.s. Haydar’ın afişlerini dağıttım, siz arayınca zorlanmayasınız diye.

BT Haber Röportajı

BT Haber’in scene geçmişimle ilgili yapmış olduğu röportaja aşağıdaki resimlere tıklayarak ulaşabilirsiniz.

BT Haber Röportajı - Sayfa 2

BT Haber Röportajı - Sayfa 2

BT Haber Röportajı - Sayfa 1

BT Haber Röportajı - Sayfa 1

Genetik Zayıflama Yöntemi

Deneyde Kullanılan Fareler

Deneyde Kullanılan Fareler

Genetik bilimi her geçen gün ilerliyor. Geçtiğimiz günlerde bilim adamları çok ilginç bir buluşun ilk adımlarını attı. Deney için seçilen iki fareden birine genetik mutasyon uygulandı. “I kappa B kinase epsilon” ya da kısacas “IKKε” şeklinde isimlendirilen gen bulunmayan fare aldığı besinleri yağa değil ısıya dönüştürerek fazla kilo almadı.

Deneyin neticesi soldaki resimde görülüyor. Bu iki fare üç ay boyunca aynı yüksek yağlı kilo aldırıcı diyet programıyla beslenmişler. Sonuç olarak soldaki genetik mutasyona uğramış fare (kulağında işaret olan) sağdaki normal fareye göre çok daha zayıf kalmayı başarmış.

Aslında bu deneyin çıkış noktası tam olarak obezitenin önüne geçmek değilmiş. Başlangıçta bu mutasyon sonucunda obezite ve şeker hastalığı arasındaki bağlantının ortadan kaldırılacağı düşünülmüş. Ancak sonuç olarak farenin obez olmadığı, kilosunu az bir artışla koruduğu sürpriz bir şekilde ortaya çıkmış.

Deney henüz insanlarda denenecek düzeye gelmemiş ancak benzer bir sonuç vereceği tahmin ediliyor. Eğer düşünülen gerçekleşirse bu buluş yeni bir antiobozite ilacı geliştirilmesi için temel hazırlayacak.

Şahsen fazla kilo sorunu olan birisi olarak bu buluşun takipçisi olacağım. Her ne kadar doğal yöntemlerle zayıflamak daha sağlıklı gözükse de benim gibi bunu deneyen ve başaramayan büyük bir kitle için güzel bir alternatif olabilir.

İstanbul’da Sel Felaketi

Siyah KurdeleTekirdağ’da 5 kişinin ölümünden sonra İstanbul’da 26 kişi öldü ve 9 kişi kayboldu. Toplamda 31 ölü, 9 kayıp var. Ölümlere, kayıplara, ülkenin uğradığı büyük maddi zararlara duyduğum üzüntünün dışında felaket sonrasında yaşanan diyaloglar da akıl alacak gibi değil. Burada daha derin konulara girmek istemiyorum ve bu konuya yorum yapılmasını da engelliyorum. Sadece kendi adıma yas ilan ediyorum.

Ekran Kartlarının Geleceği – Eski Teknik, Yeni Nesil

2000 yılından bu yana ekran kartlarının gelişimi denildiği anda akla hep shader teknolojisinin bir adım daha ileri gidişi, bellek ve GPU işlem kapasitesinin artması geliyor. Peki nereye kadar böyle devam edecek? Aslında hemen hemen bu dönemin sonuna geldik sayılır. Birkaç senedir NVidia, ATI gibi büyük ekran kartı üreticileri eski bir dost olan Ray Tracing ile flört etmeye başladı.

Eski (şu an için kullanılan) metoda biraz göz atalım.

Rasterization

Üçgenlerden Oluşan Bir Arazi

Üçgenlerden Oluşan Bir Arazi

Eski metod, Rasterization şeklinde isimlendirilmiştir. Herşey iki boyutlu çokgenler üzerinden oluşturulmaktadır. Genellikle üçgen ya da dörtgen kullanılarak ekrandaki objeler oluşturulur.

Bir üçgen nasıl çizilir? Elimizde bir kağıt varsa ve insan kadar gelişmiş bir canlıysak bu o kadar da zor bir iş değildir. Ancak bilgisayarları ele aldığımız durumda ekranda bir matris şeklinde dizilmiş pixeller karşımıza çıkıyor ve işimiz biraz zorlaşıyor. Düşünün ki kareli metod defterindeki karelerin içini karalayarak bir üçgen çizmemiz gerekiyor. Üçgeni öncelikle elimizle karelerden bağımsız olarak aşağıdaki gibi çizebiliriz.
 

Üçgen Çizimi 1

Üçgen Çizimi 1

Buradaki siyah kareler bilgisayar ekranındaki pikselleri temsil etmektedir. Üçgeni satır satır çizeceğimizi varsayalım. Öncelikle bulmamız gereken her satırda hangi karelerin ilk ve son kareler olarak seçilmesi gerektiğidir. Bu kareleri aşağıdaki resimde mavi ile işaretledik.

Üçgen Çizimi 2

Üçgen Çizimi 2

Artık tek yapılması gereken her satırdaki mavi kareler arasında kalan bölgeyi yatayda doldurmak. Bunun sonucunda ise aşağıdaki görüntü elde edilir.

Üçgen Çizimi 3

Üçgen Çizimi 3

Özetle Rasterization dediğimiz metot kullanıldığında çizim ekrandaki her bir çokgen için satır satır yapılır.

Üçgenler ya da dörtgenler karmaşık bir objeyi modellemekte yeterli olur mu? Örneğin bir insan modeli nasıl görünecektir?

Bruce Lee - Wireframe

Bruce Lee - Wireframe

Görüldüğü gibi Bruce Lee’yi tanımakta hiç zorlanmıyoruz. Ancak bu modeldeki çokgen sayısı epey bir yüksektir ve oyunlardaki gibi gerçek zamanlı olarak kullanılmak için ideal bir model değildir. Eğer yumuşak hatlara sahip bir model istiyorsak ya yüksek adette çokgen kullanacağız ya da ekran kartlarının shader özelliklerini kullanarak bazı çözümler üreteceğiz.

Şimdi gelelim diğer metoda.

Ray Tracing

Ray Tracing, gerçek yaşama uygun görüş simülasyonu için çok daha iyi bir tekniktir. İnsan gözü etrafındakileri nasıl görür, hemen hemen bunu bire bir simüle etmektedir.

Gerçek hayatta gözümüz ışık kaynağından gelen ve diğer objelerin yansıttığı ışığı toplar. Ancak bir bilgisayar ekranı söz konusu olduğunda ekrandaki tüm piksellerin ışık toplayabilmesi için ışık kaynağından oldukça yüksek sayıda (güneş mesafesindeki bir ışık kaynağı göz önüne alındığında sonsuza gidebilecek miktarda) ışın atmak gerekmektedir. Bu nedenle bilgisayarda Ray Tracing gerçek hayata göre ters bir mantıkla uygulanır. Işık kaynağından izlemciye değil izlemciden ışık kaynağına doğru ışınlar atılır. Yani ekranda kaç adet piksel var ise o sayıda ışın atılacaktır.

Ray Tracing Java Simülatör (2 Boyutlu)

Bu linkteki simülatör Ray Tracing’in çalışma presibini anlamanıza yardımcı olacaktır.

Ray Tracing sonucunda nasıl bir görüntü oluşur? Bunun Rasterization’a göre avantajı nedir? Oluşan görüntü şu şekildedir.

Bir Ray Tracing Örneği

Bir Ray Tracing Örneği

Bu örnekte de görüldüğü gibi Ray Tracing oldukça gerçekçi ve yumuşak hatlara sahip objeler ortaya çıkmasını sağlar. En önemli özelliklerinden biri de yansıma ve gölge gibi Rasterization tekniğinde oldukça yüksek maliyetli hesaplamalar gerektiren ve bu derece gerçekçi olamayan efektleri oldukça kolay ve gerçekçi bir biçimde hesaplayabilmesidir.

Peki Ray Tracing ile ne derece gerçekçi görüntüler elde edilebilir? Buna bir örnek görelim.

Tay Tracing - Cam Yüzeyler

Ray Tracing - Cam Yüzeyler

Ray Tracing’in en başarılı olduğu konulardan biri materyallerdir. Resimde de görüldüğü gibi cam yüzeylerin sahip olduğu saydamlık, ışık kırılması, gölge-yarı gölge v.b. özellikler gerçeğe çok yakın olarak simüle edilebilmektedir.

"Rasterization" - "Ray Tracing" Kıyaslama

"Rasterization" - "Ray Tracing" Kıyaslama

Rasterization ile Ray Tracing’i kıyaslayacak olursak soldaki gibi bir sonuç ile karşı karşıya geliriz. Görüldüğü üzere her iki resimde de aynı objeler, aynı kamera açısı, aynı desenler kullanılmıştır. Ancak Ray Tracing tekniğinde çaydanlık ve kaşık metalik özellikleri nedeniyle sadece ışığı değil çevredeki diğer objeleri de yansıtmaktadırlar. Bunun haricinde de genel olarak Ray Tracing metodunda objeler daha yumuşak hatlara sahiptir ve çevreyle daha uyumlu olarak resmin içinde yer almaktadırlar.

Ray Tracing günümüzde gerçek zamanlı olarak pek kullanılmamaktadır. Örnekleri mevcutsa da bu güne kadarki denemelerde yüksek çözünürlüklerde ve detaylı bir biçimde kullanıldığında en fazla saniyede birkaç kare çizdirilebilmektedir. Diğer bir deyişle oldukça düşük FPS’ler elde edilmektedir. Ancak intel, nvidia, amd gibi firmalar yakın gelecekte bunu değiştirecek donanımları hazırlamaya başladılar bile.

Quake Wars Ray Tracing 1

Quake Wars - Ray Tracing 1

Quake Wars oyununun Intel tarafından Ray Tracing kullanan bir versiyonu hazırlanmıştır. Oyunun görüntü kalitesi ve efektleri ciddi bir oranda yükselmiştir.

Quake Wars Ray Tracing 1

Quake Wars - Ray Tracing 2

Rasterization ve Ray Tracing’in Kıyaslaması, Avantaj ve Dezavantajları

Rasterization’ın en büyük özelliği bir çokgenin çizilme zamanının oldukça kısa olmasıdır. Örneğin ekranı kaplayan büyüklükte bir üçgen söz konusu olduğunda Rasterization hızlı bir biçimde bu üçgeni çizebilir. Ancak Ray Tracing kullanıldığı taktirde bu üçgenin yer aldığı bölgedeki tüm pikseller için birer (veya birden fazla) ışın atılması gerekmektedir ki bu çok daha yavaş bir işlemdir. Ancak ekrandaki çokgen sayısı arttıkça Rasterization’ın dezavantajları ortaya çıkmaya başlar. Bazı durumlarda üçgenlerin bir kısmı tamamen ya da kısmen fuzuli olarak çizdirilebilir. Bunun nedeni arkada kalan, önüne başka çokgenler çizdirilen yüzeylerdir. Ancak Ray Tracing’de her zaman ekrandaki piksel sayısı kadar ışın atılacaktır. Bu ışınlar her doğrultuda (şeffaflık durumu haricinde) en yakın yüzeye çarpacak ve arkasındaki yüzeylerle ilgili bir işleme tabi tutulmayacaklardır. Yine de her durumda o doğrultudaki en yakın çarpışma yapan yüzeyi bulmak için farklı algoritmalar kullanmak gerekmektedir.

Rasterization’ın Ray Tracing’e göre günümüzdeki en göze çarpan avantajı donanımların bu teknik için gerekli fonksiyonları donanımsal olarak desteklemeleridir. Vertex Shader, Pixel (Fragment) Shader, Geometry Shader gibi özellikler CPU’yu rahatlatarak gerekli işlemlerin GPU üzerinde yapılmasını sağlamakta ve tamamen bu hesaplara özel optimize edilmiş ekran kartları çok yüksek hızlara ulaşılmasına olanak tanımaktadır. Gelecekte Ray Tracing’in ekran kartları tarafından desteklenmeye başlaması ile Rasterization’ın bu avantajı silinecek ve çok daha gerçekçi üç boyutlu sahneler elde etmemizi sağlayan Ray Tracing, oyunlar ve uygulamalar tarafından yeni standart olarak benimsenecektir.

İşin en komik yanı ise Ray Tracing’in yeni değil, oldukça eski bir teknoloji olması ve gerçek zamanlı olarak bile birçok kullanım örneğinin bulunmasıdır. Sanırım donanım üreticileri Rasterization ile pazardan elde edebilecekleri kârın son damlasına kadar suyunu sıkmadan köklü bir değişikliğe gitmek istemediler. Ancak artık zamanıdır, yakında hep beraber Ray Tracing tekniğinin önümüze sunacağı inanılmaz gerçekçi dünyaların büyüsü ile sanal ortamlarda yolculuk ediyor olacağız.

Puls / Rrrola (256 byte demo)

Puls / Rrrola

İnsanlar ile hayvanları ayıran özellik zekadır. Peki biz zeki ve insansak, 256 byte’da bu efekti yapanlar hangi kategoriye giriyor? Demoya soldaki resime tıklayarak ulaşabilirsiniz.

Bu güne kadar çok fazla “bundan ötesi olmaz” dedirten 256 byte gördüm, geçirdim. Ama bu da artık boyutunun farkında değil. Kendini 1k falan zannediyor olsa gerek.

İşin komik tarafı tam da blog’uma ray tracing ile ilgili bir yazı hazırlıyordum ki bu demoyu gördüm. Büyük ihtimalle bundan sonraki yazımda anlatacağım bir tekniğin en küçük boyutta en muhteşem örneği budur.

İTÜ Deprem Tahmin Projesi

Deprem

İTÜ’den Doç. Dr. Oğuz Gündoğdu büyük bir iddia attı ortaya. Yer, hava ve sudaki hareketleri takip ederek depremi 4 gün önceden haber veren bir sistem yaptıklarınını duyurdu.

Proje yerdurumu.com sitesinden takip edilebiliyor. Bilgiler güncel bir biçimde halk ile de paylaşılıyor.

Bildiğiniz gibi henüz dünya üzerinde hiçbir ülke böyle birşeyi başaramadı. İddianın doğru olup olmadığını henüz bilmiyorum, konu uzmanlık alanımın oldukça dışında. Ancak bu projeyi yakından takip edeceğim ve gelişmeleri buradan sizlerle paylaşacağım.