c# - 平滑的 SDL2 精灵移动
问题描述
我制作了一个具有视差效果的场景。我无法使精灵沿 X 轴平滑移动。问题是,不管我用SDL_RenderCopyF
还是SDL_RenderCopy
,慢速移动时,精灵都是按照显示器的像素网格绘制的,伴随着抖动效果,当层数很多,每个人的移动速度不同时。
我的问题是SDL2 Smooth texture(sprite) animation between point of time function
但是有一个版本的SDL2不支持浮点渲染,作者不得不打补丁。从版本 2.0.10.0 开始,SDL_RenderCopyF
SDLSDL_FRect
中添加了 和其他功能,您可以使用这些功能实现亚像素移动精灵,但我无法让它们在我的场景中工作。
全高清分辨率有 10 层。渲染发生在 FullHD 窗口中。
窗口和渲染初始化代码:
void CreateWidnow()
{
var windowFlags = Settings.Fullscreen ?
SDL.SDL_WindowFlags.SDL_WINDOW_FULLSCREEN : Settings.Resizeble ?
SDL.SDL_WindowFlags.SDL_WINDOW_RESIZABLE : SDL.SDL_WindowFlags.SDL_WINDOW_SHOWN;
renderWindow = SDL.SDL_CreateWindow(
Settings.DebugMode ? $"{Settings.Title} [DEBUG]" : Settings.Title, SDL.SDL_WINDOWPOS_CENTERED,
SDL.SDL_WINDOWPOS_CENTERED,
Settings.Resolution.Width,
Settings.Resolution.Height,
windowFlags);
}
void CreateRenderer()
{
if(Settings.VSinc) {
renderer = SDL.SDL_CreateRenderer(
renderWindow, -1,
SDL.SDL_RendererFlags.SDL_RENDERER_PRESENTVSYNC |
SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
);
}
else
{
renderer = SDL.SDL_CreateRenderer(
renderWindow, -1,
SDL.SDL_RendererFlags.SDL_RENDERER_ACCELERATED |
SDL.SDL_RendererFlags.SDL_RENDERER_TARGETTEXTURE
);
}
}
计算的主循环deltaTime
:
void RenderLoop()
{
bool cap = Settings.FPS > 0;
var timer_fps = new Timer();
ulong now_counter = SDL.SDL_GetPerformanceCounter();
ulong last_counter = 0;
double deltaTime = 0;
while (renderLoop)
{
timer_fps.Start();
last_counter = now_counter;
now_counter = SDL.SDL_GetPerformanceCounter();
deltaTime = (double)(now_counter - last_counter) / SDL.SDL_GetPerformanceFrequency();
OnPreUpdate(deltaTime);
OnUpdate(deltaTime);
SDL.SDL_RenderPresent(renderer);
OnPostUpdate(deltaTime);
if( ( cap ) && ( timer_fps.GetTicks() < 1000 / Settings.FPS ) )
{
SDL.SDL_Delay( ( 1000 / Settings.FPS ) - timer_fps.GetTicks() );
}
}
}
精灵加载和渲染代码:
public Sprite(string path)
{
Path = path;
Transform = new Transform(new Point(0, 0));
sprite = Image.IMG_LoadTexture(Game.RenderContext, path);
SDL.SDL_QueryTexture(sprite, out format, out access, out width, out height); // get the width and height of the texture
draw_rect = new SDL.SDL_FRect();
draw_rect.w = width;
draw_rect.h = height;
scr_rect.x = 0; scr_rect.y = 0; scr_rect.w = width; scr_rect.h = height;
}
public Transform Transform
{
get; set;
}
public void Draw()
{
draw_rect.x = (float)Transform.Position.X;
draw_rect.y = (float)Transform.Position.Y;
SDL.SDL_RenderCopyExF(Game.RenderContext, sprite, ref scr_rect, ref draw_rect, Transform.Degrees, IntPtr.Zero, SDL.SDL_RendererFlip.SDL_FLIP_NONE);
}
移动函数(Transform.Translate):
public void Translate(double x, double y)
{
position.X += x;
position.Y += y;
}
视差实现函数(精灵离开屏幕后移回右侧):
void layerDraw(Sprite l1, Sprite l2, double speed)
{
l1.Transform.Translate(speed, 0);
l1.Draw();
l2.Transform.Translate(speed, 0);
l2.Draw();
if (l1.Transform.Position.X <= -Settings.Resolution.Width)
l1.Transform.SetPosition(Settings.Resolution.Width + l2.Transform.Position.X, 0);
if (l2.Transform.Position.X <= -Settings.Resolution.Width)
l2.Transform.SetPosition(Settings.Resolution.Width + l1.Transform.Position.X, 0);
}
视差渲染功能:
double speed_09 = -2.0, speed_08 = -4.0, speed_07 = -8.0, speed_06 = -16.0;
double speed_05 = -24.0, speed_04 = -32.0, speed_03 = -64.0, speed_02 = -96.0, speed_01 = -128.0;
protected override void Update(double deltaTime)
{
background.Draw();
layerDraw(forest_091, forest_092, speed_09 * deltaTime);
layerDraw(forest_081, forest_082, speed_08 * deltaTime);
layerDraw(forest_071, forest_072, speed_07 * deltaTime);
layerDraw(forest_061, forest_062, speed_06 * deltaTime);
layerDraw(particles051, particles052, speed_05 * deltaTime);
layerDraw(forest_041, forest_042, speed_04 * deltaTime);
layerDraw(particles_031, particles_032, speed_03 * deltaTime);
layerDraw(bushes_021, bushes_022, speed_02 * deltaTime);
layerDraw(mist_011, mist_012, speed_01 * deltaTime);
}
将坐标输出forest_091
到控制台:
[11:31:07:32] (x,y): = (1902,7461329999965:0), deltaTime = 0,001391, speed = -0,002782
[11:31:07:32] (x:y): = (1902,7430913999965:0), deltaTime = 0,0015208, speed = -0,0030416
[11:31:07:32] (x:y): = (1902,7400399999965:0), deltaTime = 0,0015257, speed = -0,0030514
[11:31:07:32] (x:y): = (1902,7370409999965:0), deltaTime = 0,0014995, speed = -0,002999
[11:31:07:32] (x:y): = (1902,7339605999964:0), deltaTime = 0,0015402, speed = -0,0030804
[11:31:07:33] (x:y): = (1902,7300727999964:0), deltaTime = 0,0019439, speed = -0,0038878
[11:31:07:33] (x:y): = (1902,7271281999963:0), deltaTime = 0,0014723, speed = -0,0029446
[11:31:07:33] (x:y): = (1902,7241953999962:0), deltaTime = 0,0014664, speed = -0,0029328
[11:31:07:33] (x:y): = (1902,7212207999962:0), deltaTime = 0,0014873, speed = -0,0029746
[11:31:07:33] (x:y): = (1902,7181395999962:0), deltaTime = 0,0015406, speed = -0,0030812
[11:31:07:33] (x:y): = (1902,715346599996:0), deltaTime = 0,0013965, speed = -0,002793
[11:31:07:33] (x:y): = (1902,712221399996:0), deltaTime = 0,0015626, speed = -0,0031252
[11:31:07:34] (x:y): = (1902,709382799996:0), deltaTime = 0,0014193, speed = -0,0028386
我使用 nectcore3.1、SDL2-CS和 SDL2 v2.0.10.0
UPD:记录 deltaTime 计算:
[08:48:34:25] now_counter = 1097310517365, last_counter = 1097310516099, now_counter-last_counter = 1266
[08:48:34:25] now_counter = 1097310519141, last_counter = 1097310517365, now_counter-last_counter = 1776
[08:48:34:25] now_counter = 1097310521406, last_counter = 1097310519141, now_counter-last_counter = 2265
[08:48:34:25] now_counter = 1097310532746, last_counter = 1097310521406, now_counter-last_counter = 11340
[08:48:34:25] now_counter = 1097310534069, last_counter = 1097310532746, now_counter-last_counter = 1323
[08:48:34:25] now_counter = 1097310535356, last_counter = 1097310534069, now_counter-last_counter = 1287
[08:48:34:25] now_counter = 1097310536628, last_counter = 1097310535356, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310537897, last_counter = 1097310536628, now_counter-last_counter = 1269
[08:48:34:25] now_counter = 1097310539169, last_counter = 1097310537897, now_counter-last_counter = 1272
[08:48:34:25] now_counter = 1097310540441, last_counter = 1097310539169, now_counter-last_counter = 1272`
解决方案
感谢keltar的答案和所花费的时间。其实我为解决这个问题苦苦挣扎了很久,真心不明白为什么即使在SDL2中添加了绘制浮点精灵的能力后,他们仍然按照显示器的像素网格来绘制我。
好消息:deltaTime 计算正确,并且在将坐标传输到 SDL 渲染时,舍入双精度没有问题!
坏消息:解决方案太简单了,花几天时间就可以了。
SDL.SDL_SetHint (SDL.SDL_HINT_RENDER_SCALE_QUALITY, "2");
这一行告诉 SDL2 在渲染精灵时使用各向异性过滤。它使我的动画流畅。
推荐阅读
- oracle - Update PL/SQL block inside procedure, which I'm using in web project, is taking too long
- scala - Spark 2.X throwing io.netty.buffer.PooledByteBufAllocator.metric()Lio/netty/buffer/PooledByteBufAllocatorMetric
- javascript - Fire onKeyPress Event passing parameters using JQuery does not work
- python-3.x - Averaging data while merging
- git - Data is gone after git branch
- python-3.x - How to subscribe to events in sawtooth hyperledger?
- ionic-framework - Unable to override scss in ionic3
- javascript - Select2 items show by if clause
- java - Benefits of internal iterations
- c - How to print result in order even if using threads in c?