Skip to content

Instantly share code, notes, and snippets.

@maluoi
Created July 3, 2024 17:42
Show Gist options
  • Save maluoi/d8c5feeec33a65139b74e0d12478628a to your computer and use it in GitHub Desktop.
Save maluoi/d8c5feeec33a65139b74e0d12478628a to your computer and use it in GitHub Desktop.
Frosty UI shader
// This is a QUADRANTIFIED shader, and should be used with QUADRANTIFIED meshes
// only. Queadrantified meshes are commonly found in StereoKit's UI.
#include "stereokit.hlsli"
//--frost_level = 1
//--frost_blend = 0.1
int frost_level;
float frost_blend;
struct vsIn {
float4 pos : SV_Position;
float3 norm : NORMAL0;
float2 quadrant : TEXCOORD0;
float4 color : COLOR0;
};
struct psIn {
float4 pos : SV_Position;
float3 world : TEXCOORD0;
float3 frost_norm : TEXCOORD1;
half4 color : COLOR0;
uint view_id : SV_RenderTargetArrayIndex;
};
float3 refract(float3 incidentRay, float3 normal, float eta) {
// Snell's law for refracting light. Test code, interesting, but needs review.
float cosThetaI = dot(-incidentRay, normal);
float sin2ThetaR = eta * eta * (1.0 - cosThetaI * cosThetaI);
if (sin2ThetaR > 1.0)
return reflect(incidentRay, normal);
float cosThetaR = sqrt(1.0 - sin2ThetaR);
float3 refractedRay = eta * incidentRay + (eta * cosThetaI - cosThetaR) * normal;
return normalize(refractedRay);
}
psIn vs(vsIn input, uint id : SV_InstanceID) {
psIn o;
o.view_id = id % sk_view_count;
id = id / sk_view_count;
// Extract scale from the matrix
float4x4 world_mat = sk_inst[id].world;
float2 scale = float2(
length(float3(world_mat._11,world_mat._12,world_mat._13)),
length(float3(world_mat._21,world_mat._22,world_mat._23))
);
// Restore scale to 1
world_mat[0] = world_mat[0] / scale.x;
world_mat[1] = world_mat[1] / scale.y;
// Translate the position using the quadrant (TEXCOORD0) information and
// the extracted scale.
float4 sized_pos;
sized_pos.xy = input.pos.xy + input.quadrant * scale * 0.5;
sized_pos.zw = input.pos.zw;
float3 normal = normalize(mul(input.norm, (float3x3)world_mat));
float4 world = mul(sized_pos, world_mat);
o.pos = mul(world, sk_viewproj[o.view_id]);
o.world = world.xyz;
o.color.rgb = input.color.rgb * sk_inst[id].color.rgb * sk_lighting(normal);
o.color.a = input.color.a;
float4 proj_inv = mul(o.pos, sk_proj_inv[o.view_id]);
o.frost_norm = mul(float4(proj_inv.xyz, 0), transpose(sk_view[o.view_id])).xyz;
// This can be used to simulate light bending as it passes through the
// glass. This looks kinda neat, and might be an interesting route to go
// down! However, it does often highlight the fakeness of the effect.
//o.frost_norm = refract(o.frost_norm, normal, 1.5);
return o;
}
float4 ps(psIn input) : SV_TARGET {
// This is a very smooth frosted glass effect powered by SK's spherical
// harmonics. Math, not texture lookups.
//float3 frost_col = sk_lighting(input.frost_norm);
// This samples from the skybox texture, and allows for configurable levels
// of frostiness. 1-3 would be pretty good values here, lower is frostier.
float3 frost_col = sk_cubemap.SampleLevel(sk_cubemap_s, input.frost_norm, sk_cubemap_i.z-frost_level);
// Blend in the frost "transparency" to the color.
float3 col = lerp(input.color.rgb, frost_col, frost_blend);
float glow = pow(1-saturate(sk_finger_distance(input.world) / 0.12), 10);
return float4(lerp(col, half3(1, 1, 1), glow), input.color.a);
}
@maluoi
Copy link
Author

maluoi commented Jul 3, 2024

Can be used somewhat like this:

Material matSolid = Material.UIQuadrant.Copy();
matSolid.Shader = Shader.FromFile("frosted_quadrant.hlsl");
matSolid["frost_level"] = 1;
matSolid["frost_blend"] = 0.025f;

Material matTransparent = matSolid.Copy();
matTransparent["frost_level"] = 1;
matTransparent["frost_blend"] = 0.05f;

UI.SetElementVisual(UIVisual.WindowHeadOnly, Mesh.Find("sk/ui/mesh_panel"), matSolid);
UI.SetElementVisual(UIVisual.WindowBodyOnly, Mesh.Find("sk/ui/mesh_panel"), matTransparent);
UI.SetElementVisual(UIVisual.WindowHead, Mesh.Find("sk/ui/mesh_panel_top"), matSolid);
UI.SetElementVisual(UIVisual.WindowBody, Mesh.Find("sk/ui/mesh_panel_bot"), matTransparent);

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