Created
July 3, 2024 17:42
-
-
Save maluoi/d8c5feeec33a65139b74e0d12478628a to your computer and use it in GitHub Desktop.
Frosty UI shader
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Can be used somewhat like this: