İngilizce dilinde oku

Aracılığıyla paylaş


Birden Çok Geometri Örneğini Verimli Bir Şekilde Çizme (Direct3D 9)

Aynı geometriyi kullanan birçok nesne içeren bir görünümde, işleyiciye sağlamanız gereken veri miktarını azaltarak bu geometrinin birçok örneğini farklı yönlerde, boyutlarda, renklerde vb. önemli ölçüde daha iyi bir performansla çizebilirsiniz.

Bu, iki tekniğin kullanılmasıyla gerçekleştirilebilir: ilki dizinli geometriyi çizmek için, ikincisi dizine alınamayan geometri için. Her iki teknikte de iki köşe arabelleği kullanılır: biri geometri verilerini sağlamak için, diğeri de nesne başına örnek verilerini sağlamak için. Örnek verileri dönüşüm, renk verileri veya aydınlatma verileri gibi çok çeşitli bilgiler olabilir; temel olarak köşe deklarasyonunda açıklayabileceğiniz her şey. Bu tekniklerle birçok geometri örneğinin çizilmesi, işleyiciye gönderilen veri miktarını önemli ölçüde azaltabilir.

Dizinli Geometri Çizme

Köşe arabelleği, köşe bildirimi tarafından tanımlanan köşe başına verileri içerir. Aşağıdaki diyagramda gösterildiği gibi her köşenin bir bölümünün geometri verileri içerdiğini ve her köşenin bir bölümünün nesne başına örnek verileri içerdiğini varsayalım.

İndekslenmiş geometridiyagramı

Bu teknik, 3_0 köşe gölgelendiricisi modelini destekleyen bir cihaz gerektirir. Bu teknik herhangi bir programlanabilir gölgelendiriciyle çalışır ancak sabit işlev işlem hattıyla çalışmaz.

Yukarıda gösterilen köşe arabellekleri için ilgili köşe arabellek bildirimleri şunlardır:

