Skip to content

Instantly share code, notes, and snippets.

@nbouteme
Last active June 20, 2023 09:27
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nbouteme/b8272b05492dea469167a493b945c33e to your computer and use it in GitHub Desktop.
Save nbouteme/b8272b05492dea469167a493b945c33e to your computer and use it in GitHub Desktop.
Skyward Sword Brush shader. Accurately emulates what's done with TEVs in a shader. Does NOT include the blurring pass.
#version 300 es
precision highp float;
in vec2 UV;
out vec4 out_color;
uniform float ratio, time;
uniform sampler2D texture0;
const float PI_3 = 1.0471975512;
void main(void) {
float v = 0.004f;
vec2 d = vec2(v / ratio, v);
#define hexa(k) vec2(cos(PI_3 * k), sin(PI_3 * k))
vec2 deltas[6] = vec2[6](
hexa(0.), hexa(1.), hexa(2.),
hexa(3.), hexa(4.), hexa(5.)
);
#undef hexa
vec2 xy = vec2(UV.x, 1.0f - UV.y);
vec4 col = texture(texture0, xy);
for (int i = 0; i < 6; ++i) {
vec4 col2 = texture(texture0, xy + deltas[i] * d);
vec4 t = max(sign(col2 - col), 0.);
col += (col2 - col) * t;
}
col.a = 1.0;
out_color = col;
}
@nbouteme
Copy link
Author

nbouteme commented Feb 24, 2019

This is basically a screen space filter that looks for the maximum rgb components among 6 nears samples.
Contrary to popular belief, there is no Depth of Field. The effect is just turned off for samples that are near the camera, but the brush strokes don't get bigger the furthest a sample is.

The 0.004f isn't the exact value used by the game, but close enough to not make a visible difference.
The game does that in two passes, plus another pass where it applies a blur filter. Which is just downsampling and upscaling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment