什么是动态照明的有效实施?
What is an effective implementation for dynamic lighting?
我目前正在开发一款 2D Java 游戏,目前正在实施动态光照,例如手电筒、灯泡和太阳。但是,我 运行 遇到了问题。对不同实现的多次尝试尚未提供预期的结果,要么不是我想要的,要么没有按预期工作,要么滞后于整个游戏。我尝试了以下实现:
- 使用 RadialGradientPaint 创建的 (BufferedImage) 遮罩
- 异步flood-fill
- 同步flood-fill
事实证明 RadialGradientPaint 蒙版不是我要找的东西,我的实现没有处理屏幕上的任何元素,这意味着光会 "go through" 墙。
第二个实现,异步 flood-fill,没有正常工作。它只渲染了一部分光,然后就收工了,尤其是大灯。
第三个实现,一个同步的 flood-fill,做了我想要的,但是因为它在主线程上 运行ning,它挂在进程中:
用于创建最后一张图片的代码如下:
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 内容只是从 in-game 坐标系到屏幕像素的转换,以便正确放置。
此代码每秒 运行 两次,以确保游戏不会立即冻结。多个光源或比 1f 更亮的光源(以增加半径)会卡住游戏。
所以我的问题是,有没有更effective/better的方法来实现动态光照?
如果没有,有什么办法可以改进当前的系统吗?
如果有什么不清楚的请告诉我!谢谢
我已经以自上而下的视角回答了这个问题...
...但我不是同一个问题...
使用光线追踪...
Efficient 2D Tile based lighting system
我目前正在开发一款 2D Java 游戏,目前正在实施动态光照,例如手电筒、灯泡和太阳。但是,我 运行 遇到了问题。对不同实现的多次尝试尚未提供预期的结果,要么不是我想要的,要么没有按预期工作,要么滞后于整个游戏。我尝试了以下实现:
- 使用 RadialGradientPaint 创建的 (BufferedImage) 遮罩
- 异步flood-fill
- 同步flood-fill
事实证明 RadialGradientPaint 蒙版不是我要找的东西,我的实现没有处理屏幕上的任何元素,这意味着光会 "go through" 墙。
第二个实现,异步 flood-fill,没有正常工作。它只渲染了一部分光,然后就收工了,尤其是大灯。
第三个实现,一个同步的 flood-fill,做了我想要的,但是因为它在主线程上 运行ning,它挂在进程中:
用于创建最后一张图片的代码如下:
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 内容只是从 in-game 坐标系到屏幕像素的转换,以便正确放置。
此代码每秒 运行 两次,以确保游戏不会立即冻结。多个光源或比 1f 更亮的光源(以增加半径)会卡住游戏。
所以我的问题是,有没有更effective/better的方法来实现动态光照? 如果没有,有什么办法可以改进当前的系统吗?
如果有什么不清楚的请告诉我!谢谢
我已经以自上而下的视角回答了这个问题... ...但我不是同一个问题...
使用光线追踪...
Efficient 2D Tile based lighting system