动态照明的有效实现方法是什么?

4
我目前正在开发一个2D Java游戏,并且正在实现动态照明,例如火把、灯泡和太阳。然而,我遇到了一个问题。多次尝试不同的实现方式都没有提供所需的结果,要么不是我想要的,要么工作不如预期,或者导致整个游戏卡顿。我已经尝试了以下实现方式:
  • 使用RadialGradientPaint创建的(BufferedImage)掩码
  • 异步泛洪填充
  • 同步泛洪填充
RadialGradientPaint掩码并不能满足我的需求,我的实现方式无法处理屏幕上的任何元素,这意味着光线会“穿过”墙壁。
第二种实现方式——异步泛洪填充也无法正常工作。它只渲染了一部分光线,就停止工作了,特别是对于较大的光源。
第三种实现方式——同步泛洪填充做到了我想要的效果,但由于它在主线程上运行,因此在过程中会使其挂起: 用于创建最后一张图片的代码如下:
public void lightQueue(int x, int y, float level, boolean isSun){
    float newLevel;

    Queue<LightData> queue = new LinkedList<LightData>();
    queue.add(new LightData(x,y,level));

    while(!queue.isEmpty()){
        LightData d = queue.remove();

        try{
            newLevel = d.level - Level.getBlock(d.x, d.y).getLightBlockAmount();
        }catch(NullPointerException e){
            continue;
        }

        if(newLevel <= Level.getBlock(d.x, d.y).getLightLevel()) continue;

        if(newLevel > 1f){
            Level.getBlock(d.x, d.y).setLightLevel(1f);
        } else {
            Level.getBlock(d.x, d.y).setLightLevel(newLevel);
        }

        queue.add(new LightData(d.x + 1, d.y, newLevel));
        queue.add(new LightData(d.x - 1, d.y, newLevel));
        queue.add(new LightData(d.x, d.y + 1, newLevel));
        queue.add(new LightData(d.x, d.y - 1, newLevel));
    }
}
public void tick(){
    for(Emitter e:emitters){
        e.tick();
    }
    if(Main.tickCount % 20 == 0){
        for(Emitter e:emitters){
             if(e instanceof Sun){
                lightRec((int) e.getLocation().getX(), (int)e.getLocation().getY(), e.lightLevel, true);
            } else if(Level.shouldRender(e.getLocation(), Level.camera)){
                lightRec((int) e.getLocation().getX(), (int)e.getLocation().getY(), e.lightLevel, false);
            }
        }
    }
}

编辑:块的渲染过程如下:

public void render(Graphics g, Camera c){
    g.drawImage(texture, c.getRelativePixelX(getLocation().getPixelX()), c.getRelativePixelY(getLocation().getPixelY()), null);
    g.setColor(new Color(0f, 0f, 0f, 1f - lightLevel));
    g.fillRect(c.getRelativePixelX(getLocation().getPixelX()), c.getRelativePixelY(getLocation().getPixelY()), getBounds(c).width, getBounds(c).height);
    g.setColor(Color.WHITE);
}

相对像素(RelativePixel)只是将游戏中的坐标系统转换为屏幕像素以进行正确的定位。
该代码每秒运行两次,以确保游戏不会立即冻结。多个光源或亮度大于1f的光源(以增加半径)将导致游戏冻结。
因此,我的问题是,是否有更有效/更好的实现动态照明的方法?如果没有,是否有任何方法可以改进当前系统?
如果有任何不清楚的地方,请告诉我!谢谢

1
老实说,做这件事情的正确方法是使用别人编写的代码。你可以用3D程序来模拟2D,这是我会采取的方法。搜索“java opengl库”,并使用其中一个结果。问题在于,你将花费与编写和调试3D程序相同的时间来编写和调试2D代码,所以只考虑3D是有道理的。 - markspace
3
为什么你在使用Java2D而不是像JOGL或LWJGL这样的OpenGL封装库?正确的做法是使用现有的库。 - Kevin Workman
2
@KevoSoftworks 我强烈推荐你去看看LWJGL,或者更好的是libGDX。我相信在Java2D中也可以实现,但速度和美观度都不会特别出众。抱歉,我不太确定你的问题是什么! - Kevin Workman
下次你可以尝试访问gamedev.stackexchange.com,它更专注于游戏开发问题。 - ashes999
如果您要使用OpenGL库,请查看JMonkeyEngine。我只是阅读了文档,但似乎有很多工作已经完成。此外,它们使用BSD许可证:免费的啤酒。 - markspace
显示剩余4条评论
1个回答

1

谢谢分享!我之前看过那篇文章,但是忘记试一下了。用这种方法我还是能得到合理的性能,所以优化后应该会更好。这真的帮了我很多! - KevoSoftworks
非常感谢您接受这个答案!当然有很多选项可以提高光线追踪的性能,尽管我认为它并不是非常低效的......(对我来说工作得非常好 - 我甚至在移动设备上使用它) - Martin Frank

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接