It's a bit related to how to convert shadershop formula into glsl . Only the above answer does not provide any explanation.
What I try is:
Where SineV is:
and SineH is:
This is what I have so far:
#ifdef GL_ES
precision mediump float;
#endif
float scale = 5.0;
uniform vec2 u_resolution;
float sineV(float x) {
x *= scale;
return (sin( x / 0.18 ) + sin( (x - -1.0) / 0.35 ) + 0.25);
}
float sineH(float x) {
x *= scale;
return (sin( (x - 0.18) / 0.37 ) + sin( ((x - 0.18) - -0.31) / 0.45 ) + -0.59) * 0.75 + 0.1;
}
mat2 inverse(mat2 m) {
float det_m = m[0][0]*m[1][1] - m[0][1]*m[1][0];
mat2 inv_m = mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / det_m;
return inv_m;
}
void main() {
mat2 m = mat2(0.0, -1.0,
1.0, 0.0);
vec2 st = gl_FragCoord.xy / u_resolution.xy;
float x1 = st.x;
float x2 = st.y;
vec2 x1x2 = inverse(m) * vec2(x1, x2);
vec2 tmp = m * x1x2;
float x = sineV(x1x2.x - x1x2.y) + sineH(tmp.x - tmp.y);
vec3 color = vec3( x, x, abs(x) );
gl_FragColor = vec4(color, 1.0);
}
But I reached a point where it is just guessing and trial and error. Hope someone can help.
The matrix in shadershop transforms the input tuple (x1, x2)
to (u, v)
coordinates.
The fragment shader is executed for each fragment, each fragment is associated to different (u, v) coordinates. You've to calculate the x1
and x2
corresponding to the actual (u, v) coordinate of the fragment. So you've to use the inverse matrix:
(u, v) = m * (x1, x2)
(x1, x2 = inverse(m) * (u, v)
The shader has to sum up result of the f(x1)
and the result of the f(x2)
:
x = f(x1) + f(x2)
The corresponding glsl code is:
vec2 x1x2 = inverse(m) * st.xy;
float x = sineH(x1x2.x) + sineV(x1x2.y);
The mapping of x
to the white, blue and black color can be achieved by the empirical formula (I found this out by trial and error):
vec3 color = vec3(x, x, abs(x));
For the full shader code see the example (note, the result is stretched to the canvas):
(function loadscene() {
var canvas, gl, vp_size, prog, bufObj = {};
function initScene() {
canvas = document.getElementById( "ogl-canvas");
gl = canvas.getContext( "experimental-webgl" );
if ( !gl )
return;
progDraw = gl.createProgram();
for (let i = 0; i < 2; ++i) {
let source = document.getElementById(i==0 ? "draw-shader-vs" : "draw-shader-fs").text;
let shaderObj = gl.createShader(i==0 ? gl.VERTEX_SHADER : gl.FRAGMENT_SHADER);
gl.shaderSource(shaderObj, source);
gl.compileShader(shaderObj);
let status = gl.getShaderParameter(shaderObj, gl.COMPILE_STATUS);
if (!status) alert(gl.getShaderInfoLog(shaderObj));
gl.attachShader(progDraw, shaderObj);
gl.linkProgram(progDraw);
}
status = gl.getProgramParameter(progDraw, gl.LINK_STATUS);
if ( !status ) alert(gl.getProgramInfoLog(progDraw));
progDraw.inPos = gl.getAttribLocation(progDraw, "inPos");
progDraw.u_resolution = gl.getUniformLocation(progDraw, "u_resolution");
gl.useProgram(progDraw);
var pos = [ -1, -1, 1, -1, 1, 1, -1, 1 ];
var inx = [ 0, 1, 2, 0, 2, 3 ];
bufObj.pos = gl.createBuffer();
gl.bindBuffer( gl.ARRAY_BUFFER, bufObj.pos );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( pos ), gl.STATIC_DRAW );
bufObj.inx = gl.createBuffer();
bufObj.inx.len = inx.length;
gl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, bufObj.inx );
gl.bufferData( gl.ELEMENT_ARRAY_BUFFER, new Uint16Array( inx ), gl.STATIC_DRAW );
gl.enableVertexAttribArray( progDraw.inPos );
gl.vertexAttribPointer( progDraw.inPos, 2, gl.FLOAT, false, 0, 0 );
gl.enable( gl.DEPTH_TEST );
gl.clearColor( 0.0, 0.0, 0.0, 1.0 );
window.onresize = resize;
resize();
requestAnimationFrame(render);
}
function resize() {
vp_size = [window.innerWidth, window.innerHeight];
//vp_size = [256, 256]
canvas.width = vp_size[0];
canvas.height = vp_size[1];
}
function render(deltaMS) {
gl.viewport( 0, 0, canvas.width, canvas.height );
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
gl.uniform2f(progDraw.u_resolution, canvas.width, canvas.height);
gl.drawElements( gl.TRIANGLES, bufObj.inx.len, gl.UNSIGNED_SHORT, 0 );
requestAnimationFrame(render);
}
initScene();
})();
<script id="draw-shader-vs" type="x-shader/x-vertex">
precision mediump float;
attribute vec2 inPos;
varying vec2 ndcPos;
void main()
{
gl_Position = vec4( inPos.xy, 0.0, 1.0 );
}
</script>
<script id="draw-shader-fs" type="x-shader/x-fragment">
precision mediump float;
uniform vec2 u_resolution;
float scale = 5.0;
float sineV(float x) {
x *= scale;
return (sin( x / 0.18 ) + sin( (x - -1.0) / 0.35 ) + 0.25);
}
float sineH(float x) {
x *= scale;
return (sin( (x - 0.18) / 0.37 ) + sin( ((x - 0.18) - -0.31) / 0.45 ) + -0.59) * 0.75 + 0.1;
}
mat2 inverse(mat2 m) {
float det_m = m[0][0]*m[1][1] - m[0][1]*m[1][0];
mat2 inv_m = mat2(m[1][1], -m[0][1], -m[1][0], m[0][0]) / det_m;
return inv_m;
}
void main()
{
vec2 st = 2.0 * gl_FragCoord.xy / u_resolution.xy - 1.0;
mat2 m = mat2(0.0, -1.0, 1.0, 0.0);
vec2 x1x2 = inverse(m) * st.xy;
float x = sineH(x1x2.x) + sineV(x1x2.y);
vec3 color = vec3(x, x, abs(x));
gl_FragColor = vec4(color, 1.0);
}
</script>
<canvas id="ogl-canvas" style="border: none"></canvas>