Plasma Shader is not rendering as expected - glsl

I am trying to hack this Plasma shader from ShaderToy so it works with Spark AR ... I'm very close but there is a weird issue with the shader being compressed into the corner. Are there any shader guru's who can give me some pointers? Here's what it looks like now in Spark:
The inputs are the screen size, a screen touch coordinate, the time, and a direction vec2 that could be the culprit. I'm not entirely sure what this input is doing.
Here's my converted shader code:
precision highp float;
vec4 main( in vec2 direction, in float time, in vec2 touch, in vec2 screen )
{
vec2 uv = fragment(std::getVertexTexCoord());
float t = time/.1 + touch.x;
vec2 R = uv.xy, S = screen * 0.01,
p = ( direction+direction - R ) / R * S,
q = vec2(cos(-t / 165.), cos( t / 45.)) * S - p;
t = 1. + cos( length( vec2(cos( t / 98.), sin( t / 178.)) * S - p ) / 30.)
+ cos( length( vec2(sin(-t / 124.), cos( t / 104.)) * S - p ) / 20.)
+ sin( length(q) / 25. ) * sin(q.x / 20.) * sin(q.y / 15.);
return .5 + .5* cos( (time+touch.y) / vec4(63,78,45,1) + ( t + vec4(0,1,-.5,0) ) *3.14 );
}
This is a sca file which is the Spark AR format for shaders.
It is a conversion of this code from ShaderToy:
void mainImage( out vec4 O, vec2 U )
{
float t = iTime/.1 + iMouse.x;
vec2 R = iResolution.xy, S = vec2(160,100),
p = ( U+U - R ) / R * S,
q = vec2(cos(-t / 165.), cos( t / 45.)) * S - p;
t = 1. + cos( length( vec2(cos( t / 98.), sin( t / 178.)) * S - p ) / 30.)
+ cos( length( vec2(sin(-t / 124.), cos( t / 104.)) * S - p ) / 20.)
+ sin( length(q) / 25. ) * sin(q.x / 20.) * sin(q.y / 15.);
O = .5 + .5* cos( (iTime+iMouse.y) / vec4(63,78,45,1) + ( t + vec4(0,1,-.5,0) ) *3.14 );
}
Hope someone can help.

The problem comes from the fact that you misinterpreted the iResolution variable in the shadertoy code as the uv coordinates of the fragment. iResolution is just a variable that stores the dimensions in pixels of the image on the screen. It is the same for each pixel. U on the other side, stores the coordinates of the fragment measured in pixels ( so that uv = U / iResolution ). It is called fragCoord in the default shadertoy shader.
In your case, as you already have uv going from 0 to 1, you don't need R to define p : p = ( U + U - R ) / R * S can become p = ( U/R + U/R - R/R ) * S and then p = (uv + uv - vec2(1)) * S.
I hope this fixes your problem, tell me if it doesn't.
EDIT: I just realized that you can simplify the definition of p even further as the - vec2(1) is a translation that doesn't really affect the result and the uv + uv can be replaced by uv by compensating with S. So it can become p = uv * S.

Related

Fish-eye warping about mouse position - fragment shader

I'm trying to create a fish-eye effect but only in a small radius around the mouse position. I've been able to modify this code to work about the mouse position (demo) but I can't figure out where the zooming is coming from. I'm expecting the output to warp the image similarly to this (ignore the color inversion for the sake of this question):
Relevant code:
// Check if within given radius of the mouse
vec2 diff = myUV - u_mouse - 0.5;
float distance = dot(diff, diff); // square of distance, saves a square-root
// Add fish-eye
if(distance <= u_radius_squared) {
vec2 xy = 2.0 * (myUV - u_mouse) - 1.0;
float d = length(xy * maxFactor);
float z = sqrt(1.0 - d * d);
float r = atan(d, z) / PI;
float phi = atan(xy.y, xy.x);
myUV.x = d * r * cos(phi) + 0.5 + u_mouse.x;
myUV.y = d * r * sin(phi) + 0.5 + u_mouse.y;
}
vec3 tex = texture2D(tMap, myUV).rgb;
gl_FragColor.rgb = tex;
This is my first shader, so other improvements besides fixing this issue are also welcome.
Compute the vector from the current fragment to the mouse and the length of the vector:
vec2 diff = myUV - u_mouse;
float distance = length(diff);
The new texture coordinate is the sum of the mouse position and the scaled direction vector:
myUV = u_mouse + normalize(diff) * u_radius * f(distance/u_radius);
For instance:
uniform float u_radius;
uniform vec2 u_mouse;
void main()
{
vec2 diff = myUV - u_mouse;
float distance = length(diff);
if (distance <= u_radius)
{
float scale = (1.0 - cos(distance/u_radius * PI * 0.5));
myUV = u_mouse + normalize(diff) * u_radius * scale;
}
vec3 tex = texture2D(tMap, myUV).rgb;
gl_FragColor = vec4(tex, 1.0);
}

GLSL: Sample from previous output and not texture2D

I'm trying to write a custom shader where I first blur the texture and then run sobel edge finding.
I've got sobel running ok via the following script
vec4 colorSobel = texture2D(texture, uv);
float bottomLeftIntensity = texture2D(texture, uv + vec2(-0.0015625, 0.0020833)).r;
float topRightIntensity = texture2D(texture, uv + vec2(0.0015625, -0.0020833)).r;
float topLeftIntensity = texture2D(texture, uv + vec2(-0.0015625, 0.0020833)).r;
float bottomRightIntensity = texture2D(texture, uv + vec2(0.0015625, 0.0020833)).r;
float leftIntensity = texture2D(texture, uv + vec2(-0.0015625, 0)).r;
float rightIntensity = texture2D(texture, uv + vec2(0.0015625, 0)).r;
float bottomIntensity = texture2D(texture, uv + vec2(0, 0.0020833)).r;
float topIntensity = texture2D(texture, uv + vec2(0, -0.0020833)).r;
float h = -secondary * topLeftIntensity - coef * topIntensity - secondary * topRightIntensity + secondary * bottomLeftIntensity + coef * bottomIntensity + secondary * bottomRightIntensity;
float v = -secondary * bottomLeftIntensity - coef * leftIntensity - secondary * topLeftIntensity + secondary * bottomRightIntensity + coef * rightIntensity + secondary * topRightIntensity;
float mag = length(vec2(h, v));
// alpha values removed atm
if (mag < 0.5) {
colorSobel.rgb *= (1.0 - 1.0);
colorSobel.r += 0.0 * 1.0;
colorSobel.g += 0.0 * 1.0;
colorSobel.b += 0.0 * 1.0;
colorSobel.rgb += 1.0 * mag;
} else {
colorSobel.rgb *= (1.0 - 1.0);
colorSobel.r += 0.0 * 1.0;
colorSobel.g += 0.0 * 1.0;
colorSobel.b += 0.0 * 1.0;
colorSobel.rgb += 1.0 * mag;
}
gl_FragColor = colorSobel;
However I know it works by sampling the texture via texture2D.
If I were to first manipulate the output via a simple script such as this which reduces the colours
vec4 bg = texture2D(texture,uv);
gl_FragColor = vec4(gb.rgb, 1.0);
gl_FragColor.r = float(floor(gl_FragColor.r * 0.5 ) / 0.5);
gl_FragColor.g = float(floor(gl_FragColor.g * 0.5 ) / 0.5);
gl_FragColor.b = float(floor(gl_FragColor.b * 0.5 ) / 0.5);
The output still samples from the texture and ignores the first paint.
Is there a way to sample from the color output rather than using texture2D?
The reason I'm asking is that i'm chaining my shaders at runtime depending on user interaction?

Drawing Line using matrix OpenGL

I'm working on this shaders that I modified
but I wish to simply draw a line instead of this blur / bloom effect
I understood that is the Float d that is used as a modifier but how to get this simple line instead
I based my research on this shader
Will appreciate any help
Zoltan
#ifdef GL_ES
precision mediump float;
#endif
mat4 mat = mat4 (
vec4 ( Scale * SizeTpDwn , 0.0 , 0.0 , 0.0 ),
vec4 ( 0.0 , Scale * SizeLftRght , 0.0 , 0.0 ),
vec4 ( 0.0 , 0.0 , Scale , 0.0 ),
vec4 ( 0.0 , 0.0 , 0.0 , Scale ) );
vec2 pos;
vec4 linecol = vec4 (0.5 , 0.5 , 0.7 , 0.5);
vec4 col = vec4 ( 0.0, 0.0, 0.0, 1.0 );
void Line4 ( vec4 a, vec4 b );
void Line2 ( vec2 a, vec2 b );
void main( void ) {
pos = gl_FragCoord.xy / RENDERSIZE.xy;
pos -= .5;
//Line
Line4 ( vec4 ( LengthTX, MoveTX, .2 ,-.2), vec4 (LengthTX2, MoveTX2, .2, -.2 ) );
//Line4 ( vec4 ( MoveRX, LengthRY, .2 ,-.2 ),vec4 ( MoveRX2,LengthRY2, .2, -.2 ) );
//Line4 ( vec4 (MoveLX, LengthLY, .2 ,-.2 ),vec4 (MoveLX2,LengthLY2, .2, -.2 ) );
//Line4 ( vec4 ( LengthDX,MoveDX, .2 ,-.2), vec4 (LengthDX2,MoveDX2, .2, -.2 ) );
gl_FragColor = vec4( col.xyz, 1.0 );
}
void Line4 ( vec4 a, vec4 b )
{
a = mat * a;
//a.xyz /= 1.5 + a.w * 2.;
b = mat * b;
//b.xyz /= 1.5 + b.w * 2.;
Line2 ( a.xy , b.xy );
}
void Line2 ( vec2 a, vec2 b )
{
float dtc = (distance ( pos , a ) + distance ( pos , b ) - distance ( a , b )); //+ 1e-5);
//linecol = vec4 (0.5 , 0.5 , 0.7 , 0.5);
col += max ( 1. - pow ( dtc * 14. , 0.10 ) , -.10 );
}
What you have to do is to find the closest distance of the current fragment to the line. If this distance is smaller than the half line thickness, then the fragment is on the line.
To create a line with sharp edges, I recommend to use the step function, which returns 0.0, if a value is smaller than a reference value and 1.0 otherwise.
Th draw a line which is not endless, you have to check if the point on the endless line, which is closest to the current position, is in between the start and the end of the line:
void Line2 (vec2 L1, vec2 L2)
{
vec2 P = pos;
vec2 O = L1;
vec2 D = normalize(L2-L1);
float d = dot(P-O, D);
vec2 X = L1 + D * d;
float dtc;
if (d < 0.0)
dtc = distance(L1, P); // d < 0.0 -> X is "before" L1
else if (d > distance(L1, L2))
dtc = distance(L2, P); // d > distance(L1, L2) -> X is "after" L2
else
dtc = distance(pos, X);
col += 1.0 - step(0.01, dtc);
}
Preview
Explanation:
Lets assume, that the line is defined by a Point O and a Unit vector D with gives the direction of the line. Note the length of a unit vector is 1.
Further you have the point P and you want to find the closest point X on the line (O, D) to P.
First calculate a vector V from O to P:
V = P - O;
The distance d from O to the intersection point X can be calculated by the Dot product. Note, since D is a unit vector, the dot prduct of V and D is equal the cosine of the angle between the line (O, D) and the vector V, multiplied by the amount (length) of V:
d = dot(V, D);
The intersection point X, can be calculated by shifting the point O along the line (D) by the distance d:
X = O + D * d;
So the formula for the intersection point is:
O ... any point on the line
D ... unit vector which points in the direction of the line
P ... the "Point"
X = O + D * dot(P-O, D);
Note, if the line is defined by 2 points, L1 and L2 then the unit vector D can be calcualted as follows:
D = normalize(L2-L1);

What causes this sort of tearing at the edges?

What causes this kind of tearing in GLSL? I noticed the same kind of thing going on at the teamLab art exhibit in Tokyo. Notice the imperfections in the edges.
Here is my fragment shader:
#version 300 es
precision highp float;
precision highp int;
uniform float time;
in vec2 v_pos;
out vec4 FragColor;
vec4 measureFloat(float measure_number_float){
return vec4(
float( mod ( measure_number_float, 60.0 ) ) / 60.0,
float( mod ( measure_number_float, 3600.0 ) ) / (60.0 * 60.0),
float( mod ( measure_number_float, 216000.0 ) ) / (60.0 * 60.0 * 60.0),
1.0
);
}
vec4 measureInt( int measure_number_int ){
return vec4(
float( measure_number_int % 60 ) / 60.0,
float( measure_number_int % 3600 ) / (60.0 * 60.0),
float( measure_number_int % 216000 ) / (60.0 * 60.0 * 60.0),
1.0
);
}
vec4 sampleColor(){
int x_coord_i, y_coord_i = 0;
float x_coord_f, y_coord_f = 0.0;
float res_mul_x_f = 20.0; // mul = multiplier
float res_mul_y_f = 20.0; // mul = multiplier
x_coord_i = int(v_pos.x * res_mul_x_f);
y_coord_i = int(v_pos.y * res_mul_y_f);
// return back to float:
x_coord_f = float(x_coord_i) / res_mul_x_f;
y_coord_f = float(y_coord_i) / res_mul_y_f;
int cell_number = y_coord_i * int(res_mul_x_f) + x_coord_i;
// return measureInt(cell_number);
return measureFloat(float(cell_number));
}
void main(void) {
FragColor = sampleColor();
}
This bug was present in both Chrome and Firefox, using both the measureInt function and the measureFloat function. I also don't know what to call this, so if there is a technical name for it, please do inform.

Rotate quad made in geometry shader

