使用子像素级别精度的图像绘图 Graphics2D

目前,我试图以正常的速度在屏幕上绘制图像,如视频游戏。

不幸的是,由于图像移动的速度,一些帧是相同的,因为图像尚未移动到完整的像素。

有没有办法提供
float

价值 Graphics2D 要在屏幕上显示图像,而不是
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?
已邀请:

奔跑吧少年

赞同来自:

您可以使用
BufferedImage


AffineTransform

, 绘制缓冲图像,然后在事件中绘制缓冲图像到组件 paint.


/* overrides the paint method */
@Override
public void paint/Graphics g/ {
/* clear scene buffer */
g2d.clearRect/0, 0, /int/width, /int/height/;

/* draw ball image to the memory image with transformed x/y double values */
AffineTransform t = new AffineTransform//;
t.translate/ball.x, ball.y/; // x/y set here, ball.x/y = double, ie: 10.33
t.scale/1, 1/; // scale = 1
g2d.drawImage/image, t, null/;

// draw the scene /double percision image/ to the ui component
g.drawImage/scene, 0, 0, this/;
}


查看我在这里的完整举例:
http://pastebin.com/hSAkYWqM

卫东

赞同来自:

您可以使用子像素精度来制作图像,但它是您的工作。 简单的双线性插值应该足够好玩。 以下是代码 psuedo-C++ 为了这。

通常画画 a sprite 在地点 /a, b/, 你会做这样的事情:


for /x = a; x < a + sprite.width; x++/
{
for /y = b; y < b + sprite.height; y++/
{
*dstPixel = alphaBlend /*dstPixel, *spritePixel/;
dstPixel++;
spritePixel++;
}
dstPixel += destLineDiff; // Move to start of next destination line
spritePixel += spriteLineDiff; // Move to start of next sprite line
}


要执行子像素渲染,您执行相同的周期,但要考虑子像素位移,如下所示:


float xOffset = a - floor /a/;
float yOffset = b - floor /b/;
for /x = floor/a/, spriteX = 0; x < floor/a/ + sprite.width + 1; x++, spriteX++/
{
for /y = floor/b/, spriteY = 0; y < floor /b/ + sprite.height + 1; y++, spriteY++/
{
spriteInterp = bilinearInterp /sprite, spriteX + xOffset, spriteY + yOffset/;
*dstPixel = alphaBlend /*dstPixel, spriteInterp/;
dstPixel++;
spritePixel++;
}
dstPixel += destLineDiff; // Move to start of next destination line
spritePixel += spriteLineDiff; // Move to start of next sprite line
}


功能 bilinearInterp// 它看起来像这样:


Pixel bilinearInterp /Sprite* sprite, float x, float y/
{
// Interpolate the upper row of pixels
Pixel* topPtr = sprite->dataPtr + //floor /y/ + 1/ * sprite->rowBytes/ + floor/x/ * sizeof /Pixel/;
Pixel* bottomPtr = sprite->dataPtr + /floor /y/ * sprite->rowBytes/ + floor /x/ * sizeof /Pixel/;

float xOffset = x - floor /x/;
float yOffset = y - floor /y/;

Pixel top = *topPtr + //*/topPtr + 1/ - *topPtr/ * xOffset;
Pixel bottom = *bottomPtr + //*/bottomPtr + 1/ - *bottomPtr/ * xOffset;
return bottom + /top - bottom/ * yOffset;
}


它不应该使用额外的内存,但将需要额外的时间渲染。

詹大官人

赞同来自:

我成功解决了我的问题,制作了像建议的Lawrencelan一样的东西。

最初我有以下代码在哪里
g

转换为坐标系 16:9 在调用该方法之前:


private void drawStar/Graphics2D g, Star s/ {

double radius = s.getRadius//;
double x = s.getX// - radius;
double y = s.getY// - radius;
double width = radius*2;
double height = radius*2;

try {

BufferedImage image = ImageIO.read/this.getClass//.getResource/"/images/star.png"//;
g.drawImage/image, /int/x, /int/y, /int/width, /int/height, this/;

} catch /IOException ex/ {
Logger.getLogger/View.class.getName///.log/Level.SEVERE, null, ex/;
}

}


但是,如质疑kaushik shankar所指出的,双重位置进入整数的转换使图像 "jump" 在整数中,双重测量的转换使其大规模 "jumpy" /为什么,该死的
g.drawImage

不拿双胞胎?!/. 我发现了,为我工作如下:


private void drawStar/Graphics2D g, Star s/ {

AffineTransform originalTransform = g.getTransform//;

double radius = s.getRadius//;
double x = s.getX// - radius;
double y = s.getY// - radius;
double width = radius*2;
double height = radius*2;

try {

BufferedImage image = ImageIO.read/this.getClass//.getResource/"/images/star.png"//;

g.translate/x, y/;
g.scale/width/image.getWidth//, height/image.getHeight///;

g.drawImage/image, 0, 0, this/;

} catch /IOException ex/ {
Logger.getLogger/View.class.getName///.log/Level.SEVERE, null, ex/;
}

g.setTransform/originalTransform/;

}


虽然看起来像是一种愚蠢的方式。

裸奔

赞同来自:

改变图像的分辨率,没有这样的东西 bitmap 使用子像素坐标,所以基本上您可以做的是在内存中创建图像,而不是您要在屏幕上显示的内容,但允许您 "sub-pixel" 准确性。

当您在内存中绘制大图像时,您将其复制并将其封装成较小的渲染,以最终用户可见。

例如:图像 100x100 它的模拟与尺寸 / 重新样本 50x50:


厘米。:
http://en.wikipedia.org/wiki/R ... %2529

要回复问题请先登录注册