Shaders return value

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Kymiko
Prole
Posts: 6
Joined: Wed Apr 13, 2016 8:48 pm

Shaders return value

Post by Kymiko »

Hello everyone,

I was wondering if it was possible to do general purpose calculation with shaders in Love. I am quite a noob with shaders, so sorry if the answer is obvious, but I didn't find any on the forums.

In my case, the basic idea would be for instance to check wether some pixels at given positions have a certain color. I would like a shaders that return simply true or false, according what is drawn on the screen.

Right now my best solution would be make the shader write a pixel in white, let's say at position (0,0), if the correct color is encountered. Then, from the canvas, create an imageData and evaluate the pixel at position (0,0). I wonder if it would be a good solution (or if it would even work, I didn't try it to be honest) since ImageDatas are created every frame, or if anything more appropriate is available, like shared data between CPU and GPU.

Thanks for your help !
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Shaders return value

Post by pgimeno »

As far as I know you can't read pixels from the screen. You need to draw to a canvas instead of drawing to the screen, and pass that canvas to the shader so that you can read from it. You may need to pass it another canvas to write to as well, or not. I haven't understood what you are trying to do.
User avatar
Nixola
Inner party member
Posts: 1949
Joined: Tue Dec 06, 2011 7:11 pm
Location: Italy

Re: Shaders return value

Post by Nixola »

There's no fast way to do that, unless you can cram a lot of calculations in it. You will have to use [wiki]Canvas:newImageData[/wiki] or [wiki]love.graphics.newScreenshot[/wiki] as far as I know, and they are both quite slow. It's ok if you just need to do it every once in a while, but if it's something you need to dk every frame I suggest you find another way.
lf = love.filesystem
ls = love.sound
la = love.audio
lp = love.physics
lt = love.thread
li = love.image
lg = love.graphics
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Shaders return value

Post by zorg »

Kymiko wrote:In my case, the basic idea would be for instance to check whether some pixels at given positions have a certain color.
This is never a good idea, for multiple reasons; if you want to support multiple resolutions, you can't really guarantee the number of pixels on the screen at one time, and even if you used a canvas with "internal resolution" and scaled that, it wouldn't be obvious where the 'true' pixel boundaries would be, if the scaling wouldn't be done in whole increments (2.0, 3.0, etc.).

You could do an old trick and (if your "usable" screen would be small enough) store colors in a 1D or 2D (nested) table, and check those; that said, it'll still be slow (faster than messing with canvases and imagedatas though) depending on what you really want to accomplish with what you're doing.

One more idea would be to fill a spritebatch with 1x1px solid white images, and use those numeric id-s the spritebach gives back as indices. you can't test for the color, but you can use this in tandem with the above table solution, and you can colorize each sprite instance using the already stored id-s. Not sure how fast this could work though. Faster than drawing points or 1x1 squares though.
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Kymiko
Prole
Posts: 6
Joined: Wed Apr 13, 2016 8:48 pm

Re: Shaders return value

Post by Kymiko »

Thank you for all your answers.

To be more precise, the idea would be to make the player collide with black color. That is why I would need to know if the color where the player is going is black.
Nixola wrote:There's no fast way to do that, unless you can cram a lot of calculations in it. You will have to use [wiki]Canvas:newImageData[/wiki] or [wiki]love.graphics.newScreenshot[/wiki] as far as I know, and they are both quite slow.
Right now I am taking a screen shot every frame, and that is why I came for a better solution. Even if the FPS displays 50-60, I can feel some disruptions while playing.
zorg wrote: You could do an old trick and (if your "usable" screen would be small enough) store colors in a 1D or 2D (nested) table, and check those; that said, it'll still be slow (faster than messing with canvases and imagedatas though) depending on what you really want to accomplish with what you're doing.
I don't understand this trick, since my problem is more about how to change the color in those arrays, that is the only (big) problem. The only simple way I see is taking a screen shot or generate an ImageData from the canvas as Nixola wrote.
zorg wrote: One more idea would be to fill a spritebatch with 1x1px solid white images, and use those numeric id-s the spritebach gives back as indices. you can't test for the color, but you can use this in tandem with the above table solution, and you can colorize each sprite instance using the already stored id-s. Not sure how fast this could work though. Faster than drawing points or 1x1 squares though.
I'm sorry but I don't understand the value of adding spritebatches to the equation. Do you mean to color them while drawing using a shader ? Sorry if I'm slow :crazy:

In the end it seems that is not the way to go judging by your answers, and I can probably find an other way to do what I want. I am still curious if it's possible however, so thanks for your help !
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Shaders return value

Post by zorg »

