本文介绍了高效的基于 2D Tile 的照明系统的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

What is the most efficient way to do lighting for a tile based engine in Java?
Would it be putting a black background behind the tiles and changing the tiles' alpha?
Or putting a black foreground and changing alpha of that? Or anything else?

这是我想要的照明类型的示例:

This is an example of the kind of lighting I want:

推荐答案

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

There are many ways to achieve this. Take some time before making your final decision. I will briefly sum up some techiques you could choose to use and provide some code in the end.

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

If you want to create a hard-edge lighting effect (like your example image),some approaches come to my mind:

  • 使用黑色背景
  • 根据其暗度值设置图块的 alpha 值
  • Use a black background
  • Set the tiles' alpha values according to their darkness value

问题是,您既不能让瓷砖比以前更亮(高光),也不能改变灯光的颜色.这两个方面通常都会使游戏中的照明看起来不错.

第二组瓷砖

  • 使用第二组(黑色/彩色)瓷砖
  • 将它们放在主瓷砖上
  • 根据新颜色的强度设置新图块的 alpha 值.
  • 这种方法与第一种方法具有相同的效果,但优点是您现在可以将覆盖图块着色为黑色以外的另一种颜色,这样既可以使用彩色灯光,也可以制作高光.

    示例:

    尽管很容易,但问题是,这确实是一种非常低效的方式.(每个图块有两个渲染图块,不断重新着色,许多渲染操作等)

    更有效的方法(强光和/或柔光)

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


    More Efficient Approaches (Hard and/or Soft Lighting)

    When looking at your example, I imagine the light always comes from a specific source tile (character, torch, etc.)

    • 对于每种类型的灯光(大手电筒、小手电筒、角色照明),您创建一个图像,表示相对于源图块(光遮罩)的特定照明行为.对于手电筒来说可能是这样的(白色是 alpha):
    • 对于作为光源的每个图块,您在光源位置将此图像渲染为叠加层.
    • 要添加一点浅色,您可以使用例如10% 不透明的橙色,而不是完整的 alpha.

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

    Soft light is no big deal now, just use more detail in light mask compared to the tiles. By using only 15% alpha in the usually black region you can add a low sight effect when a tile is not lit:

    您甚至可以通过更改蒙版图像轻松实现更复杂的照明形式(锥体等).

    多个光源

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

    Multiple light sources

    When combining multiple light sources, this approach leads to a problem:Drawing two masks, which intersect each other, might cancel themselves out:

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

    What we want to have is that they add their lights instead of subtracting them.Avoiding the problem:

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

    这会导致类似的结果:

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

    Assuming you render all the tiles in a BufferedImage first,I'll provide some guidance code which resembles the last shown method (only grayscale support).

    多个光罩,例如火炬和玩家可以这样组合:

    Multiple light masks for e.g. a torch and a player can be combined like this:

    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;
    }
    

    使用此方法创建并应用最终遮罩:

    The final mask is created and applied with this method:

    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);
    }
    

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

    As noted, this is a primitive example. Implementing color blending might be a bit more work.

    这篇关于高效的基于 2D Tile 的照明系统的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-04 08:03