Android'de GPU arayüzünü nasıl güvenilir bir şekilde uygulayabilirim?


11

Android'de karakter kaplaması yapmaya çalışıyorum.

Fikir oldukça vanilya: Derisi matrislerim var ve her tepe noktasıyla birlikte, dört matris indeksi ve dört karşılık gelen ağırlık gönderirim. Onları köşe gölgelendiricisinde toplarım ve her köşeye uygularım.

Bu, oyunumun iOS sürümünde köşe gölgeleyicisinde yapıyorum (normalleri önemsemeyin):

attribute vec4 in_pos;
attribute vec4 in_normal;
attribute vec2 in_texture_coords;
attribute vec4 in_bone_index;
attribute vec4 in_bone_weight;

varying vec2 fs_texture_coords;

uniform mat4 world_view_projection;
uniform mat4 bones[@bind_matrix_count];

void main()
{
    // Skinning
    vec4 transformed_pos =
        ((in_pos * bones[int(in_bone_index.x)]) * in_bone_weight.x) +
        ((in_pos * bones[int(in_bone_index.y)]) * in_bone_weight.y) +
        ((in_pos * bones[int(in_bone_index.z)]) * in_bone_weight.z) +
        ((in_pos * bones[int(in_bone_index.w)]) * in_bone_weight.w);

    gl_Position = world_view_projection * transformed_pos;
    fs_texture_coords = in_texture_coords;
}

Ve oldukça iyi çalışıyor. Bununla birlikte, Android'de aynı kodla, bazı cihazlarda (özellikle Nexus 7 2013), uniformsabit olmayan endekslere sahip olanlara erişemezsiniz . Diğer bir deyişle, bunu yapamazsınız:

bones[int(in_bone_index.w)]

çünkü bones[some_non_constant]her zaman bones[0]eğlenceli olarak değerlendirilmez . En kötü şey, gölgelendirici derleyicisinin bunu mutlu bir şekilde derlemesidir.

Bu adam tam olarak aynı soruna sahip gibi görünüyordu. Üniformalara matris yerine vektör olarak erişerek çözdü. Ben de aynısını yaptım ve aslında işe yaradı!

attribute vec4 in_pos;
attribute vec4 in_normal;
attribute vec2 in_texture_coords;
attribute vec4 in_bone_index;
attribute vec4 in_bone_weight;

varying vec2 fs_texture_coords;

uniform mat4 world_view_projection;
uniform vec4 bones[@bind_matrix_count * 4]; // four vec4's for each matrix

void main()
{
    // Skinning
    mat4 skin_0 = mat4(
        bones[4 * int(in_bone_index.x) + 0],
        bones[4 * int(in_bone_index.x) + 1],
        bones[4 * int(in_bone_index.x) + 2],
        bones[4 * int(in_bone_index.x) + 3]);
    mat4 skin_1 = mat4(
        bones[4 * int(in_bone_index.y) + 0],
        bones[4 * int(in_bone_index.y) + 1],
        bones[4 * int(in_bone_index.y) + 2],
        bones[4 * int(in_bone_index.y) + 3]);
    mat4 skin_2 = mat4(
        bones[4 * int(in_bone_index.z) + 0],
        bones[4 * int(in_bone_index.z) + 1],
        bones[4 * int(in_bone_index.z) + 2],
        bones[4 * int(in_bone_index.z) + 3]);
    mat4 skin_3 = mat4(
        bones[4 * int(in_bone_index.w) + 0],
        bones[4 * int(in_bone_index.w) + 1],
        bones[4 * int(in_bone_index.w) + 2],
        bones[4 * int(in_bone_index.w) + 3]);
    vec4 transformed_pos =
        ((in_pos * skin_0) * in_bone_weight.x) +
        ((in_pos * skin_1) * in_bone_weight.y) +
        ((in_pos * skin_2) * in_bone_weight.z) +
        ((in_pos * skin_3) * in_bone_weight.w);

    gl_Position = world_view_projection * transformed_pos;
    fs_texture_coords = in_texture_coords;
}

Ama bence bu bir şanstı. uniforms rasgele erişilmesi amaçlanmamıştır, bu yüzden bu "teknik" her cihazda işe yaramaz korkuyorum.

Bu adam matrislerini doku olarak geçiriyor, ki bu çok güzel bir fikir. 4x32 OES_texture_float doku yaptım, burada her texels bir matris satırı ve her doku satırı bir matris. Bu şekilde erişiyorum:

attribute vec4 in_pos;
attribute vec4 in_normal;
attribute vec2 in_texture_coords;
attribute vec4 in_bone_index;
attribute vec4 in_bone_weight;

varying vec2 fs_texture_coords;

uniform mat4 world_view_projection; // A texture!
uniform sampler2D bones;

