0

I am trying to develop some kind of lighting system for my game. So far I made rectangle with cut out circle in the middle with some gradient, and I really like it but I would love to have more than one light source at once and I have no idea how to do this properly.

My current code in two versions:

First:

Point2D center = new Point2D.Float(Main.localConfig.WINDOW_WIDTH/2, Main.localConfig.WINDOW_HEIGHT/2);
float[] dist = {0.0f, 1.0f};
Color[] colors = {new Color(0.0f,0.0f,0.0f,0.0f), Color.BLACK};
RadialGradientPaint p = new RadialGradientPaint(center,100,dist,colors);
g2D.setPaint(p);
g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.95f));
g2D.fillRect(0, 0, Main.localConfig.WINDOW_WIDTH, Main.localConfig.WINDOW_HEIGHT);
g2D.dispose();

And second version:

public class LightArea {
    
    public BufferedImage Shadows;
    int circleSize;
    int circleCenterCordX, circleCenterCordY;

    public LightArea(int _circleSize, int _circleCenterCordX, int _circleCenterCordY){
        this.circleSize = _circleSize;
        this.circleCenterCordX = _circleCenterCordX;
        this.circleCenterCordY = _circleCenterCordY;
        UpdateLight();
    }
     
    public void UpdateLight(){
        Shadows = new BufferedImage(Main.localConfig.WINDOW_WIDTH, Main.localConfig.WINDOW_HEIGHT, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2D = (Graphics2D) Shadows.getGraphics();
        g2D.setColor(Color.BLACK);

        Area Rectangle = new Area(new Rectangle2D.Double(0, 0, Main.localConfig.WINDOW_WIDTH, Main.localConfig.WINDOW_HEIGHT));
        Area Circle = new Area(new Ellipse2D.Double(circleCenterCordX, circleCenterCordY, circleSize, circleSize));
        Rectangle.subtract(Circle);
 
        Color[] color = new Color[5];
        float[] spacing = new float[5];
        color[0] = new Color(0,0,0,0f);
        color[1] = new Color(0,0,0,0.25f);
        color[2] = new Color(0,0,0,0.50f);
        color[3] = new Color(0,0,0,0.75f);
        color[4] = new Color(0,0,0,0.95f);

        spacing[0] = 0f;
        spacing[1] = 0.25f;
        spacing[2] = 0.50f;
        spacing[3] = 0.75f;
        spacing[4] = 0.95f;
        RadialGradientPaint gradientPaint = new RadialGradientPaint(circleCenterCordX, circleCenterCordY, circleSize,spacing,color);
        g2D.setPaint(gradientPaint);
        g2D.fill(Circle);
        g2D.fill(Rectangle);
        g2D.dispose();
    }

    public void Render(Graphics2D g2D) {
        g2D.drawImage(Shadows,0,0,null);
    }
}

And both of them were executed from this method:

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2D = (Graphics2D) g;
    for (List<Node> tempInnerList : Map)
    for (Node tempNode : tempInnerList)
    tempNode.Render(g2D);
}

(The method is in a Class which extends JPanel.

I tried to just use my code once again and draw it with:

g2D.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.95f));

With different values and rules but it didn't work. Sometimes I everything was bright as if the shadows didn't appear. Sometimes I was getting weird white pixels at the edges of the circles, and at the place where they connect they were darker instead of brighter as I was expecting it to be.

Ben the Coder
  • 539
  • 2
  • 5
  • 21
Alethia
  • 21
  • Do you know there are ready to use libraries for lighting or game development in Java and still you want to develop it yourself? – Queeg Jul 27 '23 at 21:27
  • Yes, I am aware of that but like you see I want to try to do this without them. – Alethia Jul 27 '23 at 21:30
  • Maybe use a [JLayer](https://docs.oracle.com/javase/tutorial/uiswing/misc/jlayer.html). – camickr Jul 27 '23 at 22:37
  • I was mucking about with this idea based on [this](https://stackoverflow.com/questions/76699899/how-to-delete-pixels-on-a-bufferedimage-or-other-components-using-graphics/76700996#76700996) example and what I found was, you need to do a two step pass. First, you take all the light sources and `subtract` them from the `Area`, this gives you the "cut out effect". Next you take all the light sources and then you paint the `RadialGradientPaint` for each. This seems to work until you have two light sources intersect, then you end up in all areas of weirdness – MadProgrammer Jul 27 '23 at 23:39
  • 2
    I am not sure who downvoted or votes for closure. The question is about programming, the poster gave some effort and shared the code. It is just uncomfortably difficult to answer if you do not have direct experience in 3D rendering/shading. – Queeg Jul 28 '23 at 05:57
  • @Alethia Maybe you need to study some other resources (I quickly googled https://gamedevelopment.tutsplus.com/series/a-beginners-guide-to-coding-graphics-shaders--cms-834) or go for more focused forums. Even if it sounds weird, the forums around the existing libraries could have members with more knowledge in this area. – Queeg Jul 28 '23 at 06:02
  • "Uncomfortably difficult" is an understatement. You could, I suppose, fake lighting with textures the way the OP is trying to do, but it's likely to not work unless you are able to carefully plan ahead for all contingencies. If you want try to see how this all works under the hood, read the red book: https://www.amazon.com/OpenGL-Programming-Guide-Official-Learning-dp-0134495497/dp/0134495497/ref=dp_ob_image_bk – markspace Jul 28 '23 at 06:12
  • @Queeg Like I said before I want to avoid any "external" libraries and by look of things tutorial you provided uses some. If I would like it to be perfect I would use Unity or Unreal Engine and C# or C++ instead of Java. I want to build it from nothing, for fun, to learn something, to better understand how everything works rather than jumping into deepest water and learn what one particular Engine can and cannot to. Althought thanks for this tutorial. <3 Maybe one day I will change my mind and try to do something different way. – Alethia Jul 28 '23 at 12:42
  • @MadProgrammer Exactly, it works until they overlap each other. I accidentally found kinda solution for that problem. I noticed that when I was changing values in spacing array so that last one is below 0.7f sometimes it needed to be below 0.6 weirdeness wasn't that noticable, but circle got way way smaller because of that lower spacing. – Alethia Jul 28 '23 at 12:47
  • I've been mucking about with a "weird" idea, but I don't think it's very ... efficient. Basically, the idea would be to use a "circle algorithm", from the centre position, basically grow a circle out to the desire size, on each iteration, you would increase the pixels alpha by a decreasing amount, based on the distance from the centre. Again, I don't think it's efficient, as you'd need to create `n` number of circles per light source based on the size of the light and each pixel in the circle would need to be updated – MadProgrammer Jul 28 '23 at 13:11

0 Answers0