Well, how is it decided what pixels are black and what pixels aren't? After deciding that, you have a map.
Using both my ideas, you get:
- A table (let's go with 2 dimensional for now) filled with color triplets (like {0,0,0} for black)
- A spritebatch that's filled with an Image of size 1x1, that's made up of one {255,255,255} (white) colored pixel, for drawing it out:

Code: Select all

spritebatch = love.graphics.newSpriteBatch(onepixelimage)
for i=1,#map do 
for j=1, #map[i] do
spritebatch.setColor(map[i][j])
spritebatch.add(i,j) -- no need for the returned id, since those are the same as ((i-1) * #map) + j.
end
end
So, when you want the player to collide with black, first, is the player 1 pixel as well? or is it bigger? in the former case, you just need to check the map with positions around the player for the color black, otherwise it's a bit more complicated, since the player should have a hitbox which would have edges, and one would need to see whether any edge collides with black pixels or not.

When testing for collision, use the map table.
When wanting to modify the collision data, update both the map table, and the spritebatch with the correct id-s to the new color (should be done simultaneously)
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Kymiko
Prole
Posts: 6
Joined: Wed Apr 13, 2016 8:48 pm

Re: Shaders return value

Post by Kymiko »

Ok now I understand what you mean, but the thing is the game would be like a platformer, so with a camera, so the whole content of the screen might be changed every frame, meaning that I would update every frame the 2D map you were talking about (you didn't say how to update it by the way, I guess you assumed the change every frame would be easy to compute, but it's not).

So I think this solution might not be achievable, unless I didn't understand something correctly.
User avatar
pgimeno
Party member
Posts: 3656
Joined: Sun Oct 18, 2015 2:58 pm

Re: Shaders return value

Post by pgimeno »

If I understand you correctly, what you want is pixel-precision collisions. I did that for Thrust II Reloaded, see https://github.com/pgimeno/Thrust-II-re ... e.lua#L410.

The basic idea is to paint on a canvas the collision mask of everything but the object to collide, then use multiplicative mode to paint the mask of the object to collide. Then obtain the image with [wiki]Canvas:newImageData[/wiki] and compare the data to a pattern that has all zeros (see https://github.com/pgimeno/Thrust-II-re ... e.lua#L152 for how it's initialized).

The collision masks I used are an all-black layer and the alpha delimiting the shape.
User avatar
zorg
Party member
Posts: 3465
Joined: Thu Dec 13, 2012 2:55 pm
Location: Absurdistan, Hungary
Contact:

Re: Shaders return value

Post by zorg »

Kymiko wrote:Ok now I understand what you mean, but the thing is the game would be like a platformer, so with a camera, so the whole content of the screen might be changed every frame, meaning that I would update every frame the 2D map you were talking about (you didn't say how to update it by the way, I guess you assumed the change every frame would be easy to compute, but it's not).

So I think this solution might not be achievable, unless I didn't understand something correctly.
The viewport moves due to the camera, the map shouldn't. (0,0 will be at 0,0 even if the camera points to 14,-63 as the top left place for example, you just translated the drawing.) Also, yes, this would mean that you'd need to keep in memory (as in, the tables and spritebatch, the whole area, or at least, the size you will want to update offscreen as well)
Me and my stuff :3True Neutral Aspirant. Why, yes, i do indeed enjoy sarcastically correcting others when they make the most blatant of spelling mistakes. No bullying or trolling the innocent tho.
Kymiko
Prole
Posts: 6
Joined: Wed Apr 13, 2016 8:48 pm

Re: Shaders return value

Post by Kymiko »

pgimeno wrote:If I understand you correctly, what you want is pixel-precision collisions. I did that for Thrust II Reloaded, see https://github.com/pgimeno/Thrust-II-re ... e.lua#L410.

The basic idea is to paint on a canvas the collision mask of everything but the object to collide, then use multiplicative mode to paint the mask of the object to collide. Then obtain the image with [wiki]Canvas:newImageData[/wiki] and compare the data to a pattern that has all zeros (see https://github.com/pgimeno/Thrust-II-re ... e.lua#L152 for how it's initialized).

The collision masks I used are an all-black layer and the alpha delimiting the shape.
Very interesting, thank you for that ! I guess your game doesn't experience frame drops when generating the ImageData because the canvas is quite small. I like the idea, I think I will try something like that. I wonder if it's scalable though.
zorg wrote:The viewport moves due to the camera, the map shouldn't. (0,0 will be at 0,0 even if the camera points to 14,-63 as the top left place for example, you just translated the drawing.) Also, yes, this would mean that you'd need to keep in memory (as in, the tables and spritebatch, the whole area, or at least, the size you will want to update offscreen as well)
Ok now I get it, thanks ! :)
Post Reply

Who is online

Users browsing this forum: No registered users and 5 guests