Skip to content

Instantly share code, notes, and snippets.

@mrange
Last active May 26, 2023 03:58
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mrange/1a3879f8e854e0cf52fdbecd7cf9460b to your computer and use it in GitHub Desktop.
Save mrange/1a3879f8e854e0cf52fdbecd7cf9460b to your computer and use it in GitHub Desktop.
Reactor shader inspired by Microsoft Reactor Graphics. For us in windows terminal

Install shader

Note: Doesn't work on latest preview of windows terminal (2022-09-15) but should work on later previews.

  1. Save reactor.hlsl to disk, note the path for later.
  2. Open Windows terminal settings
  3. Open settings as JSON
  4. Add a custom shader to the default profile, see excerpt below.
{
  "profiles": {
    "defaults": {
      "experimental.pixelShaderPath": "C:\\path-to-shader\\reactor.hlsl"
    }
  }
}
#define WINDOWS_TERMINAL
Texture2D shaderTexture;
SamplerState samplerState;
// --------------------
#if defined(WINDOWS_TERMINAL)
cbuffer PixelShaderSettings {
float Time;
float Scale;
float2 Resolution;
float4 Background;
};
#define TIME Time
#define RESOLUTION Resolution
#else
float time;
float2 resolution;
#define TIME time
#define RESOLUTION resolution
#endif
// --------------------
// --------------------
// GLSL => HLSL adapters
#define vec2 float2
#define vec3 float3
#define vec4 float4
#define mat2 float2x2
#define mat3 float3x3
#define fract frac
#define mix lerp
float mod(float x, float y) {
return x - y * floor(x/y);
}
vec2 mod(vec2 x, vec2 y) {
return x - y * floor(x/y);
}
static const vec2 unit2 = vec2(1.0, 1.0);
static const vec3 unit3 = vec3(1.0, 1.0, 1.0);
static const vec4 unit4 = vec4(1.0, 1.0, 1.0, 1.0);
// --------------------
#define ROT(a) mat2(cos(a), sin(a), -sin(a), cos(a))
#define PI 3.141592654
#define TAU (2.0*PI)
// License: Unknown, author: nmz (twitter: @stormoid), found: https://www.shadertoy.com/view/NdfyRM
vec3 sRGB(vec3 t) {
return mix(1.055*pow(t, unit3*(1./2.4)) - 0.055, 12.92*t, step(t, unit3*(0.0031308)));
}
// License: Unknown, author: Matt Taylor (https://github.com/64), found: https://64.github.io/tonemapping/
vec3 aces_approx(vec3 v) {
v = max(v, 0.0);
v *= 0.6f;
float a = 2.51f;
float b = 0.03f;
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
return clamp((v*(a*v+b))/(v*(c*v+d)+e), 0.0f, 1.0f);
}
// License: Unknown, author: Unknown, found: don't remember
float tanh_approx(float x) {
// Found this somewhere on the interwebs
// return tanh(x);
float x2 = x*x;
return clamp(x*(27.0 + x2)/(27.0+9.0*x2), -1.0, 1.0);
}
// License: WTFPL, author: sam hocevar, found: https://stackoverflow.com/a/17897228/418488
static const vec4 hsv2rgb_K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 hsv2rgb(vec3 c) {
vec3 p = abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www);
return c.z * mix(hsv2rgb_K.xxx, clamp(p - hsv2rgb_K.xxx, 0.0, 1.0), c.y);
}
// License: WTFPL, author: sam hocevar, found: https://stackoverflow.com/a/17897228/418488
// Macro version of above to enable compile-time constants
#define HSV2RGB(c) (c.z * mix(hsv2rgb_K.xxx, clamp(abs(fract(c.xxx + hsv2rgb_K.xyz) * 6.0 - hsv2rgb_K.www) - hsv2rgb_K.xxx, 0.0, 1.0), c.y))
// License: Unknown, author: Unknown, found: don't remember
float hash(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,58.233))) * 13758.5453);
}
// License: Unknown, author: Martijn Steinrucken, found: https://www.youtube.com/watch?v=VmrIDyYiJBA
vec2 hextile(inout vec2 p) {
// See Art of Code: Hexagonal Tiling Explained!
// https://www.youtube.com/watch?v=VmrIDyYiJBA
const vec2 sz = vec2(1.0, sqrt(3.0));
const vec2 hsz = 0.5*sz;
vec2 p1 = mod(p, sz)-hsz;
vec2 p2 = mod(p - hsz, sz)-hsz;
vec2 p3 = dot(p1, p1) < dot(p2, p2) ? p1 : p2;
vec2 n = ((p3 - p + hsz)/sz);
p = p3;
n -= (0.5);
// Rounding to make hextile 0,0 well behaved
return round(n*2.0)*0.5;
}
// License: MIT, author: Inigo Quilez, found: https://iquilezles.org/www/articles/distfunctions2d/distfunctions2d.htm
float hexagon(vec2 p, float r) {
const vec3 k = vec3(-0.866025404,0.5,0.577350269);
p = abs(p);
p -= 2.0*min(dot(k.xy,p),0.0)*k.xy;
p -= vec2(clamp(p.x, -k.z*r, k.z*r), r);
return length(p)*sign(p.y);
}
float shape(vec2 p) {
return hexagon(p.yx, 0.4)-0.075;
}
float cellHeight(float h) {
return 0.05*2.0*(-h);
}
vec3 cell(vec2 p, float h) {
float hd = shape(p);
const float he = 0.0075*2.0;
float aa = he;
float hh = -he*smoothstep(aa, -aa, hd);
return vec3(hd, hh, cellHeight(h));
}
float height(vec2 p, float h) {
return cell(p, h).y;
}
vec3 normal(vec2 p, float h) {
vec2 e = vec2(4.0/RESOLUTION.y, 0);
vec3 n;
n.x = height(p + e.xy, h) - height(p - e.xy, h);
n.y = height(p + e.yx, h) - height(p - e.yx, h);
n.z = 2.0*e.x;
return normalize(n);
}
vec3 planeColor(vec3 ro, vec3 rd, vec3 lp, vec3 pp, vec3 pnor, vec3 bcol, vec3 pcol) {
vec3 ld = normalize(lp-pp);
float dif = pow(max(dot(ld, pnor), 0.0), 1.0);
vec3 col = pcol;
col = mix(bcol, col, dif);
return col;
}
static const mat2 rots[6] = {
ROT(0.0*TAU/6.0)
, ROT(1.0*TAU/6.0)
, ROT(2.0*TAU/6.0)
, ROT(3.0*TAU/6.0)
, ROT(4.0*TAU/6.0)
, ROT(5.0*TAU/6.0)
};
static const vec2 off = vec2(1.0, 0.0);
static const vec2 offs[6] = {
mul(rots[0], off)
, mul(rots[1], off)
, mul(rots[2], off)
, mul(rots[3], off)
, mul(rots[4], off)
, mul(rots[5], off)
};
float cutSlice(vec2 p, vec2 off) {
// A bit like this but unbounded
// https://www.shadertoy.com/view/MlycD3
p.x = abs(p.x);
off.x *= 0.5;
vec2 nn = normalize(vec2(off));
vec2 n = vec2(nn.y, -nn.x);
float d0 = length(p-off);
float d1 = -(p.y-off.y);
float d2 = dot(n, p);
bool b = p.x > off.x && (dot(nn, p)-dot(nn, off)) < 0.0;
return b ? d0 : max(d1, d2);
}
float hexSlice(vec2 p, int n) {
n = 6-n;
n = n%6;
p = mul(rots[n], p);
p = p.yx;
const vec2 dim = vec2((0.5)*2.0/sqrt(3.0), (0.5));
return cutSlice(p, dim);
}
vec3 backdrop(vec2 p, vec2 q) {
const float z = 0.327;
float aa = 2.0/(z*RESOLUTION.y);
p.yx = p;
vec3 lp = vec3(3.0, 0.0, 1.0);
p -= vec2(0.195, 0.);
p /= z;
float toff = 0.2*TIME;
p.x += toff;
lp.x += toff;
vec2 hp = p;
vec2 hn = hextile(hp);
float hh = hash(hn);
vec3 c = cell(hp, hh);
float cd = c.x;
float ch = c.z;
vec3 fpp = vec3(p, ch);
vec3 bpp = vec3(p, 0.0);
vec3 ro = vec3(0.0, 0.0, 1.0);
vec3 rd = normalize(fpp-ro);
vec3 bnor = vec3(0.0, 0.0, 1.0);
vec3 bdif = lp-bpp;
float bl2 = dot(bdif, bdif);
vec3 fnor = normal(hp, hh);
vec3 fld = normalize(lp-fpp);
float sf = 0.0;
for (int i = 0; i < 6; ++i) {
vec2 ioff= offs[i];
vec2 ip = p+ioff;
vec2 ihn = hextile(ip);
float ihh = hash(ihn);
float ich = cellHeight(ihh);
float iii = (ich-ch)/fld.z;
vec3 ipp = vec3(hp, ch)+iii*fld;
float hsd = hexSlice(ipp.xy, i);
if (ich > ch) {
sf += exp(-20.0*tanh_approx(1.0/(10.0*iii))*max(hsd+0., 0.0));
}
}
const float sat = 0.23;
const vec3 bcol0 = HSV2RGB(vec3(240.0/36.0, sat, 0.14));
const vec3 bcol1 = HSV2RGB(vec3(240.0/36.0, sat, 0.19));
vec3 bpcol = planeColor(ro, rd, lp, bpp, bnor, unit3*(0.0), bcol0);
vec3 fpcol = planeColor(ro, rd, lp, fpp, fnor, bpcol, bcol1);
vec3 col = bpcol;
col = mix(col, fpcol, smoothstep(aa, -aa, cd));
col *= 1.0-tanh_approx(sf);
float fo = exp(-0.025*max(bl2-0., 0.0));
col *= fo;
col = mix(bpcol, col, fo);
return col;
}
vec3 effect(vec2 p, vec2 q) {
float aa = 2.0/RESOLUTION.y;
float dh = hexagon(p, 0.6);
float odh = abs(dh+0.016) - 0.08;
vec3 col = backdrop(p, q);
vec3 bcol = hsv2rgb(vec3(0.6, mix(0.95, 0.8, p.x+p.y),0.5));
col = mix(col, bcol, 0.4*smoothstep(aa, -aa, odh));
const vec3 gcol0 = HSV2RGB(vec3(0.6, 0.95, 0.005));
const vec3 gcol1 = HSV2RGB(vec3(0.65, 0.85, 0.005));
col += gcol0/(abs(odh));
// col += gcol1/(abs(odh)+0.05*p.y*p.y);
return col;
}
//
// PS_OUTPUT ps_main(in PS_INPUT In)
#if defined(WINDOWS_TERMINAL)
float4 main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
#else
float4 ps_main(float4 pos : SV_POSITION, float2 tex : TEXCOORD) : SV_TARGET
#endif
{
vec2 q = tex;
vec2 p = -1.0 + 2.0*q;
#if defined(WINDOWS_TERMINAL)
p.y = -p.y;
#endif
p.x *= RESOLUTION.x/RESOLUTION.y;
vec3 col = effect(p, q);
col = aces_approx(col);
col = sRGB(col);
vec4 fg = shaderTexture.Sample(samplerState, q);
vec4 sh = shaderTexture.Sample(samplerState, q-2.0*unit2/RESOLUTION.xy);
col = mix(col, 0.0*unit3, sh.w);
col = mix(col, fg.xyz, fg.w);
return vec4(col, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment