Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Hajime-san committed Mar 11, 2023
1 parent 98d3cbf commit 41735cc
Show file tree
Hide file tree
Showing 13 changed files with 965 additions and 1 deletion.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
.vite
Binary file added IMG_0086.MOV
Binary file not shown.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# three-fxr
# three-fxr
259 changes: 259 additions & 0 deletions easu.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
/*
Original:https://www.shadertoy.com/view/stXSWB
by goingdigital
*/

uniform vec2 iResolution;
uniform sampler2D iChannel0;
out vec4 fragColor;

/* EASU stage
*
* This takes a reduced resolution source, and scales it up while preserving detail.
*
* Updates:
* stretch definition fixed. Thanks nehon for the bug report!
*/

vec3 FsrEasuCF(vec2 p) {
return texture(iChannel0,p).rgb;
}

/**** EASU ****/
void FsrEasuCon(
out vec4 con0,
out vec4 con1,
out vec4 con2,
out vec4 con3,
// This the rendered image resolution being upscaled
vec2 inputViewportInPixels,
// This is the resolution of the resource containing the input image (useful for dynamic resolution)
vec2 inputSizeInPixels,
// This is the display resolution which the input image gets upscaled to
vec2 outputSizeInPixels
)
{
// Output integer position to a pixel position in viewport.
con0 = vec4(
inputViewportInPixels.x/outputSizeInPixels.x,
inputViewportInPixels.y/outputSizeInPixels.y,
.5*inputViewportInPixels.x/outputSizeInPixels.x-.5,
.5*inputViewportInPixels.y/outputSizeInPixels.y-.5
);
// Viewport pixel position to normalized image space.
// This is used to get upper-left of 'F' tap.
con1 = vec4(1,1,1,-1)/inputSizeInPixels.xyxy;
// Centers of gather4, first offset from upper-left of 'F'.
// +---+---+
// | | |
// +--(0)--+
// | b | c |
// +---F---+---+---+
// | e | f | g | h |
// +--(1)--+--(2)--+
// | i | j | k | l |
// +---+---+---+---+
// | n | o |
// +--(3)--+
// | | |
// +---+---+
// These are from (0) instead of 'F'.
con2 = vec4(-1,2,1,2)/inputSizeInPixels.xyxy;
con3 = vec4(0,4,0,0)/inputSizeInPixels.xyxy;
}

// Filtering for a given tap for the scalar.
void FsrEasuTapF(
inout vec3 aC, // Accumulated color, with negative lobe.
inout float aW, // Accumulated weight.
vec2 off, // Pixel offset from resolve position to tap.
vec2 dir, // Gradient direction.
vec2 len, // Length.
float lob, // Negative lobe strength.
float clp, // Clipping point.
vec3 c
)
{
// Tap color.
// Rotate offset by direction.
vec2 v = vec2(dot(off, dir), dot(off,vec2(-dir.y,dir.x)));
// Anisotropy.
v *= len;
// Compute distance^2.
float d2 = min(dot(v,v),clp);
// Limit to the window as at corner, 2 taps can easily be outside.
// Approximation of lancos2 without sin() or rcp(), or sqrt() to get x.
// (25/16 * (2/5 * x^2 - 1)^2 - (25/16 - 1)) * (1/4 * x^2 - 1)^2
// |_______________________________________| |_______________|
// base window
// The general form of the 'base' is,
// (a*(b*x^2-1)^2-(a-1))
// Where 'a=1/(2*b-b^2)' and 'b' moves around the negative lobe.
float wB = .4 * d2 - 1.;
float wA = lob * d2 -1.;
wB *= wB;
wA *= wA;
wB = 1.5625*wB-.5625;
float w= wB * wA;
// Do weighted average.
aC += c*w;
aW += w;
}

//------------------------------------------------------------------------------------------------------------------------------
// Accumulate direction and length.
void FsrEasuSetF(
inout vec2 dir,
inout float len,
float w,
float lA,float lB,float lC,float lD,float lE
)
{
// Direction is the '+' diff.
// a
// b c d
// e
// Then takes magnitude from abs average of both sides of 'c'.
// Length converts gradient reversal to 0, smoothly to non-reversal at 1, shaped, then adding horz and vert terms.
float lenX = max(abs(lD - lC), abs(lC - lB));
float dirX = lD - lB;
dir.x += dirX * w;
lenX = clamp(abs(dirX)/lenX,0.,1.);
lenX *= lenX;
len += lenX * w;
// Repeat for the y axis.
float lenY = max(abs(lE - lC), abs(lC - lA));
float dirY = lE - lA;
dir.y += dirY * w;
lenY = clamp(abs(dirY) / lenY,0.,1.);
lenY *= lenY;
len += lenY * w;
}

//------------------------------------------------------------------------------------------------------------------------------
void FsrEasuF(
out vec3 pix,
vec2 ip, // Integer pixel position in output.
// Constants generated by FsrEasuCon().
vec4 con0, // xy = output to input scale, zw = first pixel offset correction
vec4 con1,
vec4 con2,
vec4 con3
)
{
//------------------------------------------------------------------------------------------------------------------------------
// Get position of 'f'.
vec2 pp = ip * con0.xy + con0.zw; // Corresponding input pixel/subpixel
vec2 fp = floor(pp);// fp = source nearest pixel
pp -= fp; // pp = source subpixel

//------------------------------------------------------------------------------------------------------------------------------
// 12-tap kernel.
// b c
// e f g h
// i j k l
// n o
// Gather 4 ordering.
// a b
// r g
vec2 p0 = fp * con1.xy + con1.zw;

// These are from p0 to avoid pulling two constants on pre-Navi hardware.
vec2 p1 = p0 + con2.xy;
vec2 p2 = p0 + con2.zw;
vec2 p3 = p0 + con3.xy;

// TextureGather is not available on WebGL2
vec4 off = vec4(-.5,.5,-.5,.5)*con1.xxyy;
// textureGather to texture offsets
// x=west y=east z=north w=south
vec3 bC = FsrEasuCF(p0 + off.xw); float bL = bC.g + 0.5 *(bC.r + bC.b);
vec3 cC = FsrEasuCF(p0 + off.yw); float cL = cC.g + 0.5 *(cC.r + cC.b);
vec3 iC = FsrEasuCF(p1 + off.xw); float iL = iC.g + 0.5 *(iC.r + iC.b);
vec3 jC = FsrEasuCF(p1 + off.yw); float jL = jC.g + 0.5 *(jC.r + jC.b);
vec3 fC = FsrEasuCF(p1 + off.yz); float fL = fC.g + 0.5 *(fC.r + fC.b);
vec3 eC = FsrEasuCF(p1 + off.xz); float eL = eC.g + 0.5 *(eC.r + eC.b);
vec3 kC = FsrEasuCF(p2 + off.xw); float kL = kC.g + 0.5 *(kC.r + kC.b);
vec3 lC = FsrEasuCF(p2 + off.yw); float lL = lC.g + 0.5 *(lC.r + lC.b);
vec3 hC = FsrEasuCF(p2 + off.yz); float hL = hC.g + 0.5 *(hC.r + hC.b);
vec3 gC = FsrEasuCF(p2 + off.xz); float gL = gC.g + 0.5 *(gC.r + gC.b);
vec3 oC = FsrEasuCF(p3 + off.yz); float oL = oC.g + 0.5 *(oC.r + oC.b);
vec3 nC = FsrEasuCF(p3 + off.xz); float nL = nC.g + 0.5 *(nC.r + nC.b);

//------------------------------------------------------------------------------------------------------------------------------
// Simplest multi-channel approximate luma possible (luma times 2, in 2 FMA/MAD).
// Accumulate for bilinear interpolation.
vec2 dir = vec2(0);
float len = 0.;

FsrEasuSetF(dir, len, (1.-pp.x)*(1.-pp.y), bL, eL, fL, gL, jL);
FsrEasuSetF(dir, len, pp.x *(1.-pp.y), cL, fL, gL, hL, kL);
FsrEasuSetF(dir, len, (1.-pp.x)* pp.y , fL, iL, jL, kL, nL);
FsrEasuSetF(dir, len, pp.x * pp.y , gL, jL, kL, lL, oL);

//------------------------------------------------------------------------------------------------------------------------------
// Normalize with approximation, and cleanup close to zero.
vec2 dir2 = dir * dir;
float dirR = dir2.x + dir2.y;
bool zro = dirR < (1.0/32768.0);
dirR = inversesqrt(dirR);
dirR = zro ? 1.0 : dirR;
dir.x = zro ? 1.0 : dir.x;
dir *= vec2(dirR);
// Transform from {0 to 2} to {0 to 1} range, and shape with square.
len = len * 0.5;
len *= len;
// Stretch kernel {1.0 vert|horz, to sqrt(2.0) on diagonal}.
float stretch = dot(dir,dir) / (max(abs(dir.x), abs(dir.y)));
// Anisotropic length after rotation,
// x := 1.0 lerp to 'stretch' on edges
// y := 1.0 lerp to 2x on edges
vec2 len2 = vec2(1. +(stretch-1.0)*len, 1. -.5 * len);
// Based on the amount of 'edge',
// the window shifts from +/-{sqrt(2.0) to slightly beyond 2.0}.
float lob = .5 - .29 * len;
// Set distance^2 clipping point to the end of the adjustable window.
float clp = 1./lob;

//------------------------------------------------------------------------------------------------------------------------------
// Accumulation mixed with min/max of 4 nearest.
// b c
// e f g h
// i j k l
// n o
vec3 min4 = min(min(fC,gC),min(jC,kC));
vec3 max4 = max(max(fC,gC),max(jC,kC));
// Accumulation.
vec3 aC = vec3(0);
float aW = 0.;
FsrEasuTapF(aC, aW, vec2( 0,-1)-pp, dir, len2, lob, clp, bC);
FsrEasuTapF(aC, aW, vec2( 1,-1)-pp, dir, len2, lob, clp, cC);
FsrEasuTapF(aC, aW, vec2(-1, 1)-pp, dir, len2, lob, clp, iC);
FsrEasuTapF(aC, aW, vec2( 0, 1)-pp, dir, len2, lob, clp, jC);
FsrEasuTapF(aC, aW, vec2( 0, 0)-pp, dir, len2, lob, clp, fC);
FsrEasuTapF(aC, aW, vec2(-1, 0)-pp, dir, len2, lob, clp, eC);
FsrEasuTapF(aC, aW, vec2( 1, 1)-pp, dir, len2, lob, clp, kC);
FsrEasuTapF(aC, aW, vec2( 2, 1)-pp, dir, len2, lob, clp, lC);
FsrEasuTapF(aC, aW, vec2( 2, 0)-pp, dir, len2, lob, clp, hC);
FsrEasuTapF(aC, aW, vec2( 1, 0)-pp, dir, len2, lob, clp, gC);
FsrEasuTapF(aC, aW, vec2( 1, 2)-pp, dir, len2, lob, clp, oC);
FsrEasuTapF(aC, aW, vec2( 0, 2)-pp, dir, len2, lob, clp, nC);
//------------------------------------------------------------------------------------------------------------------------------
// Normalize and dering.
pix=min(max4,max(min4,aC/aW));
}

void main()
{
vec4 fragCoord = gl_FragCoord;
vec3 c;
vec4 con0,con1,con2,con3;

// "rendersize" refers to size of source image before upscaling.
vec2 rendersize = vec2(textureSize(iChannel0, 0));
FsrEasuCon(
con0, con1, con2, con3, rendersize, rendersize, iResolution
);
FsrEasuF(c, fragCoord.xy, con0, con1, con2, con3);
fragColor = vec4(c.xyz, 1);
}
17 changes: 17 additions & 0 deletions frag.glsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
varying vec2 vUv;
varying vec3 vViewPosition;
varying vec3 vNormal;
varying vec3 vPosition;

uniform float time;
uniform sampler2D tex;

out vec4 outColor;

void main() {

vec4 texColor = texture(tex, vUv);

// outColor = vec4(1.0, 0.0, 1.0, 1.0);
outColor = texColor;
}
39 changes: 39 additions & 0 deletions index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#container {
position: relative;
}
canvas {
position: absolute;
top: 0;
left: 0;
display: block;
width: 100%;
height: 100%;
}
</style>
<title>WebGPU</title>
<script type="module" src="./main.ts" defer></script>
</head>
<body>
<div id="container">
<video id="video" loop playsinline autoplay muted>
<source src="IMG_0086.MOV">
</video>
</div>
<div>
<input type="range" id="sharpness" name="sharpness" min="0.0" max="1000.0" value="0.2" step="0.1">
<label for="sharpness">sharpness</label>
</div>
</body>
</html>
Loading

0 comments on commit 41735cc

Please sign in to comment.