# Creating a light source in 2D world

**URL:** <https://discourse.processing.org/t/creating-a-light-source-in-2d-world/23528>\
**Category:** Coding Questions\
**Created:** [August 27, 2020, 7:37pm UTC](https://discourse.processing.org/t/creating-a-light-source-in-2d-world/23528 "2020-08-27T19:37:51Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![xSimas](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/xsimas/32/10441_2.png) [@xSimas](https://discourse.processing.org/u/xSimas)\
**Post date:** [August 27, 2020, 7:37pm UTC](https://discourse.processing.org/t/creating-a-light-source-in-2d-world/23528/1 "2020-08-27T19:37:51Z")

</div>

Hi. I’m trying to create a light source in 2D. As an example, take a game character in 2D world that is holding a torch in a dark cave and there’s some area around him that’s fully lit up and then it gets darker (as the radius gets larger, until pitch black).

I tried using `mask()` but with no success. I’m also completely new to shaders and thought that I’d give them a try. I made a shader that does exactly what I described above: the dark circle you see has color alpha value of 0.0 and as the radius increases, the alpha increases as well. I thought this would work since these alphas are 0, hence it would draw over something else. But I was wrong! Once again, completely new to shaders 😛

 ![](https://i.imgur.com/uQq2noO.png)  
What worked though, is executing `shader()` on separate PGraphics and then using `get()` to retrieve PImage. Then I used it as a mask on another image, which was just a simple red color image. But surely I’m not going to use separate PGraphics over and over since I notice big jumps in GPU and CPU (not that much) usage on my task manager.

So that’s my question: can I do this with shaders? In a way that my shader would just run over anything that’s on the screen but would not completely draw over it (transparent shader?). If so, I’m all ears and eyes. I was also thinking of just loading an image with transparent cut out circle and drawing extra black rectangles around it but idk… doesn’t seem ideal 😃

---

<div class="post-metadata">

**Author:** ![noel](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/noel/32/213_2.png) [@noel](https://discourse.processing.org/u/noel)\
**Post date:** [August 28, 2020, 7:58am UTC](https://discourse.processing.org/t/creating-a-light-source-in-2d-world/23528/2 "2020-08-28T07:58:44Z")

</div>

Maybe something like this? (use image below)

```auto
PImage img; 

void setup() { 
  size(697, 462); // Note that the size is the same as image
  img = loadImage("treasure.png");
  noCursor();
  noFill();
}                                  
void draw() { 
  background(255);
  image(img, 0, 0);
  loadPixels(); 
  img.loadPixels(); 
  for (int y = 0; y < height; y++ ) { 
    for (int x = 0; x < width; x++ ) { 
      int loc = x+y*width;  
      float r = red(img.pixels [loc]); 
      float g = green(img.pixels[loc]); 
      float b = blue(img.pixels[loc]);
      float d = dist(mouseX, mouseY, x, y);
      float factor = map(d/2, 0, 200, 2, 0);      
      pixels[loc] = color(r*factor, g*factor, b*factor);
    }
  }
  updatePixels();
}

```

 ![treasure](https://canada1.discourse-cdn.com/flex036/uploads/processingfoundation1/original/2X/f/f7ce4a39916307dfd4bcc3fe12256b1fec06c810.jpeg)

---

<div class="post-metadata">

**Author:** ![xSimas](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/xsimas/32/10441_2.png) [@xSimas](https://discourse.processing.org/u/xSimas)\
**Post date:** [August 28, 2020, 11:02am UTC](https://discourse.processing.org/t/creating-a-light-source-in-2d-world/23528/3 "2020-08-28T11:02:16Z")

</div>

> [@noel](#):
>
> ```auto
> PImage img; 
> 
> void setup() { 
> size(697, 462); // Note that the size is the same as image
> img = loadImage("treasure.png");
> noCursor();
> noFill();
> }                                  
> void draw() { 
> background(255);
> image(img, 0, 0);
> loadPixels(); 
> img.loadPixels(); 
> for (int y = 0; y < height; y++ ) { 
> for (int x = 0; x < width; x++ ) { 
> int loc = x+y*width;  
> float r = red(img.pixels [loc]); 
> float g = green(img.pixels[loc]); 
> float b = blue(img.pixels[loc]);
> float d = dist(mouseX, mouseY, x, y);
> float factor = map(d/2, 0, 200, 2, 0);      
> pixels[loc] = color(r*factor, g*factor, b*factor);
> }
> }
> updatePixels();
> }
> 
> ```

Seems like a great solution! Haven’t thought of using pixels since I’ve never worked with them before, just read about the functions. But it does achieve what I was aiming for! Thanks a bunch! 🙂

---

<div class="post-metadata">

**Author:** ![xSimas](https://yyz2.discourse-cdn.com/flex036/user_avatar/discourse.processing.org/xsimas/32/10441_2.png) [@xSimas](https://discourse.processing.org/u/xSimas)\
**Post date:** [August 28, 2020, 5:30pm UTC](https://discourse.processing.org/t/creating-a-light-source-in-2d-world/23528/4 "2020-08-28T17:30:19Z")

</div>

Although I marked this as solved, I didn’t do much testing first. While the solution is alright, looping through each pixel is really power consuming and makes the sketch drop frames.

Which is why I wanted to improve it and use a limited area only to handle pixels.

I ended up creating an image using PGraphics and `mask()` with a transparent circle in the middle (given some radius) and some extra area surrounding that circle, given the parameter again.

This is so that I can use `pixels[]` array and check the alpha of each pixel only for this given image. If the pixel turns out to have alpha higher than 0, I deal with it.

In the end, the final result looks like this ([background source](https://wallhaven.cc/w/3911w9)):

 ![](https://i.imgur.com/zshEO27.png)  
I’m also using 4 black rectangles to fill the rest of the background with darkness. I really like the way this turned out!

Sketch code:

```auto
int radius = 75;
int black = radius * 5;
float d_multi = 1 / (float(radius)/100);

PImage img;
PImage mask;

PImage bg;
BGRect[] rects;

void setup() { 
  size(1380, 780, P2D);
  
  bg = loadImage("bg.jpg");
  bg.resize(width, height);
  rects = new BGRect[] { 
    new BGRect(), new BGRect(), new BGRect(), new BGRect()
  };
  
  PGraphics pg = createGraphics(black, black);
  pg.beginDraw();
  pg.background(0, 0, 255); // Blue background does magic :)
  pg.strokeWeight(2);
  pg.stroke(255);
  pg.translate(pg.width/2, pg.height/2);
  pg.fill(0);
  pg.circle(0, 0, radius*2);
  pg.endDraw();
  mask = pg.get();
  
  pg.beginDraw();
  pg.background(0, 0, 255);
  pg.noStroke();
  pg.translate(pg.width/2, pg.height/2);
  pg.fill(0);
  pg.rect(-pg.width/2, -pg.height/2, pg.width, pg.height);
  pg.endDraw();
  img = pg.copy();
  
  pg.clear();
  img.mask(mask);
}                                  
void draw() { 
  background(170, 200, 100);
  
  // Side rects:
  rects[0].x = 0; rects[0].y = 0;
  rects[0].w = mouseX - black/2; rects[0].h = height;
  
  rects[1].x = mouseX + black/2; rects[1].y = 0;
  rects[1].w = width - rects[1].x; rects[1].h = height;
  
  // Top and down rects:
  rects[2].x = mouseX - black/2; rects[2].y = 0;
  rects[2].w = black; rects[2].h = mouseY - black/2;
  
  rects[3].x = mouseX - black/2; rects[3].y = mouseY + black/2;
  rects[3].w = black; rects[3].h = height - rects[3].y;
  
  image(bg, 0, 0);
  image(img, mouseX - black/2, mouseY - black/2);
  
  img.loadPixels();
  for(int x = 0; x < img.width; x++) {
    for(int y = 0; y < img.height; y++) {
      int loc = x + y * img.width;
      float alpha = alpha(img.pixels[loc]);
      float d = dist(mouseX, mouseY, mouseX - img.width/2 + x, mouseY - img.height/2 + y);      
      if(alpha > 0) {
        float r = red(img.pixels[loc]); 
        float g = green(img.pixels[loc]); 
        float b = blue(img.pixels[loc]);
        img.pixels[loc] = color(r, g, b, d * d_multi);
      }
    }
  }
  img.updatePixels();
  
  for(int i = 0; i < rects.length; i++) {
    rects[i].show();
  }
}

void mouseWheel(MouseEvent e) {
  if(e.getCount() == -1) {
    if(d_multi > 1 / (float(radius)/100)) d_multi -= 0.05;
  } else {
    d_multi += 0.05;
  }
}

```

…and `BGRect` class:

```auto
class BGRect {
  
  float x, y, w, h;
  
  void show() {
    pushMatrix();
    noStroke();
    fill(0);
    rect(x, y, w, h);
    popMatrix();
  }
}

```
