0

我正在用纯 Java 创建一个 2D 自上而下的平铺游戏,现在我正在尝试实现一种照明方式。

首先,关于我如何渲染的一些细节:有一个处理所有渲染的屏幕类。像素被放入一个数组中,该数组使用 a和int[width * height]绘制在实际屏幕上。BufferedImageGraphics.drawImage()

我现在进行照明的方式是创建第二个int[width * height]数组,该数组包含应该从实际像素中减去的所有亮度。我尝试仅使用从0f到的浮点数1f来表示 RGB 强度。

因此,例如,环境照明为 0.3f。我所做的是一个像素到像素的操作,对于将要绘制的每个像素,它的 RGB 值被分解,减少 70% (1f - 0.3f),重新组合成单​​个 int 并存储在辅助int[width * height]数组中。将像素传输到 BufferedImage 时,我减去辅助数组中的相应值并得到更暗的图像,正如预期的那样。

这是一个使图像变暗的示例,它工作正常,当实际点亮它们时出现问题:我给了玩家一个 lightRadius 和 3 个浅色分量浮点 (RGB)。在渲染播放器时,我还通过执行以下操作在辅助阵列内渲染它的照明:

int mask = subtractMask[xx + yy * width];

int mr = (mask >> 16) & 255;
int mg = (mask >> 8) & 255;
int mb = mask & 255;

mr -= (int) (dist * light.r * mr);
mg -= (int) (dist * light.g * mg);
mb -= (int) (dist * light.b * mb);

subtractMask[xx + yy * width] = mr << 16 | mg << 8 | mb;

其中 dist 是一个数字,范围从0f1f,使光随着与光源的距离而衰减,并且light.r/g/b是来自播放器的光的每个组成部分。这段代码所做的基本上是“将一点点从像素中取出的光还给它”。如您所见,mr、mg 和 mb 变小(-=),然后组合回将从相应像素中减去的数字内,从而使减法的结果更大(更轻)。对于白光,我得到了想要的结果:

半径为 50 像素的光

问题是当我只使用蓝色分量(r = 0f,g = 0f,b = 1f)时,得到这个:具有相同 50 像素半径的蓝光

当然,这可以通过瓷砖的蓝色值非常少的事实来解释,使环境光带走一小部分并让照明将这一小部分返回(如您所见,最大的效果是球员的裤子,是蓝色的)。我仍然无法想到的是一种使照明独立于从像素中带走多少亮度以及以任何方式组合组件看起来都不错的方法(我对第二张图像的预期结果是亮度,例如在第一个,但颜色为蓝色)。那么如何实现这样的效果呢?

另外,为了使光照循环,我简单地计算了光照 x^2 + y^2 <= radius^2,如果这句话是真的,像素应该点亮,执行我之前展示的代码。有没有更快的方法来计算这个?(我在这个效果上损失了近 50 FPS)。

编辑:我想要的效果类似于 2D 游戏胫骨。这是棕色像素上的蓝光:胫骨 - 蓝光

4

1 回答 1

1

我认为最好的方法是首先添加环境光和玩家光值,将其限制在 [0...1] 范围内,然后将像素值相乘。

所以:

环境光: [ 0.3, 0.3, 0.3 ]
玩家光(在某个位置): [ 0.0, 0.0, 1.0 ]
总光: [0.3, 0.3, 1.0 ]

原始像素值:[100,200,100]
输出像素值:[30,60,100]

如果这样做,您还可以只使用一个静态 float[] 来表示每个像素的光量,仅在环境光或播放器光发生变化时更改它。然后,您不需要计算每一帧的光,只需在整个图像上一次性应用它。

于 2013-03-19T20:17:04.570 回答