使用 Graphics2D 以亚像素级精度绘制图像
我目前正在尝试以常规速率在屏幕上绘制图像,就像在视频游戏中一样。
不幸的是,由于图像移动的速度,一些帧是相同的,因为图像尚未移动完整的像素。
有没有办法为 Graphics2D 提供 float
值来绘制图像的屏幕位置,而不是 int
值?
最初这是我所做的:
BufferedImage srcImage = sprite.getImage ( );
Position imagePosition = ... ; //Defined elsewhere
g.drawImage ( srcImage, (int) imagePosition.getX(), (int) imagePosition.getY() );
这当然是阈值,因此图片不会在像素之间移动,而是从一个像素跳到下一个像素。
下一个方法是将绘画颜色设置为纹理并在指定位置绘制。不幸的是,这产生了不正确的结果,显示的是平铺而不是正确的抗锯齿。
g.setRenderingHint ( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
BufferedImage srcImage = sprite.getImage ( );
g.setPaint ( new TexturePaint ( srcImage, new Rectangle2D.Float ( 0, 0, srcImage.getWidth ( ), srcImage.getHeight ( ) ) ) );
AffineTransform xform = new AffineTransform ( );
xform.setToIdentity ( );
xform.translate ( onScreenPos.getX ( ), onScreenPos.getY ( ) );
g.transform ( xform );
g.fillRect(0, 0, srcImage.getWidth(), srcImage.getHeight());
我应该怎么做才能达到Java中图像的亚像素渲染的预期效果?
I am currently attempting to draw images on the screen at a regular rate like in a video game.
Unfortunately, because of the rate at which the image is moving, some frames are identical because the image has not yet moved a full pixel.
Is there a way to provide float
values to Graphics2D for on-screen position to draw the image, rather than int
values?
Initially here is what I had done:
BufferedImage srcImage = sprite.getImage ( );
Position imagePosition = ... ; //Defined elsewhere
g.drawImage ( srcImage, (int) imagePosition.getX(), (int) imagePosition.getY() );
This of course thresholds, so the picture doesn't move between pixels, but skips from one to the next.
The next method was to set the paint color to a texture instead and draw at a specified position. Unfortunately, this produced incorrect results that showed tiling rather than correct antialiasing.
g.setRenderingHint ( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
BufferedImage srcImage = sprite.getImage ( );
g.setPaint ( new TexturePaint ( srcImage, new Rectangle2D.Float ( 0, 0, srcImage.getWidth ( ), srcImage.getHeight ( ) ) ) );
AffineTransform xform = new AffineTransform ( );
xform.setToIdentity ( );
xform.translate ( onScreenPos.getX ( ), onScreenPos.getY ( ) );
g.transform ( xform );
g.fillRect(0, 0, srcImage.getWidth(), srcImage.getHeight());
What should I do to achieve the desired effect of subpixel rendering of an Image in Java?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您可以使用 BufferedImage 和 AffineTransform 绘制到缓冲图像,然后将缓冲图像绘制到绘制事件中的组件。
在这里查看我的完整示例:http://pastebin.com/hSAkYWqM
You can use a
BufferedImage
andAffineTransform
, draw to the buffered image, then draw the buffered image to the component in the paint event.Check my full example here: http://pastebin.com/hSAkYWqM
您可以使用亚像素精度自行合成图像,但这需要您做更多的工作。简单的双线性插值对于游戏来说应该足够好了。下面是执行此操作的伪 C++ 代码。
通常,要在位置 (a,b) 绘制精灵,您需要执行以下操作:
要进行子像素渲染,您需要执行相同的循环,但要考虑子像素偏移,如下所示:
bilinearInterp()函数看起来像这样:
这应该不使用额外的内存,但需要额外的时间来渲染。
You can composite the image yourself using sub-pixel accuracy, but it's more work on your part. Simple bilinear interpolation should work well enough for a game. Below is psuedo-C++ code for doing it.
Normally, to draw a sprite at location (a,b), you'd do something like this:
To do sub-pixel rendering, you do the same loop, but account for the sub-pixel offset like so:
The bilinearInterp() function would look something like this:
This should use no additional memory, but will take additional time to render.
在做了像劳伦斯兰提出的事情后,我成功解决了我的问题。
最初,我有以下代码,其中
g
在调用该方法之前转换为 16:9 坐标系:但是,正如提问者 Kaushik Shankar 所指出的,将双精度位置转换为整数使得图像“跳跃”,并将双精度尺寸转换为整数使其缩放“跳跃”(为什么
g.drawImage
不接受双精度?!)。我发现对我有用的是:不过,这似乎是一种愚蠢的做法。
I successfully solved my problem after doing something like lawrencealan proposed.
Originally, I had the following code, where
g
is transformed to a 16:9 coordinate system before the method is called:However, as noted by the questioner Kaushik Shankar, turning the double positions into integers makes the image "jump" around, and turning the double dimensions into integers makes it scale "jumpy" (why the hell does
g.drawImage
not accept doubles?!). What I found working for me was the following:Seems like a stupid way of doing it though.
相应地更改图像的分辨率,不存在具有子像素坐标的位图之类的东西,因此基本上您可以做的就是创建一个比您想要渲染到屏幕上的图像更大的内存图像,但允许您“子像素” “ 准确性。
当您绘制内存中的较大图像时,您可以将其复制并重新采样为最终用户可见的较小渲染。
例如:100x100 的图像和 50x50 调整大小/重新采样的对应图像:
请参阅:http://en.wikipedia.org/wiki/Resampling_%28bitmap%29
Change the resolution of your image accordingly, there's no such thing as a bitmap with sub-pixel coordinates, so basically what you can do is create an in memory image larger than what you want rendered to the screen, but allows you "sub-pixel" accuracy.
When you draw to the larger image in memory, you copy and resample that into the smaller render visible to the end user.
For example: a 100x100 image and it's 50x50 resized / resampled counterpart:
See: http://en.wikipedia.org/wiki/Resampling_%28bitmap%29