Files
armorpaint/paint/shaders/cursor_decal.kong
T
2026-05-30 20:24:41 +02:00

138 lines
3.0 KiB
Plaintext

#[set(everything)]
const constants: {
VP: float4x4;
invVP: float4x4;
mouse: float2;
tex_step: float2;
radius: float;
camera_right: float3;
opacity: float;
angle: float2;
scale_x: float;
camera_up: float3;
camera_align: float;
};
#[set(everything)]
const sampler_linear: sampler;
#[set(everything)]
const gbufferD: tex2d;
#[set(everything)]
const texdecal: tex2d;
#[set(everything)]
const gbuffer0: tex2d;
struct vert_in {
pos: float4;
nor: float2;
tex: float2;
}
struct vert_out {
pos: float4;
tex: float2;
}
fun get_pos(uv: float2): float3 {
var depth: float = sample_lod(gbufferD, sampler_linear, float2(uv.x, 1.0 - uv.y), 0.0).r;
var wpos: float4 = float4(uv * 2.0 - 1.0, depth, 1.0);
wpos = constants.invVP * wpos;
return wpos.xyz / wpos.w;
}
fun octahedron_wrap(v: float2): float2 {
var a: float2;
if (v.x >= 0.0) {
a.x = 1.0;
}
else {
a.x = -1.0;
}
if (v.y >= 0.0) {
a.y = 1.0;
}
else {
a.y = -1.0;
}
var r: float2;
r.x = 1.0 - abs(v.y);
r.y = 1.0 - abs(v.x);
return r * a;
}
fun get_normal(uv: float2): float3 {
var g0: float2 = sample_lod(gbuffer0, sampler_linear, float2(uv.x, 1.0 - uv.y), 0.0).rg;
var n: float3;
n.z = 1.0 - abs(g0.x) - abs(g0.y);
if (n.z >= 0.0) {
n.x = g0.x;
n.y = g0.y;
}
else {
var fw: float2 = octahedron_wrap(g0.xy);
n.x = fw.x;
n.y = fw.y;
}
return n;
}
fun cursor_decal_vert(input: vert_in): vert_out {
var keep: float = input.pos.x + input.nor.x; // hlsl
var output: vert_out;
output.tex = input.tex;
var wpos: float3 = get_pos(constants.mouse);
var uv1: float2 = constants.mouse + constants.tex_step * float2(4.0, 4.0);
var uv2: float2 = constants.mouse - constants.tex_step * float2(4.0, 4.0);
var n: float3 = normalize(get_normal(constants.mouse) + get_normal(uv1) + get_normal(uv2));
var n_tan: float3;
var n_bin: float3;
if (constants.camera_align > 0.0) {
n_tan = constants.camera_right;
n_bin = -constants.camera_up;
}
else {
var cam_right: float3 = constants.camera_right;
if (abs(dot(n, cam_right)) > 0.999) { cam_right = float3(0.0, 0.0, 1.0); }
n_tan = normalize(cam_right - n * dot(cam_right, n));
n_bin = cross(n_tan, n);
}
// Rotate tangent basis by brush angle
var r_tan: float3 = constants.angle.x * n_tan + constants.angle.y * n_bin;
var r_bin: float3 = -constants.angle.y * n_tan + constants.angle.x * n_bin;
if (vertex_id() == 3) {
wpos += (-constants.scale_x * r_tan - r_bin) * constants.radius;
}
/*else */if (vertex_id() == 2) {
wpos += ( constants.scale_x * r_tan - r_bin) * constants.radius;
}
/*else */if (vertex_id() == 1) {
wpos += ( constants.scale_x * r_tan + r_bin) * constants.radius;
}
/*else */if (vertex_id() == 0) {
wpos += (-constants.scale_x * r_tan + r_bin) * constants.radius;
}
output.pos = constants.VP * float4(wpos, 1.0);
return output;
}
fun cursor_decal_frag(input: vert_out): float4 {
var col: float4 = sample_lod(texdecal, sampler_linear, input.tex, 0.0);
return float4(col.rgb, col.a * constants.opacity);
}
#[pipe]
struct pipe {
vertex = cursor_decal_vert;
fragment = cursor_decal_frag;
}