在Directx11教程(6)中, 我们曾经实现过这个功能,但那时是在SystemClass中,处理WM_SIZE时候,重新调用m_Graphics的初始化函数,这样的话,它的成员变量D3D类还有其它几个成员类,都会重新创建,所以我们的场景等于是从头重新渲染。对于静态场景,这没有问题,但是对于动画场景,我们一改变窗口大小,动画就会从头播放,这显然不是我们所希望的。
本章中,我们在D3DClass类中新建一个函数,每次改变窗口大小时候,我们就改变framebuffer大小,然后重新建立目标渲染视图、深度模版视图等等。代码是在myTutorialD3D_23的基础上改写的。
最关键的代码就是这一行:
m_swapChain->ResizeBuffers(1, screenWidth, screenHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0);
D3Class类中增加的函数为:
bool D3DClass::ResizeBuffer(int screenWidth, int screenHeight) { HRESULT result;
//交换链为空直接返回 if(!m_swapChain) return false;
//窗口最小化时候为0,会创建缓冲失败 if(screenHeight < 1) screenHeight = 1; if(screenWidth < 1) screenWidth = 1;
if(m_renderTargetView) { m_renderTargetView->Release(); m_renderTargetView = 0; } if(m_depthStencilView) { m_depthStencilView->Release(); m_depthStencilView = 0; }
if(m_depthStencilBuffer) { m_depthStencilBuffer->Release(); m_depthStencilBuffer = 0; }
//改变交换链中后后缓冲大小后,重新创建渲染目标视图 result = m_swapChain->ResizeBuffers(1, screenWidth, screenHeight, DXGI_FORMAT_R8G8B8A8_UNORM, 0); if(FAILED(result)) { HR(result); return false; } // 得到交换链中的后缓冲指针. ID3D11Texture2D* backBufferPtr; result = m_swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferPtr); if(FAILED(result)) { HR(result); return false; }
// 用后缓冲创建渲染目标视图. result = m_device->CreateRenderTargetView(backBufferPtr, NULL, &m_renderTargetView); if(FAILED(result)) { HR(result); return false; }
//释放后缓冲.(引用计数减1) backBufferPtr->Release(); backBufferPtr = 0;
D3D11_TEXTURE2D_DESC depthBufferDesc; D3D11_DEPTH_STENCIL_DESC depthStencilDesc; D3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc; D3D11_RASTERIZER_DESC rasterDesc; D3D11_VIEWPORT viewport; //创建深度模版视图 // 初始化深度缓冲描述. // 初始化深度缓冲描述. ZeroMemory(&depthBufferDesc, sizeof(depthBufferDesc));
//设置深度缓冲描述 depthBufferDesc.Width = screenWidth; depthBufferDesc.Height = screenHeight; depthBufferDesc.MipLevels = 1; //对于深度缓冲为1 depthBufferDesc.ArraySize = 1; //对于深度缓冲为1,对于纹理,这2个参数有更多用途 depthBufferDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthBufferDesc.SampleDesc.Count = 1; depthBufferDesc.SampleDesc.Quality = 0; depthBufferDesc.Usage = D3D11_USAGE_DEFAULT; depthBufferDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; depthBufferDesc.CPUAccessFlags = 0; depthBufferDesc.MiscFlags = 0;
// 创建深度缓冲. result = m_device->CreateTexture2D(&depthBufferDesc, NULL, &m_depthStencilBuffer); if(FAILED(result)) { HR(result); return false;
}
// 初始化深度模版状态描述. ZeroMemory(&depthStencilDesc, sizeof(depthStencilDesc));
// 设置深度模版状态描述. depthStencilDesc.DepthEnable = true; depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;//D3D11_DEPTH_WRITE_MASK_ZERO禁止写深度缓冲 depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS;
depthStencilDesc.StencilEnable = true; depthStencilDesc.StencilReadMask = 0xFF; depthStencilDesc.StencilWriteMask = 0xFF;
// 对于front face 像素使用的模版操作操作. depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_INCR; depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; depthStencilDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// 对于back face像素使用的模版操作模式. depthStencilDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthStencilDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_DECR; depthStencilDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; depthStencilDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
// 创建深度模版状态,使其生效 result = m_device->CreateDepthStencilState(&depthStencilDesc, &m_depthStencilState); if(FAILED(result)) { HR(result); return false;
}
// 设置深度模版状态. m_deviceContext->OMSetDepthStencilState(m_depthStencilState, 1);
// 初始化深度模版视图. ZeroMemory(&depthStencilViewDesc, sizeof(depthStencilViewDesc));
// 设置深度模版视图描述. depthStencilViewDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; depthStencilViewDesc.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; depthStencilViewDesc.Texture2D.MipSlice = 0;
// 创建深度模版视图. result = m_device->CreateDepthStencilView(m_depthStencilBuffer, &depthStencilViewDesc, &m_depthStencilView); if(FAILED(result)) { HR(result); return false; }
// 绑定渲染目标视图和深度缓冲到渲染管线. m_deviceContext->OMSetRenderTargets(1, &m_renderTargetView, m_depthStencilView);
// 设置光栅化描述,指定多边形如何被渲染. rasterDesc.AntialiasedLineEnable = false; rasterDesc.CullMode = D3D11_CULL_BACK; rasterDesc.DepthBias = 0; rasterDesc.DepthBiasClamp = 0.0f; rasterDesc.DepthClipEnable = true; rasterDesc.FillMode = D3D11_FILL_SOLID; //D3D11_FILL_SOLID rasterDesc.FrontCounterClockwise = false; rasterDesc.MultisampleEnable = false; rasterDesc.ScissorEnable = false; rasterDesc.SlopeScaledDepthBias = 0.0f;
// 创建光栅化状态 result = m_device->CreateRasterizerState(&rasterDesc, &m_rasterState); if(FAILED(result)) { HR(result); return false; }
//设置光栅化状态,使其生效 m_deviceContext->RSSetState(m_rasterState);
// 设置视口,显示全部后缓冲内容 viewport.Width = (float)screenWidth; viewport.Height = (float)screenHeight; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; viewport.TopLeftX = 0.0f; viewport.TopLeftY = 0.0f;
// 创建视口 m_deviceContext->RSSetViewports(1, &viewport);
}
// 设置透视投影矩阵 fieldOfView = (float)D3DX_PI / 4.0f; screenAspect = (float)screenWidth / (float)screenHeight;
// 创建透视投影矩阵. D3DXMatrixPerspectiveFovLH(&m_projectionMatrix, fieldOfView, screenAspect, m_screenNear, m_screenDepth);
//初始化world矩阵为单位矩阵. //该矩阵实现局部坐标到世界坐标的转换 D3DXMatrixIdentity(&m_worldMatrix);
// 创建正交投影矩阵,主要用来实施2D渲染. D3DXMatrixOrthoLH(&m_orthoMatrix, (float)screenWidth, (float)screenHeight, m_screenNear, m_screenDepth);
注意:m_screenNear,m_screenDepth是D3DClass增加的两个成员变量,在初始化函数中,它们被用来保存screenNear和screenDetph。
另外一点小变动就是在GraphicsClass中把m_D3D设置为public,还有就是SystemClass中
if(m_Graphics) { bool result = m_Graphics->m_D3D->ResizeBuffer(screenWidth, screenHeight); if(!result) { return false; } }
完整的代码请参考:
工程文件myTutorialD3D11_26
代码下载: