24.1 幕外渲染程序错误修正

24.的程序代码源于书籍附带光盘,运行得不到正确结果,由于bool InitializeObjects(),void RenderScene()这2个函数中的代码所致。先看这2个函数,原来的代码如下:

bool InitializeObjects()
{
// Setup the g_Light source.
g_Light.Type = D3DLIGHT_DIRECTIONAL;
g_Light.Direction
= D3DXVECTOR3(0.0f, 0.0f, 1.0f);
g_Light.Diffuse.r
= 1;
g_Light.Diffuse.g
= 1;
g_Light.Diffuse.b
= 1;
g_Light.Diffuse.a
= 1;
g_Light.Specular.r
= 1;
g_Light.Specular.g
= 1;
g_Light.Specular.b
= 1;
g_Light.Specular.a
= 1;

g_D3DDevice
->SetLight(0, &g_Light);
g_D3DDevice
->LightEnable(0, TRUE);

// Setup the material properties for the teapot.
ZeroMemory(&g_Material, sizeof(D3DMATERIAL9));
g_Material.Diffuse.r
= g_Material.Ambient.r = 0.6f;
g_Material.Diffuse.g
= g_Material.Ambient.g = 0.6f;
g_Material.Diffuse.b
= g_Material.Ambient.b = 0.7f;
g_Material.Specular.r
= 0.4f;
g_Material.Specular.g
= 0.4f;
g_Material.Specular.b
= 0.4f;
g_Material.Power
= 8.0f;

// Create the teapot.
if(FAILED(D3DXCreateTeapot(g_D3DDevice, &g_Teapot, NULL)))
return false;


// Create the texture that will be rendered to.
if(FAILED(D3DXCreateTexture(g_D3DDevice, WINDOW_WIDTH,
WINDOW_HEIGHT,
1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&g_SurfaceTexture))) return false;

// Set texture to offscreen surface.
g_SurfaceTexture->GetSurfaceLevel(0, &g_OffScreenSurface);


// Square that will be textured with offscreen rendering data.
stD3DVertex square[] =
{
{
-1, 1, -1, 0, 0}, {1, 1, -1, 1, 0},
{
-1, -1, -1, 0, 1}, {1, -1, -1, 1, 1}
};

g_D3DDevice
->CreateVertexBuffer(4 * sizeof(stD3DVertex), 0,
D3DFVF_VERTEX, D3DPOOL_DEFAULT,
&g_VertexBuffer, NULL);

void *pData = NULL;
g_VertexBuffer
->Lock(0, sizeof(square), (void**)&pData, 0);
memcpy(pData, square,
sizeof(square));
g_VertexBuffer
->Unlock();


// Set the image states to get a good quality image.
g_D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_D3DDevice
->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

// Set default rendering states.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
g_D3DDevice
->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
g_D3DDevice
->SetRenderState(D3DRS_ZENABLE, TRUE);

// Set the projection matrix.
D3DXMatrixPerspectiveFovLH(&g_projection, 45.0f,
WINDOW_WIDTH
/WINDOW_HEIGHT, 0.1f, 1000.0f);
g_D3DDevice
->SetTransform(D3DTS_PROJECTION, &g_projection);

// Define camera information.
D3DXVECTOR3 cameraPos(0.0f, 0.0f, -4.0f);
D3DXVECTOR3 lookAtPos(
0.0f, 0.0f, 0.0f);
D3DXVECTOR3 upDir(
0.0f, 1.0f, 0.0f);

// Build view matrix.
D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos,
&lookAtPos, &upDir);

return true;
}


void RenderScene()
{
// Get a copy of the back buffer.
g_D3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &g_BackSurface);

// Prepare to draw to the offscreen surface.
g_D3DDevice->SetRenderTarget(0, g_OffScreenSurface);

// Clear the offscreen surface.
g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(255,255,255), 1.0f, 0);

// Begin the scene. Start rendering.
g_D3DDevice->BeginScene();

// Turn on lighting.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

// Set projection.
g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

// Create rotation matrix to rotate teapot.
D3DXMATRIXA16 w;
D3DXMatrixRotationY(
&w, g_RotationAngle);
g_D3DDevice
->SetTransform(D3DTS_WORLD, &w);

// Add to the rotation.
g_RotationAngle += 0.02f;
if(g_RotationAngle >= 360)
g_RotationAngle
= 0.0f;

// Apply the view (camera).
g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);

// Set the material and draw the Teapot.
g_D3DDevice->SetMaterial(&g_Material);
g_D3DDevice
->SetTexture(0, NULL);
g_Teapot
->DrawSubset(0);

// End the scene. Stop rendering.
g_D3DDevice->EndScene();

// Switch back to our back buffer.
g_D3DDevice->SetRenderTarget(0, g_BackSurface);

