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
BIN
mod/src/main/resources/assets/lovisual/font/comfortaa.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/icons.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/icons2.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/iconsnur.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/inter_bold.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/inter_medium.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/inter_regular.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/iosevka-bold.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/iosevka-light.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/iosevka-medium.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/mediaplayer.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/monsterrat.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/msdf/comfortaa.png
Normal file
|
After Width: | Height: | Size: 358 KiB |
BIN
mod/src/main/resources/assets/lovisual/font/msdf/guiicons.png
Normal file
|
After Width: | Height: | Size: 177 KiB |
BIN
mod/src/main/resources/assets/lovisual/font/msdf/inter_bold.png
Normal file
|
After Width: | Height: | Size: 494 KiB |
|
After Width: | Height: | Size: 477 KiB |
|
After Width: | Height: | Size: 467 KiB |
|
After Width: | Height: | Size: 237 KiB |
|
After Width: | Height: | Size: 317 KiB |
|
After Width: | Height: | Size: 236 KiB |
|
After Width: | Height: | Size: 312 KiB |
|
|
@ -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":[]}
|
||||
|
After Width: | Height: | Size: 80 KiB |
BIN
mod/src/main/resources/assets/lovisual/font/msdf/monsterrat.png
Normal file
|
After Width: | Height: | Size: 387 KiB |
BIN
mod/src/main/resources/assets/lovisual/font/msdf/onest_bold.png
Normal file
|
After Width: | Height: | Size: 237 KiB |
BIN
mod/src/main/resources/assets/lovisual/font/msdf/onest_light.png
Normal file
|
After Width: | Height: | Size: 227 KiB |
|
After Width: | Height: | Size: 242 KiB |
|
After Width: | Height: | Size: 233 KiB |
BIN
mod/src/main/resources/assets/lovisual/font/msdf/profont.png
Normal file
|
After Width: | Height: | Size: 70 KiB |
BIN
mod/src/main/resources/assets/lovisual/font/msdf/richicons.png
Normal file
|
After Width: | Height: | Size: 176 KiB |
BIN
mod/src/main/resources/assets/lovisual/font/onest_bold.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/onest_light.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/onest_medium.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/onest_regular.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/profont.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/vanilla_symbols.ttf
Normal file
BIN
mod/src/main/resources/assets/lovisual/font/weather_icons.ttf
Normal file
3394
mod/src/main/resources/assets/lovisual/lang/en_us.json
Normal file
3185
mod/src/main/resources/assets/lovisual/lang/ru_ru.json
Normal file
103
mod/src/main/resources/assets/lovisual/shaders/arc_batch.frag
Normal 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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
298
mod/src/main/resources/assets/lovisual/shaders/hand_glass.frag
Normal 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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
156
mod/src/main/resources/assets/lovisual/shaders/hand_noise.frag
Normal 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);
|
||||
}
|
||||
168
mod/src/main/resources/assets/lovisual/shaders/hand_smoke.frag
Normal 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);
|
||||
}
|
||||
57
mod/src/main/resources/assets/lovisual/shaders/heat_fx.frag
Normal 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);
|
||||
}
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
@patch 2
|
||||
@require_define SHADER_STYLE
|
||||
|
||||
@insert_after_define SHADER_STYLE
|
||||
#define LOVISUAL_POST_EFFECT_OWNERSHIP
|
||||
@end
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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
|
||||
|
|
@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -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
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||