Ich mache das wie folgt.
IDirect3DDevice9 :: GetBackBuffer : Erhalten Sie Zugriff auf das IDirect3DSurface9, das den Backpuffer darstellt, wie Sie es derzeit haben. Vergessen Sie nicht, diese Oberfläche freizugeben, wenn Sie fertig sind, da dieser Aufruf den Referenzzähler erhöht!
IDirect3DSurface :: GetDesc : Ruft die Beschreibung der hinteren Pufferoberfläche ab , die Ihnen die Breite, Höhe und das Format angibt .
IDirect3DDevice9 :: CreateOffscreenPlainSurface : Erstellen Sie ein neues Oberflächenobjekt in D3DPOOL_SCRATCH. Normalerweise möchten Sie dieselbe Breite, Höhe und dasselbe Format verwenden (dies ist jedoch bei dieser Methode nicht erforderlich). Wieder freigeben, wenn Sie fertig sind. Wenn Sie diesen Vorgang in jedem Frame ausführen (in diesem Fall sollten Sie besser nach Alternativen suchen, z. B. nach einem Shader-basierten Ansatz für das, was Sie tun möchten), können Sie die Offscreen-Oberfläche einfach einmal beim Start erstellen und wiederverwenden es, anstatt es jedes Bild zu erstellen.
D3DXLoadSurfaceFromSurface : Kopieren von der hinteren Pufferoberfläche auf die Offsceen-Ebene. Dadurch wird automatisch eine Größen- und Formatkonvertierung für Sie durchgeführt. Wenn Sie das Format nicht ändern möchten oder müssen, können Sie alternativ IDirect3DDevice9 :: GetRenderTargetData verwenden . Wenn dies jedoch der Fall ist , erstellen Sie stattdessen die Offscreen-Oberfläche in D3DPOOL_SYSTEMMEM.
IDirect3DSurface9 :: LockRect : Erhalten Sie Zugriff auf die Daten in der Offscreen-Ebene und haben Sie Ihren eigenen bösen Weg damit; UnlockRect wenn fertig.
Das sieht nach viel mehr Code aus, aber Sie werden feststellen, dass es genauso schnell ist wie glReadPixels und sogar schneller sein kann, wenn Sie keine Formatkonvertierung durchführen müssen (was glReadPixels mit GL_RGB mit ziemlicher Sicherheit tun).
Bearbeiten, um hinzuzufügen: einige (überlegte und fertige) Hilfsfunktionen, die ich auch habe, die für die Verwendung dieser Methode für Screenshots nützlich sein können:
// assumes pitch is measured in 32-bit texels, not bytes; use locked_rect.Pitch >> 2
void CollapseRowPitch (unsigned *data, int width, int height, int pitch)
{
if (width != pitch)
{
unsigned *out = data;
// as a minor optimization we can skip the first row
// since out and data point to the same this is OK
out += width;
data += pitch;
for (int h = 1; h < height; h++)
{
for (int w = 0; w < width; w++)
out[w] = data[w];
out += width;
data += pitch;
}
}
}
void Compress32To24 (byte *data, int width, int height)
{
byte *out = data;
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++, data += 4, out += 3)
{
out[0] = data[0];
out[1] = data[1];
out[2] = data[2];
}
}
}
// bpp is bits, not bytes
void WriteDataToTGA (char *name, void *data, int width, int height, int bpp)
{
if ((bpp == 24 || bpp == 8) && name && data && width > 0 && height > 0)
{
FILE *f = fopen (name, "wb");
if (f)
{
byte header[18];
memset (header, 0, 18);
header[2] = 2;
header[12] = width & 255;
header[13] = width >> 8;
header[14] = height & 255;
header[15] = height >> 8;
header[16] = bpp;
header[17] = 0x20;
fwrite (header, 18, 1, f);
fwrite (data, (width * height * bpp) >> 3, 1, f);
fclose (f);
}
}
}