chore(history): squash 59 commit(s) from 2026-09-23

- refactor(hud/weather/render): Scoreboard 931→240 + Rain 903→159 + UiMeshGeometry 956→99 (8.5.2)
- refactor(chams): Chams 985 → 129 + 4×≤195 (8.5.2)
- refactor(module): Module 1031 → 139 + 4×≤134 (8.5.2)
- refactor(tooltips): BetterTooltips 960 → 181 + 4×≤199 (8.5.2)
- refactor(clickgui): ClickGuiPickerState 970→166 + ModulesMenuScreen 966→145 (8.5.2)
- refactor(clickgui): CombatProtocolHeuristicsEditorState 932→79 + 4×≤192 (8.5.2)
- refactor(hud): CompactHudStatModel 894 → 125 + 4×≤175 (8.5.2)
- refactor(iris): ShaderPatchCompiler 843→66 + 4×≤174 (8.5.2)
- refactor(tab): CustomTabList 834→136 + 4×≤166 (8.5.2)
- refactor(relations): OnlineRelationPlayerPickerComponent 837→74 + 4×≤192 (8.5.2)
- refactor(hits): HitEffect 770→120 + 4×≤176 (8.5.2)
- refactor(predict): Predictions 815→150 + 4×≤195 (8.5.2)
- refactor(config): ConfigProfilesComponent 799→125 + 4×≤195 (8.5.2)
- refactor(sim): PlayerMovementSimulation 757→157 + 4×≤194 (8.5.2)
- refactor(predict): ProjectilePuncher 747→104 + 3×≤134 (8.5.2)
- refactor(crosshair): Crosshair 743→143 + 4×≤167 (8.5.2)
- refactor(mediaplayer): MediaPlayer 743→174 + 4×≤196 (8.5.2)
- refactor(hud): Itemizer 699→193 + Cooldowns 707→151 (8.5.2)
- refactor(hud): Potions 617→176 + 4×≤166 (8.5.2)
- refactor(hud): Admins 702→118 + 4×≤138 (8.5.2)
- refactor(hud): Keybinds 611→157 + 4×≤160 (8.5.2)
- refactor(hud): ModuleList 499→181 + 3×≤150 (8.5.2)
- refactor(hud): Radar 392→161 + 2×≤124 (8.5.2)
- refactor(hud): Fps 309→168 + 3×≤107 (8.5.2)
- refactor(hud): Memory 304→151 + 3×≤144 (8.5.2)
- refactor(hud): Tps 339→154 + 3×≤143 (8.5.2)
- refactor(hud): Ping 309→145 + 3×≤125 (8.5.2)
- refactor(hud): SpeedBps 334→156 + 3×≤142 (8.5.2)
- refactor(hud): GameTime 314→150 + 3×≤127 (8.5.2)
- refactor(hud): SystemTime 300→136 + 3×≤130 (8.5.2)
- refactor(hud): Coordinates 337→174 + 2×≤172 (8.5.2)
- refactor(hud): Armor 324→162 + 2×≤148 (8.5.2)
- refactor(hud): Inventory 476→153 + 3×≤181 (8.5.2)
- docs(todo): обновлён 8.5.2 — отмечены готовые гиганты (BetterButtons/InventorySwap/Svg/Темы/WorldParticles/Module/Chams и хвост)
- docs(api): папка combatant-client-26.2/docs + addons.md (API можно ломать при рефакторе)
- refactor(visuals): BlockHighlight 692→271 + 4×≤200 (8.5.2)
- refactor(mixins): GameRendererMixin 830→344 (хуки) + 4 хелпера (8.5.2)
- refactor(visuals): WorldParticles 821→260 + 6×≤200, режимы добиты (8.5.2)
- docs(todo): 8.5.2 — WorldParticles/GameRendererMixin/BlockHighlight отмечены ГОТОВО
- refactor(render): MeshBuilder 738→447 (фасад write-API) + 3 хелпера, FrameStats снесён (8.5.2)
- docs(todo): Фаза 10 — дизайн платформы (аккаунты/конфиги/аватарки), backlog RPC-чата
- docs(todo): Подсистема 3 — Аддоны 2.0 (скрипты/версии) + витрина аддонов + админка
- docs(todo): Подсистема 2 — RPC-чат/друзья/виджеты-телеметрия + рейт-лимиты, доп. правки Подсистемы 3
- chore: переименование combatant-client-26.2 -> mod, добавлены backend/ и frontend/
- docs(backend): implementation plan for accounts-service (Подсистема 1, часть 1)
- chore: пересоздать backend/frontend через cargo new и bun create vite + tailwind; убрать таблицу компонентов из TODO.md
- docs(backend): edition 2024 в плане вместо 2021
- chore: обновить версии до реально актуальных (проверено компиляцией)
- docs: правила платформы (лимит 250 строк, антипаттерны backend/frontend по итогам ресёрча) + frontend/ARCHITECTURE.md
- docs: добавить правило ≤4 файла на папку в правила платформы (backend/frontend)
- docs: commit messages in English from now on
- chore: gitignore .superpowers/ scratch directory
- docs: commit messages in English from now on (mod)
- feat(backend): scaffold accounts-service with health check
- chore(backend): remove target/ build artifacts from git, add gitignore
- chore: track docs/ in git (was accidentally gitignored, never committed)
- chore(backend): convert to Cargo workspace, plan full microservice layout
- feat(backend): accounts/avatars/device_links schema + migration
- feat(backend): argon2id password hashing
This commit is contained in:
loki5512344 2026-09-23 22:38:08 +02:00
parent ec10395511
commit 9d08fa910a
2239 changed files with 35265 additions and 28110 deletions

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 358 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 477 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 467 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

View file

@ -0,0 +1 @@
{"atlas":{"type":"msdf","distanceRange":8,"distanceRangeMiddle":0,"size":96,"width":4096,"height":4096,"yOrigin":"bottom"},"metrics":{"emSize":1,"lineHeight":1,"ascender":0.9375,"descender":-0.0625,"underlineY":0,"underlineThickness":0},"glyphs":[{"unicode":97,"advance":1,"planeBounds":{"left":0.22265624999999997,"bottom":0.088541666666666657,"right":0.75390624999999989,"top":0.78645833333333337},"atlasBounds":{"left":335.5,"bottom":4028.5,"right":386.5,"top":4095.5}},{"unicode":98,"advance":1,"planeBounds":{"left":0.029947916666666668,"bottom":0.088541666666666657,"right":0.94661458333333337,"top":0.78645833333333337},"atlasBounds":{"left":387.5,"bottom":4028.5,"right":475.5,"top":4095.5}},{"unicode":99,"advance":0.91796875,"planeBounds":{"left":0.076822916666666671,"bottom":0.026041666666666664,"right":0.89973958333333337,"top":0.84895833333333337},"atlasBounds":{"left":255.5,"bottom":4016.5,"right":334.5,"top":4095.5}},{"unicode":105,"advance":0.9423828125,"planeBounds":{"left":0.054036458333333336,"bottom":0.015625,"right":0.82486979166666663,"top":0.86979166666666663},"atlasBounds":{"left":180.5,"bottom":4013.5,"right":254.5,"top":4095.5}},{"unicode":115,"advance":1,"planeBounds":{"left":0.024739583333333332,"bottom":-0.005208333333333333,"right":0.95182291666666663,"top":0.88020833333333337},"atlasBounds":{"left":90.5,"bottom":4010.5,"right":179.5,"top":4095.5}},{"unicode":120,"advance":1,"planeBounds":{"left":0.036458333333333336,"bottom":-0.098958333333333343,"right":0.96354166666666663,"top":0.97395833333333337},"atlasBounds":{"left":0.5,"bottom":3992.5,"right":89.5,"top":4095.5}}],"kerning":[]}

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 387 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 227 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 233 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

File diff suppressed because one or more lines are too long

Binary file not shown.

After

Width:  |  Height:  |  Size: 176 KiB

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,103 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
in vec4 v_Local;
in vec4 v_Color;
in vec4 v_Rect;
in vec4 v_Params;
in vec4 v_Params2;
out vec4 fragColor;
layout (std140) uniform UIBatch {
vec4 uScreen; // xy = framebuffer size, zw = logical size
};
float circleSDF(vec2 p, float r) {
return length(p) - r;
}
float normalizeAngle(float angleDeg) {
float outAngle = mod(angleDeg, 360.0);
return outAngle < 0.0 ? outAngle + 360.0 : outAngle;
}
vec2 arcPoint(vec2 center, float radius, float angleDeg) {
float rad = radians(angleDeg);
return center + vec2(sin(rad), -cos(rad)) * radius;
}
vec2 warpedLocal(vec4 local) {
float invW = abs(local.z) > 0.000001 ? local.z : 1.0;
return local.xy / invW;
}
void main() {
vec2 logicalScale = uScreen.zw / uScreen.xy;
vec2 frag = warpedLocal(v_Local);
vec2 halfSize = v_Rect.zw * 0.5;
vec2 center = v_Rect.xy + halfSize;
float radius = v_Params.x;
float softness = v_Params.y;
float thickness = v_Params.z;
float startDeg = normalizeAngle(v_Params.w);
float endDeg = normalizeAngle(v_Params2.x);
float capsEnabled = v_Params2.y;
vec2 local = frag - center;
float dist = length(local);
float radialD = abs(dist - radius) - thickness * 0.5;
float radialAa = max(max(softness, fwidth(radialD)), 0.0001);
float radialAlpha = 1.0 - smoothstep(0.0, radialAa, radialD);
float sweep = endDeg - startDeg;
if (sweep <= 0.0) {
sweep += 360.0;
}
float angularAlpha = 1.0;
if (sweep < 359.99) {
float angleDeg = normalizeAngle(degrees(atan(local.x, -local.y)));
if (angleDeg < startDeg) {
angleDeg += 360.0;
}
float angularSoftDeg = max(fwidth(angleDeg), degrees(softness / max(radius, 0.0001)));
float startMask;
float endMask;
if (capsEnabled > 0.5) {
// Keep the arc body inside the logical sweep; round dots are added separately below.
startMask = smoothstep(startDeg - angularSoftDeg, startDeg, angleDeg);
endMask = 1.0 - smoothstep(endDeg, endDeg + angularSoftDeg, angleDeg);
} else {
// Flat arcs must not bleed past the logical start/end angles.
startMask = smoothstep(startDeg - angularSoftDeg, startDeg, angleDeg);
endMask = 1.0 - smoothstep(endDeg, endDeg + angularSoftDeg, angleDeg);
}
angularAlpha = startMask * endMask;
float alpha = angularAlpha * radialAlpha;
if (capsEnabled > 0.5) {
float capRadius = thickness * 0.5;
float capAa = max(max(softness, fwidth(capRadius)), 0.0001);
float startCapD = circleSDF(frag - arcPoint(center, radius, startDeg), capRadius);
float endCapD = circleSDF(frag - arcPoint(center, radius, endDeg), capRadius);
float startCapAlpha = 1.0 - smoothstep(0.0, capAa, startCapD);
float endCapAlpha = 1.0 - smoothstep(0.0, capAa, endCapD);
alpha = max(alpha, max(startCapAlpha, endCapAlpha));
}
fragColor = vec4(v_Color.rgb, v_Color.a * alpha);
return;
}
fragColor = vec4(v_Color.rgb, v_Color.a * radialAlpha);
}

View file

@ -0,0 +1,60 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*/
out vec4 color;
layout (std140) uniform WaterData {
vec4 u_Color;
vec4 u_PatternColor;
float u_Time;
};
in vec2 v_TexCoord;
float hexDist(vec2 p) {
p = abs(p);
float c = dot(p, normalize(vec2(1.0, 1.73205)));
c = max(c, p.x);
return c;
}
vec2 hexCoords(vec2 uv) {
vec2 r = vec2(1.0, 1.73205);
vec2 h = r * 0.5;
vec2 a = mod(uv, r) - h;
vec2 b = mod(uv - h, r) - h;
return dot(a, a) < dot(b, b) ? a : b;
}
void main() {
vec2 uv = v_TexCoord;
float time = u_Time;
float distToEdge = min(min(uv.x, 1.0 - uv.x), min(uv.y, 1.0 - uv.y));
float edgeFrame = smoothstep(0.02, 0.0, distToEdge);
float edgeGlow = exp(-distToEdge * 14.0);
vec2 hexUv = uv * 8.0;
vec2 cell = hexCoords(hexUv);
float hex = hexDist(cell);
float hexLine = smoothstep(0.5, 0.46, hex) - smoothstep(0.46, 0.40, hex);
float flicker = 0.85 + 0.15 * sin(time * 6.0 + uv.x * 20.0);
float rise = fract(uv.y * 2.0 - time * 0.5);
float riseBand = smoothstep(0.0, 0.08, rise) * smoothstep(0.24, 0.08, rise);
vec3 baseColor = u_Color.rgb;
vec3 accentColor = u_PatternColor.rgb;
vec3 finalRGB = baseColor * (edgeFrame * 2.0 + edgeGlow * 1.2)
+ accentColor * hexLine * flicker
+ accentColor * riseBand * 0.8;
float finalAlpha = clamp(u_Color.w * (0.10 + edgeFrame * 0.9 + hexLine * 0.6 + riseBand * 0.4), 0.0, 1.0);
if (finalAlpha < 0.01) discard;
color = vec4(finalRGB, finalAlpha);
}

View file

@ -0,0 +1,43 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*/
out vec4 color;
layout (std140) uniform WaterData {
vec4 u_Color;
vec4 u_PatternColor;
float u_Time;
};
in vec2 v_TexCoord;
void main() {
vec2 uv = v_TexCoord;
float time = u_Time;
float distToEdge = min(min(uv.x, 1.0 - uv.x), min(uv.y, 1.0 - uv.y));
float edgeGlow = exp(-distToEdge * 20.0);
float scanY = fract(uv.y * 3.0 - time * 1.4);
float scanLine = smoothstep(0.0, 0.06, scanY) * smoothstep(0.18, 0.06, scanY);
float scanBand = smoothstep(0.0, 1.0, 1.0 - abs(fract(uv.y * 18.0) - 0.5) * 2.0) * 0.15;
float sweep = smoothstep(0.02, 0.0, abs(fract(time * 0.35) - uv.y));
float pulse = sin(time * 3.0) * 0.15 + 0.85;
vec3 baseColor = u_Color.rgb;
vec3 accentColor = u_PatternColor.rgb;
vec3 finalRGB = baseColor * (edgeGlow * 1.4)
+ accentColor * (scanLine * 1.6 + sweep * 0.9)
+ baseColor * scanBand;
finalRGB *= pulse;
float finalAlpha = clamp(u_Color.w * (0.12 + edgeGlow * 0.7 + scanLine * 0.6 + sweep * 0.5), 0.0, 1.0);
if (finalAlpha < 0.01) discard;
color = vec4(finalRGB, finalAlpha);
}

View file

@ -0,0 +1,48 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*/
out vec4 color;
layout (std140) uniform WaterData {
vec4 u_Color;
vec4 u_PatternColor;
float u_Time;
};
in vec2 v_TexCoord;
void main() {
vec2 vUV = v_TexCoord;
float time = u_Time;
float distToEdge = min(min(vUV.x, 1.0 - vUV.x), min(vUV.y, 1.0 - vUV.y));
float edgeGlow = exp(-distToEdge * 16.0);
float edgeFrame = smoothstep(0.03, 0.0, distToEdge);
vec2 gridUV = vUV * 6.0;
float gridAnim = sin(gridUV.x + gridUV.y + time * 2.0) * 0.5 + 0.5;
vec2 f = abs(fract(gridUV - 0.5) - 0.5);
float gridLines = smoothstep(0.05, 0.0, min(f.x, f.y));
gridLines *= (0.2 + 0.8 * gridAnim);
vec2 p = vUV * 2.0 - 1.0;
float rLen = length(p);
float wave = sin(rLen * 10.0 - time * 3.5) * 0.5 + 0.5;
wave *= smoothstep(0.8, 0.1, rLen);
float pulse = sin(time * 2.5) * 0.12 + 0.88;
vec3 baseColor = u_Color.rgb;
vec3 accentColor = u_PatternColor.rgb;
vec3 borderRGB = baseColor * (edgeGlow * 1.6 + edgeFrame * 2.2);
vec3 gridRGB = mix(baseColor, accentColor, gridAnim) * (gridLines * 0.9);
vec3 waveRGB = accentColor * (wave * 0.35);
vec3 finalRGB = (borderRGB + gridRGB + waveRGB) * pulse;
float finalAlpha = clamp(u_Color.w * (0.15 + edgeGlow * 0.85 + gridLines * 0.5 + wave * 0.2), 0.0, 1.0);
color = vec4(finalRGB, finalAlpha);
}

View file

@ -0,0 +1,78 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
in vec4 v_Local;
in vec4 v_Color;
in vec4 v_Rect;
in vec4 v_Params;
in vec4 v_Params2;
out vec4 fragColor;
layout (std140) uniform UIBatch {
vec4 uScreen; // xy = framebuffer size, zw = logical size
};
float cornerCut(float u, float v, float cutX, float cutY) {
if (cutX <= 0.0001 || cutY <= 0.0001) {
return -1.0;
}
return (1.0 - u / cutX - v / cutY) / length(vec2(1.0 / cutX, 1.0 / cutY));
}
float chamferedBoxSDF(vec2 p, vec2 halfSize, vec4 chamferX, vec4 chamferY) {
vec2 q = abs(p);
float d = max(q.x - halfSize.x, q.y - halfSize.y);
float left = p.x + halfSize.x;
float right = halfSize.x - p.x;
float top = p.y + halfSize.y;
float bottom = halfSize.y - p.y;
float tl = cornerCut(left, top, chamferX.x, chamferY.x);
float tr = cornerCut(right, top, chamferX.y, chamferY.y);
float br = cornerCut(right, bottom, chamferX.z, chamferY.z);
float bl = cornerCut(left, bottom, chamferX.w, chamferY.w);
return max(d, max(max(tl, tr), max(br, bl)));
}
float pixelAa(vec2 logicalScale) {
return max(max(logicalScale.x, logicalScale.y), 0.0001);
}
float analyticAa(float d, vec2 logicalScale) {
return max(pixelAa(logicalScale), max(fwidth(d) * 0.75, 0.0001));
}
float crispCoverage(float d, float aa) {
return clamp(0.5 - d / max(aa, 0.0001), 0.0, 1.0);
}
vec2 warpedLocal(vec4 local) {
float invW = abs(local.z) > 0.000001 ? local.z : 1.0;
return local.xy / invW;
}
void main() {
vec2 logicalScale = uScreen.zw / uScreen.xy;
vec2 frag = warpedLocal(v_Local);
vec2 halfSize = v_Rect.zw * 0.5;
vec2 center = v_Rect.xy + halfSize;
vec4 chamferX = clamp(v_Params, vec4(0.0), vec4(v_Rect.z));
vec4 chamferY = clamp(v_Params2, vec4(0.0), vec4(v_Rect.w));
float d = chamferedBoxSDF(frag - center, halfSize, chamferX, chamferY);
float edge = analyticAa(d, logicalScale);
float a = crispCoverage(d, edge);
fragColor = vec4(v_Color.rgb, v_Color.a * a);
}

View file

@ -0,0 +1,72 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
in vec4 v_Local;
in vec4 v_Color;
in vec4 v_Rect;
in vec4 v_Params;
in vec4 v_Params2;
out vec4 fragColor;
layout (std140) uniform UIBatch {
vec4 uScreen; // xy = framebuffer size, zw = logical size
};
float chamferedBoxSDF(vec2 p, vec2 halfSize, vec4 chamfer) {
vec2 q = abs(p);
float d = max(q.x - halfSize.x, q.y - halfSize.y);
float tl = (-p.x - p.y - halfSize.x - halfSize.y + chamfer.x) * 0.70710678;
float tr = ( p.x - p.y - halfSize.x - halfSize.y + chamfer.y) * 0.70710678;
float br = ( p.x + p.y - halfSize.x - halfSize.y + chamfer.z) * 0.70710678;
float bl = (-p.x + p.y - halfSize.x - halfSize.y + chamfer.w) * 0.70710678;
return max(d, max(max(tl, tr), max(br, bl)));
}
float pixelAa(vec2 logicalScale) {
return max(max(logicalScale.x, logicalScale.y), 0.0001);
}
float analyticAa(float d, vec2 logicalScale) {
return max(pixelAa(logicalScale), max(fwidth(d) * 0.75, 0.0001));
}
float crispCoverage(float d, float aa) {
return clamp(0.5 - d / max(aa, 0.0001), 0.0, 1.0);
}
vec2 warpedLocal(vec4 local) {
float invW = abs(local.z) > 0.000001 ? local.z : 1.0;
return local.xy / invW;
}
void main() {
vec2 logicalScale = uScreen.zw / uScreen.xy;
vec2 frag = warpedLocal(v_Local);
vec2 halfSize = v_Rect.zw * 0.5;
vec2 center = v_Rect.xy + halfSize;
vec4 chamfer = clamp(v_Params, vec4(0.0), vec4(min(halfSize.x, halfSize.y)));
float thickness = max(0.0, v_Params2.x);
float d = chamferedBoxSDF(frag - center, halfSize, chamfer);
vec2 innerHalf = max(vec2(0.0), halfSize - vec2(thickness));
vec4 innerChamfer = max(vec4(0.0), chamfer - vec4(thickness));
float innerD = chamferedBoxSDF(frag - center, innerHalf, innerChamfer);
float edge = analyticAa(d, logicalScale);
float outer = crispCoverage(d, edge);
float inner = crispCoverage(innerD, edge);
float a = clamp(outer - inner, 0.0, 1.0);
fragColor = vec4(v_Color.rgb, v_Color.a * a);
}

View file

@ -0,0 +1,59 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
in vec4 v_Local;
in vec4 v_Color;
in vec4 v_Rect;
in vec4 v_Params;
out vec4 fragColor;
layout (std140) uniform UIBatch {
vec4 uScreen; // xy = framebuffer size, zw = logical size
};
float circleSDF(vec2 p, float r) {
return length(p) - r;
}
float pixelAa(vec2 logicalScale) {
return max(max(logicalScale.x, logicalScale.y), 0.0001);
}
float analyticAa(float d, vec2 logicalScale) {
return max(pixelAa(logicalScale), max(fwidth(d) * 0.75, 0.0001));
}
float crispCoverage(float d, float aa) {
return clamp(0.5 - d / max(aa, 0.0001), 0.0, 1.0);
}
vec2 warpedLocal(vec4 local) {
float invW = abs(local.z) > 0.000001 ? local.z : 1.0;
return local.xy / invW;
}
void main() {
vec2 logicalScale = uScreen.zw / max(uScreen.xy, vec2(1.0));
vec2 frag = warpedLocal(v_Local);
vec2 halfSize = v_Rect.zw * 0.5;
vec2 center = v_Rect.xy + halfSize;
float radius = v_Params.x;
float softness = max(v_Params.y, 0.0);
float thickness = v_Params.z;
float d = circleSDF(frag - center, radius);
if (thickness > 0.0) {
d = abs(d) - thickness * 0.5;
}
float a = crispCoverage(d, analyticAa(d, logicalScale) + softness);
fragColor = vec4(v_Color.rgb, v_Color.a * a);
}

View file

@ -0,0 +1,95 @@
#version 330
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
#moj_import <minecraft:fog.glsl>
#moj_import <minecraft:dynamictransforms.glsl>
uniform sampler2D Sampler0;
#ifdef DISSOLVE
uniform sampler2D DissolveMaskSampler;
#endif
in float sphericalVertexDistance;
in float cylindricalVertexDistance;
#ifdef PER_FACE_LIGHTING
in vec4 vertexPerFaceColorBack;
in vec4 vertexPerFaceColorFront;
#else
in vec4 vertexColor;
#endif
#ifndef EMISSIVE
in vec4 lightMapColor;
#endif
#ifndef NO_OVERLAY
in vec4 overlayColor;
#endif
in vec2 texCoord0;
in vec3 lovisualModelPos;
out vec4 fragColor;
const ivec3 LOVISUAL_DITHER_MARK = ivec3(1, 0, 1);
const ivec3 LOVISUAL_A2C_MARK = ivec3(1, 1, 0);
void main() {
vec4 color = texture(Sampler0, texCoord0);
#ifdef ALPHA_CUTOUT
if (color.a < ALPHA_CUTOUT) {
discard;
}
#endif
#ifdef PER_FACE_LIGHTING
vec4 shadeColor = gl_FrontFacing ? vertexPerFaceColorFront : vertexPerFaceColorBack;
#else
vec4 shadeColor = vertexColor;
#endif
#ifdef DISSOLVE
if (shadeColor.a < texture(DissolveMaskSampler, texCoord0).a) {
discard;
}
// The dissolve effect entirely replaces translucency.
shadeColor.a = 1.0;
#endif
int shadeAlphaByte = int(floor(clamp(shadeColor.a, 0.0, 1.0) * 255.0 + 0.5));
int shadeRByte = int(floor(clamp(shadeColor.r, 0.0, 1.0) * 255.0 + 0.5));
int shadeGByte = int(floor(clamp(shadeColor.g, 0.0, 1.0) * 255.0 + 0.5));
int shadeBByte = int(floor(clamp(shadeColor.b, 0.0, 1.0) * 255.0 + 0.5));
ivec3 mark = ivec3(shadeRByte & 1, shadeGByte & 1, shadeBByte & 1);
bool lovisualDitherFade = shadeAlphaByte < 255 && all(equal(mark, LOVISUAL_DITHER_MARK));
bool lovisualA2CFade = shadeAlphaByte < 255 && all(equal(mark, LOVISUAL_A2C_MARK));
if (lovisualDitherFade || lovisualA2CFade) {
float fadeAlpha = float(shadeAlphaByte) / 255.0;
shadeColor.r = float(shadeRByte & 254) / 255.0;
shadeColor.g = float(shadeGByte & 254) / 255.0;
shadeColor.b = float(shadeBByte & 254) / 255.0;
// Prefer real fragment alpha. The old coverage discard made entities look like
// punctured meshes instead of a smooth whole-model texture-alpha fade.
shadeColor.a = fadeAlpha;
}
color *= shadeColor * ColorModulator;
#ifndef NO_OVERLAY
color.rgb = mix(overlayColor.rgb, color.rgb, overlayColor.a);
#endif
#ifndef EMISSIVE
color *= lightMapColor;
#endif
fragColor = apply_fog(color, sphericalVertexDistance, cylindricalVertexDistance, FogEnvironmentalStart, FogEnvironmentalEnd, FogRenderDistanceStart, FogRenderDistanceEnd, FogColor);
}

View file

@ -0,0 +1,84 @@
#version 330
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
#if defined(PER_FACE_LIGHTING) || !defined(NO_CARDINAL_LIGHTING)
#moj_import <minecraft:light.glsl>
#endif
#moj_import <minecraft:fog.glsl>
#moj_import <minecraft:dynamictransforms.glsl>
#moj_import <minecraft:projection.glsl>
#moj_import <minecraft:sample_lightmap.glsl>
in vec3 Position;
in vec4 Color;
in vec2 UV0;
in ivec2 UV1;
in ivec2 UV2;
in vec3 Normal;
#ifndef NO_OVERLAY
uniform sampler2D Sampler1;
#endif
#ifndef EMISSIVE
uniform sampler2D Sampler2;
#endif
out float sphericalVertexDistance;
out float cylindricalVertexDistance;
#ifdef PER_FACE_LIGHTING
out vec4 vertexPerFaceColorBack;
out vec4 vertexPerFaceColorFront;
#else
out vec4 vertexColor;
#endif
#ifndef EMISSIVE
out vec4 lightMapColor;
#endif
#ifndef NO_OVERLAY
out vec4 overlayColor;
#endif
out vec2 texCoord0;
out vec3 lovisualModelPos;
void main() {
gl_Position = ProjMat * ModelViewMat * vec4(Position, 1.0);
sphericalVertexDistance = fog_spherical_distance(Position);
cylindricalVertexDistance = fog_cylindrical_distance(Position);
#ifdef PER_FACE_LIGHTING
vec2 light = minecraft_compute_light(Light0_Direction, Light1_Direction, Normal);
vertexPerFaceColorBack = minecraft_mix_light_separate(-light, Color);
vertexPerFaceColorFront = minecraft_mix_light_separate(light, Color);
#elif defined(NO_CARDINAL_LIGHTING)
vertexColor = Color;
#else
vertexColor = minecraft_mix_light(Light0_Direction, Light1_Direction, Normal, Color);
#endif
#ifndef EMISSIVE
lightMapColor = sample_lightmap(Sampler2, UV2);
#endif
#ifndef NO_OVERLAY
overlayColor = texelFetch(Sampler1, UV1, 0);
#endif
texCoord0 = UV0;
#ifdef APPLY_TEXTURE_MATRIX
texCoord0 = (TextureMat * vec4(UV0, 0.0, 1.0)).xy;
#endif
lovisualModelPos = Position;
}

View file

@ -0,0 +1,43 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
out vec4 color;
uniform sampler2D u_Texture;
layout (std140) uniform PostProcess {
vec4 u_Params;
};
in vec2 v_TexCoord;
void main() {
vec4 base = texture(u_Texture, v_TexCoord);
vec3 col = base.rgb;
float desat = clamp(u_Params.y, 0.0, 1.0);
float contrast = clamp(u_Params.z, 0.0, 1.0);
float strength = clamp(u_Params.x, 0.0, 1.0);
float luma = dot(col, vec3(0.2126, 0.7152, 0.0722));
col = mix(col, vec3(luma), desat);
col = (col - 0.5) * (1.0 + contrast) + 0.5;
col = clamp(col, 0.0, 1.0);
float dist = distance(v_TexCoord, vec2(0.5));
float edge = smoothstep(0.4, 0.85, dist);
float vignette = clamp(edge * strength, 0.0, 1.0);
vec3 tinted = col * vec3(1.0, 0.45, 0.45);
col = mix(col, tinted, vignette);
col *= (1.0 - 0.25 * vignette);
color = vec4(col, 1.0);
}

View file

@ -0,0 +1,23 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
layout (location = 0) in vec2 Position;
layout (std140) uniform MeshData {
mat4 u_Proj;
mat4 u_ModelView;
};
out vec2 v_TexCoord;
void main() {
vec4 p = vec4(Position, 0.0, 1.0);
gl_Position = u_Proj * u_ModelView * p;
v_TexCoord = Position * 0.5 + 0.5;
}

View file

