Странная вещь в 2D-анимации D3D9 — высокий FPS, но все еще не плавный

Анимация довольно проста: вывести изображение на весь экран и переместить изображение за горизонтальное положение за 1 секунду, как эффект переключения слайд-шоу в MS PowerPoint.

Я использую поверхность D3D9 для реализации анимации, потому что я хочу, чтобы программа была совместима с Windows XP, и мне также могут понадобиться некоторые 3D-эффекты отображения изображений.

Когда я включаю VSYNC (d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT), fps остается на 60, но я все еще могу видеть, как картинка движется с перерывами (очень очевидно). Когда я выключаю VSYNC, fps остается около 1600, картинка движется более плавно (но все еще немного отстает).

Странная часть обоих случаев заключается в том, что я вижу зигзагообразную границу изображения и разрыв на изображении:

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

У меня нет опыта ни в DX, ни в 2D-анимации, поэтому мне нужна ваша помощь.

Ключевая часть кода выглядит следующим образом:

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

0

Решение

То, что ваша анимация не является плавной, может быть вызвано недостаточным разрешением timeGetTime(), Это может вызвать эти проблемы (см. MSDN timeGetTime ()), потому что при высоком FPS кадр может быть короче миллисекунды. Ты можешь попробовать QueryPerformanceCounter() чтобы получить таймер с более высокой частотой (MSDN для QueryPerformanceCounter ()). Тогда это не должно отставать. Я не могу себе представить, почему зигзаги на скорости 60 кадров в секунду, но с D3DPRESENT_INTERVAL_IMMEDIATE разрывы нормальны, потому что экран не может постоянно обновляться.

1

Другие решения

У меня есть решение, которое использует мировую матрицу для перевода текстуры, ключевые шаги, как показано ниже

  • Создать текстовое будущее из файла
  • Показать текст
  • Обнови мировую матрицу
    • если прошедшее время меньше 2 секунд, отобразить текстуру
    • иначе переведите текстуру вправо, пока она не выйдет из экрана, переведите
      Матрица была основана на времени, вы можете просто обновить матрицу.

полный код, как показано ниже, вы должны заменить файл текстуры на ваш локальный файл, чтобы увидеть эффект, см. код в функции 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;
}
0

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector