如何在操作 BufferedImage 的像素数据时实现淡化效果?

huangapple go评论65阅读模式
英文:

How do I fade a BufferedImage when manipulating it's pixel data?

问题

我正在尝试做一些我以前从未做过的事情。
我的目标是能够操作BufferedImage的不透明度。首先,我不使用Graphics。我正在开发一个简单的游戏引擎,我只使用来自BufferedImages的像素数据。

我尝试了什么?

我创建了自己的“Image”类,该类接受一个BufferedImage。

BufferedImage image = null;
try {
    image = ImageIO.read(Image.class.getResourceAsStream(resourcePath));
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}

width = image.getWidth();
height = image.getHeight();
hasAlpha = image.getColorModel().hasAlpha();

pixels = image.getRGB(0, 0, width, height, null, 0, width);

然后,我继续进行渲染代码。我有一个名为“drawImage()”的函数,该函数接受图像及其数据,然后根据用户的意愿将其放置在屏幕上的特定位置。然而,我希望用户也能选择其不透明度。

我首先获取了该像素的像素数据,然后创建了一个Color对象。

Color c = new Color(image.getPixels()[value2], true);

关于“true”语句,据我所知,它表示它应该“关心”Alpha通道。

然后,我使用以下代码放置像素:

pixels[x + y * pWidth] = new Color(c.getRed(), c.getGreen(), c.getBlue(), alphaValue).getRGB();

这并不起作用。它不会输出任何错误,我可以将alphaValue更改为介于0和无穷大之间的数字。然而,我发现的一个问题是,当我将alpha从255更改为50时,它根本不影响图像。效果在0-5之间。我还注意到的另一件事是,当我将alphaValue设置为2时,我会得到一个动画,而不是具有较低不透明度的图像。听起来很奇怪,这就是我提供问题的.gif文件:

如何在操作 BufferedImage 的像素数据时实现淡化效果?

我向您保证没有代码会更改alphaValue。在那个“动画”期间,它被设置为2,没有其他操作。

因此,这里有一些奇怪的地方,我想知道您是否知道问题所在?

可能与Image类有关,我没有将其设置为BufferedImage.RGBA,但我不知道在加载图像时该如何设置?

如果您需要更多信息,请留言,我会提供更多信息!

提前感谢!

编辑
我通过操作背景像素(也是BufferedImage)每1/60秒清空屏幕一次:

public void clear() {
    for (int i = 0; i < pixels.length; i++) {
        pixels[i] = clearColor.getRGB();
    }
}

可能的问题
我进行了一些故障排除,发现它实际上在每一帧中以某种方式增加了不透明度,就像@Joni所说的那样。不知何故,每帧的不透明度或alpha似乎都在增加,但我在绘制之间清除了屏幕。我将进一步排除故障。

更新
我使图像可以移动,发现了这种奇怪的行为:

链接到Imgur

似乎“alpha”没有重置。我知道RGB已经被重置了,但是在Alpha方面出现了一些问题。

我将清除函数更改为:

public void clear() {
    for (int i = 0; i < pixels.length; i++) {
        pixels[i] = new Color(clearColor.getRed(), clearColor.getGreen(), clearColor.getBlue(), 255).getRGB();
    }
}

并且我定义了clearColor:

Color clearColor = new Color(Color.black.getRGB(), true);

然而,这也没有起作用。是否有人有解决办法?

英文:

I am trying to do something I have never done before.
My goal is to be able to manipulate the opacity of a BufferedImage. First off, I do not use Graphics. I am developing a simple Game Engine and I only use pixel data from BufferedImages.

What have I tried?

I made my own "Image" class that takes in a BufferedImage.

BufferedImage image = null;
	try {
		image = ImageIO.read(Image.class.getResourceAsStream(resourcePath));
	} catch (IOException e) {
		// TODO Auto-generated catch block
		e.printStackTrace();
	}
	
	width = image.getWidth();
	height = image.getHeight();
	hasAlpha = image.getColorModel().hasAlpha();
	
	pixels = image.getRGB(0, 0, width, height,null,0,width);

