0

The animation is quite simple: display a picture full-screen and move the picture out of the screen horizontally in 1 second, just like the slide show switching effect in MS PowerPoint.

I'm using the D3D9 surface to realize the animation, because I want the program to be compatible with Windows XP and I might also need some 3D effects of displaying pictures.

When I turn on the VSYNC(d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT), the fps stays at 60 but I can still see the picture moving discontinuously(very obvious). When I turn off the VSYNC, the fps stays around 1600, the picture moves more smoothly(but still lags a little).

The strange part for both cases is that I can see a zig-zag border of the picture and rupture in the picture:

    ##########
    ##########
     #########
     #########
      ########

I have no exprience in either DX or 2D-animation, so I need your help.

The key part of the code is as follows:

D3DPRESENT_PARAMETERS d3dpp = {0};
d3dpp.BackBufferCount       = 3; 
d3dpp.Windowed              = TRUE; 
d3dpp.SwapEffect            = D3DSWAPEFFECT_DISCARD; 
d3dpp.BackBufferFormat      = D3DFMT_UNKNOWN;
d3dpp.PresentationInterval  = D3DPRESENT_INTERVAL_IMMEDIATE; //VSYNC off
//  d3dpp.PresentationInterval  = D3DPRESENT_INTERVAL_DEFAULT; //VSYNC

......
if(FAILED(D3DXLoadSurfaceFromFile(g_pSurface, NULL, NULL, PICPATH, NULL, D3DX_FILTER_NONE, 0, NULL)))
    return E_FAIL;
......
 while(1)
{
    if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
    {
        if (msg.message == WM_QUIT)
            break ;
        TranslateMessage (&msg) ;
        DispatchMessage (&msg) ;
    }
     else DxRender();
}

VOID DxRender() 
{ 

LPDIRECT3DSURFACE9 pBackBuffer = NULL;
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 ); 

static int offs = 0;
static float StartTime = timeGetTime() * 0.001f;
float CurTime = timeGetTime() * 0.001f;
offs = CurTime - StartTime * g_cxClient / ANIMATION_TIME_S;
// ANIMATION_TIME_S = 1.0f
if(offs >= g_cxClient)
{
    StartTime = CurTime;
    offs -= g_cxClient;
}


RECT srcrect1 = {0,0,g_cxClient-1-offs,g_cyClient-1}; 
POINT dstpt1 = {offs,0};

if( SUCCEEDED( g_pd3dDevice->BeginScene() ) ) 
{ 

    if(FAILED(g_pd3dDevice->GetBackBuffer(0,0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)))
    {
        MessageBox(NULL, TEXT("GetBackBuffer"), TEXT("Error"), MB_OK); 
    }
    g_pd3dDevice->UpdateSurface(g_pSurface, &srcrect1, pBackBuffer, &dstpt1);
    ShowFPS();

    g_pd3dDevice->EndScene(); 
} 

g_pd3dDevice->Present( NULL, NULL, NULL, NULL ); 
    if(pBackBuffer != NULL)
        pBackBuffer->Release();
} 
4

2 回答 2

1

您的动画不流畅可能是由于分辨率不足造成的timeGetTime()这可能会导致这些问题(请参阅timeGetTime()的 MSDN ),因为在高 FPS 下,一帧可能短于一毫秒。您可以尝试QueryPerformanceCounter()使用更高频率的计时器(MSDN 到QueryPerformanceCounter())。那么它不应该落后。我无法想象,为什么在 60 FPS 时会出现锯齿形,但 D3DPRESENT_INTERVAL_IMMEDIATE 破裂是正常的,因为屏幕无法跟上刷新。

于 2012-11-25T22:13:54.840 回答
0

我有一个使用世界矩阵转换纹理的解决方案,关键步骤如下

  • 从文件创建纹理
  • 显示纹理
  • 更新世界矩阵
    • 如果经过的时间少于 2 秒,则显示纹理
    • 否则将纹理向右平移直到它离开屏幕,平移矩阵是基于时间的,您可以更新矩阵。_41 文件。

完整代码如下,将纹理文件替换为本地文件即可查看效果,具体翻译请参见函数SetupMatrix中的代码。

#include <d3dx9.h>

LPDIRECT3D9             g_pD3D              = NULL ; // Used to create the D3DDevice
LPDIRECT3DDEVICE9       g_pd3dDevice        = NULL ; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB               = NULL ; // Vertex buffer
LPDIRECT3DTEXTURE9      g_pTexture          = NULL ; // Texture

