Open Shiv2k3 opened 2 years ago
Hi, have you tried using the backbuffer
texture?
That one gets reset ever frame right?
Not reset, but overwritten with the next frame. So the backbuffer always contains the last image. To some extend, this can be used to transfer information between frames (have a look at the Game of Life sample shader that comes with the app). But that's probably not enough for what you're trying to do, sorry 😬
At the moment, there's no persistent buffer a fragment shader can write to. As far as I can see, there would be two options for that: SSBOs or imageStore in GLES 3.10.
SSBOs would be the way to go I think, but they aren't supported in Shader Editor yet.
@markusfisch The buffers which shadertoy has provided are great. Will they be implemented in Shader Editor?
Related to saving to the backbuffer. Hopefully it can start a discussion of tips and examples of how to save data to the backbuffer for the FAQ.
Any idea why casting resolution uniform as a vec2 is needed in this code to match a pixel / save data?
uniform vec2 resolution
ivec2 px = ivec2(0, 1); // pixel coord
vec2 offset = vec2(0.5); // texture coords center of texel
vec2 coord = ( vec2(px) + offset )
/ resolution; //****
return (coord == uv) ? 1.0 : 0.0;
Fails to match coordinates
vs
vec2 coord = ( vec2(px) + offset )
/ vec2(resolution); //****
return (coord == uv) ? 1.0 : 0.0;
Works
I assume it's related to
#ifdef GL_FRAGMENT_PRECISION_HIGH
precision highp float;
#else
precision mediump float;
#endif
If I comment that out (causing low precision?) I lose pixels (not matching) and probably have to switch to a square range of pixels to save one vec3.
So I guess resolution comes in as a lowp and is doing a lowp division. if not cast to a vec3.
Maybe this is done poorly.
I have this function.
float saveAtPixel(ivec2 px, vec2 resolution, vec2 uv){
/*
Return 1.0 if uv == target pixel
Otherwise return 0.0
Use like
vec4 color = calculated color
color = mix(color, data, saveAtPixel)
gl_FragColor = color;
Will swap calculated color for data if at the right coordinate
*/
vec2 coord = (vec2(px) + vec2(0.5)) / resolution;
return (coord == uv) ? 1.0 : 0.0;
}
I was passing in the uniform vec3 resolution
to the function and it worked just fine.
To stop abusing the gpu calculating everything at every frame for every pixel, I tried moving the test into an updateAndSave function.
In that function I called vec2 coord = (vec2(px) + vec2(0.5)) / resolution; if (coord == uv) dowork = true; Using the resolution uniform directly, and it wouldn't match any pixels unless I recast it as vec2(resolution). I assume changing the precision of the vec2/floats.
Here's some of my first implementation of saving to the backbuffer.
To be more efficient, instead of calculating everything and deciding whether to save the results with mix(outColor, data, doISaveAtThisCoordinate). I'll subject every pixel to many if else checks or adding doISavePosHere + doISaveVelocityHere and calculate the new data depending on if it's a pixel for storage.
// Keeping an old and new pair of stuff
// Render old, calculate and save new
void betterFunctionMaybe(){
float save = 0.0;
for(Nobjects){
save += doISavePos(uv, object);
save += doISavePropertyX(uv, object);
// etc
}
if (save > 0.5) {
updateObjects
physics
magic
saveData(uv, updatedObjects)
}
}
The end... Apologies if there's a uvw vs stq holy war I'm not aware of.
#define Nballs 5
vec4 readAtPixel(ivec2 px, vec2 res, sampler2D buffer){
vec2 coord = (vec2(px) + vec2(0.5)) / res;
return texture2D(buffer, coord);
}
float saveAtPixel(ivec2 px, vec2 resolution, vec2 uv){
/*
Return 1.0 if uv == target pixel
Otherwise return 0.0
Use like
vec4 color = mix(color, data, saveAtPixel)
gl_FragColor = color;
Will swap calculated color for data if at the right coordinate
*/
vec2 coord = (vec2(px) + vec2(0.5)) / resolution;
return (coord == uv) ? 1.0 : 0.0;
}
void readIn(inout vec2[Nballs] balls,
inout vec2[Nballs] dir,
inout float[Nballs] speed,
inout float rand,
in int row) // should be column
{
// Should switch to save and read vec4? Wasn't sure about alpha channel open.
vec3 data = readAtPixel(
ivec2(row, 1), resolution, backbuffer).rgb;
balls[0] = data.rg;
rand = data.b;
// ds dir & speed
vec3 ds = readAtPixel(
ivec2(row, 3), resolution, backbuffer).rgb;
dir[0] = ds.rg;
dir[0] = (dir[0] * 2.) - vec2(1.);
speed[0] = ds.b;
for(int i = 1; i < Nballs; i++){
balls[i] = readAtPixel(
ivec2(row, 1+i*4), resolution, backbuffer).rg;
ds = readAtPixel(
ivec2(row, 3+i*4), resolution, backbuffer).rgb;
dir[i] = (ds.rg * 2.) - vec2(1.);
speed[i] = ds.b;
}
}
main... {
// Doing all of this at every pixel
// Nballs = 5 is the best I could do to stay at 60 fps
// readIn
// if 0.0, initialize
// Do something
vec3 oldColor = texture2D(backbuffer, uv).xyz * colorfade;
// Fade to black quicker
// Should change to log or exp with colorfade param
vec3 ocolor = oldColor;
for(int i = 0; i < Nballs; i++){
float b = inCircleSmooth(uv, balls[i], aspectRatio, sqRadius, circleFade);
// too bright ocolor += color[i] * b;
ocolor = mix(ocolor, color[i], b);
}
// Save objects for next frame
// Pos is 0-1
// Dir pis -1 - +1
// Dir stored + 1 * 0.5
// Doing all this every pixel to decide if we should save
// Save data func
vec3 data = vec3(balls[0].x, balls[0].y, rand);
// Change color to position data if saveAtPixel returns 1
// else pass the
ocolor = mix(ocolor,
data,
saveAtPixel(ivec2(row, 2), resolution, uv));
data.xy = (dir[0].xy + vec2(1.)) * 0.5;
data.z = speed[0];
ocolor = mix(ocolor,
data,
saveAtPixel(ivec2(row, 4), resolution, uv));
for(int i = 1; i < Nballs; i++){
data.xy = balls[i].xy;
ocolor = mix(ocolor, data,
saveAtPixel(ivec2(row, 2+i*5), resolution, uv));
data.xy = (dir[i].xy + vec2(1.)) * 0.5;
data.z = speed[i];
ocolor = mix(ocolor, data,
saveAtPixel(ivec2(row, 4+i*5), resolution, uv));
}
gl_FragColor = vec4(ocolor, 1.0);
I am new to glsl and I'm trying to create a fluid simulation in this shader editor but I can't seem to find anyway to save the texture with the fluid particle's data, I have tried using arrays but they are very laggy.