@ -0,0 +1,272 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
out vec4 color;
uniform sampler2D u_Texture;
uniform sampler2D u_MainDepth;
uniform sampler2D u_TranslucentDepth;
uniform sampler2D u_ItemEntityDepth;
uniform sampler2D u_ParticlesDepth;
uniform sampler2D u_WeatherDepth;
uniform sampler2D u_CloudsDepth;
layout (std140) uniform DepthOfField {
mat4 u_Projection;
vec4 u_Screen; // invW, invH, width, height
vec4 u_Focus; // mode, fallbackFocusDistance, farStart, farTransition
vec4 u_Params; // strength, maxRadiusPx, taps, edgeProtection
vec4 u_State; // debugCoc, reserved, reserved, reserved
vec4 u_DepthA; // main, translucent, item_entity, particles availability
vec4 u_DepthB; // weather, clouds, reserved, reserved availability
};
in vec2 v_TexCoord;
const float DEPTH_NEAR_EPS = 0.000001;
const float DEPTH_FAR_EPS = 0.999999;
const float INVALID_DISTANCE = 100000.0;
bool depthEnabled(float v) {
return v > 0.5;
}
bool validRawDepth(float d) {
return d == d && d > DEPTH_NEAR_EPS && d < DEPTH_FAR_EPS;
}
bool hasEnabledDepthSource() {
return depthEnabled(u_DepthA.x)
|| depthEnabled(u_DepthA.y)
|| depthEnabled(u_DepthA.z)
|| depthEnabled(u_DepthA.w)
|| depthEnabled(u_DepthB.x)
|| depthEnabled(u_DepthB.y);
}
float mergeDepth(float currentDepth, float candidateDepth, float enabled) {
if (!depthEnabled(enabled) || !validRawDepth(candidateDepth)) {
return currentDepth;
}
if (!validRawDepth(currentDepth)) {
return candidateDepth;
}
return min(currentDepth, candidateDepth);
}
float readSceneDepth(vec2 uv) {
float d = 1.0;
d = mergeDepth(d, texture(u_MainDepth, uv).r, u_DepthA.x);
d = mergeDepth(d, texture(u_TranslucentDepth, uv).r, u_DepthA.y);
d = mergeDepth(d, texture(u_ItemEntityDepth, uv).r, u_DepthA.z);
d = mergeDepth(d, texture(u_ParticlesDepth, uv).r, u_DepthA.w);
d = mergeDepth(d, texture(u_WeatherDepth, uv).r, u_DepthB.x);
d = mergeDepth(d, texture(u_CloudsDepth, uv).r, u_DepthB.y);
return d;
}
vec3 reconstructViewPosition(vec2 uv, float rawDepth) {
float m22 = u_Projection[2][2];
float m23 = u_Projection[2][3];
float m32 = u_Projection[3][2];
float m33 = u_Projection[3][3];
float denom = rawDepth * m23 - m22;
if (abs(denom) < 0.000001) {
denom = denom < 0.0 ? -0.000001 : 0.000001;
}
float z = (m32 - rawDepth * m33) / denom;
float clipW = m23 * z + m33;
vec2 ndc = uv * 2.0 - 1.0;
float rhsX = ndc.x * clipW - u_Projection[2][0] * z - u_Projection[3][0];
float rhsY = ndc.y * clipW - u_Projection[2][1] * z - u_Projection[3][1];
float det = u_Projection[0][0] * u_Projection[1][1] - u_Projection[1][0] * u_Projection[0][1];
if (abs(det) < 0.000001) {
det = det < 0.0 ? -0.000001 : 0.000001;
}
float x = (rhsX * u_Projection[1][1] - u_Projection[1][0] * rhsY) / det;
float y = (u_Projection[0][0] * rhsY - rhsX * u_Projection[0][1]) / det;
return vec3(x, y, z);
}
float reconstructDistance(vec2 uv, float rawDepth) {
if (!validRawDepth(rawDepth)) {
return INVALID_DISTANCE;
}
return length(reconstructViewPosition(uv, rawDepth));
}
void accumulateFocusSample(vec2 uv, inout float sum, inout float count) {
float d = readSceneDepth(uv);
if (!validRawDepth(d)) {
return;
}
float distanceToCamera = reconstructDistance(uv, d);
if (distanceToCamera >= INVALID_DISTANCE * 0.5) {
return;
}
sum += distanceToCamera;
count += 1.0;
}
float centerFocusDistance() {
vec2 texel = u_Screen.xy;
vec2 c = vec2(0.5);
float fallback = max(u_Focus.y, 0.01);
float sum = 0.0;
float count = 0.0;
accumulateFocusSample(c, sum, count);
accumulateFocusSample(c + vec2(texel.x * 2.0, 0.0), sum, count);
accumulateFocusSample(c - vec2(texel.x * 2.0, 0.0), sum, count);
accumulateFocusSample(c + vec2(0.0, texel.y * 2.0), sum, count);
accumulateFocusSample(c - vec2(0.0, texel.y * 2.0), sum, count);
if (count <= 0.5) {
return fallback;
}
return clamp(sum / count, 0.01, INVALID_DISTANCE);
}
float focusDistance() {
if (u_Focus.x < 0.5) {
return centerFocusDistance();
}
return max(u_Focus.y, 0.01);
}
float computeCoc(float distanceToCamera, float focus) {
if (distanceToCamera >= INVALID_DISTANCE * 0.5) {
return 0.0;
}
float farStart = max(u_Focus.z, 0.0);
float farTransition = max(u_Focus.w, 0.001);
float coc = smoothstep(farStart, farStart + farTransition, distanceToCamera);
coc = pow(clamp(coc, 0.0, 1.0), 1.35);
return coc * max(u_Params.x, 0.0);
}
float depthCompatibility(float centerDistance, float sampleDistance) {
if (sampleDistance >= INVALID_DISTANCE * 0.5 || centerDistance >= INVALID_DISTANCE * 0.5) {
return 0.0;
}
float protection = clamp(u_Params.w, 0.0, 1.0);
float relBase = max(centerDistance, 1.0);
float relativeDelta = abs(sampleDistance - centerDistance) / relBase;
float softWidth = mix(0.10, 0.018, protection);
float weight = 1.0 - smoothstep(softWidth, softWidth * 3.0, relativeDelta);
if (sampleDistance + 0.001 < centerDistance) {
float foregroundDelta = (centerDistance - sampleDistance) / relBase;
float fgWidth = mix(0.07, 0.010, protection);
weight *= 1.0 - smoothstep(fgWidth, fgWidth * 3.0, foregroundDelta);
}
return clamp(weight, 0.0, 1.0);
}
vec3 depthAwareBlur(vec2 uv, float centerDistance, float centerCoc, float radiusPx, float focus) {
int taps = int(clamp(floor(u_Params.z + 0.5), 1.0, 32.0));
vec2 texel = u_Screen.xy;
vec3 accum = texture(u_Texture, uv).rgb;
float weightSum = 1.0;
for (int i = 0; i < 32; i++) {
if (i >= taps) {
break;
}
float fi = float(i) + 0.5;
float ftaps = max(float(taps), 1.0);
float r = sqrt(fi / ftaps);
float a = fi * 2.399963229728653;
vec2 sampleUv = uv + vec2(cos(a), sin(a)) * r * radiusPx * texel;
if (sampleUv.x < 0.0 || sampleUv.x > 1.0 || sampleUv.y < 0.0 || sampleUv.y > 1.0) {
continue;
}
float sampleRawDepth = readSceneDepth(sampleUv);
if (!validRawDepth(sampleRawDepth)) {
continue;
}
float sampleDistance = reconstructDistance(sampleUv, sampleRawDepth);
float sampleCoc = computeCoc(sampleDistance, focus);
float cocWeight = smoothstep(0.0, 0.30, max(centerCoc, sampleCoc));
float depthWeight = depthCompatibility(centerDistance, sampleDistance);
float radialWeight = 1.0 - r * 0.35;
float weight = radialWeight * depthWeight * cocWeight;
if (weight <= 0.001) {
continue;
}
accum += texture(u_Texture, sampleUv).rgb * weight;
weightSum += weight;
}
return accum / max(weightSum, 0.0001);
}
void main() {
vec2 uv = v_TexCoord;
vec4 base = texture(u_Texture, uv);
float rawDepth = readSceneDepth(uv);
bool validDepth = validRawDepth(rawDepth);
bool anyDepthSource = hasEnabledDepthSource();
if (!anyDepthSource) {
if (u_State.x > 0.5) {
color = vec4(1.0, 0.0, 1.0, 1.0); // no depth binding reached the shader
} else {
color = vec4(base.rgb, 1.0);
}
return;
}
if (!validDepth) {
if (u_State.x > 0.5) {
color = vec4(1.0, 0.0, 0.0, 1.0); // clear/invalid depth pixel, not a far object
} else {
color = vec4(base.rgb, 1.0);
}
return;
}
float strength = max(u_Params.x, 0.0);
float maxRadius = max(u_Params.y, 0.0);
if (strength <= 0.0001 || maxRadius <= 0.0001) {
color = vec4(base.rgb, 1.0);
return;
}
float distanceToCamera = reconstructDistance(uv, rawDepth);
float focus = focusDistance();
float coc = computeCoc(distanceToCamera, focus);
float radiusPx = clamp(coc * maxRadius, 0.0, maxRadius);
if (u_State.x > 0.5) {
color = vec4(vec3(clamp(coc, 0.0, 1.0)), 1.0);
return;
}
if (radiusPx < 0.35) {
color = vec4(base.rgb, 1.0);
return;
}
vec3 blurred = depthAwareBlur(uv, distanceToCamera, coc, radiusPx, focus);
vec3 result = mix(base.rgb, blurred, clamp(coc, 0.0, 1.0));
color = vec4(result, 1.0);
}

View file

@ -0,0 +1,39 @@
#version 150
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
uniform sampler2D Sampler0;
in vec4 vertexColor;
in vec2 texCoord0;
out vec4 fragColor;
vec3 mixRgb(vec3 from, vec3 to, float t) {
return mix(from, to, clamp(t, 0.0, 1.0));
}
void main() {
vec4 tex = texture(Sampler0, texCoord0);
if (tex.a <= 0.001) {
discard;
}
vec3 base = vertexColor.rgb;
float luma = dot(tex.rgb, vec3(0.2126, 0.7152, 0.0722));
float ink = smoothstep(0.00, 0.34, luma);
float shine = smoothstep(0.48, 1.00, luma);
vec3 shadow = mixRgb(base * 0.30, vec3(0.0), 0.18);
vec3 mid = mixRgb(base * 0.72, base, 0.58);
vec3 highlight = mixRgb(base, vec3(1.0), 0.34);
vec3 mapped = mix(shadow, mid, ink);
mapped = mix(mapped, highlight, shine);
fragColor = vec4(mapped, tex.a * vertexColor.a);
}

View file

@ -0,0 +1,88 @@
#version 330 core
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandChams {
vec4 u_View; // x = resX, y = resY, z = time
vec4 u_Mix; // x = effectAlpha, y = chromaSpeed, z = chromaSaturation, w = chromaBrightness
vec4 u_ColorA; // rgb = colorA
vec4 u_ColorB; // rgb = colorB
vec4 u_ColorC; // rgb = colorC
vec4 u_ColorD; // rgb = colorD (r = contrast, g = lighting)
vec4 u_Common; // x = snowIntensity, y = snowSpeed, z = stripesWidth, w = stripesSpeed
vec4 u_Glow; // x = fillGlow, y = glowRadius, z = glowPower, w = glowDispersion
vec4 u_Flags; // x = hideHand
};
float handMaskAt(vec2 uv) {
vec4 m = texture(u_Mask, uv);
return max(m.a, max(m.r, max(m.g, m.b)));
}
#define SPIN_ROTATION -2.0
#define SPIN_SPEED 7.0
#define OFFSET vec2(0.0)
#define SPIN_AMOUNT 0.25
#define PIXEL_FILTER 745.0
#define SPIN_EASE 1.0
#define PI 3.14159265359
#define IS_ROTATE false
vec4 effect(vec2 screenSize, vec2 screen_coords, float contrast, float lighting) {
float pixel_size = length(screenSize.xy) / PIXEL_FILTER;
vec2 effectUv = (floor(screen_coords.xy*(1./pixel_size))*pixel_size - 0.5*screenSize.xy)/length(screenSize.xy) - OFFSET;
float uv_len = length(effectUv);
float speed = (SPIN_ROTATION*SPIN_EASE*0.2);
if(IS_ROTATE){
speed = u_View.z * speed;
}
speed += 302.2;
float new_pixel_angle = atan(effectUv.y, effectUv.x) + speed - SPIN_EASE*20.*(1.*SPIN_AMOUNT*uv_len + (1. - 1.*SPIN_AMOUNT));
vec2 mid = (screenSize.xy/length(screenSize.xy))/2.;
effectUv = (vec2((uv_len * cos(new_pixel_angle) + mid.x), (uv_len * sin(new_pixel_angle) + mid.y)) - mid);
effectUv *= 30.;
speed = u_View.z*(SPIN_SPEED);
vec2 uv2 = vec2(effectUv.x+effectUv.y);
for(int i=0; i < 5; i++) {
uv2 += sin(max(effectUv.x, effectUv.y)) + effectUv;
effectUv += 0.5*vec2(cos(5.1123314 + 0.353*uv2.y + speed*0.131121),sin(uv2.x - 0.113*speed));
effectUv -= 1.0*cos(effectUv.x + effectUv.y) - 1.0*sin(effectUv.x*0.711 - effectUv.y);
}
float contrast_mod = (0.25*contrast + 0.5*SPIN_AMOUNT + 1.2);
float paint_res = min(2., max(0.,length(effectUv)*(0.035)*contrast_mod));
float c1p = max(0.,1. - contrast_mod*abs(1.-paint_res));
float c2p = max(0.,1. - contrast_mod*abs(paint_res));
float c3p = 1. - min(1., c1p + c2p);
float light = (lighting - 0.2)*max(c1p*5. - 4., 0.) + lighting*max(c2p*5. - 4., 0.);
vec4 colour1 = vec4(u_ColorA.rgb, 1.0);
vec4 colour2 = vec4(u_ColorB.rgb, 1.0);
vec4 colour3 = vec4(u_ColorC.rgb, 1.0);
return (0.3/contrast)*colour1 + (1. - 0.3/contrast)*(colour1*c1p + colour2*c2p + vec4(c3p*colour3.rgb, c3p*colour1.a)) + light;
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
if (mask <= 0.02) {
fragColor = base;
return;
}
float contrast = clamp(u_ColorD.r, 0.1, 1.0) * 10.0;
float lighting = clamp(u_ColorD.g, 0.0, 1.0);
vec4 effectColor = effect(u_View.xy, v_TexCoord * u_View.xy, contrast, lighting);
vec3 finalColor = mix(base.rgb, effectColor.rgb, u_Mix.x * smoothstep(0.02, 0.3, mask));
fragColor = vec4(finalColor, 1.0);
}

View file

@ -0,0 +1,68 @@
#version 330 core
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Shader1;
uniform sampler2D u_Shader2;
uniform sampler2D u_Mask;
layout (std140) uniform HandBlend {
vec4 u_Blend; // x = blendMode (0=Mix,1=Add,2=Multiply,3=Screen,4=Overlay,5=Difference), y = blendIntensity, z = shader1Strength, w = shader2Strength
};
float maskAt(vec2 uv) {
vec4 m = texture(u_Mask, uv);
return max(m.a, max(m.r, max(m.g, m.b)));
}
vec3 blendAdd(vec3 base, vec3 blend) {
return min(base + blend, vec3(1.0));
}
vec3 blendScreen(vec3 base, vec3 blend) {
return vec3(1.0) - (vec3(1.0) - base) * (vec3(1.0) - blend);
}
vec3 blendOverlay(vec3 base, vec3 blend) {
vec3 result;
result.r = base.r < 0.5 ? (2.0 * base.r * blend.r) : (1.0 - 2.0 * (1.0 - base.r) * (1.0 - blend.r));
result.g = base.g < 0.5 ? (2.0 * base.g * blend.g) : (1.0 - 2.0 * (1.0 - base.g) * (1.0 - blend.g));
result.b = base.b < 0.5 ? (2.0 * base.b * blend.b) : (1.0 - 2.0 * (1.0 - base.b) * (1.0 - blend.b));
return result;
}
void main() {
vec4 shader1Color = texture(u_Shader1, v_TexCoord);
vec4 shader2Color = texture(u_Shader2, v_TexCoord);
float mask = maskAt(v_TexCoord);
if (mask <= 0.01) {
fragColor = shader1Color;
return;
}
vec3 color1 = shader1Color.rgb * u_Blend.z;
vec3 color2 = shader2Color.rgb * u_Blend.w;
float intensity = u_Blend.y;
vec3 blendedColor;
int mode = int(u_Blend.x);
if (mode == 0) {
blendedColor = mix(color1, color2, intensity);
} else if (mode == 1) {
blendedColor = mix(color1, blendAdd(color1, color2), intensity);
} else if (mode == 2) {
blendedColor = mix(color1, color1 * color2, intensity);
} else if (mode == 3) {
blendedColor = mix(color1, blendScreen(color1, color2), intensity);
} else if (mode == 4) {
blendedColor = mix(color1, blendOverlay(color1, color2), intensity);
} else if (mode == 5) {
blendedColor = mix(color1, abs(color1 - color2), intensity);
} else {
blendedColor = color1;
}
fragColor = vec4(blendedColor, 1.0);
}

View file

@ -0,0 +1,55 @@
#version 330 core
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandChams {
vec4 u_View; // x = resX, y = resY, z = time
vec4 u_Mix; // x = effectAlpha, y = chromaSpeed, z = chromaSaturation, w = chromaBrightness
vec4 u_ColorA; // rgb = colorA
vec4 u_ColorB; // rgb = colorB
vec4 u_ColorC; // rgb = colorC
vec4 u_ColorD; // rgb = colorD
vec4 u_Common; // x = snowIntensity, y = snowSpeed, z = stripesWidth, w = stripesSpeed
vec4 u_Glow; // x = fillGlow, y = glowRadius, z = glowPower, w = glowDispersion
vec4 u_Flags; // x = hideHand
};
float handMaskAt(vec2 uv) {
vec4 m = texture(u_Mask, uv);
return max(m.a, max(m.r, max(m.g, m.b)));
}
vec3 hsv2rgb(vec3 c) {
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(c.xxx + K.xyz) * 6.0 - K.www);
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
}
vec3 createChromaEffect(vec2 coord, float t) {
float hue = fract(coord.y * 0.5 + coord.x * 0.3 + t * u_Mix.y);
float wave = sin(coord.y * 10.0 + t * 3.0) * 0.05;
hue += wave;
return hsv2rgb(vec3(hue, u_Mix.z, u_Mix.w));
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
if (mask <= 0.02) {
fragColor = base;
return;
}
float time = u_View.z;
float maskGain = smoothstep(0.02, 0.3, mask);
vec3 chromaColor = createChromaEffect(v_TexCoord, time);
float pulse = 0.9 + sin(time * 4.0) * 0.1;
chromaColor *= pulse;
vec3 finalColor = mix(base.rgb, chromaColor, u_Mix.x * maskGain);
fragColor = vec4(finalColor, 1.0);
}

View file

