我创建了简单的、与帧无关的、可变时间步长的线性运动Direct3D9
using ID3DXSprite
。大多数用户无法注意到它,但在某些(包括我的)计算机上它经常发生,有时甚至会很卡顿。
EDIT:
即使发生卡顿,帧增量时间也不会超出 16 .. 17 毫秒的范围。
似乎我的帧增量时间测量日志代码被窃听了。我现在修好了。
- 通常启用垂直同步的帧渲染时间为 17 毫秒,但有时(可能发生卡顿时)它会跳至 25-30 毫秒。
(我只在应用程序退出时转储日志一次,而不是在运行、渲染时转储日志,因此它不会影响性能)
device->Clear(0, 0, D3DCLEAR_TARGET, D3DCOLOR_ARGB(255, 255, 255, 255), 0, 0);
device->BeginScene();
sprite->Begin(D3DXSPRITE_ALPHABLEND);
QueryPerformanceCounter(&counter);
float time = counter.QuadPart / (float) frequency.QuadPart;
float deltaTime = time - currentTime;
currentTime = time;
position.x += velocity * deltaTime;
if (position.x > 640)
velocity = -250;
else if (position.x < 0)
velocity = 250;
position.x = (int) position.x;
sprite->Draw(texture, 0, 0, &position, D3DCOLOR_ARGB(255, 255, 255, 255));
sprite->End();
device->EndScene();
device->Present(0, 0, 0, 0);
感谢 Eduard Witch 和 Ben Voigt 修复了计时器(尽管它没有解决最初的问题)
float time()
{
static LARGE_INTEGER start = {0};
static LARGE_INTEGER frequency;
if (start.QuadPart == 0)
{
QueryPerformanceFrequency(&frequency);
QueryPerformanceCounter(&start);
}
LARGE_INTEGER counter;
QueryPerformanceCounter(&counter);
return (float) ((counter.QuadPart - start.QuadPart) / (double) frequency.QuadPart);
}
EDIT #2:
到目前为止我尝试了三种更新方法:
1)可变时间步长
x += velocity * deltaTime;
2)固定时间步长
x += 4;
3)固定时间步长+插值
accumulator += deltaTime;
float updateTime = 0.001f;
while (accumulator > updateTime)
{
previousX = x;
x += velocity * updateTime;
accumulator -= updateTime;
}
float alpha = accumulator / updateTime;
float interpolatedX = x * alpha + previousX * (1 - alpha);
所有方法的工作原理几乎相同,固定时间步长看起来更好,但它并不是一个依赖于帧速率的选项,并且它不能完全解决问题(仍然很少偶尔跳跃(口吃))。
到目前为止禁用AERO Transparent Glass
或者全屏显示只是重大的积极变化。
我在用NVIDIA
最新驱动程序GeForce 332.21 Driver
and Windows 7 x64 Ultimate
.