I'm drawing a quad using Geometry Shader, but can't figure out how to rotate it with angle.
void main(void)
{
float scaleX = 2.0f / u_resolution.x;
float scaleY = 2.0f / u_resolution.y;
float nx = (u_position.x * scaleX) - 1.0f;
float ny = -(u_position.y * scaleY) + 1.0f;
float nw = u_size.x * scaleX;
float nh = u_size.y * scaleY;
gl_Position = vec4( nx+nw, ny, 0.0, 1.0 );
texcoord = vec2( 1.0, 0.0 );
EmitVertex();
gl_Position = vec4(nx, ny, 0.0, 1.0 );
texcoord = vec2( 0.0, 0.0 );
EmitVertex();
gl_Position = vec4( nx+nw, ny-nh, 0.0, 1.0 );
texcoord = vec2( 1.0, 1.0 );
EmitVertex();
gl_Position = vec4(nx, ny-nh, 0.0, 1.0 );
texcoord = vec2( 0.0, 1.0 );
EmitVertex();
EndPrimitive();
}
Should I use a rotation matrix or sin and cos? I'm not too great at math.
You don't have to use matrices, but you need to use those sine functions. Here is a way to rotate a 3D position about some arbitrary axis by some angle specified in degrees:
// This is the 3D position that we want to rotate:
vec3 p = position.xyz;
// Specify the axis to rotate about:
float x = 0.0;
float y = 0.0;
float z = 1.0;
// Specify the angle in radians:
float angle = 90.0 * 3.14 / 180.0; // 90 degrees, CCW
vec3 q;
q.x = p.x * (x*x * (1.0 - cos(angle)) + cos(angle))
+ p.y * (x*y * (1.0 - cos(angle)) + z * sin(angle))
+ p.z * (x*z * (1.0 - cos(angle)) - y * sin(angle));
q.y = p.x * (y*x * (1.0 - cos(angle)) - z * sin(angle))
+ p.y * (y*y * (1.0 - cos(angle)) + cos(angle))
+ p.z * (y*z * (1.0 - cos(angle)) + x * sin(angle));
q.z = p.x * (z*x * (1.0 - cos(angle)) + y * sin(angle))
+ p.y * (z*y * (1.0 - cos(angle)) - x * sin(angle))
+ p.z * (z*z * (1.0 - cos(angle)) + cos(angle));
gl_Position = vec4(q, 1.0);
If you know that you are rotating about some standard x-, y-, or z-axis, you can simplify the "algorithm" a lot by defining it explicitly for that standard axis.
Notice how we rotate about the z-axis in the above code. For example, rotation about the x-axis would be (x,y,z) = (1,0,0). You could set the variables to anything, but the values should result in the axis being a unit vector (if that even matters.)
Then again, you might as well use matrices:
vec3 n = vec3(0.0, 0.0, 1.0); // the axis to rotate about
// Specify the rotation transformation matrix:
mat3 m = mat3(
n.x*n.x * (1.0f - cos(angle)) + cos(angle), // column 1 of row 1
n.x*n.y * (1.0f - cos(angle)) + n.z * sin(angle), // column 2 of row 1
n.x*n.z * (1.0f - cos(angle)) - n.y * sin(angle), // column 3 of row 1
n.y*n.x * (1.0f - cos(angle)) - n.z * sin(angle), // column 1 of row 2
n.y*n.y * (1.0f - cos(angle)) + cos(angle), // ...
n.y*n.z * (1.0f - cos(angle)) + n.x * sin(angle), // ...
n.z*n.x * (1.0f - cos(angle)) + n.y * sin(angle), // column 1 of row 3
n.z*n.y * (1.0f - cos(angle)) - n.x * sin(angle), // ...
n.z*n.z * (1.0f - cos(angle)) + cos(angle) // ...
);
// Apply the rotation to our 3D position:
vec3 q = m * p;
gl_Position = vec4(q, 1.0);
Notice how the elements of the matrix are laid out such that we first complete the first column, and then the second, and so on; the matrix is in column-major order. This matters when you try to transfer a matrix written in mathematical notation into a data type in your code. You basically need to transpose it (to flip the elements diagonally) in order to use it in your code. Also, we are essentially multiplying a matrix on left with a column vector on right.
If you need a 4-by-4 homogeneous matrix, then you would simply add an extra column and a row into the above matrix, such that both the new rightmost column and bottommost row would consist of [0 0 0 1]:
vec4 p = position.xyzw; // new dimension
vec3 n = ...; // same
mat4 m = mat4( // new dimension
...
0.0,
...
0.0,
...
0.0,
0.0,
0.0,
0.0,
1.0
);
vec4 q = m * p;
gl_Position = q;
Again, notice the order of the multiplication when applying the rotation, it is important because it affects the end result. What happens in the multiplication is basically that a new vector is formed by calculating the dot-product of the position vector and each column in the matrix; each coordinate in the resulting vector is the dot-product of the original vector and a single column in the matrix (see the first code example.)
The
q.x = p.x * (x*x * (1.0 - cos(angle)) + cos(angle))
+ p.y * (x*y * (1.0 - cos(angle)) + z * sin(angle))
+ p.z * (x*z * (1.0 - cos(angle)) - y * sin(angle));
Is same as:
q.x = dot(p, m[0]);
One could even compose the matrix with itself: m = m*m; which would result in a 180-degree counterclockwise rotation matrix, depending on the angle used.