// Clear the back buffer.
g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,0), 1.0f, 0);

// Begin the scene. Start rendering.
g_D3DDevice->BeginScene();

// Turn off lighting. Don't need it.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);

// Set projection.
g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

// Rotate just a little to see this is a flat surface.
D3DXMatrixRotationY(&w, 120);
g_D3DDevice
->SetTransform(D3DTS_WORLD, &w);

// Apply the view (camera).
g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);

g_D3DDevice
->SetTexture(0, g_SurfaceTexture);
g_D3DDevice
->SetStreamSource(0, g_VertexBuffer, 0, sizeof(stD3DVertex));
g_D3DDevice
->SetFVF(D3DFVF_VERTEX);
g_D3DDevice
->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

// End the scene. Stop rendering.
g_D3DDevice->EndScene();

// Display the scene.
g_D3DDevice->Present(NULL, NULL, NULL, NULL);
}

  

在InitializeObjects()函数中创建纹理时用的是WINDOW_WIDTH, WINDOW_HEIGHT作为纹理的宽度和高度,然后获取与该纹理关联的离屏表面,将场景渲染到这个离屏表面上去,再渲染该表面,这个就是主要的思路。

注意:创建纹理时,是不会为纹理创建深度缓存的,所以在将场景渲染到离屏表面时是用的backbuffer的深度缓存!但是backbuffer的深度缓存的宽度和高度要小于WINDOW_WIDTH, WINDOW_HEIGHT(windows渲染窗口的宽度和高度分别是WINDOW_WIDTH, WINDOW_HEIGHT,但是要剪掉窗口的外框,菜单框。。之后实际上backbuffer的宽度和高度要小于WINDOW_WIDTH, WINDOW_HEIGHT。也就是说向离屏表面上渲染的时候离屏表面的深度缓存的尺寸与数据缓存的尺寸不一致。)此时深度缓存的尺寸要小于效应的数据缓存,所以出错!!!

解决的办法有2种:

1. 

    if(FAILED(D3DXCreateTexture(g_D3DDevice, 256,
256, 1, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&g_SurfaceTexture))) return false;

  在创建纹理的时候将宽度和高度改成小于窗口的宽度和高度一定的数值即可。此时离屏表面的数据缓存的尺寸小于backbuffer的深度缓存的尺寸,所以就算用backbuffer的深度缓存来作为自己的深度缓存也不会出错。

2. 手动为离屏表面创建深度缓存。

bool InitializeObjects()
{
// Setup the g_Light source.
g_Light.Type = D3DLIGHT_DIRECTIONAL;
g_Light.Direction
= D3DXVECTOR3(0.0f, 0.0f, 1.0f);
g_Light.Diffuse.r
= 1;
g_Light.Diffuse.g
= 1;
g_Light.Diffuse.b
= 1;
g_Light.Diffuse.a
= 1;
g_Light.Specular.r
= 1;
g_Light.Specular.g
= 1;
g_Light.Specular.b
= 1;
g_Light.Specular.a
= 1;

g_D3DDevice
->SetLight(0, &g_Light);
g_D3DDevice
->LightEnable(0, TRUE);

// Setup the material properties for the teapot.
ZeroMemory(&g_Material, sizeof(D3DMATERIAL9));
g_Material.Diffuse.r
= g_Material.Ambient.r = 0.6f;
g_Material.Diffuse.g
= g_Material.Ambient.g = 0.6f;
g_Material.Diffuse.b
= g_Material.Ambient.b = 0.7f;
g_Material.Specular.r
= 0.4f;
g_Material.Specular.g
= 0.4f;
g_Material.Specular.b
= 0.4f;
g_Material.Power
= 8.0f;

// Create the teapot.
if(FAILED(D3DXCreateTeapot(g_D3DDevice, &g_Teapot, NULL)))
return false;


// Create the texture that will be rendered to.
if(FAILED(D3DXCreateTexture(g_D3DDevice, WINDOW_WIDTH,
WINDOW_HEIGHT,
0, D3DUSAGE_RENDERTARGET, D3DFMT_A8R8G8B8,
D3DPOOL_DEFAULT,
&g_SurfaceTexture))) return false;

if(FAILED(g_D3DDevice->CreateDepthStencilSurface(WINDOW_WIDTH,
WINDOW_HEIGHT, D3DFMT_D16, D3DMULTISAMPLE_NONE,
0, TRUE,
&g_SurfaceTextureDepth, NULL))) return false;

// Set texture to offscreen surface.
g_SurfaceTexture->GetSurfaceLevel(0, &g_OffScreenSurface);

// Square that will be textured with offscreen rendering data.
stD3DVertex square[] =
{
{
-1, 1, -1, 0, 0}, {1, 1, -1, 1, 0},
{
-1, -1, -1, 0, 1}, {1, -1, -1, 1, 1}
};

g_D3DDevice
->CreateVertexBuffer(4 * sizeof(stD3DVertex), 0,
D3DFVF_VERTEX, D3DPOOL_DEFAULT,
&g_VertexBuffer, NULL);

void *pData = NULL;
g_VertexBuffer
->Lock(0, sizeof(square), (void**)&pData, 0);
memcpy(pData, square,
sizeof(square));
g_VertexBuffer
->Unlock();


// Set the image states to get a good quality image.
g_D3DDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_D3DDevice
->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);

