keep variable value beteen loops in shader
Asked Answered
R

16

0

So, another question on shaders.

Well, its just that, is in the experimentations i had it seens that for each run( in this case, pixelwise, of the fragment shader), it seens to reset the variables to the original declared state of the headder.

shader_type canvas_item; varying float varvar; void fragment() { varvar += 2.;//This one changes the value, but for the whole screen, aka, every pixels get the null varvar+2 textex = texture(texarr, vec3(UV, mod(varvar,3)+0.0)); varvar += 2.;//This does nothing. and if used alone, trows error beacuse i think above line acess null value.

The result i was expecting was a mono-dimensional plot of the 3 textures across the whole UV map. But, insted, all point get the same value.

Soo, i guess it is reseting the variable for each fragment()run.

How to keep the value of the variable everincreasing?(even if it stackoverflow, that not a problem, i thinkg, beacuse if it round-robin, i an already putting it inside a mod operator, soo that fine i guess)

TLDR: How to keep a variable value across each run inside a shader?

Thanks for the help.

Resee answered 2/3, 2022 at 14:21 Comment(0)
C
0

https://gamedev.stackexchange.com/questions/54801/set-a-variable-inside-a-glsl-fragment-shader-that-persists-for-the-render

The above is a good explanation of how fragment shaders work which may cause you to rethink your approach and how you might address the issue (ie with a texture)

i am not well familiar with shaders too much but i think using another texture with the modulo offsets will get you what you want.

Candie answered 2/3, 2022 at 17:18 Comment(0)
R
0

Yeah bro, that was what i was thinking, the concurrency nature of the execution, already removes the possibility of a linear control variable.

The alternative, is using the uniform keyword, so i can get the data to GDScript

But... If the variable is a uniform, i cant change it from inside the shader.

If i use a uniform, i can process in GDscript, but not in shader If i use a varying, i kinda can process in shader, but not GDscript.

Kinda dead end?

Resee answered 2/3, 2022 at 17:45 Comment(0)
C
0

Kinda dead end?

You will need to use a texture to define the modulo as mentioned in the link and use it as an input texture.

I don't know if you can use a small texture and then arrange for it to be 'tiled' to the fragment shader so you will only need say a 3x3 (modulo size) texture as a source for your modulo value, but it would be an additional input set as a uniform texture to your shader program overall

Candie answered 2/3, 2022 at 18:29 Comment(0)
B
0

Shaders are run in parallel, so there is not even an idea of a logical sequence. They may be thousands of iterations running simultaneously, with no clear before or after. So you can't think sequentially. Can you explain in English what you are trying to do (as in the end result of the effect)? I don't understand the code you posted.

Bellwort answered 2/3, 2022 at 18:53 Comment(0)
R
0

I will create a short derivative shadder that simplify some aspects of the implementation that i guess are the most relevant.

But, the fast go faster, so in plain english you may already put some correct context to the problem.

What i want, lets say, i have a simple 3*3 in size, ColorRect.

I just want to map the (0,0|0,1|0,2|1,0|1,1|1,2|2,0|2,1|2,2)coordinates of the image to a linear: 0,1,2,3,4,5,6,7,8.

IN that way, i can atribuite several tranformations in a precise way using shader logic.

uniform sampler2DArray texarr : hint_black; textex = texture(texarr, vec3(UV, LINEARMAGIC));

And, then, i can map that using the sampler2DArray. I was very happy when generic arrays come out, but only godot4. I think i can solve my problems using the already present sampler2DArray.

But, i need to map the UV to the Array index, in that case, using a simple nested 2-dimensional loop, as above stated.

The thing is i do not understand very well the uv and tranformations, i tryied brute force, but only get some cool moire efects

Like the

results

That shows it is possible to make the dance going, but whats the correct move? haha.

The image shoud show, as my array is[red,green,blue], and in the case of a 4;4 image:

R,G,B,R G,B,R,G B,R,G,B R,G,B,R

Can you easly understand the shadder needed to map to a n dimensional grid? Sorry for putting my "homework" here.

Thanks for the support and eforts all you guys.

Resee answered 2/3, 2022 at 19:45 Comment(0)
B
0

Probably the fastest thing would be to use a look up table (LUT). You can generate a PNG image with GDScript and save it to your project. With GDScript, you can use set_pixel and standard loops, so you don't have to worry about parallel processing. Then you pass the LUT into the shader as a uniform sampler2D and just sample it in the fragment function. And the LUT can contain anything you can represent as a color. These could be vectors, positions, results of math formulas like sin or cos, square root, whatever. And this will be the fastest possible as the image is saved (such as with a PNG) and can be pre-calculated once. And the shader just takes 1 sample, which is quick.

Bellwort answered 2/3, 2022 at 21:38 Comment(0)
R
0

Yes, perfectly. That somewhat what i am doing in the past, but as you imagine. and not using shaders at all, you can just set_pixel and tranform it to a texture in the end and update, end game.

But, as your response already puts out, i do indeed need and want to worry about the parallel processing. That the thing that make everthings works(Maybe, that the whole quest) in a production manner.

See, this whole create image/change image then process to a texture is a REALLY ineficient game. It does not matter the content of the change, and do not ask me to a do a ImageTexture.set_data() after the first create_from_image(). IT IS NOT PERFORMANT. to me, it taked the aparentluy same time.

Well. The thing is, using the shader purely, can be perfomant.

I just dont know how to implement the array transformation from the UV map to the linear one.

I will continue to investigate, but please, any insight on how to map the ~~> @PeterPM said:

I just want to map the (0,0|0,1|0,2|1,0|1,1|1,2|2,0|2,1|2,2)coordinates of the image to a linear: 0,1,2,3,4,5,6,7,8.

So, that on each pass of the shader, i can output a linear number that can acess the corred array position.

The transformation is easy to do along you get a vector2.

So, i just need:

How tranform the hipotetical output of a UV in a shader of a texture that is aplied to a CanvasItem to a Vector2 that mach in integers the pixel position, like in the 3x3 above exemple so that i can know for each pass a Vec2(X,Y) that is maped and generated by a (UV.x, UV.y).

I think understanding that i can already go on on my problem. Thanks.

Resee answered 2/3, 2022 at 23:3 Comment(0)
B
0

Well texture drawing in GDScript is very slow, but you only do it once ever. Not once when the game starts, I mean once on your development machine and it is saved forever. You can even draw it in Photoshop, but this would be complex and it is easier to do with code.

Bellwort answered 2/3, 2022 at 23:44 Comment(0)
C
0

@PeterPM said:

How tranform the hipotetical output of a UV in a shader of a texture that is aplied to a CanvasItem to a Vector2 that mach in integers the pixel position, like in the 3x3 above exemple so that i can know for each pass a Vec2(X,Y) that is maped and generated by a (UV.x, UV.y).

So I am having a little trouble following but is your question how a UV is mapped to the dimension of the canvas item?

Candie answered 3/3, 2022 at 1:35 Comment(0)
B
0

So basically, you save numbers into the texture as colors, and there is some conversion in the shader. For example, if you want the value of (0, 0) to be the number zero, you save the color (let's say the red channel of the pixel) for the position of 0 on the x and 0 on the y to be the color (0, x, x) (the green and blue channels don't need to be used). The the pixel coordinates on the x/y of (2, 1) would save the color (7, x, x) where red is an integer of 7 and green and blue are not used. You can save up to 256 numbers in one channel, or combine the channels together (maybe with a function) to store thousands or millions of numbers. And the input to the function is always 2 values (the x and y positions) so you can have as many inputs as you want, assuming you make a large enough texture. In your case, you won't have to do much conversion, but in other cases you can process different inputs (like say a 3 float vector) and collapse them into a 2 float (or 2 int) value, as input to the function. Similarly, the output need not be a single integer or just a float. It can be anything you can process from 3 (or 4) float values.

Bellwort answered 3/3, 2022 at 2:0 Comment(0)
R
0

Yeah, and i think i have already done some of that work on past projects, but it was somehow imprecise, doing the UV and the GET_PIXEL_SIZE operation, to get to the correct that the UV is doing the process.

I think maybe thats the only way to get that done.

But all i need is to know in integer in what pixel i am working, in a Vec2 manner.

The UV output it in a 0-1 absolute form, right?

Well, i think i will try to look on my old code that translated that, but as i remeber, it was imprecise...

All i wanted is to have the same workflow you get in GDScript in the shader.

In gdscript you simple do a

func _ready(): var x = 4 var y = 4 for a in x: for b in y: var state = (a*x)+b print(state)

and then i get the linearity i need, line by line of the image:

--- Debugging process started --- Godot Engine v3.4.3.stable.official.242c05d12 - https://godotengine.org OpenGL ES 3.0 Renderer: Intel(R) HD Graphics 4000 OpenGL ES Batching: ON

0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 --- Debugging process stopped ---

I just need to something like that with the UV

Resee answered 3/3, 2022 at 2:1 Comment(0)
B
0

Yes, you can define functions in shader code and call them from the vertex or fragment function to do basically whatever you want. The conversion is quite simple, but I'm doing some stuff right now, maybe I can post the code later tonight. But you already have the equation in your code.

(a*x)+b

You don't need a lot, because the UV x/y values already pertain to what would be in the loop. The part you have to figure out is how to convert a float number into an integer number. For that you would need to know the size of the texture you are working with. The UV goes from 0.0 to 1.0. So if you multiply that by the dimensions of the texture, you have the pixel coordinates in floating point. Then use floor(val) to snap them to integers.

Bellwort answered 3/3, 2022 at 2:6 Comment(0)
R
0

Thanks for the insights, cyberreality, but thats note the premisse i think i need, but i will try to understand more, maybe there some usecases.

But, my aprouch is using the TextureArray, and not to carry data, but the image in itself.

The data is maped using that matricial distribuition, on the dual dimesions being fused in the nested loops described by the above code.;

As far i understand, the UV variable gives us that, the X and Y position of the current pixel. I want to convert that to INTEGERS relative to the texture size of the rect in question.

Really sorry for not expressing my need in the most consise way, and again, rejoicing in this conjoint efort for help..

Resee answered 3/3, 2022 at 2:7 Comment(0)
R
0

@cybereality said: Yes, you can define functions in shader code and call them from the vertex or fragment function to do basically whatever you want. The conversion is quite simple, but I'm doing some stuff right now, maybe I can post the code later tonight. But you already have the equation in your code.

(a*x)+b

You don't need a lot, because the UV x/y values already pertain to what would be in the loop. The part you have to figure out is how to convert a float number into an integer number. For that you would need to know the size of the texture you are working with. The UV goes from 0.0 to 1.0. So if you multiply that by the dimensions of the texture, you have the pixel coordinates in floating point. Then use floor(val) to snap them to integers.

Well thanks for the direct instructions, will try to code that, and will come back later with results of the shader code.

Seya.

Resee answered 3/3, 2022 at 2:9 Comment(0)
B
0

I don't have time to test the code, but it would look something like this:

uniform vec2 texture_size;

void fragment() {
    vec2 pixel_coords = floor(UV * texture_size);
}

I don't remember if floor() can take a vector, you might have to do x/y separate.

Bellwort answered 3/3, 2022 at 3:54 Comment(0)
R
0

I love you all.

Resee answered 3/3, 2022 at 12:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.