[D3D9] 红龙书

来源:互联网 发布:长虹网络电视看直播 编辑:程序博客网 时间:2024/06/05 16:52

注意:阅读本文时,需要读者具有D3D9纹理渲染的基础。

红龙书第六章,介绍了纹理映射的知识。但是运行书中的纹理矩形demo(工程名TexQuad)时,发现图片显示模糊,尝试修改D3DSAMP_MINFILTER和D3DSAMP_MAGFILTER的值后 效果依旧不理想 。

经过调查与编码验证,发现显示图片时如果使用离屏表面,就不会有以上问题。书中TexQuad工程的逻辑就不阐述了 感兴趣的可以自己研究一下,本文重点介绍离屏表面的方法。

需要定义的相关变量如下:

HWND m_hPreview; // 预览窗口的句柄SIZE m_szD3DResolution; // 初始化D3D设备的宽高 (通常使用显示器的宽高 如果有多个显示器 则使用最大的宽高)LPDIRECT3D9 m_pDirect3D9; // D3D9对象LPDIRECT3DDEVICE9 m_pDevice9; // 宽高使用m_szD3DResolutionLPDIRECT3DTEXTURE9 m_pTexture9; // 宽高使用m_szD3DResolutionLPDIRECT3DVERTEXBUFFER9m_pVertexBuffer9; // 顶点缓冲区SIZE m_szVideoResolution; // 视频数据的宽高(与预览窗口宽高无关)LPDIRECT3DSURFACE9 m_pOffscreenSurface; // 缓冲离屏表面,临时保存一帧图像的数据 宽高使用m_szVideoResolution

本文重点介绍:初始化D3D、渲染一帧图像。(文中只会提及与离屏表面相关的逻辑,需要读者具有纹理渲染的基础)。

1、初始化D3D对象

(1)初始化D3D设备对象、纹理对象、顶点缓冲(宽高使用显示器宽高,而不是使用预览窗口的宽高。如果有多个显示器 则使用最大的宽高)
    注意需要调用 如下代码:
m_pDevice9->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);m_pDevice9->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
(2)初始化离屏表面m_pOffscreenSurface(宽高使用视频帧的宽高值)
D3DDISPLAYMODE dm = {};m_pDirect3D9->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &dm);m_pDevice9->CreateOffscreenPlainSurface(m_szVideoResolution.cx,m_szVideoResolution.cy, dm.Format,D3DPOOL_DEFAULT, &m_pOffscreenSurface,NULL);
2、渲染一帧图像
(1)获取到一帧图像, 将数据写入到离屏表面m_pOffscreenSurface中
关键词:LPDIRECT3DSURFACE9::LockRect、memcpy、LPDIRECT3DSURFACE9::UnlockRect

BOOL CD3D9Render::WriteOffscreenSurface(BYTE* pData){if (!m_bInited || !pData)return FALSE;  D3DLOCKED_RECT lockRect = {};   if (FAILED(m_pOffscreenSurface->LockRect(&lockRect, NULL, 0)))return FALSE;BYTE* pDest = (BYTE*)lockRect.pBits;int nStride = m_szVideoResolution.cx * 4; // 4 : ARGBassert(lockRect.Pitch == nStride);for (LONG i = 0; i < m_szVideoResolution.cy; i++){memcpy(pDest + (i * nStride),   pData + (i * nStride),   nStride);}m_pOffscreenSurface->UnlockRect();return TRUE;}

(2)将离屏表面的数据,复制到m_pTexture9 
关键词: LPDIRECT3DTEXTURE9::GetSurfaceLevel、LPDIRECT3DDEVICE9::StretchRect
RECT rcSrc = {0, 0, m_szVideoResolution.cx, m_szVideoResolution.cy};LPDIRECT3DSURFACE9 pSurface9 = NULL;m_pTexture9->GetSurfaceLevel(0, &pSurface9);CRect rcDst;GetClientRect(m_hPreview, &rcDst);// 如果预览窗口的宽高 大于初始化D3D时的宽高  StretchRect会调用失败assert(rcDst.width <= m_szD3DResolution.cx  && rcDst.height <= m_szD3DResolution.cy);m_pDirect3DDevice9->StretchRect(m_pOffscreenSurface, &rcSrc,  // sourcepSurface9, &rcDst, // destD3DTEXF_LINEAR);
(3)实际的渲染函数调用,逻辑与普通的纹理渲染是相同的(可以参考TexQuad的逻辑)
m_pDevice9->BeginScene m_pDevice9->SetTexture(0, m_pTexture9)m_pDevice9->DrawPrimitive m_pDevice9->EndScenem_pDevice9->Present
注意
如果预览窗口的宽或高,大于初始化D3D对象时的宽高(即m_szD3DResolution),那么调用LPDIRECT3DDEVICE9::StretchRect时会失败。
所以要满足一个要求:m_hPreview.width <= m_szD3DResolution.cx  && m_hPreview.height <= m_szD3DResolution.cy。
通常可以使用最大显示器的宽高来初始化D3D,因为一般来说,很少有应用程序中预览窗口的宽高,会大于显示器宽高的情况。
0 0
原创粉丝点击