วิธีคัดลอกข้อมูล frontBuffer ไปยังพื้นผิว DirectX 9

ดูเหมือนว่าฉันไม่สามารถหาวิธีสร้างพื้นผิวจากข้อมูลพื้นผิวที่ฉันได้รับผ่านข้อมูลบัฟเฟอร์ด้านหน้าของแอปพลิเคชันของฉันได้

นี่คือรหัสที่ฉันค่อนข้างแน่ใจว่าใช้งานได้ (Direct X 9, C++)

// capture screen
IDirect3DSurface9* pSurface;
g_pd3dDevice->CreateOffscreenPlainSurface(640, 480,
    D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &pSurface, NULL);
g_pd3dDevice->GetFrontBufferData(0, pSurface);

ตอนนี้ฉันมี frontBufferData แล้ว ฉันต้องการสร้างออบเจ็กต์ IDirect3DTexture9 ด้วย

ฟังก์ชันนี้ / D3DXCreateTextureFromFileInMemory / ดูเหมือนจะสมเหตุสมผลที่สุด แต่ดูเหมือนจะไม่ช่วยอะไร

ฉันค่อนข้างแน่ใจว่ามีวิธีการทำเช่นนี้ แต่ยากฉันไม่แน่ใจว่าทำอย่างไร ความช่วยเหลือใด ๆ จะได้รับการต้อนรับอย่างมาก!

ขอบคุณ!


person zeroxgames    schedule 30.05.2012    source แหล่งที่มา


คำตอบ (1)


ควรใช้ GetRenderTargetData() แทน GetFrontBufferData() เนื่องจากแบบแรกเร็วกว่า ด้วยที่กล่าวว่านั่นไม่ใช่คำถามจริงๆ คุณต้องการจัดเก็บข้อมูลที่คุณได้รับจากบัฟเฟอร์หน้าหรือสิ่งที่คุณสังเกตบนหน้าจออยู่เป็นพื้นผิว

ก่อนอื่น IDirect3DTexture9 และ IDirect3DSurface9 จริงๆ แล้วเป็นพี่น้องกัน แต่ ไม่ เหมือนกัน แม้ว่า ณ จุดใดจุดหนึ่งในระดับชั้นของพวกเขา พวกเขาจะมาบรรจบกันที่ IDirect3DResource9 (ซึ่งก็สมเหตุสมผลดีเหมือนกัน ทรัพยากร). สิ่งที่ดีเกี่ยวกับทั้งคู่คือพวกเขาใช้ฟังก์ชันทั่วไป โดยเฉพาะความเป็นไปได้ของ LockRect() และการคัดลอกข้อมูลจากพื้นผิวด้วยตนเอง (ซึ่งก็คืออย่างคร่าวๆ เป็นเพียงพื้นผิวระดับ mipmap เดียว (กลุ่มของ พิกเซล) ไปยังพื้นผิว (ซึ่งอาจประกอบด้วยระดับ mipmap หลายระดับ) ดังนั้นเป้าหมายของคุณคือพื้นผิวระดับ 0 ของวัตถุพื้นผิว

ด้วยเหตุนี้ เนื่องจาก CreateOffscreenPlainSurface() ทั้งหมดถูกพิจารณาว่าแยกจากกัน เราจึงไม่พบพื้นผิวหลักที่พื้นผิวนี้อาจเป็นลูกของ (เป็นแผนที่ขนาดย่อของพื้นผิวโดยเฉพาะ) เรื่องสั้นสั้น หากเราไม่ LockRect ทั้งสองอย่างและคัดลอกข้อมูลด้วยตนเอง เราก็สามารถใช้ StretchRect() ได้

แม้ว่าชื่อของมันอาจจะไม่ได้บอกถึงจุดประสงค์ของมัน แต่มันก็จะช่วยเราได้ อย่าลืมพูดถึงการเปรียบเทียบของเราระหว่างพื้นผิวและพื้นผิว พื้นผิวเป็นเหมือนน้องชายคนเล็กของพวกเขา ถ้าคุณกำหนดพื้นผิวอย่างถูกต้อง (เหมือนกับพื้นผิว) จริงๆ แล้วคุณจะได้รับระดับ miplevel อัตโนมัติ ซึ่งคุณสามารถกำหนดจำนวนพื้นผิวได้ด้วยตนเอง แต่โดยพื้นฐานแล้ว แต่ละระดับเหล่านี้เป็นเพียงพื้นผิว และ "การแปลง" จาก IDirect3DSurface9 เป็น IDirect3DTexture9 เป็นเพียงเรื่องของการบรรจุพื้นผิว miplevel ที่เหมาะสม (ซึ่งในกรณีนี้ควรจะเป็นระดับ 0 เนื่องจากโดยพื้นฐานแล้วมันเป็นภาพหน้าจอ)

ดังนั้นการจิบสิ่งนี้ลงในโค้ดหยาบจะทำให้เรา:

IDirect3DTexture9* texture; // needs to be created, of course
IDirect3DSurface9* dest = NULL; // to be our level0 surface of the texture
texture->GetSurfaceLevel(0, &dest);
g_pD3DDevice->StretchRect(pSurface, NULL, dest, NULL, D3DTEXF_LINEAR);

และไปได้แล้ว IDirect3DTexture9 หนึ่งอันที่จะไป คุณต้องการมันฝรั่งทอดด้วยไหม? โปรดทราบว่าฉันกำลังใช้งานหน่วยความจำที่นี่ ฉันไม่ได้แตะ DX9 มาระยะหนึ่งแล้ว (เลิกใช้ DX10) หวังว่ามันจะช่วยได้

person Community    schedule 30.05.2012
comment
ด้วยความยินดี. โปรดพิจารณายอมรับว่าสิ่งนี้เป็นคำตอบหากสามารถแก้ไขปัญหาของคุณได้ - person ; 02.06.2012