Erstellen von Texturressourcen (Direct3D 10)
Eine Texturressource ist eine strukturierte Sammlung von Daten. In der Regel werden Farbwerte in Texturen gespeichert und während des Renderings von der Pipeline in verschiedenen Phasen für Eingabe und Ausgabe aufgerufen. Das Erstellen von Texturen und definieren, wie sie verwendet werden, ist ein wichtiger Teil des Renderns von interessanten Szenen in Direct3D 10.
Obwohl Texturen in der Regel Farbinformationen enthalten, ermöglicht ihnen das Erstellen von Texturen mithilfe eines anderen _ DXGI-FORMATS das Speichern verschiedener Arten von Daten. Diese Daten können dann von der Direct3D 10-Pipeline auf nicht herkömmliche Weise genutzt werden.
Für alle Texturen gelten Grenzwerte für den Arbeitsspeicher und die enthaltene Texel. Diese Grenzwerte werden durch Ressourcenkonst constants angegeben.
- Erstellen einer Textur aus einer Datei
- Erstellen leerer Texturen
- Mehrere Rendertargets
- Zugehörige Themen
Erstellen einer Textur aus einer Datei
Hinweis
Die D3DX-Hilfsprogrammbibliothek ist für Windows 8 veraltet und wird für Windows Store unterstützt.
Wenn Sie eine Textur in Direct3D 10 erstellen, müssen Sie auch eine Ansicht erstellen. Eine Ansicht ist ein Objekt, das das Gerät darüber informiert, wie während des Renderings auf eine Textur zugegriffen werden soll. Die gängigste Methode für den Zugriff auf eine Textur ist das Lesen aus dieser mithilfe eines Shaders. Eine Shaderressourcenansicht gibt einem Shader an, wie während des Renderings aus einer Textur gelesen werden soll. Die Art der Ansicht, die eine Textur verwendet, muss beim Erstellen angegeben werden.
Das Erstellen einer Textur und das Laden der ursprünglichen Daten kann auf zwei verschiedene Arten erfolgen: Erstellen Sie eine Textur und eine Ansicht separat, oder erstellen Sie die Textur und die Ansicht gleichzeitig. Die API bietet beide Techniken, damit Sie auswählen können, welche Ihren Anforderungen besser entspricht.
Separat erstellen von Textur und Ansicht
Die einfachste Möglichkeit zum Erstellen einer Textur ist das Laden aus einer Bilddatei. Um die Textur zu erstellen, füllen Sie einfach eine Struktur aus, und geben Sie den Namen der Textur D3DX10CreateTextureFromFile an.
ID3D10Device *pDevice = NULL;
// Initialize D3D10 device...
D3DX10_IMAGE_LOAD_INFO loadInfo;
ZeroMemory( &loadInfo, sizeof(D3DX10_IMAGE_LOAD_INFO) );
loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE;
ID3D10Resource *pTexture = NULL;
D3DX10CreateTextureFromFile( pDevice, L"sample.bmp", &loadInfo, NULL, &pTexture, NULL );
Die D3DX-Funktion D3DX10CreateTextureFromFile führt drei Dinge aus: Zuerst wird ein Direct3D 10-Texturobjekt erstellt. zweitens wird die Eingabebilddatei gelesen. drittens werden die Bilddaten im Texturobjekt gespeichert. Im obigen Beispiel wird eine BMP-Datei geladen, aber die Funktion kann eine Vielzahl von Dateitypen laden.
Das Bindungsflag gibt an, dass die Textur als Shaderressource erstellt wird, die es einer Shaderstufe ermöglicht, während des Renderings aus der Textur zu lesen.
Im obigen Beispiel werden nicht alle Ladeparameter angegeben. Tatsächlich ist es oft vorteilhaft, die Ladeparameter einfach auf null zu legen, da D3DX auf der Grundlage des Eingabebilds geeignete Werte auswählen kann. Wenn sie möchten, dass das Eingabebild alle Parameter bestimmt, mit der die Textur erstellt wird, geben Sie einfach NULL für den loadInfo-Parameter wie den folgenden an:
D3DX10CreateTextureFromFile( pDevice, L"sample.bmp", NULL, NULL, &pTexture, NULL );
Die Angabe von NULL für die Ladeinformationen ist eine einfache, aber leistungsstarke Verknüpfung.
Nachdem nun eine Textur erstellt wurde, müssen Sie eine Shaderressourcenansicht erstellen, damit die Textur als Eingabe an einen Shader gebunden werden kann. Da D3DX10CreateTextureFromFile einen Zeiger auf eine Ressource und keinen Zeiger auf eine Textur zurückgibt, müssen Sie den genauen Typ der geladenen Ressource bestimmen. Anschließend können Sie mit CreateShaderResourceVieweine Shaderressourcenansicht erstellen.
D3D10_SHADER_RESOURCE_VIEW_DESC srvDesc;
D3D10_RESOURCE_DIMENSION type;
pTexture->GetType( &type );
switch( type )
{
case D3D10_RESOURCE_DIMENSION_BUFFER:
//...
break;
case D3D10_RESOURCE_DIMENSION_TEXTURE1D:
//...
break;
case D3D10_RESOURCE_DIMENSION_TEXTURE2D:
{
D3D10_TEXTURE2D_DESC desc;
ID3D10Texture2D *pTexture2D = (ID3D10Texture2D*)pTexture;
pTexture2D->GetDesc( &desc );
srvDesc.Format = desc.Format;
srvDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srvDesc.Texture2D.MipLevels = desc.MipLevels;
srvDesc.Texture2D.MostDetailedMip = desc.MipLevels -1;
}
break;
case D3D10_RESOURCE_DIMENSION_TEXTURE3D:
//...
break;
default:
//...
break;
}
ID3D10ShaderResourceView *pSRView = NULL;
pDevice->CreateShaderResourceView( pTexture, &srvDesc, &pSRView );
Obwohl im obigen Beispiel eine 2D-Shader-Ressourcenansicht erstellt wird, ist der Code zum Erstellen anderer Shader-Ressourcen-Ansichtstypen sehr ähnlich. Jede Shaderstufe kann diese Textur jetzt als Eingabe verwenden.
Die Verwendung von D3DX10CreateTextureFromFile und CreateShaderResourceView zum Erstellen einer Textur und der zugehörigen Ansicht ist eine Möglichkeit, eine Textur für die Bindung an eine Shaderstufe vorzubereiten. Eine weitere Möglichkeit besteht in der gleichzeitigen Erstellung der Textur und ihrer Ansicht. Dies wird im nächsten Abschnitt erläutert.
Gleichzeitiges Erstellen von Textur und Ansicht
Direct3D 10 erfordert sowohl eine Textur- als auch eine Shaderressourcenansicht, um während der Laufzeit aus einer Textur zu lesen. Da die Erstellung einer Textur und einer Shader-Ressourcenansicht eine so häufige Aufgabe ist, stellt D3DX das D3DX10CreateShaderResourceViewFromFile-Objekt für Sie zur Vervollst.
D3DX10_IMAGE_LOAD_INFO loadInfo;
ZeroMemory( &loadInfo, sizeof(D3DX10_IMAGE_LOAD_INFO) );
loadInfo.BindFlags = D3D10_BIND_SHADER_RESOURCE;
loadInfo.Format = DXGI_FORMAT_BC1_UNORM;
ID3D10ShaderResourceView *pSRView = NULL;
D3DX10CreateShaderResourceViewFromFile( pDevice, L"sample.bmp", &loadInfo, NULL, &pSRView, NULL );
Mit einem einzelnen D3DX-Aufruf werden sowohl die Textur- als auch die Shaderressourcenansicht erstellt. Die Funktionalität des loadInfo-Parameters bleibt unverändert. Sie können damit anpassen, wie die Textur erstellt wird, oder die erforderlichen Parameter aus der Eingabedatei ableiten, indem Sie NULL für den loadInfo-Parameter angeben.
Das von der D3DX10CreateShaderResourceViewFromFile-Funktion zurückgegebene ID3D10ShaderResourceView-Objekt kann später verwendet werden, um bei Bedarf die ursprüngliche ID3D10Resource-Schnittstelle abzurufen. Dies kann durch Aufrufen der GetResource-Methode erfolgen.
D3DX bietet eine einzelne Funktion, um eine Textur- und Shaderressourcenansicht als Kontinenz zu erstellen. Sie müssen entscheiden, welche Methode zum Erstellen einer Textur und Ansicht den Anforderungen Ihrer Anwendung am besten entspricht.
Nachdem Sie nun wissen, wie Sie eine Textur und ihre Shaderressourcenansicht erstellen, wird im nächsten Abschnitt gezeigt, wie Sie mithilfe eines Shaders Stichproben aus dieser Textur erstellen (lesen).
Erstellen leerer Texturen
Manchmal möchten Anwendungen eine Textur erstellen und die in der Textur zu speichernden Daten berechnen oder die Grafikpipeline verwenden, um in dieser Textur zu rendern und die Ergebnisse später in einer anderen Verarbeitung zu verwenden. Diese Texturen können von der Grafikpipeline oder von der Anwendung selbst aktualisiert werden, je nachdem, welche Art von Verwendung für die Textur beim Erstellen angegeben wurde.
Rendern in eine Textur
Der häufigste Fall beim Erstellen einer leeren Textur, die zur Laufzeit mit Daten gefüllt werden soll, ist der Fall, in dem eine Anwendung in einer Textur rendern und dann die Ergebnisse des Rendering-Vorgangs in einem nachfolgenden Durchgang verwenden möchte. Texturen, die mit diesem Zweck erstellt werden, sollten die Standardverwendung angeben.
Im folgenden Codebeispiel wird eine leere Textur erstellt, in der die Pipeline gerendert und anschließend als Eingabe für einen Shader verwendet werden kann.
// Create the render target texture
D3D10_TEXTURE2D_DESC desc;
ZeroMemory( &desc, sizeof(desc) );
desc.Width = 256;
desc.Height = 256;
desc.MipLevels = 1;
desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R32G32B32A32_FLOAT;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DEFAULT;
desc.BindFlags = D3D10_BIND_RENDER_TARGET | D3D10_BIND_SHADER_RESOURCE;
ID3D10Texture2D *pRenderTarget = NULL;
pDevice->CreateTexture2D( &desc, NULL, &pRenderTarget );
Zum Erstellen der Textur muss die Anwendung einige Informationen zu den Eigenschaften angeben, über die die Textur verfügen soll. Die Breite und Höhe der Textur in Texeln ist auf 256 festgelegt. Für dieses Renderziel benötigen wir nur eine einzelne Mipmapebene. Es ist nur ein Renderziel erforderlich, sodass die Arraygröße auf 1 festgelegt ist. Jedes Texel enthält vier 32-Bit-Gleitkommawerte, die zum Speichern sehr präziser Informationen verwendet werden können (siehe DXGI _ FORMAT). Ein Beispiel pro Pixel ist alles, was benötigt wird. Die Verwendung ist auf den Standardwert festgelegt, da dies die effizienteste Platzierung des Renderziels im Arbeitsspeicher ermöglicht. Schließlich wird die Tatsache angegeben, dass die Textur als Renderziel und als Shaderressource an unterschiedlichen Zeitpunkten gebunden wird.
Texturen können nicht direkt an die Pipeline gerendert werden. Verwenden Sie eine Renderzielansicht, wie im folgenden Codebeispiel gezeigt.
D3D10_RENDER_TARGET_VIEW_DESC rtDesc;
rtDesc.Format = desc.Format;
rtDesc.ViewDimension = D3D10_RTV_DIMENSION_TEXTURE2D;
rtDesc.Texture2D.MipSlice = 0;
ID3D10RenderTargetView *pRenderTargetView = NULL;
pDevice->CreateRenderTargetView( pRenderTarget, &rtDesc, &pRenderTargetView );
Das Format der Renderzielansicht wird einfach auf das Format der ursprünglichen Textur festgelegt. Die Informationen in der Ressource sollten als 2D-Textur interpretiert werden, und wir möchten nur die erste Mipmapebene des Renderziels verwenden.
Ähnlich wie eine Renderzielansicht erstellt werden muss, damit das Renderziel für die Ausgabe an die Pipeline gebunden werden kann, muss eine Shaderressourcenansicht erstellt werden, damit das Renderziel als Eingabe an die Pipeline gebunden werden kann. Dies wird im folgenden Codebeispiel veranschaulicht.
// Create the shader-resource view
D3D10_SHADER_RESOURCE_VIEW_DESC srDesc;
srDesc.Format = desc.Format;
srDesc.ViewDimension = D3D10_SRV_DIMENSION_TEXTURE2D;
srDesc.Texture2D.MostDetailedMip = 0;
srDesc.Texture2D.MipLevels = 1;
ID3D10ShaderResourceView *pShaderResView = NULL;
pDevice->CreateShaderResourceView( pRenderTarget, &srDesc, &pShaderResView );
Die Parameter von Shader-Ressourcenansichtsbeschreibungen ähneln denen von Beschreibungen der Renderzielansicht und wurden aus denselben Gründen ausgewählt.
Manuelles Auffüllen von Texturen
Manchmal möchten Anwendungen Werte zur Laufzeit berechnen, manuell in eine Textur setzen und diese Textur dann von der Grafikpipeline in späteren Renderingvorgängen verwenden lassen. Hierzu muss die Anwendung eine leere Textur so erstellen, dass die CPU auf den zugrunde liegenden Arbeitsspeicher zugreifen kann. Dies erfolgt durch Erstellen einer dynamischen Textur und Erlangen des Zugriffs auf den zugrunde liegenden Arbeitsspeicher durch Aufrufen einer bestimmten Methode. Die erforderliche Vorgehensweise wird im folgenden Codebeispiel veranschaulicht:
D3D10_TEXTURE2D_DESC desc;
desc.Width = 256;
desc.Height = 256;
desc.MipLevels = desc.ArraySize = 1;
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
desc.SampleDesc.Count = 1;
desc.Usage = D3D10_USAGE_DYNAMIC;
desc.BindFlags = D3D10_BIND_SHADER_RESOURCE;
desc.CPUAccessFlags = D3D10_CPU_ACCESS_WRITE;
ID3D10Texture2D *pTexture = NULL;
pd3dDevice->CreateTexture2D( &desc, NULL, &pTexture );
Beachten Sie, dass das Format auf 32 Bits pro Pixel festgelegt ist, wobei jede Komponente durch 8 Bits definiert wird. Der Verwendungsparameter wird auf dynamisch festgelegt, während die Bindungsflags so festgelegt sind, dass angegeben wird, dass auf die Textur von einem Shader zugegriffen wird. Der Rest der Texturbeschreibung ähnelt dem Erstellen eines Renderziels.
Durch Aufrufen von Map kann die Anwendung auf den zugrunde liegenden Speicher der Textur zugreifen. Der abgerufene Zeiger wird dann verwendet, um die Textur mit Daten zu füllen. Dies ist im folgenden Codebeispiel zu sehen.
D3D10_MAPPED_TEXTURE2D mappedTex;
pTexture->Map( D3D10CalcSubresource(0, 0, 1), D3D10_MAP_WRITE_DISCARD, 0, &mappedTex );
UCHAR* pTexels = (UCHAR*)mappedTex.pData;
for( UINT row = 0; row < desc.Height; row++ )
{
UINT rowStart = row * mappedTex.RowPitch;
for( UINT col = 0; col < desc.Width; col++ )
{
UINT colStart = col * 4;
pTexels[rowStart + colStart + 0] = 255; // Red
pTexels[rowStart + colStart + 1] = 128; // Green
pTexels[rowStart + colStart + 2] = 64; // Blue
pTexels[rowStart + colStart + 3] = 32; // Alpha
}
}
pTexture->Unmap( D3D10CalcSubresource(0, 0, 1) );
Mehrere Rendertargets
Bis zu acht Renderzielansichten können gleichzeitig an die Pipeline gebunden werden (mit OMSetRenderTargets). Für jedes Pixel (oder jedes Beispiel, wenn Multisampling aktiviert ist) erfolgt das Mischen unabhängig für jede Renderzielansicht. Zwei der Variablen für den Überblendungszustand – BlendEnable und RenderTargetWriteMask – sind Arrays von acht. Jedes Arraymitglied entspricht einer Renderzielansicht. Bei Verwendung mehrerer Renderziele muss jedes Renderziel denselben Ressourcentyp aufweisen (Puffer, 1D-Textur, 2D-Texturarray usw.) und dieselbe Dimension aufweisen (Breite, Höhe, Tiefe für 3D-Texturen und Arraygröße für Texturarrays). Wenn die Renderziele multisampled sind, müssen sie alle die gleiche Anzahl von Stichproben pro Pixel haben.
Es kann nur ein Tiefen-Schablonenpuffer aktiv sein, unabhängig davon, wie viele Renderziele aktiv sind. Wenn Texturarrays als Renderziele verwendet werden, müssen alle Ansichtsdimensionen übereinstimmen. Die Renderziele müssen nicht das gleiche Texturformat aufweisen.