• 24. 幕外渲染


      通常在图形编程中,需要能够将场景渲染到纹理上,并且针对某些目的可以使用这些纹理,例如,也许想在游戏中有一个安全监视器,游戏中间有一个电视屏可以在不同的位置显示游戏的状态。这对游戏玩家而言,非常有用,并且可以在很大程度上提高程序的真实感。

     同样,也可以使用幕外渲染技术创建映射、阴影映射纹理和大量如场地模糊、夜视、热视力、高精度动态范围渲染等许多不同的后处理效果。在Direct3D中实现幕外渲染需要创建幕外表面,并对其渲染而不是渲染到常用的后台缓存中。然后将渲染结果存储在贴在幕外表面上的纹理图像中。并且可以像所有常用的纹理图像一样使用。要增加幕外渲染功能,只要创建一个LPDIRECT3DSURFACE9对象,并在想要渲染该对象时,切换到该对象即可。Direct3D在内部可以处理这一切工作,所以尤其是和OpenGL中的幕外渲染相比,这里的工作量要少很多。

     为了创建幕外表面,就必须创建一个想要保存渲染结果的LPDIRECT3DTEXTURE9对象。这通过调用D3DXCreateTexture()函数就可以实现。该函数的参数有pDevice、纹理的宽度(Width)和高度(Height)、纹理中Mipmap的个数(Miplevels)、指定纹理使用方式的标识符(Usage)、图像格式(Format)、描述放置图像的内存类(Pool),以及正在创建的纹理对象(ppTexture)。

     有了创建好的纹理,就可以调用LPDIRECT3DTEXTURE9的成员函数GetSurfaceLevel()创建幕外表面。GetSurfaceLevel()函数是一个可以从纹理对象中获取表面对象的函数。该表面就是要渲染的表面,而纹理对象将场景存储为一幅图像,而不是将其显示在屏幕上。GetSurfaceLevel()函数原型如程序清单4.23所示。其中,Level是创建表面时的纹理资源级别。ppSurfaceLevel是正在创建的LPDIRECT3DSURFACE9对象。

           程序清单4.23 GetSurfaceLevel()函数原型

    HRESULT GetSurfaceLevel(
    UINT Level,
    // 创建表面时的纹理资源级别
    IDirect3DSurface9** ppSurfaceLevel // 正在创建的LPDIRECT3DSURFACE9对象
    );

        有了这两个函数,就需要一个渲染用的幕外表面和纹理。要牢记:为了避免内存泄漏,在使用完对象后,一定要释放它们。到目前为止,这对所创建和使用的每个Direct3D对象都是如此。

     当要渲染表面时,有两件事要做。首先,需要一份后台缓存表面的副本,这样在处理完幕外表面时,可以返回正常的渲染。这通过使用Direct3D设备函数GetBackBuffer()就可以实现。GetBackBuffer()函数原型如程序清单4.24所示,其中iSwapChain是一个无符号整数,用于指定正在使用的交换链索引,BackBuffer是后台缓存索引,Type在Direct3D9.0中只能是D3DBACKBUFFER_TYPE_MODO,ppBackBuffer是保存后台缓存的LPDIRECT3DSURFACE9对象。

           程序清单4.24 GetBackBuffer()函数原型

    HRESULT GetBackBuffer(
    UINT iSwapChain,
    // 指定正在使用的交换链索引
    UINT BackBuffer, // 后台缓存索引
    D3DBACKBUFFER_TYPE Type,
    IDirect3DSurface9
    ** ppBackBuffer // 保存后台缓存的LPDIRECT3DSURFACE9对象
    );

         其次,当有了后台缓存后,就可以转换到想要用的所有渲染目标,这只需调用Direct3D设备函数SetRenderTarget()即可。SetRenderTarget()函数原型如程序清单4.25所示,其中RenderTargetIndex是渲染目标的索引,pRenderTarget代表要绘制的LPDIRECT3DSURFACE9对象。

    HRESULT SetRenderTarget(

      DWORD RenderTargetIndex,            // 渲染目标的索引

      IDirect3DSurface9 * pRenderTarget   // 要绘制的LPDIRECT3DSURFACE9对象

    );

     至此,就得到该演示程序的全部内容。有了这4个函数,就包含了所要渲染的全部内容。既然已经了解到这一点,接下来就可以开发一个程序,实现幕外渲染功能。

    #include<d3d9.h>
    #include
    <d3dx9.h>

    #define WINDOW_CLASS "UGPDX"
    #define WINDOW_NAME "Off-Screen Rendering"
    #define WINDOW_WIDTH 640
    #define WINDOW_HEIGHT 480

    // Function Prototypes...
    bool InitializeD3D(HWND hWnd, bool fullscreen);
    bool InitializeObjects();
    void RenderScene();
    void Shutdown();


    // Direct3D object and device.
    LPDIRECT3D9 g_D3D = NULL;
    LPDIRECT3DDEVICE9 g_D3DDevice
    = NULL;

    // Matrices.
    D3DXMATRIX g_projection;
    D3DXMATRIX g_ViewMatrix;

    // stD3DVertex buffer to hold the square's geometry.
    LPDIRECT3DVERTEXBUFFER9 g_VertexBuffer = NULL;

    // g_Teapot object and its material.
    LPD3DXMESH g_Teapot = NULL;
    D3DMATERIAL9 g_Material;
    float g_RotationAngle = 0.0f;

    // Light object.
    D3DLIGHT9 g_Light;

    // Back buffer, offscreen texture, offscreen surface.
    LPDIRECT3DSURFACE9 g_BackSurface = NULL;
    LPDIRECT3DTEXTURE9 g_SurfaceTexture
    = NULL;
    LPDIRECT3DSURFACE9 g_OffScreenSurface
    = NULL;


    // A structure for our custom vertex type
    struct stD3DVertex
    {
    float x, y, z;
    float tu, tv;
    };

    // Our custom FVF, which describes our custom vertex structure
    #define D3DFVF_VERTEX (D3DFVF_XYZ | D3DFVF_TEX1)


    LRESULT WINAPI MsgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
    {
    switch(msg)
    {
    case WM_DESTROY:
    PostQuitMessage(
    0);
    return 0;
    break;

    case WM_KEYUP:
    if(wParam == VK_ESCAPE) PostQuitMessage(0);
    break;
    }

    return DefWindowProc(hWnd, msg, wParam, lParam);
    }


    int WINAPI WinMain(HINSTANCE hInst, HINSTANCE prevhInst, LPSTR cmdLine, int show)
    {
    // Register the window class
    WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, MsgProc, 0L, 0L,
    GetModuleHandle(NULL), NULL, NULL, NULL, NULL,
    WINDOW_CLASS, NULL };
    RegisterClassEx(
    &wc);

    // Create the application's window
    HWND hWnd = CreateWindow(WINDOW_CLASS, WINDOW_NAME, WS_OVERLAPPEDWINDOW,
    100, 100, WINDOW_WIDTH, WINDOW_HEIGHT,
    GetDesktopWindow(), NULL, wc.hInstance, NULL);

    // Initialize Direct3D
    if(InitializeD3D(hWnd, false))
    {
    // Show the window
    ShowWindow(hWnd, SW_SHOWDEFAULT);
    UpdateWindow(hWnd);

    // Enter the message loop
    MSG msg;
    ZeroMemory(
    &msg, sizeof(msg));

    while(msg.message != WM_QUIT)
    {
    if(PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE))
    {
    TranslateMessage(
    &msg);
    DispatchMessage(
    &msg);
    }
    else
    RenderScene();
    }
    }

    // Release any and all resources.
    Shutdown();

    // Unregister our window.
    UnregisterClass(WINDOW_CLASS, wc.hInstance);
    return 0;
    }


    bool InitializeD3D(HWND hWnd, bool fullscreen)
    {
    D3DDISPLAYMODE displayMode;

    // Create the D3D object.
    g_D3D = Direct3DCreate9(D3D_SDK_VERSION);
    if(g_D3D == NULL) return false;

    // Get the desktop display mode.
    if(FAILED(g_D3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &displayMode)))
    return false;

    // Set up the structure used to create the D3DDevice
    D3DPRESENT_PARAMETERS d3dpp;
    ZeroMemory(
    &d3dpp, sizeof(d3dpp));

    if(fullscreen)
    {
    d3dpp.Windowed
    = FALSE;
    d3dpp.BackBufferWidth
    = WINDOW_WIDTH;
    d3dpp.BackBufferHeight
    = WINDOW_HEIGHT;
    }
    else
    d3dpp.Windowed
    = TRUE;
    d3dpp.SwapEffect
    = D3DSWAPEFFECT_DISCARD;
    d3dpp.BackBufferFormat
    = displayMode.Format;
    d3dpp.BackBufferCount
    = 1;
    d3dpp.EnableAutoDepthStencil
    = TRUE;
    d3dpp.AutoDepthStencilFormat
    = D3DFMT_D16;

    // Create the D3DDevice
    if(FAILED(g_D3D->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
    D3DCREATE_SOFTWARE_VERTEXPROCESSING,
    &d3dpp, &g_D3DDevice)))
    {
    return false;
    }

    // Initialize any objects we will be displaying.
    if(!InitializeObjects()) return false;

    return true;
    }


    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(200,200,200), 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);
    }


    void Shutdown()
    {
    if(g_D3DDevice != NULL) g_D3DDevice->Release();
    g_D3DDevice
    = NULL;

    if(g_D3D != NULL) g_D3D->Release();
    g_D3D
    = NULL;

    if(g_VertexBuffer != NULL) g_VertexBuffer->Release();
    g_VertexBuffer
    = NULL;

    if(g_Teapot != NULL) g_Teapot->Release();
    g_Teapot
    = NULL;

    if(g_BackSurface != NULL) g_BackSurface->Release();
    g_BackSurface
    = NULL;

    if(g_SurfaceTexture != NULL) g_SurfaceTexture->Release();
    g_SurfaceTexture
    = NULL;

    if(g_OffScreenSurface != NULL) g_OffScreenSurface->Release();
    g_OffScreenSurface
    = NULL;
    }

      

      

        




  • 相关阅读:
    JVM 源码分析
    GGGGCCCC
    正则化(Regularization)、过拟合(Overfitting)
    名校课程
    数据库垂直拆分 水平拆分
    运维角度浅谈MySQL数据库优化
    表的垂直拆分和水平拆分
    Eclipse去掉对JS文件的Validation
    Linux定时任务工具crontab详解及系统时间同步
    高性能分布式哈希表FastDHT
  • 原文地址:https://www.cnblogs.com/kex1n/p/2156495.html
Copyright © 2020-2023  润新知