@ -0,0 +1,97 @@
#version 330 core
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandChams {
vec4 u_View; // x = resX, y = resY, z = time
vec4 u_Mix; // x = effectAlpha, y = chromaSpeed, z = chromaSaturation, w = chromaBrightness
vec4 u_ColorA; // rgb = colorA
vec4 u_ColorB; // rgb = colorB
vec4 u_ColorC; // rgb = colorC
vec4 u_ColorD; // rgb = colorD
vec4 u_Common; // x = snowIntensity, y = snowSpeed, z = stripesWidth, w = stripesSpeed
vec4 u_Glow; // x = fillGlow, y = glowRadius, z = glowPower, w = glowDispersion
vec4 u_Flags; // x = hideHand
};
float handMaskAt(vec2 uv) {
vec4 m = texture(u_Mask, uv);
return max(m.a, max(m.r, max(m.g, m.b)));
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
if (mask <= 0.02 && u_Glow.w <= 1.0) {
fragColor = base;
return;
}
float time = u_View.z;
float maskGain = smoothstep(0.02, 0.3, mask);
vec2 texelSize = 1.0 / max(u_View.xy, vec2(1.0));
// Маска: 0 = фон, >0 = рука. Инвертируем в depth-семантику (1 = фон).
float centerDepth = 1.0 - mask;
float edgeStrength = 0.0;
float outwardGlow = 0.0;
int disperseRadius = int(clamp(u_Glow.w, 1.0, 12.0));
for (int y = -disperseRadius; y <= disperseRadius; y++) {
for (int x = -disperseRadius; x <= disperseRadius; x++) {
if (x == 0 && y == 0) continue;
vec2 offset = vec2(x, y) * texelSize;
float neighborMask = handMaskAt(v_TexCoord + offset);
float neighborDepth = 1.0 - neighborMask;
float dist = length(vec2(x, y));
// Сосед — фон, а мы — рука: край руки
if (neighborDepth > 0.9 && centerDepth < 0.9) {
edgeStrength += (1.0 / (dist + 0.1));
}
// Мы — фон рядом с рукой: внешнее свечение
if (centerDepth > 0.9 && neighborDepth < 0.9) {
float falloff = 1.0 - (dist / float(disperseRadius));
falloff = pow(max(falloff, 0.0), 2.5);
outwardGlow += falloff * 0.2;
}
}
}
edgeStrength = clamp(edgeStrength * 0.15, 0.0, 1.0) * maskGain;
outwardGlow = clamp(outwardGlow, 0.0, 1.0);
float pulse = 0.9 + sin(time * 2.0) * 0.1;
float fill = u_Glow.x;
float glowRadius = max(u_Glow.y, 0.01);
float glowPower = max(u_Glow.z, 0.0);
// Фон рядом с рукой: внешнее свечение
if (centerDepth > 0.9 && outwardGlow > 0.01) {
vec3 dispersedGlow = u_ColorC.rgb * outwardGlow * glowPower * pulse * glowRadius * 10.0;
fragColor = vec4(dispersedGlow, outwardGlow * 0.8);
return;
}
vec3 finalColor;
if (fill > 0.5) {
vec3 handGlow = u_ColorC.rgb * (glowRadius * 10.0);
vec3 edgeGlow = u_ColorC.rgb * edgeStrength * glowPower * pulse * 2.5;
float glowMix = u_Flags.x > 0.5 ? 1.0 : 0.75;
finalColor = mix(base.rgb, handGlow + edgeGlow, glowMix);
} else {
vec3 edgeGlow = u_ColorC.rgb * edgeStrength * glowPower * pulse * glowRadius * 25.0;
finalColor = base.rgb + edgeGlow;
}
fragColor = vec4(finalColor, 1.0);
}

View file

@ -0,0 +1,38 @@
#version 330 core
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandChams {
vec4 u_View; // x = resX, y = resY, z = time
vec4 u_Mix; // x = effectAlpha
vec4 u_ColorA;
vec4 u_ColorB;
vec4 u_ColorC;
vec4 u_ColorD;
vec4 u_Common;
vec4 u_Glow;
vec4 u_Flags; // x = hideHand
};
float handMaskAt(vec2 uv) {
vec4 m = texture(u_Mask, uv);
return max(m.a, max(m.r, max(m.g, m.b)));
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
if (mask <= 0.02 || u_Flags.x > 0.5) {
fragColor = base;
return;
}
float maskGain = smoothstep(0.02, 0.3, mask);
vec3 inverted = vec3(1.0) - base.rgb;
vec3 finalColor = mix(base.rgb, inverted, u_Mix.x * maskGain);
fragColor = vec4(finalColor, 1.0);
}

View file

@ -0,0 +1,164 @@
#version 330 core
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandChams {
vec4 u_View; // x = resX, y = resY, z = time
vec4 u_Mix; // x = effectAlpha, y = chromaSpeed, z = chromaSaturation, w = chromaBrightness
vec4 u_ColorA; // rgb = colorA
vec4 u_ColorB; // rgb = colorB
vec4 u_ColorC; // rgb = colorC
vec4 u_ColorD; // rgb = colorD
vec4 u_Common; // x = snowIntensity, y = snowSpeed, z = stripesWidth, w = stripesSpeed
vec4 u_Glow; // x = fillGlow, y = glowRadius, z = glowPower, w = glowDispersion
vec4 u_Flags; // x = hideHand
};
float handMaskAt(vec2 uv) {
vec4 m = texture(u_Mask, uv);
return max(m.a, max(m.r, max(m.g, m.b)));
}
#define pi 3.14159265359
const int nbFlakes = 500;
const vec3 flakedomain = vec3(2.5, 3.0, 2.5);
const float flakeMinSpeed = 0.8;
const float flakeMaxSpeed = 2.0;
const float flakeMinSinVariation = 0.015;
const float flakeMaxSinVariation = 0.035;
const float flakeMinFreq = 3.0;
const float flakeMaxFreq = 8.0;
const vec2 flakeWindFact = vec2(0.25, 0.05);
const float starNbBranches = 6.0;
const float starPow = 1.5;
const float starStrength = 1.0;
vec2 rotateVec(vec2 vect, float angle) {
vec2 rv;
rv.x = vect.x * cos(angle) - vect.y * sin(angle);
rv.y = vect.x * sin(angle) + vect.y * cos(angle);
return rv;
}
float hash(float n) {
return fract(sin(n) * 753.5453123);
}
float rand(float minVal, float maxVal, float seed) {
return minVal + (maxVal - minVal) * hash(seed);
}
vec3 getFlakePosition(int flakeNr, float t) {
float fn = float(flakeNr);
float s = rand(flakeMinSpeed, flakeMaxSpeed, fn * 348.0 + 173.0) * u_Common.y;
float posY = mod(-(t + 15.0 * hash(fn * 1613.0 + 1354.0)) * s, flakedomain.y * 2.0) - flakedomain.y;
float posX = rand(-flakedomain.x, flakedomain.x, fn * 743.0 + 514.0) + posY * flakeWindFact.x;
float posZ = rand(-flakedomain.z, flakedomain.z, fn * 284.0 + 483.0) + posY * flakeWindFact.y;
float sinvar = rand(flakeMinSinVariation, flakeMaxSinVariation, fn * 842.0 + 951.0);
float sinfreq = rand(flakeMinFreq, flakeMaxFreq, fn * 348.0 + 173.0);
float dd = hash(fn * 235.0 + 934.0);
posX += sinvar * sin(t * sinfreq) * dd;
posZ += sinvar * sin(t * sinfreq) * sqrt(1.0 - dd * dd);
return vec3(posX, posY, posZ);
}
float nppow(float x, float p) {
return sign(x) * pow(abs(x), p);
}
float getSnowProfile(float val, float dist, vec3 fpos, vec3 ray, vec3 campos, int flakeNr) {
float val2 = -log(1.0 - val);
if (dist < 1.5) {
vec3 v3 = (fpos - campos) - dot((fpos - campos), ray) * ray;
vec3 vx = vec3(1.0, 0.0, 0.0);
vx.xy = rotateVec(vx.xy, 2.0 * float(flakeNr) * 152.5 + u_View.z * 0.4);
vx = normalize(vx - dot(vx, ray) * ray);
vec3 vy = vec3(ray.y * vx.z - ray.z * vx.y, ray.z * vx.x - ray.x * vx.z, ray.x * vx.y - ray.y * vx.x);
float a = atan(dot(v3, vx), dot(v3, vy));
float spp = 1.0 + starStrength * nppow(sin(a * starNbBranches), starPow);
val2 += 1.3 * spp * pow(smoothstep(1.6, 0.1, dist), 2.0);
}
float delta = 1.5 - 0.9 / pow(dist + 1.0, 0.3);
float midpoint = 10.0 / pow(dist + 0.1, 0.3);
float pr = smoothstep(midpoint - delta * 0.5, midpoint + delta * 0.5, val2);
float d = 1.0 - pow(abs(1.0 - 2.0 * pr), 2.0);
float f = 1.3 / pow(dist + 0.8, 2.5);
if (val2 < 8.0) {
pr += 32.0 * pow(f, 1.5) * max(0.0, dist - 2.0) * d * (0.5 + sin(val2 * 230.0 / (3.8 + dist) - midpoint * 90.0) * 0.5);
}
return pr * f;
}
vec3 getFlakes(vec3 ray, vec3 campos) {
vec3 rc1 = vec3(0.0);
vec3 rc2 = vec3(0.0);
vec3 fpos;
float lp;
for (int l = 0; l < nbFlakes; l++) {
fpos = getFlakePosition(l, u_View.z);
float val = max(0.0, dot(ray, normalize(fpos - campos)));
if (val > 0.996) {
vec3 camtarget = vec3(0.0, 0.0, 0.0);
float dist1 = distance(camtarget, fpos);
float dist2 = distance(campos, fpos);
float dist = max(5.2 * pow(dist1 / dist2, 1.7), 0.32);
lp = getSnowProfile(val, dist, fpos, ray, campos, l);
const float fogdens = 0.08;
lp *= clamp(exp(-pow(fogdens * dist2, 2.0)), 0.0, 1.0);
lp *= smoothstep(-flakedomain.y, -flakedomain.y * 0.75, fpos.y);
lp *= smoothstep(flakedomain.y, flakedomain.y * 0.75, fpos.y);
rc1 += clamp(normalize(mix(u_ColorA.rgb, vec3(1.0), 0.55 * lp)) * lp, 0.0, 1.0);
rc2 = max(rc2, clamp(normalize(mix(u_ColorA.rgb, vec3(1.0), 0.55 * lp)) * lp, 0.0, 1.0));
}
}
return mix(rc1, rc2, 0.7);
}
vec3 getCameraRayDir(vec2 vWindow) {
float fov = 3.8;
vec3 vForward = normalize(vec3(0.0, 0.0, -1.0));
vec3 vRight = normalize(cross(vec3(0.0, 1.0, 0.0), vForward));
vec3 vUp = normalize(cross(vForward, vRight));
return normalize(vWindow.x * vRight + vWindow.y * vUp + vForward * fov);
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
if (mask <= 0.02) {
fragColor = base;
return;
}
vec2 screenUv = v_TexCoord * 2.0 - 1.0;
screenUv.x *= u_View.x / max(u_View.y, 1.0);
vec3 ray = getCameraRayDir(screenUv);
vec3 campos = vec3(0.0, 0.0, 3.5);
vec3 flakes = getFlakes(ray, campos);
flakes *= u_Common.x * 1.8 * smoothstep(0.02, 0.3, mask);
vec3 finalColor = u_Flags.x > 0.5 ? flakes : base.rgb + flakes;
fragColor = vec4(finalColor, 1.0);
}

View file

@ -0,0 +1,48 @@
#version 330 core
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandChams {
vec4 u_View; // x = resX, y = resY, z = time
vec4 u_Mix; // x = effectAlpha, y = chromaSpeed, z = chromaSaturation, w = chromaBrightness
vec4 u_ColorA; // rgb = colorA
vec4 u_ColorB; // rgb = colorB
vec4 u_ColorC; // rgb = colorC
vec4 u_ColorD; // rgb = colorD
vec4 u_Common; // x = snowIntensity, y = snowSpeed, z = stripesWidth, w = stripesSpeed
vec4 u_Glow; // x = fillGlow, y = glowRadius, z = glowPower, w = glowDispersion
vec4 u_Flags; // x = hideHand
};
float handMaskAt(vec2 uv) {
vec4 m = texture(u_Mask, uv);
return max(m.a, max(m.r, max(m.g, m.b)));
}
vec3 createVerticalGradient(vec2 coord, vec3 color1, vec3 color2, float t) {
float factor = coord.y + t;
factor = sin(factor * 3.14159 * 2.0) * 0.5 + 0.5;
return mix(color1, color2, factor);
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
if (mask <= 0.02) {
fragColor = base;
return;
}
float time = u_View.z;
float maskGain = smoothstep(0.02, 0.3, mask);
vec3 gradientColor = createVerticalGradient(v_TexCoord, u_ColorA.rgb, u_ColorB.rgb, time);
float brightness = 0.85 + sin(time * 6.28318) * 0.15;
gradientColor *= brightness;
vec3 finalColor = mix(base.rgb, gradientColor, u_Mix.x * maskGain);
fragColor = vec4(finalColor, 1.0);
}

View file

@ -0,0 +1,49 @@
#version 330 core
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandChams {
vec4 u_View; // x = resX, y = resY, z = time
vec4 u_Mix; // x = effectAlpha, y = chromaSpeed, z = chromaSaturation, w = chromaBrightness
vec4 u_ColorA; // rgb = colorA
vec4 u_ColorB; // rgb = colorB
vec4 u_ColorC; // rgb = colorC
vec4 u_ColorD; // rgb = colorD
vec4 u_Common; // x = snowIntensity, y = snowSpeed, z = stripesWidth, w = stripesSpeed
vec4 u_Glow; // x = fillGlow, y = glowRadius, z = glowPower, w = glowDispersion
vec4 u_Flags; // x = hideHand
};
float handMaskAt(vec2 uv) {
vec4 m = texture(u_Mask, uv);
return max(m.a, max(m.r, max(m.g, m.b)));
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
if (mask <= 0.02) {
fragColor = base;
return;
}
vec2 effectUv = v_TexCoord;
effectUv.x *= u_View.x / max(u_View.y, 1.0);
// Плавные анимированные диагональные полосы с мягкими краями
float angle = 0.65;
float d = (effectUv.x * cos(angle) + effectUv.y * sin(angle)) + u_View.z * u_Common.w;
float stripe = abs(sin(d * 3.14159265 / max(u_Common.z, 0.001)));
stripe = pow(stripe, 1.5);
vec3 col = mix(u_ColorB.rgb, u_ColorA.rgb, stripe);
col += u_ColorA.rgb * (0.12 + 0.10 * sin(d * 6.0 + u_View.z * 2.0));
float strength = u_Mix.x * (0.35 + 0.65 * stripe) * smoothstep(0.02, 0.3, mask);
vec3 finalColor = mix(base.rgb, col, strength);
fragColor = vec4(finalColor, 1.0);
}

View file