After that I proceeded to my rendering code. I have a function called "drawImage()" that takes the image and it's data and then puts it out on a specific spot on the screen depending on the users wishes. I however want the user to choose it's opacity as well.

I started out by taking the pixel data for that pixel and I instead made a Color.

Color c = new Color(image.getPixels()[value2],true);

The "true" statement, what I know of, says that it should "care" about Alpha.

After that I place the pixel by using this code:

pixels[x + y * pWidth] = new Color(c.getRed(),c.getGreen(),c.getBlue(),alphaValue).getRGB();

This doesn't work. It doesnt output any errors and I can change the alphaValue to a number between 0 and infinity. However one issue I found is that it doesnt affect the image at all when I change the alpha from 255 to something like 50. It stays the same. The affect comes at 0-5. Another thing that I noticed is that when I set alphaValue to something like 2 I get an animation instead of the image with lower opacity. Sounds weird, that's why I provided a .GIF of the issue:

如何在操作 BufferedImage 的像素数据时实现淡化效果?

I guarantee you that there is no code that changes the alphaValue. During that "animation" it is set to 2 and nothing else.

So something is weird here and I wonder if you guys know the issue?

It might have something to do with the Image class and that I don't set it to BufferedImage.RGBA but I don't know how I can do so when I load an image?

If you need any more information, please leave a comment and I will provide more info!

Thanks in advance!

EDIT
I clear the screen every 1/60 of a second by manipulating the backgrounds pixels (also a bufferedImage):

public void clear() {
	for(int i = 0; i &lt; pixels.length; i++) {
		pixels[i] = clearColor.getRGB();
	}
	
	
}

Possible issue

I did some troubleshooting and I found out that it actually somehow increased in opacity each frame as @Joni said. Somehow the opacity or alpha seems to increase each frame but I am clearing the screen between drawings. I will troubleshoot further.

UPDATE

I made so I could move the image around and found this weird behaviour:

Link to Imgur

It seems that the "alpha" isn't reset. I know that the RGB is being reset but something is really off when it comes to the Alpha.

I changed the clear function to this:

public void clear() {
	for(int i = 0; i &lt; pixels.length; i++) {
		pixels[i] = new Color(clearColor.getRed(),clearColor.getGreen(),clearColor.getBlue(),255).getRGB();
	}
	
	
}

And I defined clearColor as:

Color clearColor = new Color(Color.black.getRGB(),true);

That did however not work either. Does anyone have a solution?

答案1

得分: 2

你的游戏引擎在循环中将图像绘制在自身顶部。绘制足够多次后,效果与未使用透明度效果相同。透明度越低,所需时间越长:使用50%透明度,您需要7帧才能达到99%的不透明度,使用5%透明度大约需要90帧。

例如,假设您在初始为0(黑色)且透明度为50%的屏幕上绘制像素值为100。第一帧后,输出像素值为0.5100 + 0.50 = 50。第二帧绘制在第一帧之上,因此输出像素值为0.5100 + 0.550 = 75。第三帧绘制在第二帧之上,将显示0.5100 + 0.575 = 87.5。

为了避免这种情况,在每一帧的图像下方填充一个纯色背景。

英文:

Your game engine is drawing the image on top of itself in a loop. After drawing it enough many times the effect is the same as not having used transparency at all. The lower the alpha, the longer it takes though: with 50% alpha you need 7 frames to get 99% opacity, with 5% alpha you need about 90 frames.

For example, suppose you are drawing a pixel value of 100 on a screen that's intially 0 (black) with 50% opacity. After the first frame, the output pixel value is .5*100 + .5*0 = 50. The second frame is drawn on top of the first frame, so the output pixel value is .5*100 + .5*50 = 75. The third frame, drawn on top of the second frame, will show .5*100 + .5*75 = 87.5.

To avoid this, you need to fill a solid background color under the image in every frame.

huangapple
  • 本文由 发表于 2020年8月21日 00:00:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/63508947.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定