// Set default rendering states.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
g_D3DDevice
->SetRenderState(D3DRS_CULLMODE, D3DCULL_CCW);
g_D3DDevice
->SetRenderState(D3DRS_ZENABLE, TRUE);
g_D3DDevice
->SetRenderState(D3DRS_ZWRITEENABLE, TRUE);


// Set the projection matrix.
D3DXMatrixPerspectiveFovLH(&g_projection, 45.0f,
WINDOW_WIDTH
/WINDOW_HEIGHT, 0.1f, 1000.0f);
g_D3DDevice
->SetTransform(D3DTS_PROJECTION, &g_projection);

// Define camera information.
D3DXVECTOR3 cameraPos(0.0f, 0.0f, -4.0f);
D3DXVECTOR3 lookAtPos(
0.0f, 0.0f, 0.0f);
D3DXVECTOR3 upDir(
0.0f, 1.0f, 0.0f);

// Build view matrix.
D3DXMatrixLookAtLH(&g_ViewMatrix, &cameraPos,
&lookAtPos, &upDir);

return true;
}


void RenderScene()
{
// Begin the scene. Start rendering.
g_D3DDevice->BeginScene();

// Get a copy of the back buffer.
// g_D3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &g_BackSurface);

g_D3DDevice
->GetRenderTarget(0, &g_BackSurface);
// Prepare to draw to the offscreen surface.
g_D3DDevice->SetRenderTarget(0, g_OffScreenSurface);
g_D3DDevice
->SetDepthStencilSurface(g_SurfaceTextureDepth);

// Clear the offscreen surface.
g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255,100,100,255), 1.0f, 0);

// Turn on lighting.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, TRUE);
g_D3DDevice
->SetRenderState(D3DRS_ZENABLE, TRUE);
// Set projection.
g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

// Create rotation matrix to rotate teapot.
D3DXMATRIXA16 w;
D3DXMatrixRotationY(
&w, g_RotationAngle);
g_D3DDevice
->SetTransform(D3DTS_WORLD, &w);

// Add to the rotation.
g_RotationAngle += 0.02f;
if(g_RotationAngle >= 360)
g_RotationAngle
= 0.0f;

// Apply the view (camera).
g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);

// Set the material and draw the Teapot.
g_D3DDevice->SetMaterial(&g_Material);
g_D3DDevice
->SetTexture(0, NULL);
g_Teapot
->DrawSubset(0);

// End the scene. Stop rendering.
//g_D3DDevice->EndScene();

// Switch back to our back buffer.
g_D3DDevice->SetRenderTarget(0, g_BackSurface);
g_D3DDevice
->SetDepthStencilSurface(NULL);


// Begin the scene. Start rendering.
g_D3DDevice->BeginScene();
// Clear the back buffer.
g_D3DDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(255,0,0,255), 1.0f, 0);

// Turn off lighting. Don't need it.
g_D3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE);
g_D3DDevice
->SetRenderState(D3DRS_ZENABLE, FALSE);

// Set projection.
g_D3DDevice->SetTransform(D3DTS_PROJECTION, &g_projection);

// Rotate just a little to see this is a flat surface.
D3DXMatrixRotationY(&w, 120);
g_D3DDevice
->SetTransform(D3DTS_WORLD, &w);

// Apply the view (camera).
g_D3DDevice->SetTransform(D3DTS_VIEW, &g_ViewMatrix);


g_D3DDevice
->SetTexture(0, g_SurfaceTexture);
g_D3DDevice
->SetStreamSource(0, g_VertexBuffer, 0, sizeof(stD3DVertex));
g_D3DDevice
->SetFVF(D3DFVF_VERTEX);
g_D3DDevice
->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);

// End the scene. Stop rendering.
g_D3DDevice->EndScene();

// Display the scene.
g_D3DDevice->Present(NULL, NULL, NULL, NULL);

g_BackSurface
->Release();
}

  

 为离屏表面创建的深度缓存的尺寸与离屏表面的数据缓存的尺寸一样都是WINDOW_WIDTH, WIDNOW_HEIGHT.

原文地址:https://www.cnblogs.com/kex1n/p/2159604.html