const D3DVERTEXELEMENT9 g_VBDecl_Geometry[] =
{
{0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
{0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT,  0},
{0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0},
{0, 48, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
D3DDECL_END()
};

const D3DVERTEXELEMENT9 g_VBDecl_InstanceData[] =
{
{1, 0,  D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
{1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2},
{1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3},
{1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4},
{1, 64, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,    0},
D3DDECL_END()
};

Bu bildirimler iki köşe arabelleği tanımlar. İlk bildirim (1. sütundaki sıfırlarla gösterilen akış 0 için), konum, normal, tanjant, binormal ve doku koordinat verilerinden oluşan geometri verilerini tanımlar.

İkinci bildirim (1. sütunda belirtilen akış 1 için), nesne başına örnek verilerini tanımlar. Her örnek dört bileşenli kayan nokta sayısı ve dört bileşenli bir renkle tanımlanır. İlk dört değer bir 4x4 matrisi başlatmak için kullanılabilir; bu da bu verilerin geometrinin her örneğini benzersiz olarak boyutlandıracağı, konumlandıracağı ve döndüreceği anlamına gelir. İlk dört bileşen doku koordinatı semantiği kullanır ve bu örnekte "bu genel dört bileşenli bir sayıdır" anlamına gelir. Köşe bildiriminde rastgele veriler kullandığınızda, işaretlemek için doku koordinatı semantiği kullanın. Akıştaki son öğe renk verileri için kullanılır. Bu, her örneğe benzersiz bir renk vermek için köşe gölgelendiricisine uygulanabilir.

İşlemeden önce, köşe arabellek akışlarını cihaza bağlamak için SetStreamSourceFreq çağırmanız gerekir. Her iki köşe arabelleği de bağlayan bir örnek aşağıda verilmiştir:

// Set up the geometry data stream
pd3dDevice->SetStreamSourceFreq(0,
    (D3DSTREAMSOURCE_INDEXEDDATA | g_numInstancesToDraw));
pd3dDevice->SetStreamSource(0, g_VB_Geometry, 0,
    D3DXGetDeclVertexSize( g_VBDecl_Geometry, 0 ));

// Set up the instance data stream
pd3dDevice->SetStreamSourceFreq(1,
    (D3DSTREAMSOURCE_INSTANCEDATA | 1));
pd3dDevice->SetStreamSource(1, g_VB_InstanceData, 0, 
    D3DXGetDeclVertexSize( g_VBDecl_InstanceData, 1 ));

SetStreamSourceFreq, dizine alınan geometri verilerini tanımlamak için D3DSTREAMSOURCE_INDEXEDDATA kullanır. Bu durumda akış 0, nesne geometrisini açıklayan dizine alınan verileri içerir. Bu değer, çizilen geometri örneklerinin sayısıyla mantıksal olarak birleştirilir.

D3DSTREAMSOURCE_INDEXEDDATA ve çizilecek örnek sayısının her zaman sıfırıncı akışta ayarlanması gerektiğini unutmayın.

İkinci çağrıda SetStreamSourceFreq, örnek verilerini içeren akışı tanımlamak için D3DSTREAMSOURCE_INSTANCEDATA kullanır. Her köşe bir örnek veri kümesi içerdiğinden bu değer mantıksal olarak 1 ile birleştirilir.

Son iki çağrı SetStreamSource köşe arabellek işaretçilerini cihaza bağlar.

Örnek verilerini işlemeyi bitirdiğinizde, köşe akışı sıklığını varsayılan durumuna geri döndürdiğinizden emin olun (bu işlem, instancing kullanmaz). Bu örnekte iki akış kullanıldığı için her iki akışı da aşağıda gösterildiği gibi ayarlayın:

pd3dDevice->SetStreamSourceFreq(0,1);
pd3dDevice->SetStreamSourceFreq(1,1);

Dizinli Geometri Performansı Karşılaştırması

Bu tekniğin her uygulamada işleme süresini ne kadar azaltabileceği hakkında tek bir sonuç elde etmek mümkün olmasa da, çalışma zamanına akışla aktarılan veri miktarındaki farkı ve instancing tekniğini kullanırsanız azaltılacak durum değişikliklerinin sayısını göz önünde bulundurun. Bu işleme dizisi, aynı geometrinin birden çok örneğini çizme avantajından yararlanır:

if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
    // Set up the geometry data stream
    pd3dDevice->SetStreamSourceFreq(0,
                (D3DSTREAMSOURCE_INDEXEDDATA | g_numInstancesToDraw));
    pd3dDevice->SetStreamSource(0, g_VB_Geometry, 0,
                D3DXGetDeclVertexSize( g_VBDecl_Geometry, 0 ));

    // Set up the instance data stream
    pd3dDevice->SetStreamSourceFreq(1,
                (D3DSTREAMSOURCE_INSTANCEDATA | 1));
    pd3dDevice->SetStreamSource(1, g_VB_InstanceData, 0, 
                D3DXGetDeclVertexSize( g_VBDecl_InstanceData, 1 ));

    pd3dDevice->SetVertexDeclaration( ... );
    pd3dDevice->SetVertexShader( ... );
    pd3dDevice->SetIndices( ... );

    pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 
                g_dwNumVertices, 0, g_dwNumIndices/3 );
    
    pd3dDevice->EndScene();
}

İşleme döngüsünün bir kez çağrıldığına, geometri verilerinin bir kez ve n örneğin bir kez akışa alındığını dikkat edin. Bu sonraki render dizisi aynı işlevselliğe sahiptir, ancak instansiyasyondan yararlanmaz.

if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
    for(int i=0; i < g_numObjects; i++)
    {
        pd3dDevice->SetStreamSource(0, g_VB_Geometry, 0,
                D3DXGetDeclVertexSize( g_VBDecl_Geometry, 0 ));


        pd3dDevice->SetVertexDeclaration( ... );
        pd3dDevice->SetVertexShader( ... );
        pd3dDevice->SetIndices( ... );

        pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 
                g_dwNumVertices, 0, g_dwNumIndices/3 );
    }                             
    
    pd3dDevice->EndScene();
}

