Motor İşleme boru hattı: Gölgelendiricileri genel hale getirme


10

OpenGL ES 2.0 (şimdilik iOS) kullanarak bir 2D oyun motoru yapmaya çalışıyorum. Objective C Uygulama katmanı yazdım ve ayrı bir bağımsız RendererGLES20 C ++. Oluşturucunun dışında GL'ye özel bir çağrı yapılmaz. Mükemmel çalışıyor.

Ancak gölgelendiricileri kullanırken bazı tasarım sorunlarım var. Her gölgelendiricinin ana çizim çağrısından hemen önce ayarlanması gereken kendine özgü özellikleri ve üniformaları vardır (bu durumda glDrawArrays). Örneğin, bazı geometri çizmek için yapardım:

void RendererGLES20::render(Model * model)
{
    // Set a bunch of uniforms
    glUniformMatrix4fv(.......);
    // Enable specific attributes, can be many
    glEnableVertexAttribArray(......);
    // Set a bunch of vertex attribute pointers:
    glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, m->pCoords);

    // Now actually Draw the geometry
    glDrawArrays(GL_TRIANGLES, 0, m->vertexCount);

    // After drawing, disable any vertex attributes:
    glDisableVertexAttribArray(.......);
}

Gördüğünüz gibi bu kod son derece katı. Başka bir gölgelendirici kullanacak olsaydım, dalgalanma efekti, fazladan üniforma, köşe askısı vb. Geçirmem gerekiyordu.

Gölgelendirici nesnesini tamamen genel yapmanın bir yolu var mı? Like Sadece gölgelendirici nesnesini değiştirmek ve oyun kaynağının yeniden derlenmesinden endişe etmemek istersem ne olur? Oluşturucuyu üniforma ve nitelik vb. Agnostik hale getirmenin herhangi bir yolu var mı? Verileri üniformalara geçirmemiz gerekse de, bunu yapmak için en iyi yer hangisidir? Model sınıfı? Model sınıfı gölgelendiriciye özgü üniformaların ve özelliklerin farkında mı?

Aktör sınıfını aşağıda görebilirsiniz:

class Actor : public ISceneNode
{
    ModelController * model;
    AIController * AI;
};

Model denetleyici sınıfı: class ModelController {class IShader * shader; int textureId; vec4 tonu; float alfa; struct Vertex * vertexArray; };

Shader sınıfı yalnızca shader nesnesini içerir, alt rutinleri derler ve bağlar vb.

Game Logic sınıfında aslında nesneyi oluşturuyorum:

void GameLogic::update(float dt)
{
    IRenderer * renderer = g_application->GetRenderer();

    Actor * a = GetActor(id);
    renderer->render(a->model);
}

Actor ISceneNode'u genişletmesine rağmen, henüz SceneGraph'ı uygulamaya başlamadığımı lütfen unutmayın. Bu sorunu çözer çözmez bunu yapacağım.

Bunu nasıl geliştireceğine dair bir fikrin var mı? İlgili tasarım desenleri vb?

Soruyu okuduğunuz için teşekkür ederim.



Bunun tam bir kopya olup olmadığından emin değilim, ama yapmaya çalıştığınız şeyin etine geliyor, sanırım.
Sean Middleditch

Yanıtlar:


12

Gölgelendirici sisteminizi daha fazla veriye dayalı hale getirmek mümkündür, böylece üniforma ve tepe biçimleri için gölgelendiriciye özgü çok fazla kodunuz yoktur, ancak bunları gölgelendiricilere ekli meta verilere dayanarak programlı olarak ayarlayın.

İlk olarak feragatname: veriye dayalı bir sistem yeni gölgelendiricilerin eklenmesini kolaylaştırabilir, ancak diğer yandan sistemin artan karmaşıklığı açısından maliyetlerle birlikte gelir ve bu da bakım ve hata ayıklamayı zorlaştırır. Bu nedenle, sizin için ne kadar veri güdülüğünün iyi olacağını düşünmek iyi bir fikirdir (küçük bir proje için, cevap "hiçbiri" olabilir) ve aşırı derecede genelleştirilmiş bir sistem kurmaya çalışmayın.

Tamam, önce köşe biçimleri (özellikler) hakkında konuşalım. Verilecek verileri içeren bir yapı glVertexAttribPointer(tek bir özniteliğin dizini, türü, boyutu vb.) Yaparak ve tüm köşe biçimini temsil edecek bu yapılardan oluşan bir diziye sahip olarak bir veri açıklaması oluşturabilirsiniz . Bu bilgi verildiğinde, köşe öznitelikleriyle ilgili tüm GL durumunu programlı olarak ayarlayabilirsiniz.

Bu açıklamayı dolduracak veriler nereden geliyor? Kavramsal olarak, bence en temiz yol gölgelendiriciye ait olmaktır. Bir kafes için köşe verilerini oluşturduğunuzda, kafes üzerinde hangi gölgelendiricinin kullanıldığını arar, bu gölgelendiricinin gerektirdiği köşe biçimini bulur ve köşe tamponunu buna göre oluşturur. Her gölgelendiricinin beklediği köşe biçimini belirtmesi için sadece bir yol gerekir.

Bunu yapmanın çeşitli yolları vardır; örneğin gölgelendiricideki öznitelikler için standart bir ad kümesi ("attrPosition", "attrNormal" vb.) ve "position 3 float" gibi bazı sabit kodlanmış kurallarınız olabilir. Daha sonra glGetAttribLocationgölgelendiricinin hangi öznitelikleri kullandığını sorgulamak için veya benzerliğini kullanır ve köşe biçimini oluşturmak için kuralları uygularsınız. Başka bir yol, biçimi tanımlayan, gölgelendirici kaynağına bir yorumda gömülü olan ve araçlarınız veya bu satırlardaki bir şey tarafından çıkarılan bir XML pasajına sahip olmaktır.

Üniformalar için, OpenGL 3.1 veya üstünü kullanabiliyorsanız, tek tip arabellek nesneleri (D3D'nin sabit arabelleklerinin OpenGL eşdeğeri) kullanılması iyi bir fikirdir . Ne yazık ki, GL ES 2.0 bunlara sahip değil, bu yüzden üniformalar ayrı ayrı ele alınmalıdır. Bunu yapmanın bir yolu, ayarlamak istediğiniz her parametre için tek tip konum içeren bir yapı oluşturmak olacaktır - kamera matrisi, aynasal güç, dünya matrisi vb. Örnekleyici konumları da burada olabilir. Bu yaklaşım, tüm gölgelendiriciler arasında paylaşılan standart bir parametre seti olmasına bağlıdır. Her gölgelendiricinin her bir parametreyi kullanması gerekmez, ancak tüm parametrelerin bu yapıda olması gerekir.

Her gölgelendiricinin bu yapının bir örneği olur ve gölgelendiriciyi yüklediğinizde, tüm glGetUniformLocationadları , standart adları ve kullanarak tüm parametrelerin konumlarını sorgularsınız . Daha sonra, koddan bir üniforma ayarlamanız gerektiğinde, bu gölgelendiricide mevcut olup olmadığını kontrol edebilir ve sadece konumunu arayabilir ve ayarlayabilirsiniz.

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.