D3DXMATRIX g_worldMatrix ;

float                   g_ShowTimeInterval  = 2.0f;  // How long will the picture displays.
float                   g_totalShowTime     = 0.0f;  // Time elapsed since the picture start to display.

#define SAFE_RELEASE(P) if(P){ P->Release(); P = NULL;}

struct Vertex
{
    float x, y, z ; // Vertex position
    float u, v ;    // Texture coordinates
};

#define VertexFVF D3DFVF_XYZ | D3DFVF_TEX1

HRESULT InitD3D( HWND hWnd )
{
    DWORD ScreenW = 0;
    DWORD ScreenH = 0;

    DEVMODE devMode ;
    devMode.dmSize = sizeof(devMode) ;
    DWORD iModeNum = 0 ;
    DWORD r = 1 ;

    while(r != 0)
    {
        r = EnumDisplaySettings(NULL, iModeNum, &devMode) ;
        // Store the maximum resolution currently
        if(devMode.dmPelsWidth >= ScreenW && devMode.dmPelsHeight >= ScreenH)
        {
            ScreenW = devMode.dmPelsWidth ;
            ScreenH = devMode.dmPelsHeight ;
        }

        //OutputModeInfo(iModeNum, devMode) ;
        iModeNum++ ;
    }

    // Create the D3D object.
    if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
        return E_FAIL;

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

    d3dpp.Windowed               = FALSE;
    d3dpp.SwapEffect             = D3DSWAPEFFECT_DISCARD; 
    d3dpp.BackBufferWidth        = ScreenW; 
    d3dpp.BackBufferHeight       = ScreenH;
    d3dpp.BackBufferFormat       = D3DFMT_X8R8G8B8; 

    // Create device
    if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dpp, &g_pd3dDevice ) ) )
    {
        MessageBoxA(NULL, "Create D3D9 device failed!", "Error", 0) ;
        return E_FAIL;
    }

    // Disable lighting, since we didn't specify color for vertex
    g_pd3dDevice->SetRenderState( D3DRS_LIGHTING , FALSE );  

    D3DXMatrixIdentity(&g_worldMatrix);

    // Create Texture
    HRESULT hr ;
    hr = D3DXCreateTextureFromFile(g_pd3dDevice, "../Common/Media/chessboard.jpg", &g_pTexture) ;
    if (FAILED(hr))
    {
        MessageBoxA(NULL, "Create Texture failed!", "Error", 0) ;
    }

    return S_OK;
}

// Prepare vertex buffer
void InitVB()
{
    Vertex Quad[] = 
    {
        {-5.0f,  5.0f, 0,    0,    0},  // 1
        { 5.0f,  5.0f, 0, 1.0f,    0},  // 2
        {-5.0f, -5.0f, 0,    0, 1.0f},  // 4
        { 5.0f, -5.0f, 0, 1.0f, 1.0f},  // 3
    } ;

    // Create vertex buffer
    HRESULT hr ;
    hr = g_pd3dDevice->CreateVertexBuffer(6 * sizeof(Vertex), D3DUSAGE_WRITEONLY, 
        VertexFVF, D3DPOOL_MANAGED, &g_pVB, NULL) ;
    if (FAILED(hr))
    {
        MessageBoxA(NULL, "Create vertex buffer failed!", "Error", 0) ;
    }

    // Copy data
    Vertex* v ;
    g_pVB->Lock(0, 0, (void**)&v, 0) ;
    memcpy(v, Quad, 6 * sizeof(Vertex)) ;
    g_pVB->Unlock() ;
}

VOID Cleanup()
{
    SAFE_RELEASE(g_pTexture) ;

    SAFE_RELEASE(g_pVB) ;

    SAFE_RELEASE(g_pd3dDevice) ;

    SAFE_RELEASE(g_pD3D) ;
}