İşleme döngüsünün tamamının, her nesneyi çizmek için ikinci bir döngü tarafından sarmalandığını görebilirsiniz. Artık geometri verileri işleyici n kez (bir kez yerine) içine akışla aktarılır ve tüm işlem hattı durumları da çizilen her nesne için yedekli olarak ayarlanabilir. Bu işleme dizisinin çok daha yavaş olma olasılığı çok yüksektir. Ayrıca DrawIndexedPrimitiveparametrelerinin iki işleme döngüsü arasında değişmediğine de dikkat edin.

İndekslenmemiş Geometri Çizimi

Çizim Dizinli Geometri'da, köşe arabellekleri daha verimli bir şekilde birden fazla dizinli geometri örneği çizmek üzere yapılandırıldı. Ayrıca, dizinlenmemiş geometri çizmek için SetStreamSourceFreq'i kullanabilirsiniz. Bunun için farklı bir köşe arabelleği düzeni gerekir ve farklı kısıtlamaları vardır. Indekssiz geometri çizmek için vertex arabelleklerinizi aşağıdaki diyagramda gösterildiği gibi hazırlayın.

İndekslenmemiş geometri için köşe arabellek diyagramı

Bu teknik, herhangi bir cihazda donanım hızlandırma tarafından desteklenmez. Yalnızca yazılım tabanlı köşe işleme tarafından desteklenir ve yalnızca vs_3_0 gölgelendiricilerle çalışır.

Bu teknik dizine alınmamış geometriyle çalıştığından dizin arabelleği yoktur. Diyagramda gösterildiği gibi, geometri içeren köşe arabelleği geometri verilerinin n kopyasını içerir. Çizilen her örnek için geometri verileri ilk köşe arabelleğinden, örnek verileri ise ikinci köşe arabelleğinden okunur.

İlgili köşe arabelleği bildirimleri şunlardır:

const D3DVERTEXELEMENT9 g_VBDecl_Geometry[] =
{
{0,  0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0},
{0, 12, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL,   0},
{0, 24, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TANGENT,  0},
{0, 36, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BINORMAL, 0},
{0, 48, D3DDECLTYPE_FLOAT2, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 0},
D3DDECL_END()
};

const D3DVERTEXELEMENT9 g_VBDecl_InstanceData[] =
{
{1, 0,  D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 1},
{1, 16, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 2},
{1, 32, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 3},
{1, 48, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, 4},
{1, 64, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR,    0},
D3DDECL_END()
};

Bu bildirimler, dizine alınan geometri örneğinde yapılan bildirimlerle aynıdır. Bir kez daha, ilk bildirim (akış 0 için) geometri verilerini tanımlarken ikinci bildirim (akış 1 için) nesne başına örnek verilerini tanımlar. İlk köşe arabelleği oluşturduğunuzda, çizilecek geometri verilerinin örnek sayısıyla yüklediğinizden emin olun.

İşlemeden önce, çalışma zamanına ilk köşe arabelleğinin n örneğe nasıl bölüneceğini bildiren ayırıcıyı ayarlamanız gerekir. Ardından aşağıdaki gibi SetStreamSourceFreq kullanarak ayırıcıyı ayarlayın:

// Set the divider
pd3dDevice->SetStreamSourceFreq(0, 1);
// Bind the stream to the vertex buffer
pd3dDevice->SetStreamSource(0, g_VB_Geometry, 0,
        D3DXGetDeclVertexSize( g_VBDecl_Geometry, 0 ));

// Set up the instance data stream
pd3dDevice->SetStreamSourceFreq(1, verticesPerInstance);
pd3dDevice->SetStreamSource(1, g_VB_InstanceData, 0, 
        D3DXGetDeclVertexSize( g_VBDecl_InstanceData, 1 ));

SetStreamSourceFreq ilk çağrısı, 0 akışının m köşelerinin n örneğini içerdiğini söyler. SetStreamSource ardından 0 akışını geometri köşe arabelleğine bağlar.