@ -0,0 +1,298 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
in vec2 v_TexCoord;
out vec4 fragColor;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandGlass {
vec4 uScreen; // xy = framebuffer size, z = time, w = inner edge width in pixels
vec4 uTint; // rgb = glass tint, a = overlay alpha
vec4 uMaterial; // x = strength, y = refraction pixels, z = edge haze strength, w = frost blur radius pixels
vec4 uReserved; // x = body frost strength, y = chromatic pixels, z = edge refraction multiplier, w = clarity
};
const vec3 LUMA = vec3(0.2126, 0.7152, 0.0722);
float saturate(float v) {
return clamp(v, 0.0, 1.0);
}
vec3 saturate(vec3 v) {
return clamp(v, 0.0, 1.0);
}
float luminance(vec3 c) {
return dot(c, LUMA);
}
vec2 safeNormalize(vec2 v, vec2 fallback) {
float len2 = dot(v, v);
if (len2 <= 1e-6) return fallback;
return v * inversesqrt(len2);
}
ivec2 clampPixel(ivec2 p) {
ivec2 size = textureSize(u_Mask, 0);
return clamp(p, ivec2(0), max(size - ivec2(1), ivec2(0)));
}
ivec2 pixelFromUv(vec2 uv) {
ivec2 size = textureSize(u_Mask, 0);
vec2 p = floor(clamp(uv, vec2(0.0), vec2(0.999999)) * vec2(size));
return clampPixel(ivec2(p));
}
float rawMaskPixel(ivec2 p) {
vec4 mask = texelFetch(u_Mask, clampPixel(p), 0);
return max(mask.a, max(mask.r, max(mask.g, mask.b)));
}
float solidMaskPixel(ivec2 p) {
return step(0.16, rawMaskPixel(p));
}
float maskSupport1(ivec2 p) {
float s = solidMaskPixel(p);
s += solidMaskPixel(p + ivec2( 1, 0));
s += solidMaskPixel(p + ivec2(-1, 0));
s += solidMaskPixel(p + ivec2( 0, 1));
s += solidMaskPixel(p + ivec2( 0, -1));
s += solidMaskPixel(p + ivec2( 1, 1));
s += solidMaskPixel(p + ivec2(-1, 1));
s += solidMaskPixel(p + ivec2( 1, -1));
s += solidMaskPixel(p + ivec2(-1, -1));
return s;
}
float maskSupport2(ivec2 p) {
float s = 0.0;
s += solidMaskPixel(p + ivec2( 2, 0));
s += solidMaskPixel(p + ivec2(-2, 0));
s += solidMaskPixel(p + ivec2( 0, 2));
s += solidMaskPixel(p + ivec2( 0, -2));
s += solidMaskPixel(p + ivec2( 2, 2));
s += solidMaskPixel(p + ivec2(-2, 2));
s += solidMaskPixel(p + ivec2( 2, -2));
s += solidMaskPixel(p + ivec2(-2, -2));
return s;
}
float filteredMaskPixel(ivec2 p) {
float raw = rawMaskPixel(p);
if (raw < 0.16) return 0.0;
// Mask is captured from vanilla hand render, so glint/texture sparkle can leave
// isolated alpha dots. Kill unsupported pixels before the glass material runs.
float s1 = maskSupport1(p);
float s2 = maskSupport2(p);
float keep = step(2.5, s1) * step(0.5, s1 + s2);
return raw * keep;
}
float maskAt(vec2 uv) {
return filteredMaskPixel(pixelFromUv(uv));
}
float maskAtOffset(vec2 uv, ivec2 offset) {
return filteredMaskPixel(pixelFromUv(uv) + offset);
}
vec3 sceneAt(vec2 uv) {
return texture(u_Src, clamp(uv, vec2(0.001), vec2(0.999))).rgb;
}
float erodeMin8(vec2 uv, float radiusPx) {
int r = int(clamp(floor(radiusPx + 0.5), 1.0, 32.0));
ivec2 p = pixelFromUv(uv);
float m = filteredMaskPixel(p);
m = min(m, filteredMaskPixel(p + ivec2( r, 0)));
m = min(m, filteredMaskPixel(p + ivec2(-r, 0)));
m = min(m, filteredMaskPixel(p + ivec2(0, r)));
m = min(m, filteredMaskPixel(p + ivec2(0, -r)));
m = min(m, filteredMaskPixel(p + ivec2( r, r)));
m = min(m, filteredMaskPixel(p + ivec2(-r, r)));
m = min(m, filteredMaskPixel(p + ivec2( r, -r)));
m = min(m, filteredMaskPixel(p + ivec2(-r, -r)));
return m;
}
vec2 maskNormal(vec2 uv, float radiusPx) {
int r = int(clamp(floor(radiusPx + 0.5), 1.0, 8.0));
ivec2 p = pixelFromUv(uv);
float l = filteredMaskPixel(p + ivec2(-r, 0));
float rgt = filteredMaskPixel(p + ivec2( r, 0));
float d = filteredMaskPixel(p + ivec2(0, -r));
float u = filteredMaskPixel(p + ivec2(0, r));
return safeNormalize(vec2(l - rgt, d - u), vec2(0.0, -1.0));
}
vec2 liquidFlow(vec2 uv, float time) {
vec2 p = uv * vec2(5.2, 3.7);
float a = sin(p.y * 1.62 + time * 0.42 + sin(p.x * 0.84 + time * 0.18));
float b = cos(p.x * 1.48 - time * 0.36 + cos(p.y * 0.92 - time * 0.14));
float c = sin((p.x - p.y) * 0.98 + time * 0.25);
float d = cos((p.x + p.y) * 0.72 - time * 0.20);
return vec2(a + c * 0.34 + d * 0.12, b - c * 0.30 + d * 0.10) * 0.5;
}
vec3 frostedScene(vec2 uv, vec2 normal, vec2 texel, float radiusPx) {
vec2 n = safeNormalize(normal, vec2(0.0, -1.0));
vec2 t = vec2(-n.y, n.x);
float r = max(radiusPx, 0.15);
vec2 n1 = n * texel * r;
vec2 t1 = t * texel * r;
vec2 n2 = n * texel * (r * 1.85);
vec2 t2 = t * texel * (r * 1.55);
vec2 d1 = (n + t) * texel * (r * 1.15);
vec2 d2 = (n - t) * texel * (r * 1.15);
vec2 d3 = (-n + t) * texel * (r * 1.15);
vec2 d4 = (-n - t) * texel * (r * 1.15);
vec3 c = sceneAt(uv) * 0.185;
c += sceneAt(uv + n1) * 0.095;
c += sceneAt(uv - n1) * 0.095;
c += sceneAt(uv + t1) * 0.095;
c += sceneAt(uv - t1) * 0.095;
c += sceneAt(uv + d1) * 0.070;
c += sceneAt(uv + d2) * 0.070;
c += sceneAt(uv + d3) * 0.070;
c += sceneAt(uv + d4) * 0.070;
c += sceneAt(uv + n2) * 0.0425;
c += sceneAt(uv - n2) * 0.0425;
c += sceneAt(uv + t2) * 0.0425;
c += sceneAt(uv - t2) * 0.0425;
c += sceneAt(uv + n2 + t1 * 0.75) * 0.025;
c += sceneAt(uv + n2 - t1 * 0.75) * 0.025;
c += sceneAt(uv - n2 + t1 * 0.75) * 0.025;
c += sceneAt(uv - n2 - t1 * 0.75) * 0.025;
return c;
}
vec3 glassTone(vec3 scene, vec3 tint, float strength, float haze) {
float l = max(luminance(scene), 1e-4);
float peak = max(scene.r, max(scene.g, scene.b));
float bright = smoothstep(0.42, 0.88, l);
float glare = smoothstep(0.72, 1.00, peak);
float targetLuma = mix(l, 0.56 + 0.26 * sqrt(l), saturate(0.42 + haze * 0.48 + strength * 0.025));
targetLuma *= 1.0 - glare * 0.055;
vec3 mapped = scene * (targetLuma / l);
float ml = luminance(mapped);
float sat = mix(0.82, 1.05, saturate(1.0 - haze * 0.55));
mapped = vec3(ml) + (mapped - vec3(ml)) * sat;
float tl = luminance(tint);
mapped += (tint - vec3(tl)) * (0.055 + strength * 0.018 + haze * 0.050);
mapped += mix(vec3(1.0), tint, 0.18) * (0.020 + bright * 0.020) * haze;
return saturate(mapped);
}
void main() {
vec2 fbSize = max(uScreen.xy, vec2(1.0));
vec2 texel = 1.0 / fbSize;
vec2 uv = v_TexCoord;
vec3 base = sceneAt(uv);
float mask = saturate(maskAt(uv));
if (mask <= 0.001) {
fragColor = vec4(base, 1.0);
return;
}
float time = uScreen.z;
float edgeWidthPx = clamp(uScreen.w, 3.0, 28.0);
float strength = max(uMaterial.x, 0.0);
float refractionPx = max(uMaterial.y, 0.0);
float hazeStrength = saturate(uMaterial.z);
float frostBlurPx = max(uMaterial.w, 0.0);
float bodyFrost = saturate(uReserved.x);
float chromaPxBase = max(uReserved.y, 0.0);
float edgeRefractionMul = max(uReserved.z, 0.0);
float clarity = saturate(uReserved.w);
vec3 tint = saturate(uTint.rgb);
float alpha = saturate(uTint.a);
// Inner silhouette zones only. This is a fog/refraction band, not legacy outline.
float erodedTight = erodeMin8(uv, max(1.5, edgeWidthPx * 0.28));
float erodedMid = erodeMin8(uv, max(2.5, edgeWidthPx * 0.62));
float erodedWide = erodeMin8(uv, edgeWidthPx);
float tightEdge = saturate((mask - erodedTight) * 3.10);
float midEdge = saturate((mask - erodedMid) * 2.15);
float broadEdge = saturate((mask - erodedWide) * 1.55);
float edge = saturate(max(tightEdge, max(midEdge * 0.86, broadEdge * 0.72)));
float body = smoothstep(0.03, 0.98, mask);
vec2 maskN = maskNormal(uv, mix(1.4, 6.6, edge));
vec2 flowN = safeNormalize(liquidFlow(uv, time), maskN);
vec2 normal = safeNormalize(mix(flowN, maskN, saturate(0.48 + edge * 0.48)), maskN);
float pulse = 0.84 + 0.16 * sin(time * 0.52 + uv.y * 9.0 + uv.x * 5.0);
float bodyRefraction = refractionPx * (0.14 + bodyFrost * 0.18) * body;
float edgeRefraction = refractionPx * edgeRefractionMul * (0.34 + edge * 1.18) * pulse;
vec2 refractUv = clamp(uv + normal * texel * (bodyRefraction + edgeRefraction), vec2(0.001), vec2(0.999));
float blurPx = frostBlurPx * (0.78 + bodyFrost * 0.34 + edge * 0.58);
vec3 blurred = frostedScene(refractUv, normal, texel, blurPx);
vec3 widerBlur = frostedScene(refractUv + liquidFlow(uv * 0.56 + 0.17, time) * texel * blurPx * 0.42,
normal, texel, blurPx * (1.48 + edge * 0.34));
vec3 clean = sceneAt(refractUv);
float edgeHaze = saturate(edge * hazeStrength);
float fogAmount = saturate(bodyFrost * body * (0.64 + 0.11 * strength) + edgeHaze * 0.74);
vec3 glassScene = mix(clean, blurred, fogAmount);
glassScene = mix(glassScene, widerBlur, saturate((edgeHaze * 0.56 + bodyFrost * 0.30) * (1.0 - clarity * 0.50)));
vec3 glass = glassTone(glassScene, tint, strength, saturate(fogAmount + edgeHaze * 0.45));
float chromaPx = chromaPxBase * (0.28 + edge * 1.32 + bodyFrost * 0.18);
vec2 chroma = normal * texel * chromaPx;
vec3 prism = vec3(
sceneAt(refractUv + chroma).r,
frostedScene(refractUv, normal, texel, blurPx * 0.82).g,
sceneAt(refractUv - chroma).b
);
prism = glassTone(prism, tint, strength + 0.28, saturate(edgeHaze + 0.22));
glass = mix(glass, prism, saturate(edge * 0.26 + tightEdge * 0.14));
float topLight = saturate(dot(normal, normalize(vec2(-0.30, 0.96))) * 0.5 + 0.5);
float sceneLuma = luminance(glassScene);
float brightScene = smoothstep(0.50, 0.90, sceneLuma);
// Smooth liquid movement only. No thresholded caustic/sparkle pattern: it was
// visible as isolated white pixels on enchanted/high-contrast item textures.
float waveA = 0.5 + 0.5 * sin((uv.x + normal.x * 0.05) * 7.5 + time * 0.52);
float waveB = 0.5 + 0.5 * cos((uv.y - normal.y * 0.04) * 5.2 - time * 0.38);
float liquidSheen = waveA * waveB;
glass += mix(tint, vec3(1.0), 0.58) * liquidSheen * body * (1.0 - edge * 0.45) * (0.010 + 0.014 * saturate(strength));
vec3 fogTint = mix(vec3(luminance(glass)), mix(vec3(1.0), tint, 0.16), 0.64);
float milkyFog = saturate(edgeHaze * (0.38 + 0.28 * topLight) + bodyFrost * body * 0.17);
milkyFog *= 1.0 - brightScene * 0.28;
glass = mix(glass, fogTint, milkyFog);
vec3 edgeHighlight = mix(vec3(1.0), tint, 0.10 + brightScene * 0.06);
float highlight = saturate((tightEdge * 0.10 + midEdge * 0.075) * (0.74 + 0.30 * topLight) * (1.0 - brightScene * 0.45));
glass = mix(glass, edgeHighlight, highlight);
glass = saturate(glass);
float bodyMix = body * alpha * (0.30 + 0.12 * saturate(strength) + bodyFrost * 0.18);
float edgeMix = edge * alpha * (0.56 + 0.18 * saturate(strength)) * (0.82 + 0.18 * topLight);
float finalMix = saturate(bodyMix + edgeMix);
finalMix *= mix(1.0, 0.82, clarity);
vec3 outColor = mix(base, glass, finalMix);
fragColor = vec4(saturate(outColor), 1.0);
}

View file