void main()
{
    // Skinning
    mat4 bone0 = mat4(
        texture2D(bones, vec2(0.00, in_bone_index.x / 32.0)),
        texture2D(bones, vec2(0.25, in_bone_index.x / 32.0)),
        texture2D(bones, vec2(0.50, in_bone_index.x / 32.0)),
        texture2D(bones, vec2(0.75, in_bone_index.x / 32.0)));
    mat4 bone1 = mat4(
        texture2D(bones, vec2(0.00, in_bone_index.y / 32.0)),
        texture2D(bones, vec2(0.25, in_bone_index.y / 32.0)),
        texture2D(bones, vec2(0.50, in_bone_index.y / 32.0)),
        texture2D(bones, vec2(0.75, in_bone_index.y / 32.0)));
    mat4 bone2 = mat4(
        texture2D(bones, vec2(0.00, in_bone_index.z / 32.0)),
        texture2D(bones, vec2(0.25, in_bone_index.z / 32.0)),
        texture2D(bones, vec2(0.50, in_bone_index.z / 32.0)),
        texture2D(bones, vec2(0.75, in_bone_index.z / 32.0)));
    mat4 bone3 = mat4(
        texture2D(bones, vec2(0.00, in_bone_index.w / 32.0)),
        texture2D(bones, vec2(0.25, in_bone_index.w / 32.0)),
        texture2D(bones, vec2(0.50, in_bone_index.w / 32.0)),
        texture2D(bones, vec2(0.75, in_bone_index.w / 32.0)));
    vec4 transformed_pos =
        ((in_pos * bone0) * in_bone_weight.x) +
        ((in_pos * bone1) * in_bone_weight.y) +
        ((in_pos * bone2) * in_bone_weight.z) +
        ((in_pos * bone3) * in_bone_weight.w);

    gl_Position = world_view_projection * transformed_pos;
    fs_texture_coords = in_texture_coords;
}

Aslında, bu oldukça iyi çalıştı ... Galaxy Note 2'mde denemene kadar. Bu kez derleyici texture2Dköşe gölgeleyicisinde kullanamayacağımdan şikayet etti !

Yani yaptığım şey GPU'nun köşe gölgeleyicisinde doku erişimlerini destekleyip desteklemediğini ve OES_texture_float'ı destekleyip desteklemediğini kontrol etmektir. Varsa, doku yaklaşımını kullanıyorum. Değilse, vektör yaklaşımını kullanıyorum.

Ancak, doku yaklaşımı tüm platformlarda mevcut değildir ve vektör yaklaşımı tesadüfen çalışmaktadır. Kaplama matrislerimi tüm cihazlarda güvenilir bir şekilde çalışan köşe gölgeleyicisine geçirmenin bir yolu olup olmadığını bilmek istiyorum.

Android 4.1+ gibi minimum makul işletim sistemi gereksinimlerine sahip olabilirim, ancak bu gereksinimleri karşılayan tüm cihazlarda çalışan bir çözüme sahip olmak istiyorum.


Alternatifleri düşünemiyorum, TBH Bence en iyi seçenek hangisinin mevcut olduğuna bağlı olarak her iki tekniği de kullanmaktır, eğer ikisi de mevcut değilse GPU arayüzünü kullanmazsanız CPU kaplama uygulamasına (muhtemelen daha az detaylı modellerde) ?).
concept3d

@ concept3d: Bilmiyorum, belki bu sorunu çözmek için tasarlanan veya aynı sonuçlarla kavramsal olarak farklı bir şey yapan android 4.1+ üzerinde var olması garanti edilen bir uzantı. Kendimi birçok konunun genel kavramlarında oldukça yetkin görüyorum, ancak Android platformu hakkındaki bilgim çok sınırlı ve bu soruna tamamen teknik bir çözüm olabileceğini düşünüyordum.
Panda Pijama

Bu yüzden belki de bu yüzden Nexus 7 üzerinde çalışmak için kaplayamadım:: / Teşekkürler, sorunuz gözlerimi açtı!
async

Yanıtlar:


4

Bu, Nexus 7 (Adreno GPU) tarafından uygun olmayan bir davranıştır. "Üniformalar rastgele erişilmek istemiyor" diyorsunuz, ancak spesifikasyonun Ek A'ya göre :

Üniformalar (örnekleyiciler hariç)

Köşe gölgelendiricide, dizi dizine eklemenin tüm biçimleri için destek zorunludur. Parça gölgelendiricide, dizin oluşturma desteği yalnızca sabit dizin ifadeleri için zorunludur.

Bu tartışmadan sesler burada çözüm yoluyla vektörler güvenilir çalışması olasıdır ve diğer GPU'ları (Ben Mali ve PowerVR GPU'larında en azından rasgele birörnek indeksleme çalıştığını biliyorum) taşınabilir olması, böylece bu böcek, sadece tek tip matris diziler için geçerli olduğunu.


Hmm, sanırım bu doğru görünüyor. Sanırım bu konuyu daha önce okumuştum, ama Qualcomm'dan bu sorunu onaylayan bir onay yok.
Panda Pijama
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.