高效的基于 2D Tile 的照明系统 [英] Efficient 2D Tile based lighting system

查看:23
本文介绍了高效的基于 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

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

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.

第二组瓷砖

  • 使用第二组(黑色/彩色)瓷砖
  • 将它们放在主瓷砖上
  • 根据新颜色的强度设置新图块的 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.

    示例:

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

    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.)

    <小时>

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

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


    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:

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

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

    多个光源

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

    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 的照明系统的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