@ -0,0 +1,167 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
out vec4 color;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandMetallic {
vec4 u_Base; // rgb, fill alpha
vec4 u_Highlight; // rgb, alpha
vec4 u_Glow; // rgb, alpha
vec4 u_Shadow; // rgb, alpha
vec4 u_Params0; // intensity, sharpness, edgeStrength, time
vec4 u_Params1; // sweepSpeed, sweepScale, brushedLines, flakes
vec4 u_Params2; // glowStrength, shadowStrength, edgeWidth, prism
};
in vec2 v_TexCoord;
float handMetalHash21(vec2 p) {
p = fract(p * vec2(234.34, 435.45));
p += dot(p, p + 31.31);
return fract(p.x * p.y);
}
float handMetalNoise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
float a = handMetalHash21(i);
float b = handMetalHash21(i + vec2(1.0, 0.0));
float c = handMetalHash21(i + vec2(0.0, 1.0));
float d = handMetalHash21(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
float handMetalFbm(vec2 p) {
float v = 0.0;
float a = 0.55;
mat2 r = mat2(0.74, 0.67, -0.67, 0.74);
for (int i = 0; i < 3; ++i) {
v += a * handMetalNoise(p);
p = r * p * 2.11 + vec2(19.7, 43.2);
a *= 0.50;
}
return v;
}
float maskAt(vec2 uv) {
vec4 mask = texture(u_Mask, uv);
return max(mask.a, max(mask.r, max(mask.g, mask.b)));
}
float handMetalEdgeDistance(vec2 oneTexel, float edgeWidth, out float hitAmount) {
float best = 1.0e5;
float hit = 0.0;
float radiusPx = max(edgeWidth, 1.0);
const int rings = 4;
const int dirs = 12;
for (int r = 1; r <= rings; ++r) {
float rr = float(r) / float(rings);
float distPx = radiusPx * rr;
for (int i = 0; i < dirs; ++i) {
float angle = (float(i) + float(r) * 0.37) * 6.28318530718 / float(dirs);
vec2 dir = vec2(cos(angle), sin(angle));
float a = maskAt(v_TexCoord + dir * oneTexel * distPx);
if (a > 0.02) {
best = min(best, rr);
hit = max(hit, a);
}
}
}
hitAmount = hit;
return best;
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = maskAt(v_TexCoord);
ivec2 sz = textureSize(u_Mask, 0);
vec2 resolution = max(vec2(sz), vec2(1.0));
vec2 oneTexel = 1.0 / resolution;
float intensity = max(u_Params0.x, 0.0);
float sharpness = max(u_Params0.y, 0.15);
float edgeStrength = max(u_Params0.z, 0.0);
float time = u_Params0.w;
float sweepSpeed = u_Params1.x;
float sweepScale = max(u_Params1.y, 0.1);
float brushedLines = max(u_Params1.z, 0.0);
float flakes = max(u_Params1.w, 0.0);
float glowStrength = max(u_Params2.x, 0.0);
float shadowStrength = max(u_Params2.y, 0.0);
float edgeWidth = max(u_Params2.z, 0.0);
float prism = max(u_Params2.w, 0.0);
if (mask > 0.01) {
float mL = maskAt(v_TexCoord + vec2(-oneTexel.x, 0.0));
float mR = maskAt(v_TexCoord + vec2(oneTexel.x, 0.0));
float mU = maskAt(v_TexCoord + vec2(0.0, -oneTexel.y));
float mD = maskAt(v_TexCoord + vec2(0.0, oneTexel.y));
float edge = clamp(1.0 - min(min(mL, mR), min(mU, mD)), 0.0, 1.0);
edge = pow(edge, 0.68);
vec2 aspect = vec2(resolution.x / max(resolution.y, 1.0), 1.0);
vec2 p = v_TexCoord * aspect;
float diagonal = dot(p, normalize(vec2(0.82, -0.57)));
float sweep = sin(diagonal * sweepScale + time * sweepSpeed);
sweep = pow(clamp(sweep * 0.5 + 0.5, 0.0, 1.0), sharpness);
float fine = handMetalFbm(p * resolution.y * 0.030 + vec2(time * 0.04, -time * 0.025));
float brushed = 0.5 + 0.5 * sin((p.y * resolution.y * 0.20 + p.x * 18.0 + fine * 7.0) * (0.34 + brushedLines * 0.32));
brushed = mix(1.0, mix(0.78, 1.14, brushed), clamp(brushedLines, 0.0, 1.0));
// Smooth procedural sparkle. No floor(cell) blocks: the old variant made visible square garbage on edges.
float sparkleNoise = handMetalFbm(p * resolution.y * 0.11 + vec2(time * 0.06, time * 0.035));
float sparkle = smoothstep(0.76, 0.98, sparkleNoise) * flakes;
sparkle *= 0.55 + 0.45 * sin(time * 2.2 + sparkleNoise * 17.0);
float rim = pow(edge, sharpness * 0.55) * edgeStrength;
float highlight = clamp(sweep * 0.70 + rim + sparkle * 0.85, 0.0, 1.0);
vec3 metal = u_Base.rgb * brushed;
metal += u_Highlight.rgb * intensity * highlight * u_Highlight.a;
metal += u_Highlight.rgb * sparkle * 0.26 * intensity;
if (prism > 0.001) {
vec3 prismTint = vec3(
sin(diagonal * 11.0 + time * 0.7) * 0.5 + 0.5,
sin(diagonal * 11.0 + 2.1 + time * 0.62) * 0.5 + 0.5,
sin(diagonal * 11.0 + 4.2 + time * 0.58) * 0.5 + 0.5
);
metal = mix(metal, metal * (0.68 + prismTint * 0.62), clamp(prism * highlight, 0.0, 0.65));
}
vec3 outCol = mix(base.rgb, metal, clamp(u_Base.a * mask, 0.0, 1.0));
outCol = mix(outCol, u_Shadow.rgb, edge * u_Shadow.a * shadowStrength * 0.34);
outCol += u_Glow.rgb * edge * u_Glow.a * glowStrength * 0.25;
color = vec4(clamp(outCol, 0.0, 1.0), 1.0);
return;
}
float hitAmount = 0.0;
float d = handMetalEdgeDistance(oneTexel, edgeWidth, hitAmount);
if (hitAmount > 0.01) {
float falloff = clamp(1.0 - d, 0.0, 1.0);
falloff = falloff * falloff * (3.0 - 2.0 * falloff);
float shadowA = falloff * u_Shadow.a * shadowStrength * 0.48;
float glowA = pow(falloff, 1.28) * u_Glow.a * glowStrength * 0.40;
vec3 outCol = mix(base.rgb, u_Shadow.rgb, shadowA);
outCol += u_Glow.rgb * glowA;
color = vec4(clamp(outCol, 0.0, 1.0), 1.0);
return;
}
color = vec4(base.rgb, 1.0);
}

View file

@ -0,0 +1,156 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
out vec4 color;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandNoise {
vec4 u_Color; // rgb, alpha
vec4 u_Glow; // rgb, alpha
vec4 u_Params0; // edgeWidth, quality, octaves, time
vec4 u_Params1; // resX, resY, scale, speed
vec4 u_Params2; // contrast, breathe, glowStrength, density
};
in vec2 v_TexCoord;
float handNoiseHash21(vec2 p) {
p = fract(p * vec2(127.31, 311.7));
p += dot(p, p + 41.31);
return fract(p.x * p.y);
}
float handNoiseValue(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
float a = handNoiseHash21(i);
float b = handNoiseHash21(i + vec2(1.0, 0.0));
float c = handNoiseHash21(i + vec2(0.0, 1.0));
float d = handNoiseHash21(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
float handNoiseFbm(vec2 p, int octaves) {
float v = 0.0;
float a = 0.55;
mat2 r = mat2(0.80, 0.60, -0.60, 0.80);
int o = clamp(octaves, 1, 3);
for (int i = 0; i < 3; ++i) {
if (i >= o) break;
v += a * handNoiseValue(p);
p = r * p * 2.07 + vec2(23.3, 41.7);
a *= 0.5;
}
return v;
}
float handMaskAt(vec2 uv) {
vec4 mask = texture(u_Mask, uv);
return max(mask.a, max(mask.r, max(mask.g, mask.b)));
}
float handNoiseEdgeDistance(vec2 oneTexel, int quality, float edgeWidth, out float hitAmount) {
float best = 1.0e5;
float hit = 0.0;
int rings = clamp(quality, 1, 4);
int dirs = quality <= 1 ? 8 : 12;
float radiusPx = max(edgeWidth, 1.0);
for (int r = 1; r <= 4; ++r) {
if (r > rings) continue;
float rr = float(r) / float(rings);
float distPx = radiusPx * rr;
for (int i = 0; i < 12; ++i) {
if (i >= dirs) continue;
float angle = (float(i) + float(r) * 0.37) * 6.28318530718 / float(dirs);
vec2 dir = vec2(cos(angle), sin(angle));
float a = handMaskAt(v_TexCoord + dir * oneTexel * distPx);
if (a > 0.02) {
best = min(best, rr);
hit = max(hit, a);
}
}
}
hitAmount = hit;
return best;
}
float handNoiseField(vec2 fragCoord, vec2 resolution, float time, int octaves) {
float scale = max(u_Params1.z, 0.05);
float speed = max(u_Params1.w, 0.0);
float contrast = max(u_Params2.x, 0.05);
float breathe = clamp(u_Params2.y, 0.0, 1.0);
float density = max(u_Params2.w, 0.0);
vec2 uv = fragCoord / max(resolution, vec2(1.0));
vec2 aspect = vec2(resolution.x / max(resolution.y, 1.0), 1.0);
vec2 p = (uv - 0.5) * aspect * scale;
float t = time * speed;
vec2 warp = vec2(
handNoiseFbm(p * 1.3 + vec2(0.0, t * 0.32), octaves),
handNoiseFbm(p * 1.3 + vec2(5.2, -t * 0.26), octaves)
) - 0.5;
float n = handNoiseFbm(p * 1.9 + warp * 1.35 + vec2(t * 0.21, -t * 0.14), octaves);
float pulse = 0.5 + 0.5 * sin(t * 1.6 + warp.x * 2.4);
n = clamp(n * (1.0 + breathe * (pulse - 0.5) * 0.9), 0.0, 1.0);
return pow(clamp(n * (0.85 + density * 0.3), 0.0, 1.0), 1.0 / contrast);
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
vec2 resolution = max(u_Params1.xy, vec2(1.0));
vec2 oneTexel = 1.0 / resolution;
float edgeWidth = max(u_Params0.x, 0.0);
int quality = int(u_Params0.y + 0.5);
int octaves = clamp(int(u_Params0.z + 0.5), 1, 3);
float time = u_Params0.w;
float glowStrength = max(u_Params2.z, 0.0);
if (mask > 0.01) {
float n = handNoiseField(gl_FragCoord.xy, resolution, time, octaves);
float nL = handMaskAt(v_TexCoord + vec2(-oneTexel.x, 0.0));
float nR = handMaskAt(v_TexCoord + vec2(oneTexel.x, 0.0));
float nU = handMaskAt(v_TexCoord + vec2(0.0, -oneTexel.y));
float nD = handMaskAt(v_TexCoord + vec2(0.0, oneTexel.y));
float innerEdge = clamp(1.0 - min(min(nL, nR), min(nU, nD)), 0.0, 1.0);
innerEdge = pow(innerEdge, 0.72);
float alpha = clamp(u_Color.a * mask, 0.0, 1.0);
vec3 shade = u_Color.rgb * (0.55 + 0.75 * n);
shade = mix(shade, u_Glow.rgb, clamp((n - 0.68) * 1.4, 0.0, 0.35));
vec3 outCol = mix(base.rgb, shade, alpha);
outCol += u_Glow.rgb * innerEdge * u_Glow.a * glowStrength * (0.18 + 0.30 * n);
color = vec4(clamp(outCol, 0.0, 1.0), 1.0);
return;
}
float hitAmount = 0.0;
float d = handNoiseEdgeDistance(oneTexel, quality, edgeWidth, hitAmount);
if (hitAmount > 0.01) {
float n = handNoiseField(gl_FragCoord.xy, resolution, time, octaves);
float falloff = clamp(1.0 - d, 0.0, 1.0);
falloff = falloff * falloff * (3.0 - 2.0 * falloff);
float glowA = pow(falloff, 1.3) * u_Glow.a * glowStrength * (0.30 + 0.40 * n);
vec3 outCol = mix(base.rgb, u_Glow.rgb, glowA * 0.5);
outCol += u_Glow.rgb * glowA;
color = vec4(clamp(outCol, 0.0, 1.0), 1.0);
return;
}
color = vec4(base.rgb, 1.0);
}

View file

@ -0,0 +1,168 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
out vec4 color;
uniform sampler2D u_Src;
uniform sampler2D u_Mask;
layout (std140) uniform HandSmoke {
vec4 u_Fill; // rgb, fill alpha
vec4 u_Glow; // rgb, alpha
vec4 u_Shadow; // rgb, alpha
vec4 u_Params0; // edgeWidth, quality, octaves, time
vec4 u_Params1; // resX, resY, scale, contrast
vec4 u_Params2; // swirl, glowStrength, shadowStrength, density
};
in vec2 v_TexCoord;
float handSmokeHash21(vec2 p) {
p = fract(p * vec2(123.34, 345.45));
p += dot(p, p + 34.345);
return fract(p.x * p.y);
}
float handSmokeValueNoise(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
float a = handSmokeHash21(i);
float b = handSmokeHash21(i + vec2(1.0, 0.0));
float c = handSmokeHash21(i + vec2(0.0, 1.0));
float d = handSmokeHash21(i + vec2(1.0, 1.0));
vec2 u = f * f * (3.0 - 2.0 * f);
return mix(mix(a, b, u.x), mix(c, d, u.x), u.y);
}
float handSmokeFbm(vec2 p, int octaves) {
float v = 0.0;
float a = 0.55;
mat2 r = mat2(0.80, 0.60, -0.60, 0.80);
int o = clamp(octaves, 1, 4);
for (int i = 0; i < 4; ++i) {
if (i >= o) break;
v += a * handSmokeValueNoise(p);
p = r * p * 2.03 + vec2(37.1, 17.7);
a *= 0.52;
}
return v;
}
float handMaskAt(vec2 uv) {
vec4 mask = texture(u_Mask, uv);
return max(mask.a, max(mask.r, max(mask.g, mask.b)));
}
float handEdgeDistance(vec2 oneTexel, int quality, float edgeWidth, out float hitAmount) {
float best = 1.0e5;
float hit = 0.0;
int rings = clamp(quality, 1, 4);
int dirs = quality <= 1 ? 8 : 12;
float radiusPx = max(edgeWidth, 1.0);
for (int r = 1; r <= 4; ++r) {
if (r > rings) continue;
float rr = float(r) / float(rings);
float distPx = radiusPx * rr;
for (int i = 0; i < 12; ++i) {
if (i >= dirs) continue;
float angle = (float(i) + float(r) * 0.37) * 6.28318530718 / float(dirs);
vec2 dir = vec2(cos(angle), sin(angle));
float a = handMaskAt(v_TexCoord + dir * oneTexel * distPx);
if (a > 0.02) {
best = min(best, rr);
hit = max(hit, a);
}
}
}
hitAmount = hit;
return best;
}
vec3 handSmokeField(vec2 fragCoord, vec2 resolution, float time, int octaves) {
float scale = max(u_Params1.z, 0.05);
float contrast = max(u_Params1.w, 0.05);
float swirl = u_Params2.x;
float density = max(u_Params2.w, 0.0);
vec2 uv = fragCoord / max(resolution, vec2(1.0));
vec2 aspect = vec2(resolution.x / max(resolution.y, 1.0), 1.0);
vec2 p = (uv - 0.5) * aspect * scale;
float slow = time * 0.13;
vec2 curl = vec2(
handSmokeFbm(p * 1.35 + vec2(0.0, slow), octaves),
handSmokeFbm(p * 1.35 + vec2(5.2, -slow * 0.85), octaves)
) - 0.5;
p += curl * (0.45 + swirl * 0.35);
p.y -= time * 0.035;
float body = handSmokeFbm(p * 2.0 + vec2(time * 0.025, -time * 0.055), octaves);
float wisps = handSmokeFbm(p * 5.2 + vec2(-time * 0.06, time * 0.025), max(octaves - 1, 1));
float veins = 0.5 + 0.5 * sin((p.x + curl.y * 0.8) * 7.5 + body * 3.2);
veins = smoothstep(0.28, 0.88, veins);
float m = mix(body, body * wisps, 0.34);
m = mix(m, m * (0.74 + veins * 0.38), 0.42);
m = pow(clamp(m * (0.9 + density * 0.35), 0.0, 1.0), 1.0 / contrast);
vec3 smoke = mix(u_Fill.rgb * 0.48, u_Fill.rgb, m);
smoke = mix(smoke, u_Glow.rgb, clamp((m - 0.62) * 1.55, 0.0, 0.38));
return smoke * (0.50 + m * 0.72);
}
void main() {
vec4 base = texture(u_Src, v_TexCoord);
float mask = handMaskAt(v_TexCoord);
vec2 resolution = max(u_Params1.xy, vec2(1.0));
vec2 oneTexel = 1.0 / resolution;
float edgeWidth = max(u_Params0.x, 0.0);
int quality = int(u_Params0.y + 0.5);
int octaves = clamp(int(u_Params0.z + 0.5), 1, 4);
float time = u_Params0.w;
float glowStrength = max(u_Params2.y, 0.0);
float shadowStrength = max(u_Params2.z, 0.0);
if (mask > 0.01) {
vec3 smoke = handSmokeField(gl_FragCoord.xy, resolution, time, octaves);
float nL = handMaskAt(v_TexCoord + vec2(-oneTexel.x, 0.0));
float nR = handMaskAt(v_TexCoord + vec2(oneTexel.x, 0.0));
float nU = handMaskAt(v_TexCoord + vec2(0.0, -oneTexel.y));
float nD = handMaskAt(v_TexCoord + vec2(0.0, oneTexel.y));
float innerEdge = clamp(1.0 - min(min(nL, nR), min(nU, nD)), 0.0, 1.0);
innerEdge = pow(innerEdge, 0.72);
float alpha = clamp(u_Fill.a * mask, 0.0, 1.0);
vec3 outCol = mix(base.rgb, smoke, alpha);
outCol = mix(outCol, u_Shadow.rgb, innerEdge * u_Shadow.a * shadowStrength * 0.34);
outCol += u_Glow.rgb * innerEdge * u_Glow.a * glowStrength * 0.24;
color = vec4(clamp(outCol, 0.0, 1.0), 1.0);
return;
}
float hitAmount = 0.0;
float d = handEdgeDistance(oneTexel, quality, edgeWidth, hitAmount);
if (hitAmount > 0.01) {
float falloff = clamp(1.0 - d, 0.0, 1.0);
falloff = falloff * falloff * (3.0 - 2.0 * falloff);
vec3 smoke = handSmokeField(gl_FragCoord.xy, resolution, time, octaves);
float shadowA = falloff * u_Shadow.a * shadowStrength * 0.54;
float glowA = pow(falloff, 1.32) * u_Glow.a * glowStrength * 0.40;
vec3 outCol = mix(base.rgb, u_Shadow.rgb, shadowA);
outCol = mix(outCol, smoke, glowA * 0.28);
outCol += u_Glow.rgb * glowA;
color = vec4(clamp(outCol, 0.0, 1.0), 1.0);
return;
}
color = vec4(base.rgb, 1.0);
}

View file

@ -0,0 +1,57 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*
* Licensed under the GNU General Public License v3.0.
*/
out vec4 color;
uniform sampler2D u_Texture;
layout (std140) uniform Heat {
vec4 u_Params1;
vec4 u_Params2;
};
in vec2 v_TexCoord;
void main() {
float intensity = clamp(u_Params1.x, 0.0, 2.0);
float distortion = u_Params1.y;
float scale = max(u_Params1.z, 0.01);
float speed = u_Params1.w;
float vignetteStrength = clamp(u_Params2.x, 0.0, 1.0);
float vignetteRadius = clamp(u_Params2.y, 0.1, 0.95);
float vignetteSoftness = clamp(u_Params2.z, 0.01, 1.0);
float time = u_Params2.w;
float wave1 = sin((v_TexCoord.y * scale * 12.0) + time * speed * 2.1);
float wave2 = cos((v_TexCoord.x * scale * 10.0) - time * speed * 1.7);
float warp = wave1 * wave2;
float wave3 = sin((v_TexCoord.x + v_TexCoord.y) * scale * 6.0 + time * speed * 1.3);
vec2 offset = vec2(warp, wave3) * 0.002 * distortion;
vec2 chroma = offset * (1.0 + intensity * 0.6);
float r = texture(u_Texture, v_TexCoord + chroma).r;
float g = texture(u_Texture, v_TexCoord + offset * 0.6).g;
float b = texture(u_Texture, v_TexCoord - chroma).b;
vec3 col = vec3(r, g, b);
vec3 warm = vec3(1.0, 0.75, 0.45);
float warmMix = clamp(intensity * 0.5, 0.0, 1.0);
col = mix(col, col * warm + vec3(0.05, 0.02, 0.0), warmMix);
float dist = distance(v_TexCoord, vec2(0.5));
float edge = smoothstep(vignetteRadius, vignetteRadius + vignetteSoftness, dist);
float vignette = edge * vignetteStrength;
col = mix(col, col * vec3(1.0, 0.6, 0.2), vignette);
col *= (1.0 - vignette * 0.15);
color = vec4(col, 1.0);
}

View file

@ -0,0 +1,6 @@
@patch 2
@require_define SHADER_STYLE
@insert_after_define SHADER_STYLE
#define LOVISUAL_POST_EFFECT_OWNERSHIP
@end

View file

@ -0,0 +1,93 @@
@patch 2
@require_ident screenPos1
@require_ident lightFog
@require_ident volumetricEffect
@require_call GetBloomFog
@require_hash 44a431424820bc74930238e468887efc59a07ea3a6af1ccb8c26998124810aad
@require_hash 76c77fdbcc40f9aa86445f791963258aff2e988af8357d2ef56eff81e2e5ef3c
@require_hash 66f7777d5e3c5e6d73f190330c204ab666bedb95742804616f9d22ed9a74b96a
@require_hash aaed6040ac1863b853475599111e60a963468da1b3ea1b035d73e720929a82d8
@require_hash 57988c23b79933a6e5cc7a01d6bb9e037cc6e95a4cef457de72823e372c4f3c8
@require_hash 52e964df49ed95ee9b9458b2ddeb2de3f5228d52fdb3e090e96af0283baa9afa
@require_hash dff672ad281b811a955db023bb9ca21cea88e2d6d92aa2c80be8184f5c71b0ed
@insert_zone declarations
#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
uniform bool lovisualWorldTweaksFogControl;
uniform bool lovisualWorldTweaksFogModify;
uniform float lovisualWorldTweaksFogStart;
uniform float lovisualWorldTweaksFogEnd;
uniform vec3 lovisualWorldTweaksFogColor;
uniform int lovisualWorldTweaksFogDisableMask;
#endif
#ifndef LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED
#define LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED
uniform bool lovisualFullbrightEnabled;
uniform float lovisualFullbrightMinLight;
uniform float lovisualOverrideAmbientLight;
#endif
float lovisualComposite1FogAmount(float distanceToCamera, float sceneDepth) {
float lovisualFogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0);
float lovisualFog = smoothstep(0.0, 1.0, clamp((distanceToCamera - lovisualWorldTweaksFogStart) / lovisualFogRange, 0.0, 1.0));
if (sceneDepth >= 0.999999) lovisualFog *= 0.16;
return lovisualFog;
}
void lovisualComposite1ApplyFog(inout vec3 value, float distanceToCamera, float sceneDepth) {
value = mix(value, lovisualWorldTweaksFogColor, lovisualComposite1FogAmount(distanceToCamera, sceneDepth));
}
@end
@insert_before_ident screenPos1 1
if (lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify && isEyeInWater != 1 && z0 != z1) {
lovisualComposite1ApplyFog(color, lViewPos, z0); // lovisualComposite1TranslucentFog
}
@end
@insert_after_hash 76c77fdbcc40f9aa86445f791963258aff2e988af8357d2ef56eff81e2e5ef3c 3
float lovisualUnderwaterFullbright = max(
lovisualFullbrightEnabled ? clamp(lovisualFullbrightMinLight, 0.0, 1.0) : 0.0,
clamp(lovisualOverrideAmbientLight, 0.0, 1.0)
);
bool lovisualCustomUnderwaterFog = lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify;
bool lovisualDisableUnderwaterFog = lovisualWorldTweaksFogControl && (lovisualWorldTweaksFogDisableMask & 1) != 0;
vec3 lovisualUnderwaterBaseMult = vec3(0.97, 0.985, 1.0);
vec3 lovisualUnderwaterMult = mix(lovisualUnderwaterBaseMult * 0.98, vec3(1.0), lovisualUnderwaterFullbright);
if (lovisualCustomUnderwaterFog) {
lovisualComposite1ApplyFog(color, lViewPos, z0);
} else if (!lovisualDisableUnderwaterFog) {
if (z0 == 1.0) {
float lovisualUnderwaterFogTint = 0.08 * (1.0 - lovisualUnderwaterFullbright);
color.rgb = mix(color.rgb, waterFogColor, lovisualUnderwaterFogTint);
}
color.rgb *= lovisualUnderwaterMult;
volumetricEffect.rgb *= mix(vec3(0.94), vec3(1.0), lovisualUnderwaterFullbright);
}
@end
@remove_line_hash 66f7777d5e3c5e6d73f190330c204ab666bedb95742804616f9d22ed9a74b96a
@remove_line_hash aaed6040ac1863b853475599111e60a963468da1b3ea1b035d73e720929a82d8
@remove_line_hash 57988c23b79933a6e5cc7a01d6bb9e037cc6e95a4cef457de72823e372c4f3c8
@remove_line_hash 52e964df49ed95ee9b9458b2ddeb2de3f5228d52fdb3e090e96af0283baa9afa
@insert_before_hash dff672ad281b811a955db023bb9ca21cea88e2d6d92aa2c80be8184f5c71b0ed
if (!lovisualCustomUnderwaterFog && !lovisualDisableUnderwaterFog) {
lightFog *= lovisualUnderwaterMult;
}
@end
@remove_line_hash dff672ad281b811a955db023bb9ca21cea88e2d6d92aa2c80be8184f5c71b0ed
@insert_before_hash 44a431424820bc74930238e468887efc59a07ea3a6af1ccb8c26998124810aad
color *= (
lovisualWorldTweaksFogControl
&& (lovisualWorldTweaksFogModify || (isEyeInWater == 1 && (lovisualWorldTweaksFogDisableMask & 1) != 0))
) ? 1.0 : GetBloomFog(lViewPos);
@end
@remove_line_hash 44a431424820bc74930238e468887efc59a07ea3a6af1ccb8c26998124810aad

View file

@ -0,0 +1,32 @@
@patch 2
@require_function main
@require_ident MOTION_BLUR_EFFECT
@require_ident MOTION_BLURRING_STRENGTH
@require_uniform colortex0
@require_uniform depthtex0
@insert_zone declarations
uniform bool lovisualSuppressShaderpackMotionBlur;
@end
@replace_line_hash f0b1efea375e99f7eb451fbe3c21fe59d260c1eb9c034c7522b8f269690edef6
float lovisualMotionCenterDepth = texture2D(depthtex0, texCoord).r;
float lovisualMotionCenterCloudDepth = texelFetch(colortex5, texelCoord, 0).a;
if (z <= 0.56 || z >= 0.999 || lovisualMotionCenterDepth <= 0.001 || lovisualMotionCenterDepth >= 0.999 || lovisualMotionCenterCloudDepth != 1.0) {
@end
@insert_after_hash e5016804e90f4ce2655161db06f0b0b48b92bf5e158f841c226a26ea3d2e5857
if (lovisualSuppressShaderpackMotionBlur) velocity = vec2(0.0);
@end
@insert_after_hash cdfeb6b2c575899a59b37a61d41eefae85abd6cbce3ba90ed0263aefcdcf0b52
ivec2 lovisualMotionTapTexel = ivec2(coordb * (vec2(viewWidth, viewHeight) - vec2(1.0)));
float lovisualMotionTapDepth = texelFetch(depthtex0, lovisualMotionTapTexel, 0).r;
float lovisualMotionTapCloudDepth = texelFetch(colortex5, lovisualMotionTapTexel, 0).a;
if (lovisualMotionTapDepth <= 0.001 || lovisualMotionTapDepth >= 0.999 || lovisualMotionTapCloudDepth != 1.0) continue;
@end
@replace_line_hash 86fc0536f7fd9675a50ca4155385b1f297ad36187ab856d5bad191927040cb62
color = mbwg > 0.0 ? color / mbwg : texelFetch(colortex0, texelCoord, 0).rgb;
@end

View file

@ -0,0 +1,25 @@
@patch 2
@require_ident texCoord
@require_call DoFog
@require_ident lViewPos
@require_ident z0
@insert_zone declarations
#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
uniform bool lovisualWorldTweaksFogControl;
uniform bool lovisualWorldTweaksFogModify;
uniform float lovisualWorldTweaksFogStart;
uniform float lovisualWorldTweaksFogEnd;
uniform vec3 lovisualWorldTweaksFogColor;
uniform int lovisualWorldTweaksFogDisableMask;
#endif
@end
@insert_before_drawbuffers 1
if (lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify && isEyeInWater != 1) {
lovisualApplyWorldTweaksFog(color, lViewPos, z0);
}
@end

View file

@ -0,0 +1,56 @@
@patch 2
@require_function DoBorderFog
@require_function DoAtmosphericFog
@require_function DoFog
@require_ident isEyeInWater
@insert_before_function DoFog
#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
uniform bool lovisualWorldTweaksFogControl;
uniform bool lovisualWorldTweaksFogModify;
uniform float lovisualWorldTweaksFogStart;
uniform float lovisualWorldTweaksFogEnd;
uniform vec3 lovisualWorldTweaksFogColor;
uniform int lovisualWorldTweaksFogDisableMask;
#endif
bool lovisualDisableComplementaryFog() {
if (!lovisualWorldTweaksFogControl) return false;
if (lovisualWorldTweaksFogModify) return true;
if (isEyeInWater == 1 && (lovisualWorldTweaksFogDisableMask & 1) != 0) return true;
if (isEyeInWater == 2 && (lovisualWorldTweaksFogDisableMask & 2) != 0) return true;
if (isEyeInWater == 3 && (lovisualWorldTweaksFogDisableMask & 4) != 0) return true;
#ifdef OVERWORLD
if ((lovisualWorldTweaksFogDisableMask & 8) != 0) return true;
#endif
#ifdef NETHER
if ((lovisualWorldTweaksFogDisableMask & 16) != 0) return true;
#endif
#ifdef END
if ((lovisualWorldTweaksFogDisableMask & 32) != 0) return true;
#endif
return (lovisualWorldTweaksFogDisableMask & 192) != 0;
}
void lovisualApplyWorldTweaksFog(inout vec3 color, float lViewPos, float sceneDepth) {
float lovisualFogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0);
float lovisualFogDistance = min(lViewPos, lovisualWorldTweaksFogEnd);
float lovisualFog = smoothstep(0.0, 1.0, clamp((lovisualFogDistance - lovisualWorldTweaksFogStart) / lovisualFogRange, 0.0, 1.0));
if (sceneDepth >= 0.999999) lovisualFog *= 0.16;
color = mix(color, lovisualWorldTweaksFogColor, lovisualFog);
}
void lovisualApplyWorldTweaksFog(inout vec4 color, float lViewPos, float sceneDepth) {
float lovisualFogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0);
float lovisualFogDistance = min(lViewPos, lovisualWorldTweaksFogEnd);
float lovisualFog = smoothstep(0.0, 1.0, clamp((lovisualFogDistance - lovisualWorldTweaksFogStart) / lovisualFogRange, 0.0, 1.0));
if (sceneDepth >= 0.999999) lovisualFog *= 0.16;
color.rgb = mix(color.rgb, lovisualWorldTweaksFogColor, lovisualFog);
}
@end
@insert_after_function_open DoFog
if (lovisualDisableComplementaryFog()) return;
@end

View file

@ -0,0 +1,40 @@
@patch 2
@require_function DoLighting
@require_ident lightmap
@require_ident minLighting
@require_ident darknessLightFactor
@require_hash 198c38564559ab224c3616a2a7b4a8947fa62d2e7a970103017b95fd06b94b22
@require_hash 6f70f1b5528262776dcef7ec3997df09c8b9af515db2744743e26480b0dac711
@insert_before_function DoLighting
#ifndef LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED
#define LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED
uniform bool lovisualFullbrightEnabled;
uniform float lovisualFullbrightMinLight;
uniform float lovisualOverrideAmbientLight;
#endif
@end
@insert_after_function_open DoLighting
float lovisualFullbrightStrength = lovisualFullbrightEnabled ? clamp(lovisualFullbrightMinLight, 0.0, 1.0) : 0.0;
float lovisualAmbientOverrideStrength = clamp(lovisualOverrideAmbientLight, 0.0, 1.0);
float lovisualEffectiveLightStrength = max(lovisualFullbrightStrength, lovisualAmbientOverrideStrength);
if (lovisualEffectiveLightStrength > 0.0) {
lightmap = max(lightmap, vec2(lovisualEffectiveLightStrength));
}
@end
@insert_after_hash 198c38564559ab224c3616a2a7b4a8947fa62d2e7a970103017b95fd06b94b22
if (lovisualEffectiveLightStrength > 0.0) {
minLighting = max(minLighting, vec3(pow2(lovisualEffectiveLightStrength)));
}
@end
@insert_before_hash 6f70f1b5528262776dcef7ec3997df09c8b9af515db2744743e26480b0dac711
float lovisualDarknessLightFactor = mix(darknessLightFactor, 0.0, lovisualEffectiveLightStrength);
color.rgb *= pow2(1.0 - lovisualDarknessLightFactor);
@end
@remove_line_hash 6f70f1b5528262776dcef7ec3997df09c8b9af515db2744743e26480b0dac711

View file

@ -0,0 +1,68 @@
{
"schemaVersion": 1,
"id": "complementary_reimagined.r5",
"priority": 500,
"identity": {
"family": "complementary_reimagined",
"policy": "pack_name_and_structural_probes",
"profile": "complementary_reimagined",
"packNameRegex": ".*complementary.*reimagined.*"
},
"compatibility": {
"policy": "pack_name_gated_structural_probes",
"verifiedShaderpackVersions": [
"r5.6.1"
],
"verifiedMinecraftVersions": [
"1.21.11"
],
"verifiedIrisVersions": [
"1.10.7+1.21.11-fabric"
],
"features": [
"fullbright",
"worldtweaks_fog",
"translucent_ssr_fog",
"underwater_fog",
"shaderpack_motion_blur_suppression"
],
"notes": "Runtime application is gated by active Iris shaderpack name first, then by structural probes compiled against the loaded expanded GLSL. Patch payload remains LoVisual-owned; exact SHA-256 anchors are reserved for dangerous line-level mutations. Stage gating is intentionally not used for expanded include targets; fragment-only composite logic avoids new shaderpack uniforms in declaration payload."
},
"targets": [
{
"path": "/lib/common.glsl",
"patch": "common.patch",
"marker": "LOVISUAL_POST_EFFECT_OWNERSHIP"
},
{
"path": "/lib/lighting/mainLighting.glsl",
"patch": "lighting.patch",
"marker": "lovisualFullbrightStrength"
},
{
"path": "/lib/atmospherics/fog/mainFog.glsl",
"patch": "fog.patch",
"marker": "lovisualApplyWorldTweaksFog"
},
{
"path": "/program/deferred1.glsl",
"patch": "deferred1.patch",
"marker": "lovisualApplyWorldTweaksFog(color, lViewPos, z0)"
},
{
"path": "/program/composite1.glsl",
"patch": "composite1.patch",
"marker": "lovisualComposite1TranslucentFog"
},
{
"path": "/program/composite4.glsl",
"patch": "composite4.patch",
"marker": "lovisualSuppressShaderpackMotionBlur"
},
{
"path": "/program/gbuffers_water.glsl",
"patch": "water.patch",
"marker": "lovisualWaterSurfaceFog"
}
]
}

View file

@ -0,0 +1,28 @@
@patch 2
@require_ident mat
@require_ident translucentMult
@require_call DoFog
@require_ident glColor
@require_hash 98a8ecbdc8e127052fe7c968dc602301791bb3069ced369c924e1ff7d3e04f92
@insert_zone declarations
#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
uniform bool lovisualWorldTweaksFogControl;
uniform bool lovisualWorldTweaksFogModify;
uniform float lovisualWorldTweaksFogStart;
uniform float lovisualWorldTweaksFogEnd;
uniform vec3 lovisualWorldTweaksFogColor;
uniform int lovisualWorldTweaksFogDisableMask;
#endif
@end
@insert_after_hash 98a8ecbdc8e127052fe7c968dc602301791bb3069ced369c924e1ff7d3e04f92
if (lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify) {
float lovisualWaterSurfaceFogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0);
float lovisualWaterSurfaceFog = smoothstep(0.0, 1.0, clamp((lViewPos - lovisualWorldTweaksFogStart) / lovisualWaterSurfaceFogRange, 0.0, 1.0));
color.a = mix(color.a, 1.0, lovisualWaterSurfaceFog);
translucentMult.rgb = mix(translucentMult.rgb, vec3(0.0), lovisualWaterSurfaceFog);
} // lovisualWaterSurfaceFog
@end

