Tam ekran dörtlü görüntü oluşturma hedefine mükemmel piksel oluşturma


9

Bir rendertarget için bir grup değer oluşturmada sorun yaşıyorum. Değerler asla olmasını istediğim aralıkta sonuçlanmaz. Temelde rendertarget dokumuza işlemek için bir tam ekran dörtlü ve bir piksel gölgelendirici kullanıyorum ve daha sonra gölgelendiricideki bazı hesaplamalar için doku koordinatlarını temel almak niyetindeyim. Dörtlüün doku koordinatları sol üstte (0,0) ile sağ alt köşede (1,1) arasında değişir ... sorun, enterpolasyondan sonra bu değerlerin piksel gölgelendiricisine bu şekilde ulaşmamasıdır. .

Bir örnek: 4x4 bir dokuya render ediyorum ve bu durumda gölgelendirici, kırmızı ve yeşil kanallardaki doku koordinatlarını (u, v) çıktılar:

return float4(texCoord.rg, 0, 1);

Bundan çıkmak istediğim, sol üstteki pikselin RGB (0,0,0) ve böylece siyah olduğu, sağ üstteki pikselin RGB (255,0,0) ve böylece parlak olduğu bir doku. kırmızı ve sol alttaki piksel RGB (0,255,0) - parlak yeşil.

Ancak, bunun yerine burada sağda olsun:

(düz dörtlü oluşturma, düzeltme yok)
dörtlü düz işleme, düzeltme uygulanmadı

Sol üst piksel siyah, ancak diğer köşelerde yalnızca nispeten koyu kırmızı ve koyu yeşil elde ediyorum. RGB değerleri (191,0,0) ve (0,191,0) 'dır. Dörtlüün örnekleme konumlarıyla ilgili olduğundan şüpheliyim: sol üst piksel dörtlünün sol üst köşesini doğru bir şekilde örnekliyor ve UV koordinatları olarak (0,0) alıyor, ancak diğer köşe pikselleri örneklemiyor dörtlünün diğer köşeleri. Bunu sol görüntüde dörtlü temsil eden mavi kutu ve beyaz noktalar üst örnekleme koordinatlarını gösterdim.

Direct3D9'da ekran hizalı dörtlüleri oluştururken koordinatlarınıza uygulamanız gereken yarım piksel ofsetini biliyorum. Bundan ne tür bir sonuç aldığımı görelim:

(DX9'un yarım piksel ofseti ile oluşturulmuş dörtlü)
yarım piksel ofseti ile oluşturulan dörtlü

Kırmızı ve yeşil daha parlak hale geldi, ancak hala doğru değil: 223 kırmızı veya yeşil renk kanalında aldığım maksimum. Ama şimdi, artık saf siyahım bile yok, bunun yerine RGB ile koyu, sarımsı bir gri (32,32,0)!

Aslında ihtiyacım olan bu tür bir render olurdu:

(hedef oluşturma, azaltılmış dörtlü boyut)
doğru enterpolasyonlu saf siyahlar, yeşiller ve kırmızılar

İlk şekle kıyasla dörtlemin sağ ve alt kenarlığını tam olarak bir piksel yukarı ve sola hareket ettirmem gerekiyor gibi görünüyor. Ardından, sağ sütun ve alt piksel sırası, UV koordinatlarını dörtlüün sınırından doğru bir şekilde almalıdır:

VertexPositionTexture[] quad = new VertexPositionTexture[]
{
    new VertexPositionTexture(new Vector3(-1.0f,  1.0f, 1f), new Vector2(0,0)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X,  1.0f, 1f), new Vector2(1,0)),
    new VertexPositionTexture(new Vector3(-1.0f, -1.0f + pixelSize.Y, 1f), new Vector2(0,1)),
    new VertexPositionTexture(new Vector3(1.0f - pixelSize.X, -1.0f + pixelSize.Y, 1f), new Vector2(1,1)),
};

Ancak bu pek işe yaramadı ve alt ve sağ piksellerin hiç görüntülenmemesine neden oldu. Sanırım bu piksellerin merkezleri dörtlü tarafından kaplanmadı ve bu nedenle gölgelendirici tarafından işlenmeyecek. Quad'i küçük bir miktar daha büyük yapmak için pixelSize hesaplamasını küçük bir miktar olarak değiştirirsem, en azından 4x4 dokuda çalışır ... Daha küçük dokular üzerinde çalışmaz ve uv değerlerinin daha büyük dokulardaki eşit dağılımını ustaca bozduğundan korkarım:

Vector2 pixelSize = new Vector2((2f / textureWidth) - 0.001f, (2f / textureHeight) - 0.001f);

(PixelSize hesaplamasını 0.001f olarak değiştirdim - daha küçük dokular için, örneğin 1D arama tabloları, bu işe yaramıyor ve 0,01 f'ye veya daha büyük bir şeye yükseltmem gerekiyor)

Tabii ki bu önemsiz bir örnek ve bu hesaplamayı UV'leri piksel merkezlerine eşleme konusunda endişelenmeden CPU'da çok daha kolay yapabilirim ... yine de, tam, eksiksiz bir render yapmak için bir yol olmalı [0, 1] bir rendertarget üzerindeki piksel aralığı !?


Bunun bir yardımı olmadığı için değil, aynı problemi yaşıyorum.
IUsedToBeAPygmy

1
Doğrusal örneklemeyi de devre dışı bırakmayı unutmayın.
r2d2rigo

Kullandığınız koordinat sistemi ekranın pikselleriyle eşleşmiyor gibi görünüyor - öyleyse, burada sadece 2 × 2 piksel çiziyorsunuz gibi görünüyor. Çözdüğüm ilk sorun, proje ve model görünümü matrislerini, koordinat alanındaki +1'nin ekranda 1 piksellik bir kayma olacak şekilde ölçeklendirilmesidir.
Slipp D.Thompson

Yanıtlar:


4

Sorununuz UV'lerin doku koordinatları olarak tasarlanmasıdır. 0,0 koordinatı, dokuda sol üst pikselin sol üst köşesidir ve normalde dokuyu okumak istediğiniz yer değildir. 2D için bu pikselin ortasındaki dokuyu okumak istersiniz.

Eğer benim matematik doğru ise yuvarlak çalışmak için yapmanız gerekenler:

return float4((texCoord.rg - (0.5f/textureSize)) * (textureSize/(textureSize-1)), 0, 1);

Yani sol üst pikseli 0,0 olarak almak için uygun ofseti çıkarırsınız ve sonra sağ alttaki doğru olanı elde etmek için bir ölçek uygularsınız.

Aynı şey, geometri için UV koordinatlarının 0-1 aralığının dışında genişletilmesiyle de elde edilebilir.


Son cümle üzerinde durmak için: bu dönüşümü, dörtlünün dört köşesi için köşe tamponundaki UV'lere uygulayabilirsiniz, sonra piksel gölgelendiricisinde yapın return float4(texCoord.rg, 0, 1);.
Nathan Reed

Yukarıda önerilen formülü denedim ve pek işe yaramadı: yukarıdan 4x4 örnek rendertarget'ımda R ve G kanallarında soldan sağa veya yukarıdan aşağıya 0, 42, 127 ve 212 alıyorum. Ancak, eşit aralıklarla (0, 85, 170 ve 255 olacak bir 4x4 doku için) 0 ila 255 değerleri istiyorum. Ayrıca UV koordinatlarını değiştirmeye çalıştım, ancak henüz doğru dengeyi bulamadım.
Mario

0

İlk şekle kıyasla dörtlemin sağ ve alt kenarlığını tam olarak bir piksel yukarı ve sola hareket ettirmem gerekiyor gibi görünüyor.

Neredeyse, ama pikselin sadece yarısı. Dört köşelerinizden 0,5 çıkarın. Aynı dokuya sahip 256x256 dörtlü istiyorsanız, işte puanlarınız:

p1 = (-0.5, -0.5)
p2 = (-0.5, 255-0.5)
p3 = (255-0.5, 255-0.5)
p4 = (255-0.5, -0.5)

Veya bunun yerine piksel gölgelendiriciye pikselin yarısını ekleyebilirsiniz (texCoord.rg + 0.5 * (1.0 / texSize))

Yarım piksel ofseti DX9'da bilinen bir gerçektir. Bu ve bu makaleler de size yardımcı olabilir.


0

Buna kesinlikle doğrusal örnekleme neden olmaktadır. Tam siyah sol üst pikselin altındaki ve sağındaki metinlere bakarsanız, R ve / veya G kanallarında 63 ve 2'sinde B'de 2 olduğunu görürsünüz. çamurlu-koyu-sarı olsun; R ve G'de 31 ve B'de 1'dir.


-2

Bu, köşe gölgelendiriciyi işledikten sonra sabit sürücü tarafından enterpolasyonlu köşe çıkışından texCoords kullandığınız için basittir.

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.