Fry3DX 0.4: an easy 3D modeller

Shapes with live settings, shape editing, knife and hole tools, drawing
shapes onto other objects, combining objects (add / subtract / overlap),
copies, thickness, painting with stickers and layers, a Layout tab, a
Print tab with checks, packed .fry files with autosave, export to GLB,
glTF, FBX, OBJ, 3MF, STL and PLY, folders in Layers, its own crash
screen, and a website for GitHub Pages in docs/.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NMSrd5oe1GpUD7E6d825KP
This commit is contained in:
Nexoniarz 2026-10-19 21:18:35 +02:00
commit f3e8eca87b
135 changed files with 23423 additions and 0 deletions

View file

@ -0,0 +1,78 @@
#version 460
#define KEEL_POST // screen-space: render targets, sampled clamped
#include "backend.glsl"
#include "upsample.glsl"
// HDR scene → display: ambient occlusion, bloom, exposure, ACES filmic curve, a light grade
// (saturation, vignette), then sRGB encoding.
PUSH_BLOCK {
uint scene;
float exposure;
uint ao; // 0 = none
uint bloom; // 0 = none
float bloomStrength;
float saturation;
float vignette;
float sharpen; // after TAA: give back a little crispness (0 = none)
uint depth; // scene depth (1 = sky)
uint ssr; // reflections to add (when TAA didn't), 0 = none
uint adapt; // eye adaptation (1×1 exposure multiplier), 0 = none
uint pad2;
vec4 shafts; // sun shafts: the sun's uv, strength (0 = none)
vec4 sunColor;
} pc;
// Sun shafts (screen-space light scattering, GPU Gems 3 ch. 13): march towards the sun's spot
// on screen, adding up how much open sky lies on the way; air lit by the sun glows there,
// fading with distance from the sun. Started at a per-pixel offset so the steps don't band.
vec3 sunShafts(vec2 uv) {
const int N = 32;
vec2 toSun = pc.shafts.xy - uv;
vec2 stepUv = toSun * (0.85 / float(N));
float jitter = fract(52.9829189 * fract(dot(gl_FragCoord.xy, vec2(0.06711056, 0.00583715))));
vec2 p = uv + stepUv * jitter;
vec3 lit = vec3(0.0);
float w = 1.0, total = 0.0;
for (int i = 0; i < N; ++i, p += stepUv) {
bool inside = all(greaterThanEqual(p, vec2(0.0))) && all(lessThanEqual(p, vec2(1.0)));
if (inside && sampleTexLod(pc.depth, p, 0.0).r >= 1.0) // open sky: its light, the sun's brightest
lit += max(sampleTexLod(pc.scene, p, 0.0).rgb - 1.0, vec3(0.0)) * w;
total += w;
w *= 0.97;
}
vec2 aspect = vec2(float(texSize(pc.scene).x) / float(texSize(pc.scene).y), 1.0);
float fall = exp(-length(toSun * aspect) * 1.5);
return min(lit / total, vec3(8.0)) * fall * pc.shafts.z;
}
layout(location = 0) in vec2 v_uv;
layout(location = 0) out vec4 o_color;
vec3 aces(vec3 x) {
return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0);
}
vec3 toSrgb(vec3 c) {
return mix(c * 12.92, 1.055 * pow(c, vec3(1.0 / 2.4)) - 0.055, step(0.0031308, c));
}
void main() {
vec3 hdr = sampleTex(pc.scene, v_uv).rgb;
const ivec2 px = ivec2(v_uv * vec2(texSize(pc.depth)));
if (pc.ssr != 0u) hdr += upsampleDepthAware(pc.ssr, pc.depth, px).rgb;
if (pc.sharpen > 0.0) { // unsharp mask against the 4 neighbours, limited so edges don't ring
vec2 t = 1.0 / vec2(texSize(pc.scene));
vec3 n = sampleTex(pc.scene, v_uv + vec2(t.x, 0)).rgb + sampleTex(pc.scene, v_uv - vec2(t.x, 0)).rgb
+ sampleTex(pc.scene, v_uv + vec2(0, t.y)).rgb + sampleTex(pc.scene, v_uv - vec2(0, t.y)).rgb;
hdr = max(hdr + clamp((hdr - n * 0.25) * pc.sharpen, -0.1 * (hdr + 0.05), 0.1 * (hdr + 0.05)), 0.0);
}
if (pc.ao != 0u) hdr *= upsampleDepthAware(pc.ao, pc.depth, px).r;
if (pc.bloom != 0u) hdr = mix(hdr, sampleTex(pc.bloom, v_uv).rgb, pc.bloomStrength);
if (pc.shafts.z > 0.0) hdr += sunShafts(v_uv);
float exposure = pc.exposure * (pc.adapt != 0u ? sampleTexLod(pc.adapt, vec2(0.5), 0.0).r : 1.0);
vec3 c = aces(hdr * exposure);
float l = dot(c, vec3(0.2126, 0.7152, 0.0722));
c = max(mix(vec3(l), c, pc.saturation), 0.0);
vec2 d = v_uv - 0.5;
c *= 1.0 - pc.vignette * dot(d, d) * 2.0;
o_color = vec4(toSrgb(c), 1.0);
}