View file

@ -0,0 +1,7 @@
{
"schemaVersion": 1,
"manifests": [
"assets/lovisual/shaders/iris-patches/complementary_reimagined/r5/manifest.json",
"assets/lovisual/shaders/iris-patches/photon/v1_3b/manifest.json"
]
}

View file

@ -0,0 +1,51 @@
@patch 2
@require_ident isEyeInWater
@require_call raymarch_air_fog
@require_call raymarch_water_fog
@require_hash edca557442dab12ad7e45ab3d92af16882dac5dbe47803ecda08ea07dcf82d25
@require_hash 04c1c600e2564adc886777a68521ea4876b7ff06ece947d48590eed71b959168
@insert_zone declarations
#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
uniform bool lovisualWorldTweaksFogControl;
uniform bool lovisualWorldTweaksFogModify;
uniform float lovisualWorldTweaksFogStart;
uniform float lovisualWorldTweaksFogEnd;
uniform vec3 lovisualWorldTweaksFogColor;
uniform int lovisualWorldTweaksFogDisableMask;
#endif
bool lovisualPhotonSuppressDefaultAirFog() {
if (!lovisualWorldTweaksFogControl) return false;
if (lovisualWorldTweaksFogModify) return true;
#if defined WORLD_OVERWORLD
return (lovisualWorldTweaksFogDisableMask & 200) != 0;
#elif defined WORLD_NETHER
return (lovisualWorldTweaksFogDisableMask & 16) != 0;
#elif defined WORLD_END
return (lovisualWorldTweaksFogDisableMask & 32) != 0;
#else
return false;
#endif
}
void lovisualPhotonSoftenWaterFog(inout mat2x3 waterFog) {
if (!lovisualWorldTweaksFogControl) return;
float visibility = lovisualWorldTweaksFogModify || (lovisualWorldTweaksFogDisableMask & 1) != 0 ? 1.0 : 0.78;
waterFog[0] *= 1.0 - 0.88 * visibility;
waterFog[1] = mix(waterFog[1], vec3(1.0), visibility);
} // lovisualPhotonSoftenWaterFog
@end
@insert_before_hash edca557442dab12ad7e45ab3d92af16882dac5dbe47803ecda08ea07dcf82d25
if (lovisualPhotonSuppressDefaultAirFog()) {
fog = mat2x3(vec3(0.0), vec3(1.0));
}
@end
@insert_before_hash 04c1c600e2564adc886777a68521ea4876b7ff06ece947d48590eed71b959168
lovisualPhotonSoftenWaterFog(water_fog);
@end

View file

@ -0,0 +1,37 @@
@patch 2
@require_ident view_distance
@require_ident is_sky
@require_ident fog_transmittance
@require_ident fog_scattering
@require_hash be5ef0bea5057e7d62bad71bec7721dc0048bffd6e941be27511a801bbe48a0a
@insert_zone declarations
#ifndef LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
#define LOVISUAL_WORLD_TWEAKS_FOG_UNIFORMS_DECLARED
uniform bool lovisualWorldTweaksFogControl;
uniform bool lovisualWorldTweaksFogModify;
uniform float lovisualWorldTweaksFogStart;
uniform float lovisualWorldTweaksFogEnd;
uniform vec3 lovisualWorldTweaksFogColor;
uniform int lovisualWorldTweaksFogDisableMask;
#endif
float lovisualPhotonWorldTweaksFogAmount(float distanceToCamera, bool sky) {
float fogRange = max(lovisualWorldTweaksFogEnd - lovisualWorldTweaksFogStart, 1.0);
float fogDistance = min(distanceToCamera, lovisualWorldTweaksFogEnd);
float fog = smoothstep(0.0, 1.0, clamp((fogDistance - lovisualWorldTweaksFogStart) / fogRange, 0.0, 1.0));
if (sky) fog *= 0.16;
return fog;
}
void lovisualPhotonApplyWorldTweaksFog(inout vec3 color, float distanceToCamera, bool sky) {
color = mix(color, lovisualWorldTweaksFogColor, lovisualPhotonWorldTweaksFogAmount(distanceToCamera, sky));
} // lovisualPhotonApplyWorldTweaksFog
@end
@insert_after_hash be5ef0bea5057e7d62bad71bec7721dc0048bffd6e941be27511a801bbe48a0a
if (lovisualWorldTweaksFogControl && lovisualWorldTweaksFogModify) {
lovisualPhotonApplyWorldTweaksFog(fragment_color, view_distance, is_sky);
}
@end

View file

@ -0,0 +1,31 @@
@patch 2
@require_function get_diffuse_lighting
@require_ident light_levels
@require_ident shadows
@require_ident darknessFactor
@require_ident nightVision
@insert_before_function get_diffuse_lighting
#ifndef LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED
#define LOVISUAL_FULLBRIGHT_UNIFORMS_DECLARED
uniform bool lovisualFullbrightEnabled;
uniform float lovisualFullbrightMinLight;
uniform float lovisualOverrideAmbientLight;
#endif
@end
@insert_after_function_open get_diffuse_lighting
float lovisualPhotonFullbrightStrength = max(
lovisualFullbrightEnabled ? clamp(lovisualFullbrightMinLight, 0.0, 1.0) : 0.0,
clamp(lovisualOverrideAmbientLight, 0.0, 1.0)
);
if (lovisualPhotonFullbrightStrength > 0.0) {
light_levels = max(light_levels, vec2(lovisualPhotonFullbrightStrength));
ao = max(ao, lovisualPhotonFullbrightStrength);
float lovisualPhotonFullbrightSquared = lovisualPhotonFullbrightStrength * lovisualPhotonFullbrightStrength;
shadows = max(shadows, vec3(lovisualPhotonFullbrightSquared));
sss_depth = max(sss_depth, 0.0);
}
@end

View file

@ -0,0 +1,51 @@
{
"schemaVersion": 1,
"id": "photon.v1_3b",
"priority": 450,
"identity": {
"family": "photon",
"policy": "pack_name_and_structural_probes",
"profile": "photon",
"packNameRegex": ".*photon.*"
},
"compatibility": {
"policy": "pack_name_gated_structural_probes",
"verifiedShaderpackVersions": [
"v1.3b"
],
"verifiedMinecraftVersions": [
"1.21.11"
],
"verifiedIrisVersions": [
"1.10.7+1.21.11-fabric"
],
"features": [
"fullbright",
"worldtweaks_fog",
"underwater_fog",
"shaderpack_motion_blur_suppression"
]
},
"targets": [
{
"path": "/program/c0_vl.fsh",
"patch": "c0_vl.patch",
"marker": "lovisualPhotonSoftenWaterFog"
},
{
"path": "/program/c1_blend_layers.fsh",
"patch": "c1_blend_layers.patch",
"marker": "lovisualPhotonApplyWorldTweaksFog"
},
{
"path": "/include/lighting/diffuse_lighting.glsl",
"patch": "lighting.patch",
"marker": "lovisualPhotonFullbrightStrength"
},
{
"path": "/program/c16_motion_blur.fsh",
"patch": "motion_blur.patch",
"marker": "lovisualSuppressShaderpackMotionBlur"
}
]
}

View file

@ -0,0 +1,38 @@
@patch 2
@require_function main
@require_ident scene_color
@require_uniform colortex0
@insert_zone declarations
uniform bool lovisualSuppressShaderpackMotionBlur;
uniform sampler2D colortex11;
@end
@insert_after_function_open main
if (lovisualSuppressShaderpackMotionBlur) {
scene_color = texelFetch(colortex0, ivec2(gl_FragCoord.xy), 0).rgb;
return;
}
@end
@insert_before_hash c457646c5b8fbc05a6af08576060fa8407243f144aebaaa1f8568fbe317487ef
float lovisualMotionCloudTransmittance = texelFetch(colortex11, view_texel, 0).a;
if (depth <= 0.001 || depth >= 0.999 || lovisualMotionCloudTransmittance != 1.0) {
vec3 lovisualMotionSkyColor = texelFetch(colortex0, texel, 0).rgb;
scene_color = lovisualMotionSkyColor;
return;
}
@end
@replace_line_hash e1d6d7148b22846d3dcffd3f701a78cf65a444ada7151311a22452724f264ae3
float lovisualMotionTapCloudTransmittance = texelFetch(colortex11, view_tap, 0).a;
float weight = (clamp01(pos) == pos && depth > max(hand_depth, 0.001) && depth < 0.999 && lovisualMotionTapCloudTransmittance == 1.0) ? 1.0 : 0.0;
@end
@replace_line_hash 482cbf201e7d21c755826f352cf8b8dc5726687bfe3c0aae9debda2b7603e694
vec3 lovisualMotionFallbackColor = texelFetch(colortex0, texel, 0).rgb;
scene_color = weight_sum > 0.0 ? color_sum * rcp(weight_sum) : lovisualMotionFallbackColor;
@end

View file

@ -0,0 +1,162 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*/
out vec4 color;
layout (std140) uniform KillEffectBeam {
vec4 u_Params0; // time, progress, intensity, size
vec4 u_Color;
};
in vec2 v_TexCoord;
in vec4 v_Color;
float hash21(vec2 p) {
p = fract(p * vec2(443.8975, 397.2973));
p += dot(p, p + 19.19);
return fract(p.x * p.y);
}
void main() {
vec2 center = vec2(0.5);
vec2 uv = v_TexCoord;
vec2 dir = uv - center;
float dist = length(dir);
float angle = atan(dir.y, dir.x);
float time = u_Params0.x;
float progress = u_Params0.y;
float intensity = u_Params0.z;
float appear = smoothstep(0.0, 0.10, progress);
float vanish = 1.0 - smoothstep(0.70, 1.0, progress);
vanish = vanish * vanish * (3.0 - 2.0 * vanish);
float radius = 0.05 + 0.55 * progress;
radius *= (0.9 + 0.1 * sin(time * 2.5));
radius *= (0.15 + 0.85 * vanish);
radius = max(radius, 0.001);
float phi = dist * 3.14159;
float theta = angle;
float sx = sin(phi) * cos(theta);
float sz = cos(phi);
float rotAngle = time * 0.6;
float cx = sx * cos(rotAngle) - sz * sin(rotAngle);
float cz = sx * sin(rotAngle) + sz * cos(rotAngle);
sx = cx; sz = cz;
float sphereMask = 1.0 - smoothstep(0.0, radius, dist);
float grid = 0.0;
float lat = sin(phi * 8.0 + time * 0.2) * 0.5 + 0.5;
float lon = sin(theta * 6.0 + time * 0.4) * 0.5 + 0.5;
grid = (lat > 0.97 || lon > 0.97) ? 1.0 : 0.0;
grid *= sphereMask * (0.6 + 0.4 * sz);
grid *= 1.5;
float rings = 0.0;
for (int i = 0; i < 4; i++) {
float fi = float(i);
float radiusRing = 0.25 + fi * 0.15 + 0.05 * sin(time * 0.4 + fi * 1.1);
float ringDist = length(dir);
float ringWidth = 0.01 + 0.01 * (1.0 - progress);
float ring = 1.0 - smoothstep(radiusRing - ringWidth, radiusRing + ringWidth, ringDist);
ring *= (1.0 - abs(ringDist - radiusRing) * 4.0);
ring *= (0.7 + 0.3 * sin(time * 1.0 + fi * 1.3));
ring *= sphereMask * (0.5 + 0.5 * sz);
rings += ring * 0.8;
}
rings *= 1.8;
float lightning = 0.0;
for (int i = 0; i < 8; i++) {
float seed = float(i) * 1.73 + 0.5;
float a = hash21(vec2(seed, 0.0)) * 6.2832;
float len = 0.3 + 0.7 * hash21(vec2(seed, 1.0));
float life = fract(time * 0.8 + seed * 0.5);
float bright = 1.0 - smoothstep(0.1, 0.9, life);
float rad = radius * (0.2 + 0.8 * len);
vec2 pos = vec2(0.5 + rad * cos(a + time * 0.4), 0.5 + rad * sin(a + time * 0.4));
vec2 delta = uv - pos;
vec2 dirToPoint = normalize(pos - center);
vec2 perp = vec2(-dirToPoint.y, dirToPoint.x);
float proj = dot(delta, dirToPoint);
float perpDist = abs(dot(delta, perp));
float line = 1.0 - smoothstep(0.0, 0.02, perpDist);
line *= smoothstep(0.0, 0.1, proj) * smoothstep(1.0, 0.85, proj / (rad + 0.001));
lightning += line * bright * 1.2;
}
lightning *= sphereMask * (0.5 + 0.5 * sz);
lightning *= 1.5;
float coreDist = length(dir) / (0.03 + 0.02 * progress);
float core = exp(-coreDist * coreDist) * 2.5;
core *= (1.0 - progress * 0.2);
core *= (0.6 + 0.4 * sz);
float particles = 0.0;
for (int i = 0; i < 60; i++) {
float seed = float(i) * 1.37;
float a = hash21(vec2(seed, 0.0)) * 6.2832;
float r = radius * (0.1 + 0.9 * hash21(vec2(seed, 1.0)));
float life = fract(time * 0.5 + seed * 0.3);
float bright = 1.0 - smoothstep(0.1, 0.9, life);
float angleOff = time * (0.4 + 0.6 * hash21(vec2(seed, 2.0)));
float phiP = (r / radius) * 3.14159;
float thetaP = a + angleOff;
float sxP = sin(phiP) * cos(thetaP);
float syP = sin(phiP) * sin(thetaP);
float szP = cos(phiP);
vec2 pos = center + vec2(sxP, syP) * radius * 0.5;
float szFactor = 0.5 + 0.5 * szP;
float sz2 = 0.005 + 0.025 * hash21(vec2(seed, 3.0));
float d = length(uv - pos);
float p = exp(-d * d / (2.0 * sz2 * sz2));
particles += p * bright * 0.8 * szFactor;
}
particles *= (1.0 - progress * 0.5);
particles *= 1.8;
float glow = exp(-dist * 5.0) * 0.6 * (1.0 + 0.3 * sin(time * 2.5));
glow *= (1.0 - progress * 0.3);
glow *= (0.6 + 0.4 * sz);
float bloom = exp(-dist * 3.0) * 0.3;
float ring2 = 0.0;
float r2 = radius * 1.7 * progress;
ring2 = 1.0 - smoothstep(r2 - 0.03, r2 + 0.03, dist);
ring2 *= 0.5 * (1.0 - progress) * sin(progress * 3.14159);
ring2 *= 1.5;
vec3 baseColor = u_Color.rgb;
vec3 gridColor = mix(baseColor, vec3(0.9, 0.95, 1.0), 0.4);
vec3 ringColor = mix(baseColor, vec3(1.0, 0.9, 0.5), 0.5);
vec3 lightningColor = vec3(0.8, 0.9, 1.0);
vec3 coreColor = vec3(1.0, 0.98, 0.9);
vec3 particleColor = vec3(1.0, 0.85, 0.5);
vec3 glowColor = mix(baseColor, vec3(0.6, 0.8, 1.0), 0.5);
float finalIntensity = grid + rings + lightning + core + particles + glow + bloom + ring2;
vec3 finalColor = gridColor * grid * 1.5
+ ringColor * rings * 1.2
+ lightningColor * lightning * 1.0
+ coreColor * core * 2.5
+ particleColor * particles * 0.9
+ glowColor * glow * 0.6
+ vec3(0.8, 0.9, 1.0) * bloom * 0.5
+ baseColor * ring2 * 0.6;
finalColor *= intensity * 1.2;
float finalAlpha = clamp(finalIntensity * 1.6, 0.0, 1.0) * v_Color.a;
float vignette = 1.0 - dist * 0.5;
finalAlpha *= mix(vignette, 1.0, 0.5);
finalAlpha *= appear * vanish;
if (finalAlpha < 0.01) discard;
color = vec4(clamp(finalColor, 0.0, 1.0), finalAlpha);
}

View file

@ -0,0 +1,106 @@
#version 330 core
/*
* This file is part of the LoVisual Client distribution.
* Copyright (c) 2026 loki5512344.
*/
out vec4 color;
layout (std140) uniform KillEffectBeam {
vec4 u_Params0; // time, progress, intensity, size
vec4 u_Color;
};
in vec2 v_TexCoord;
in vec4 v_Color;
float hash21(vec2 p) {
p = fract(p * vec2(443.8975, 397.2973));
p += dot(p, p + 19.19);
return fract(p.x * p.y);
}
float smoothNoise2D(vec2 p) {
vec2 i = floor(p);
vec2 f = fract(p);
f = f * f * (3.0 - 2.0 * f);
return mix(
mix(hash21(i), hash21(i + vec2(1.0, 0.0)), f.x),
mix(hash21(i + vec2(0.0, 1.0)), hash21(i + vec2(1.0, 1.0)), f.x),
f.y
);
}
float fbm2D(vec2 p, int octaves) {
float v = 0.0, a = 0.5, freq = 1.0;
for (int k = 0; k < octaves; k++) {
v += a * smoothNoise2D(p * freq);
freq *= 2.03;
a *= 0.48;
}
return v;
}
void main() {
if (v_TexCoord.y < 0.0) discard;
float x = v_TexCoord.x * 2.0 - 1.0;
float y = v_TexCoord.y;
float t = u_Params0.x;
float prog = clamp(u_Params0.y, 0.0, 1.0);
float intensity = u_Params0.z;
float baseFade = smoothstep(0.0, 0.05, y);
float topFade = 1.0 - smoothstep(0.55, 0.98, y);
float rise = 0.10 + prog * 1.0;
float growing = 1.0 - smoothstep(rise - 0.12, rise, y);
float body = growing * topFade * baseFade;
if (body <= 0.001) discard;
float radius = mix(0.10, 0.95, pow(y, 1.4));
float r = abs(x) / max(radius, 1.0e-4);
float wall = 1.0 - smoothstep(0.0, 1.0, abs(r - 0.72) * 2.2);
vec2 sw = vec2(x * 3.0, y * 6.0 - t * 2.5);
float twirl = fbm2D(sw + vec2(t * 0.3, 0.0), 4);
float bands = smoothstep(0.30, 0.80, twirl + 0.2 * sin(x * 8.0 + y * 12.0 - t * 4.0));
float core = exp(-(x * x) / (2.0 * 0.11 * 0.11)) * smoothstep(0.0, 0.10, y);
float particles = 0.0;
for (int i = 0; i < 20; i++) {
float seed = float(i) * 1.37 + 3.1;
float hgt = fract(t * 0.35 + hash21(vec2(seed, 0.0)) * 0.8);
if (hgt > rise - 0.1) continue;
float angular = (hgt * 3.0 + t) * 3.0;
float px = sin(angular + seed) * 0.55;
float sz = 0.03 + 0.05 * hash21(vec2(seed, 1.0));
vec2 dc = vec2((x - px) * 1.2, (y - hgt) * 2.0);
particles += exp(-dot(dc, dc) / (2.0 * sz * sz)) * 0.7;
}
float glow = exp(-abs(x) * 2.6) * 0.4 * (0.6 + 0.4 * sin(t * 2.0));
vec3 base = u_Color.rgb;
vec3 spiralColor = mix(base, vec3(0.45, 0.50, 1.00), 0.55);
vec3 coreColor = vec3(0.90, 0.85, 1.00);
vec3 particleColor = vec3(0.60, 0.80, 1.00);
vec3 finalColor = spiralColor * bands * wall * 1.10
+ coreColor * core * 1.60
+ particleColor * particles * 0.90
+ vec3(0.40, 0.50, 1.00) * glow;
float fin = (wall * bands * 0.80 + core + particles * 0.50 + glow * 0.30) * body;
float alpha = clamp(fin * 1.20, 0.0, 1.0) * v_Color.a;
float fadeIn = smoothstep(0.0, 0.08, prog);
float fadeOut = 1.0 - smoothstep(0.60, 1.0, prog);
alpha *= fadeIn * fadeOut * intensity;
if (alpha < 0.01) discard;
color = vec4(clamp(finalColor * intensity, 0.0, 1.0), alpha);
}

Some files were not shown because too many files have changed in this diff Show more