void SetupMatrix(float timeDelta)
{
    g_totalShowTime += timeDelta;
    if(g_totalShowTime > g_ShowTimeInterval)
    {
        g_worldMatrix._41 += timeDelta * 10;
        g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_worldMatrix) ;
    }
    else
    {
        D3DXMatrixTranslation(&g_worldMatrix, 0.0f, 0.0f, 0.0f) ;
        g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_worldMatrix) ;
    }

    // set view
    D3DXVECTOR3 eyePt(0.0f, 0.0f, -15.0f) ;
    D3DXVECTOR3 upVec(0.0f, 1.0f, 0.0f) ;
    D3DXVECTOR3 lookCenter(0.0f, 0.0f, 0.0f) ;

    D3DXMATRIX view ;
    D3DXMatrixLookAtLH(&view, &eyePt, &lookCenter, &upVec) ;
    g_pd3dDevice->SetTransform(D3DTS_VIEW, &view) ;

    // set projection
    D3DXMATRIX proj ;
    D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4, 1.0f, 1.0f, 1000.0f) ;
    g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ;
}

void SetupTexture()
{
    // Create Texture
    HRESULT hr ;
    hr = D3DXCreateTextureFromFile(g_pd3dDevice, "../Common/Media/crate.jpg", &g_pTexture) ;
    if (FAILED(hr))
    {
        MessageBoxA(NULL, "Create Texture failed!", "Error", 0) ;
    }

    // Setup texture
    g_pd3dDevice->SetTexture(0, g_pTexture) ;
    g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
    g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
    g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
    g_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU,  D3DTADDRESS_WRAP );
    g_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV,  D3DTADDRESS_WRAP );
}

void RenderQuad()
{
    SetupTexture();

    // Set stream source
    g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(Vertex) );
    g_pd3dDevice->SetFVF(VertexFVF) ;
    g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2) ;

}

VOID Render(float timeDelta)
{
    SetupMatrix(timeDelta) ;

    g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0 );

    // Begin the scene
    if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
    {
        RenderQuad() ;

        // End the scene
        g_pd3dDevice->EndScene();
    }

    // Present the back-buffer contents to the display
    g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}

LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
    case WM_KEYDOWN:
        {
            switch( wParam )
            {
            case VK_ESCAPE:
                SendMessage( hWnd, WM_CLOSE, 0, 0 );
                break ;
            default:
                break ;
            }
        }
        break ;

    case WM_DESTROY:
        Cleanup();
        PostQuitMessage( 0 );
        return 0;
    }

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

INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR szCmdLine, int iCmdShow)
{
    WNDCLASSEX winClass ;

    winClass.lpszClassName = "ScreenQuad";
    winClass.cbSize        = sizeof(WNDCLASSEX);
    winClass.style         = CS_HREDRAW | CS_VREDRAW;
    winClass.lpfnWndProc   = MsgProc;
    winClass.hInstance     = hInstance;
    winClass.hIcon         = NULL ;
    winClass.hIconSm       = NULL ;
    winClass.hCursor       = LoadCursor(NULL, IDC_ARROW) ; // to avoid busy cursor
    winClass.hbrBackground = NULL ;
    winClass.lpszMenuName  = NULL ;
    winClass.cbClsExtra    = 0;
    winClass.cbWndExtra    = 0;

    RegisterClassEx (&winClass) ;  

    HWND hWnd = CreateWindowEx(NULL,  
        winClass.lpszClassName,     // window class name
        "ScreenQuad",               // window caption
        WS_OVERLAPPEDWINDOW,        // window style
        32,                         // initial x position
        32,                         // initial y position
        600,                        // initial window width
        600,                        // initial window height
        NULL,                       // parent window handle
        NULL,                       // window menu handle
        hInstance,                  // program instance handle
        NULL) ;                     // creation parameters

    // Create window failed
    if(hWnd == NULL)
    {
        MessageBoxA(hWnd, "Create Window failed!", "Error", 0) ;
        return -1 ;
    }

    // Initialize Direct3D
    if( SUCCEEDED(InitD3D(hWnd)))
    { 
        InitVB() ;

        // Show the window
        ShowWindow( hWnd, SW_SHOWDEFAULT );
        UpdateWindow( hWnd );

        // Enter the message loop
        MSG    msg ; 
        ZeroMemory( &msg, sizeof(msg) );
        PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );

        static DWORD lastTime = timeGetTime();

        while (msg.message != WM_QUIT)  
        {
            if( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
            {
                TranslateMessage (&msg) ;
                DispatchMessage (&msg) ;
            }
            else // Render the game if there is no message to process
            {
                DWORD currentTime = timeGetTime();
                float timeDelta = (currentTime - lastTime) * 0.001f;

                Render(timeDelta) ;

                lastTime = currentTime;
            }
        }
    }

    UnregisterClass(winClass.lpszClassName, hInstance) ;
    return 0;
}
于 2012-11-27T13:29:30.487 回答