İkinci çağrıda SetStreamSourceFreq, örnek verilerinin kaynağı olarak akış 1'i tanımlar. İkinci parametre, her nesnedeki (m) köşe sayısıdır. Örnek veri akışının her zaman ikinci akış olarak bildirilmesi gerektiğini unutmayın. SetStreamSource, ardından akış 1'i örnek verilerini içeren köşe arabelleğine bağlar.

Örnek verilerini işlemeyi bitirdiğinizde köşe akışı sıklığını varsayılan durumuna geri döndürdiğinizden emin olun. Bu örnekte iki akış kullanıldığı için her iki akışı da aşağıda gösterildiği gibi ayarlayın:

pd3dDevice->SetStreamSourceFreq(0,1);
pd3dDevice->SetStreamSourceFreq(1,1);

Endekslenmemiş Geometri Performansı Karşılaştırması

Bu örnek oluşturma stilinin en büyük avantajı, dizine alınamayan geometride kullanılabilmesidir. Bu tekniğin her uygulamada işleme süresini ne kadar azaltabileceği hakkında tek bir sonuç elde etmek mümkün olmasa da, çalışma zamanına akışı yapılan veri miktarındaki farkı ve aşağıdaki işleme dizisi için azaltılacak durum değişikliklerinin sayısını göz önünde bulundurun:

if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
    // Set the divider
    pd3dDevice->SetStreamSourceFreq(0, 1);
    pd3dDevice->SetStreamSource(0, g_VB_Geometry, 0,
                D3DXGetDeclVertexSize( g_VBDecl_Geometry, 0 ));

    // Set up the instance data stream
    pd3dDevice->SetStreamSourceFreq(1, verticesPerInstance));
    pd3dDevice->SetStreamSource(1, g_VB_InstanceData, 0, 
                D3DXGetDeclVertexSize( g_VBDecl_InstanceData, 1 ));

    pd3dDevice->SetVertexDeclaration( ... );
    pd3dDevice->SetVertexShader( ... );
    pd3dDevice->SetIndices( ... );

    pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 
                g_dwNumVertices, 0, g_dwNumIndices/3 );
    
    pd3dDevice->EndScene();
}

İşleme döngüsünün bir kez çağrıldığına dikkat edin. Geometri verilerinin akışı bir kez yapılır, ancak akışı yapılan geometrinin n örneği vardır. Örnek köşe arabelleğindeki veriler bir kez akışa alınır. Bu sonraki render sırası aynı işlevselliğe sahiptir, ancak instancing avantajını kullanmaz.

if( SUCCEEDED( pd3dDevice->BeginScene() ) )
{
    for(int i=0; i < g_numObjects; i++)
    {
        pd3dDevice->SetStreamSource(0, g_VB_Geometry, 0,
                D3DXGetDeclVertexSize( g_VBDecl_Geometry, 0 ));

        pd3dDevice->SetVertexDeclaration( ... );
        pd3dDevice->SetVertexShader( ... );
        pd3dDevice->SetIndices( ... );

        pd3dDevice->DrawIndexedPrimitive( D3DPT_TRIANGLELIST, 0, 0, 
                g_dwNumVertices, 0, g_dwNumIndices/3 );
    }
    
    pd3dDevice->EndScene();
}

Nesneleştirme olmadan, her bir nesneyi çizmek için işleme döngüsünü ikinci bir döngü ile sarmalamak gerekir. İkinci işleme döngüsünü ortadan kaldırarak, döngü içinde çağrılan daha az işleme durumu değişikliği nedeniyle daha iyi performans beklemelisiniz.

Genel olarak, dizine alınan teknik geometri verilerinin yalnızca bir kopyasını akışla aktardığından dizine alınan tekniğin (Dizine Alınan GeometriÇizim) dizine eklenmemiş teknikten (Dizinli Olmayan Geometri) daha iyi performans göstermesini beklemek mantıklıdır. DrawIndexedPrimitiveparametrelerinin işleme dizilerinden hiçbirinde değişmediğine dikkat edin.

Gelişmiş Konular

İndirme Örneği