java - 高效的基于 2D Tile 的照明系统

标签 java 2d tile lighting

在 Java 中为基于图 block 的引擎进行照明的最有效方法是什么?
是否会在图 block 后面放置黑色背景并更改图 block 的 alpha?
或者放一个黑色前景并改变它的 alpha?或者别的什么?

这是我想要的那种照明的例子:
http://i.stack.imgur.com/F5Lzo.png

最佳答案

有很多方法可以实现这一点。在做出最终决定之前花一些时间。我将简要总结一些您可以选择使用的技术,并在最后提供一些代码。


强光

如果您想创建硬边照明效果(如您的示例图片), 我想到了一些方法:

hard light example

快速而肮脏(如您所建议的)

  • 使用黑色背景
  • 根据它们的暗度值设置图 block 的 alpha 值

A problem is, that you can neither make a tile brighter than it was before (highlights) nor change the color of the light. Both of these are aspects which usually make lighting in games look good.

第二组图 block

  • 使用第二组(黑色/彩色)瓷砖
  • 将它们放在主瓷砖上
  • 根据新颜色的强度设置新图 block 的 alpha 值。

This approach has the same effect as the first one with the advantage, that you now may color the overlay tile in another color than black, which allows for both colored lights and doing highlights.

例子: hard light with black tiles example

Even though it is easy, a problem is, that this is indeed a very inefficent way. (Two rendered tiles per tile, constant recoloring, many render operations etc.)


更有效的方法(硬光和/或软光)

在查看您的示例时,我想光总是来自特定的源图 block (角色、手电筒等)

  • 对于每种类型的灯(大手电筒、小手电筒、人物照明),您 创建一个图像来表示相对于源图 block (光掩模)的特定照明行为。也许像这样的 torch (白色是阿尔法):

centered light mask

  • 对于作为光源的每个图 block ,您将在光源位置渲染此图像作为叠加层。
  • 要添加一点浅色,您可以使用例如10% 不透明橙色而不是完整的 alpha。

结果

image mask hard light result

添加柔光

柔光现在没什么大不了的,与平铺相比,只需在光罩中使用更多细节即可。通过在通常为黑色的区域中仅使用 15% 的 alpha,您可以在瓷砖未点亮时添加低视线效果:

soft light

You may even easily achieve more complex lighting forms (cones etc.) just by changing the mask image.

多个光源

当组合多个光源时,这种做法会导致一个问题: 绘制两个相互交叉的蒙版可能会相互抵消:

mask cancellation

我们想要的是他们添加灯光而不是减去灯光。 避免问题:

  • 反转所有光蒙版(alpha 为暗区,不透明为亮区)
  • 将所有这些光罩渲染成与视口(viewport)具有相同尺寸的临时图像
  • 在整个场景中反转并渲染新图像(好像它是唯一的光罩)。

这将导致类似的结果: result image

掩码反转方法代码

假设您首先渲染 BufferedImage 中的所有图 block , 我将提供一些类似于最后显示的方法的指导代码(仅支持灰度)。

多个遮光罩,例如手电筒和播放器可以这样组合:

public BufferedImage combineMasks(BufferedImage[] images)
{
    // create the new image, canvas size is the max. of all image sizes
    int w, h;

    for (BufferedImage img : images)
    {
        w = img.getWidth() > w ? img.getWidth() : w;
        h = img.getHeight() > h ? img.getHeight() : h;
    }

    BufferedImage combined = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);

    // paint all images, preserving the alpha channels
    Graphics g = combined.getGraphics();

    for (BufferedImage img : images)
        g.drawImage(img, 0, 0, null);

    return combined;
}

使用此方法创建并应用最终蒙版:

public void applyGrayscaleMaskToAlpha(BufferedImage image, BufferedImage mask)
{
    int width = image.getWidth();
    int height = image.getHeight();

    int[] imagePixels = image.getRGB(0, 0, width, height, null, 0, width);
    int[] maskPixels = mask.getRGB(0, 0, width, height, null, 0, width);

    for (int i = 0; i < imagePixels.length; i++)
    {
        int color = imagePixels[i] & 0x00ffffff; // Mask preexisting alpha

        // get alpha from color int
        // be careful, an alpha mask works the other way round, so we have to subtract this from 255
        int alpha = (maskPixels[i] >> 24) & 0xff;
        imagePixels[i] = color | alpha;
    }

    image.setRGB(0, 0, width, height, imagePixels, 0, width);
}

如前所述,这是一个原始示例。实现颜色混合可能需要更多工作。

关于java - 高效的基于 2D Tile 的照明系统,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18525214/

相关文章:

java - 带有子查询的 JPQL 以选择最大计数

java - Solr 导入命令不起作用

c++ - 跨平台 C++ 库到 : display a window, 在屏幕上渲染 2D 形状,在屏幕上渲染文本

python - Jupyter 的 2D 绘图?

java - Android 上的平铺 map

java - Tapestry动态生成图像

java - Java中用于链接文本和音频的数据结构

Java : my program "sometimes" wont store the smallest element per row of a 2d array

java - 将资源加载到基于图 block 的游戏的 ArrayList 中。 ( java )

java - 检查二维矩阵上的所选图 block 是否全部连接