fp64 Newton fractal

fp64 Newton fractal

z³ = 1을 푸는 뉴턴 방법입니다. 색은 그 픽셀이 어느 세제곱근으로 수렴하는지 나타냅니다.

// ═══ typeshade example — fp64 Newton fractal (z³ = 1) ═══
//
// The fp64 family's DIVISION showcase: Newton's method z ← z − (z³−1)/(3z²)
// runs a full complex division every iteration, and the f64 side does it with
// df64_div (the long-division EFT) — the one emulated op an add/mul-only demo
// never touches. The camera sits on a basin boundary of the three cube roots;
// the boundary is the Julia set of the Newton map and has the Wada property
// (every boundary point touches ALL THREE basins), so any zoom depth shows the
// three colours interleaved — CPU-verified to 50+ distinct (root, steps) cells
// per 48² window down to a 1e-11 span. The plain-f32 left half collapses once
// the span drops under one ulp of the center (~1e-7).
//
// The `_fp64` guard uniform is auto-injected by the lowering; the render
// harnesses bind it to 1.0f by probing the program for the Fp64Guard block.
import {
fn,
module,
vec3,
vec4,
f32,
f64,
pow,
mix,
toF32,
toF64,
f32T,
vec2fT,
vec2f64T,
If,
Loop,
Var,
Let,
u32,
uniformStruct,
} from '../src/index.js';
import { VsOut, vs } from './_fullscreen.js';
import type { ShaderExample } from './_shared.js';
// A boundary point between the basins of 1 and e^{2πi/3} (CPU bisection to
// ~1e-19, so the window straddles the boundary at every reachable zoom).
const CENTER_X = 0.17616732990860245;
const CENTER_Y = 0.7111381151066305;
const ITER = 48;
// Cube roots of unity (exactly representable enough for f32 CLASSIFICATION —
// the roots are attracting, so classification is precision-insensitive).
const R_IM = 0.8660254037844386; // √3/2
const U = uniformStruct(
'Uniforms',
{ group: 0, binding: 0, as: 'u' },
{
center: vec2f64T, // one DF64Vec2 slot — host packs [hi.x, hi.y, lo.x, lo.y]
resolution: vec2fT,
zoom_exp: f32T, // view span = 10^-zoom_exp complex units
fp64: f32T, // toggle: 1 = split-screen f32 | f64 (canonical), 0 = all-f32
},
);
const fsNewton = fn(
'fs_newton',
{ vo: VsOut },
(p) => {
const span = Let(pow(f32(10.0), U.field.zoom_exp.neg()));
const half = Let(p.vo.uv.x.mul(2.0));
const sx = Let(half.sub(p.vo.uv.x.lt(0.5).select(0.0, 1.0)));
const dx = Let(sx.sub(0.5).mul(span));
const dy = Let(
p.vo.uv.y.sub(0.5).mul(span).mul(U.field.resolution.y.div(U.field.resolution.x).mul(2.0)),
);
// Iterate to convergence; hand the FINAL z (narrowed) + step count out.
const fx = Var(f32(0)); // final Re z
const fy = Var(f32(0)); // final Im z
const it = Var(f32(0)); // steps until the update went sub-epsilon
If(p.vo.uv.x.lt(0.5).or(U.field.fp64.lt(0.5)), () => {
// f32 twin — z₀ from the narrowed center: at deep zoom every pixel
// starts at the SAME quantized point and the basins collapse flat.
const zx = Var(toF32(U.field.center.x).add(dx));
const zy = Var(toF32(U.field.center.y).add(dy));
Loop(
u32(0),
(j) => j.lt(u32(ITER)),
() => {
const z2x = Let(zx.mul(zx).sub(zy.mul(zy)));
const z2y = Let(zx.mul(zy).mul(2.0));
const nx = Let(z2x.mul(zx).sub(z2y.mul(zy)).sub(1.0)); // Re(z³−1)
const ny = Let(z2x.mul(zy).add(z2y.mul(zx))); // Im(z³−1)
const gx = Let(z2x.mul(3.0)); // Re(3z²)
const gy = Let(z2y.mul(3.0));
const inv = Let(f32(1.0).div(gx.mul(gx).add(gy.mul(gy))));
const qx = Let(nx.mul(gx).add(ny.mul(gy)).mul(inv));
const qy = Let(ny.mul(gx).sub(nx.mul(gy)).mul(inv));
zx.assign(zx.sub(qx));
zy.assign(zy.sub(qy));
If(qx.mul(qx).add(qy.mul(qy)).gt(1e-14), () => {
it.assign(it.add(1.0));
});
},
);
fx.assign(zx);
fy.assign(zy);
}).else(() => {
// f64 — the SAME Newton step; the quotient runs through df64_div.
const zx = Var(U.field.center.x.add(toF64(dx)));
const zy = Var(U.field.center.y.add(toF64(dy)));
Loop(
u32(0),
(j) => j.lt(u32(ITER)),
() => {
const z2x = Let(zx.mul(zx).sub(zy.mul(zy)));
const z2y = Let(zx.mul(zy).mul(2.0));
const nx = Let(z2x.mul(zx).sub(z2y.mul(zy)).sub(1.0));
const ny = Let(z2x.mul(zy).add(z2y.mul(zx)));
const gx = Let(z2x.mul(3.0));
const gy = Let(z2y.mul(3.0));
const inv = Let(f64(1.0).div(gx.mul(gx).add(gy.mul(gy))));
const qx = Let(nx.mul(gx).add(ny.mul(gy)).mul(inv));
const qy = Let(ny.mul(gx).sub(nx.mul(gy)).mul(inv));
zx.assign(zx.sub(qx));
zy.assign(zy.sub(qy));
If(toF32(qx.mul(qx).add(qy.mul(qy))).gt(1e-14), () => {
it.assign(it.add(1.0));
});
},
);
fx.assign(toF32(zx));
fy.assign(toF32(zy));
});
// Classify the landing root (attracting fixed points — f32 suffices) and
// shade by convergence speed: boundary-hugging pixels stay near-black.
const d0 = Let(fx.sub(1.0).mul(fx.sub(1.0)).add(fy.mul(fy)));
const d1 = Let(
fx
.add(0.5)
.mul(fx.add(0.5))
.add(fy.sub(R_IM).mul(fy.sub(R_IM))),
);
const d2 = Let(
fx
.add(0.5)
.mul(fx.add(0.5))
.add(fy.add(R_IM).mul(fy.add(R_IM))),
);
const c0 = vec3(0.91, 0.34, 0.22); // root 1 — vermilion
const c1 = vec3(0.2, 0.66, 0.88); // root e^{2πi/3} — sky
const c2 = vec3(0.98, 0.78, 0.22); // root e^{−2πi/3} — gold
const base = Let(d0.le(d1).and(d0.le(d2)).select(c0, d1.le(d2).select(c1, c2)));
const speed = Let(f32(1).sub(it.div(ITER)));
const rgb = base.mul(mix(f32(0.25), f32(1.0), speed));
return vec4(rgb, f32(1));
},
{ stage: 'fragment', retAttr: '@location(0)' },
);
// `_fp64` guard lands at (group 0, binding 1) automatically.
const fp64NewtonModule = module({
funcs: [vs, fsNewton],
uses: [U, VsOut],
});
export const fp64Newton: ShaderExample = {
id: 'fp64-newton',
title: 'fp64 Newton fractal',
blurb:
'Newton’s method for z³ = 1, colour = which cube root a pixel falls into — a full complex DIVISION per step, running through df64_div on the f64 side. The basin boundary has the Wada property (all three colours touch at every boundary point), so the interleaving persists to any depth: the f32 left half collapses flat past a ~1e-7 span while the emulated-double right half keeps dividing cleanly. Drag to pan, wheel to zoom, flip the fp64 toggle to compare.',
category: 'generic',
file: 'fp64-newton.ts',
module: fp64NewtonModule,
renderable: true,
splitLabels: ['f32', 'f64 (emulated)'],
controls: {
center: {
kind: 'pan2d',
value: [CENTER_X, CENTER_Y],
zoomExpField: 'zoom_exp',
unitsPerWidth: 2,
},
resolution: { kind: 'resolution' },
zoom_exp: {
kind: 'slider',
label: 'Zoom 10^-x',
min: 1,
max: 13,
step: 0.05,
value: 4,
wheel: true,
},
fp64: { kind: 'toggle', label: 'fp64 emulation', value: true },
},
};
struct Uniforms {
@align(16) center: DF64Vec2,
resolution: vec2<f32>,
zoom_exp: f32,
fp64: f32,
}
struct VsOut {
@builtin(position) pos: vec4<f32>,
@location(0) uv: vec2<f32>,
}
struct DF64Vec2 {
hi: vec2<f32>,
lo: vec2<f32>,
}
@group(0) @binding(0) var<uniform> u: Uniforms;
@group(0) @binding(1) var _fp64: texture_2d<f32>;
@vertex
fn vs(@builtin(vertex_index) vi: u32) -> VsOut {
let _cse0 = ((f32((vi & 1u)) * 4.0) - 1.0);
let _cse1 = ((f32((vi >> 1u)) * 4.0) - 1.0);
return VsOut(vec4<f32>(_cse0, _cse1, 0.0, 1.0), vec2<f32>(((_cse0 * 0.5) + 0.5), ((_cse1 * 0.5) + 0.5)));
}
@fragment
fn fs_newton(vo: VsOut) -> @location(0) vec4<f32> {
let _fp64_g = textureLoad(_fp64, vec2<i32>(0, 0), 0).x;
let _cse5 = bitcast<f32>(bitcast<u32>(0.0));
let _licm0 = vec2<f32>(_cse5, _cse5);
let _v0 = pow(10.0, (-u.zoom_exp));
let _v1 = (vo.uv.x * 2.0);
let _cse0 = (vo.uv.x < 0.5);
let _v2 = (_v1 - select(1.0, 0.0, _cse0));
let _v3 = ((_v2 - 0.5) * _v0);
let _v4 = (((vo.uv.y - 0.5) * _v0) * ((u.resolution.y / u.resolution.x) * 2.0));
var _v5: f32 = 0.0;
var _v6: f32 = 0.0;
var _v7: f32 = 0.0;
let _cse1 = vec2<f32>(u.center.hi.x, u.center.lo.x);
let _cse2 = vec2<f32>(u.center.hi.y, u.center.lo.y);
if ((_cse0 || (u.fp64 < 0.5))) {
var _v8: f32 = (df64_narrow(_cse1) + _v3);
var _v9: f32 = (df64_narrow(_cse2) + _v4);
for (var _v10: u32 = 0u; (_v10 < 48u); _v10 = (_v10 + 1u)) {
let _v11 = ((_v8 * _v8) - (_v9 * _v9));
let _v12 = ((_v8 * _v9) * 2.0);
let _v13 = (((_v11 * _v8) - (_v12 * _v9)) - 1.0);
let _v14 = ((_v11 * _v9) + (_v12 * _v8));
let _v15 = (_v11 * 3.0);
let _v16 = (_v12 * 3.0);
let _v17 = (1.0 / ((_v15 * _v15) + (_v16 * _v16)));
let _v18 = (((_v13 * _v15) + (_v14 * _v16)) * _v17);
let _v19 = (((_v14 * _v15) - (_v13 * _v16)) * _v17);
_v8 = (_v8 - _v18);
_v9 = (_v9 - _v19);
if ((((_v18 * _v18) + (_v19 * _v19)) > 1e-14)) {
_v7 = (_v7 + 1.0);
}
}
_v5 = _v8;
_v6 = _v9;
} else {
var _v20: vec2<f32> = df64_add(_cse1, vec2<f32>(_v3, 0.0), _fp64_g);
var _v21: vec2<f32> = df64_add(_cse2, vec2<f32>(_v4, 0.0), _fp64_g);
let _cse3 = df64_add(vec2<f32>(1.0, 0.0), _licm0, _fp64_g);
let _cse4 = vec2<f32>(3.0, 0.0);
for (var _v22: u32 = 0u; (_v22 < 48u); _v22 = (_v22 + 1u)) {
let _v23 = df64_sub(df64_sqr(_v20, _fp64_g), df64_sqr(_v21, _fp64_g), _fp64_g);
let _v24 = (df64_mul(_v20, _v21, _fp64_g) * 2.0);
let _v25 = df64_sub(df64_sub(df64_mul(_v23, _v20, _fp64_g), df64_mul(_v24, _v21, _fp64_g), _fp64_g), _cse3, _fp64_g);
let _v26 = df64_add(df64_mul(_v23, _v21, _fp64_g), df64_mul(_v24, _v20, _fp64_g), _fp64_g);
let _v27 = df64_mul(_v23, _cse4, _fp64_g);
let _v28 = df64_mul(_v24, _cse4, _fp64_g);
let _v29 = df64_div(_cse3, df64_add(df64_sqr(_v27, _fp64_g), df64_sqr(_v28, _fp64_g), _fp64_g), _fp64_g);
let _v30 = df64_mul(df64_add(df64_mul(_v25, _v27, _fp64_g), df64_mul(_v26, _v28, _fp64_g), _fp64_g), _v29, _fp64_g);
let _v31 = df64_mul(df64_sub(df64_mul(_v26, _v27, _fp64_g), df64_mul(_v25, _v28, _fp64_g), _fp64_g), _v29, _fp64_g);
_v20 = df64_sub(df64_add(_v20, _licm0, _fp64_g), df64_add(_v30, _licm0, _fp64_g), _fp64_g);
_v21 = df64_sub(df64_add(_v21, _licm0, _fp64_g), df64_add(_v31, _licm0, _fp64_g), _fp64_g);
if ((df64_narrow(df64_add(df64_sqr(_v30, _fp64_g), df64_sqr(_v31, _fp64_g), _fp64_g)) > 1e-14)) {
_v7 = (_v7 + 1.0);
}
}
_v5 = df64_narrow(_v20);
_v6 = df64_narrow(_v21);
}
let _lc0 = (_v5 - 1.0);
let _v32 = ((_lc0 * _lc0) + (_v6 * _v6));
let _gv0 = (_v5 + 0.5);
let _lc2 = (_v6 - 0.8660254037844386);
let _gv1 = (_gv0 * _gv0);
let _v33 = (_gv1 + (_lc2 * _lc2));
let _lc4 = (_v6 + 0.8660254037844386);
let _v34 = (_gv1 + (_lc4 * _lc4));
let _v35 = select(select(vec3<f32>(0.98, 0.78, 0.22), vec3<f32>(0.2, 0.66, 0.88), (_v33 <= _v34)), vec3<f32>(0.91, 0.34, 0.22), ((_v32 <= _v33) && (_v32 <= _v34)));
let _v36 = (1.0 - (_v7 / 48.0));
return vec4<f32>((_v35 * mix(0.25, 1.0, _v36)), 1.0);
}
fn df64_twoSum(a: f32, b: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = (a + b);
let _v1 = (((_v0 * _fp64_g) - a) * _fp64_g);
let _v2 = (((a - ((_v0 - _v1) * _fp64_g)) * _fp64_g) + (b - _v1));
return vec2<f32>(_v0, _v2);
}
fn df64_quickTwoSum(a: f32, b: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = ((a + b) * _fp64_g);
let _v1 = (b - ((_v0 - a) * _fp64_g));
return vec2<f32>(_v0, _v1);
}
fn df64_split(a: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = (a * (_fp64_g * 4097.0));
let _v1 = ((_v0 * _fp64_g) - (_v0 - a));
let _v2 = ((a * _fp64_g) - _v1);
return vec2<f32>(_v1, _v2);
}
fn df64_twoProd(a: f32, b: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = (a * b);
let _v1 = df64_split(a, _fp64_g);
let _v2 = df64_split(b, _fp64_g);
let _v3 = (((((_v1.x * _v2.x) - _v0) + (_v1.x * _v2.y)) + (_v1.y * _v2.x)) + (_v1.y * _v2.y));
return vec2<f32>(_v0, _v3);
}
fn df64_twoSqr(a: f32, _fp64_g: f32) -> vec2<f32> {
let _v0 = (a * a);
let _v1 = df64_split(a, _fp64_g);
let _v2 = (((((_v1.x * _v1.x) - _v0) * _fp64_g) + (((_v1.x * _v1.y) * 2.0) * _fp64_g)) + ((_v1.y * _v1.y) * _fp64_g));
return vec2<f32>(_v0, _v2);
}
fn df64_add(a: vec2<f32>, b: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
var _v0: vec2<f32> = df64_twoSum(a.x, b.x, _fp64_g);
let _v1 = df64_twoSum(a.y, b.y, _fp64_g);
_v0.y = (_v0.y + _v1.x);
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
_v0.y = (_v0.y + _v1.y);
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
return _v0;
}
fn df64_sub(a: vec2<f32>, b: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
return df64_add(a, (-b), _fp64_g);
}
fn df64_mul(a: vec2<f32>, b: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
var _v0: vec2<f32> = df64_twoProd(a.x, b.x, _fp64_g);
_v0.y = (_v0.y + (a.x * b.y));
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
_v0.y = (_v0.y + (a.y * b.x));
return df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
}
fn df64_sqr(a: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
var _v0: vec2<f32> = df64_twoSqr(a.x, _fp64_g);
_v0.y = (_v0.y + ((a.x * a.y) * 2.0));
return df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
}
fn df64_div(a: vec2<f32>, b: vec2<f32>, _fp64_g: f32) -> vec2<f32> {
let _v0 = (_fp64_g / b.x);
let _v1 = (a * _v0);
let _v2 = df64_sub(a, df64_mul(b, _v1, _fp64_g), _fp64_g).x;
let _v3 = df64_twoProd(_v0, _v2, _fp64_g);
return df64_add(_v1, _v3, _fp64_g);
}
fn df64_narrow(a: vec2<f32>) -> f32 {
return (a.x + a.y);
}
#version 300 es
precision highp float;
precision highp int;
out vec2 uv;
void main() {
uint vi = uint(gl_VertexID);
float _cse0 = ((float((vi & 1u)) * 4.0) - 1.0);
float _cse1 = ((float((vi >> 1u)) * 4.0) - 1.0);
gl_Position = vec4(_cse0, _cse1, 0.0, 1.0);
uv = vec2(((_cse0 * 0.5) + 0.5), ((_cse1 * 0.5) + 0.5));
}
#version 300 es
precision highp float;
precision highp int;
struct DF64Vec2 {
vec2 hi;
vec2 lo;
};
layout(std140) uniform Uniforms {
DF64Vec2 center;
vec2 resolution;
float zoom_exp;
float fp64;
} u;
uniform highp sampler2D _fp64;
vec2 df64_twoSum(float a, float b, float _fp64_g) {
float _v0 = (a + b);
float _v1 = (((_v0 * _fp64_g) - a) * _fp64_g);
float _v2 = (((a - ((_v0 - _v1) * _fp64_g)) * _fp64_g) + (b - _v1));
return vec2(_v0, _v2);
}
vec2 df64_quickTwoSum(float a, float b, float _fp64_g) {
float _v0 = ((a + b) * _fp64_g);
float _v1 = (b - ((_v0 - a) * _fp64_g));
return vec2(_v0, _v1);
}
vec2 df64_split(float a, float _fp64_g) {
float _v0 = (a * (_fp64_g * 4097.0));
float _v1 = ((_v0 * _fp64_g) - (_v0 - a));
float _v2 = ((a * _fp64_g) - _v1);
return vec2(_v1, _v2);
}
vec2 df64_twoProd(float a, float b, float _fp64_g) {
float _v0 = (a * b);
vec2 _v1 = df64_split(a, _fp64_g);
vec2 _v2 = df64_split(b, _fp64_g);
float _v3 = (((((_v1.x * _v2.x) - _v0) + (_v1.x * _v2.y)) + (_v1.y * _v2.x)) + (_v1.y * _v2.y));
return vec2(_v0, _v3);
}
vec2 df64_twoSqr(float a, float _fp64_g) {
float _v0 = (a * a);
vec2 _v1 = df64_split(a, _fp64_g);
float _v2 = (((((_v1.x * _v1.x) - _v0) * _fp64_g) + (((_v1.x * _v1.y) * 2.0) * _fp64_g)) + ((_v1.y * _v1.y) * _fp64_g));
return vec2(_v0, _v2);
}
vec2 df64_add(vec2 a, vec2 b, float _fp64_g) {
vec2 _v0 = df64_twoSum(a.x, b.x, _fp64_g);
vec2 _v1 = df64_twoSum(a.y, b.y, _fp64_g);
_v0.y = (_v0.y + _v1.x);
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
_v0.y = (_v0.y + _v1.y);
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
return _v0;
}
vec2 df64_sub(vec2 a, vec2 b, float _fp64_g) {
return df64_add(a, (-b), _fp64_g);
}
vec2 df64_mul(vec2 a, vec2 b, float _fp64_g) {
vec2 _v0 = df64_twoProd(a.x, b.x, _fp64_g);
_v0.y = (_v0.y + (a.x * b.y));
_v0 = df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
_v0.y = (_v0.y + (a.y * b.x));
return df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
}
vec2 df64_sqr(vec2 a, float _fp64_g) {
vec2 _v0 = df64_twoSqr(a.x, _fp64_g);
_v0.y = (_v0.y + ((a.x * a.y) * 2.0));
return df64_quickTwoSum(_v0.x, _v0.y, _fp64_g);
}
vec2 df64_div(vec2 a, vec2 b, float _fp64_g) {
float _v0 = (_fp64_g / b.x);
vec2 _v1 = (a * _v0);
float _v2 = df64_sub(a, df64_mul(b, _v1, _fp64_g), _fp64_g).x;
vec2 _v3 = df64_twoProd(_v0, _v2, _fp64_g);
return df64_add(_v1, _v3, _fp64_g);
}
float df64_narrow(vec2 a) {
return (a.x + a.y);
}
in vec2 uv;
layout(location = 0) out vec4 _ret;
void main() {
float _fp64_g = texelFetch(_fp64, ivec2(0, 0), 0).x;
float _cse5 = uintBitsToFloat(floatBitsToUint(0.0));
vec2 _licm0 = vec2(_cse5, _cse5);
float _v0 = pow(10.0, (-u.zoom_exp));
float _v1 = (uv.x * 2.0);
bool _cse0 = (uv.x < 0.5);
float _v2 = (_v1 - (_cse0 ? 0.0 : 1.0));
float _v3 = ((_v2 - 0.5) * _v0);
float _v4 = (((uv.y - 0.5) * _v0) * ((u.resolution.y / u.resolution.x) * 2.0));
float _v5 = 0.0;
float _v6 = 0.0;
float _v7 = 0.0;
vec2 _cse1 = vec2(u.center.hi.x, u.center.lo.x);
vec2 _cse2 = vec2(u.center.hi.y, u.center.lo.y);
if ((_cse0 || (u.fp64 < 0.5))) {
float _v8 = (df64_narrow(_cse1) + _v3);
float _v9 = (df64_narrow(_cse2) + _v4);
for (uint _v10 = 0u; (_v10 < 48u); _v10 = (_v10 + 1u)) {
float _v11 = ((_v8 * _v8) - (_v9 * _v9));
float _v12 = ((_v8 * _v9) * 2.0);
float _v13 = (((_v11 * _v8) - (_v12 * _v9)) - 1.0);
float _v14 = ((_v11 * _v9) + (_v12 * _v8));
float _v15 = (_v11 * 3.0);
float _v16 = (_v12 * 3.0);
float _v17 = (1.0 / ((_v15 * _v15) + (_v16 * _v16)));
float _v18 = (((_v13 * _v15) + (_v14 * _v16)) * _v17);
float _v19 = (((_v14 * _v15) - (_v13 * _v16)) * _v17);
_v8 = (_v8 - _v18);
_v9 = (_v9 - _v19);
if ((((_v18 * _v18) + (_v19 * _v19)) > 1e-14)) {
_v7 = (_v7 + 1.0);
}
}
_v5 = _v8;
_v6 = _v9;
} else {
vec2 _v20 = df64_add(_cse1, vec2(_v3, 0.0), _fp64_g);
vec2 _v21 = df64_add(_cse2, vec2(_v4, 0.0), _fp64_g);
vec2 _cse3 = df64_add(vec2(1.0, 0.0), _licm0, _fp64_g);
vec2 _cse4 = vec2(3.0, 0.0);
for (uint _v22 = 0u; (_v22 < 48u); _v22 = (_v22 + 1u)) {
vec2 _v23 = df64_sub(df64_sqr(_v20, _fp64_g), df64_sqr(_v21, _fp64_g), _fp64_g);
vec2 _v24 = (df64_mul(_v20, _v21, _fp64_g) * 2.0);
vec2 _v25 = df64_sub(df64_sub(df64_mul(_v23, _v20, _fp64_g), df64_mul(_v24, _v21, _fp64_g), _fp64_g), _cse3, _fp64_g);
vec2 _v26 = df64_add(df64_mul(_v23, _v21, _fp64_g), df64_mul(_v24, _v20, _fp64_g), _fp64_g);
vec2 _v27 = df64_mul(_v23, _cse4, _fp64_g);
vec2 _v28 = df64_mul(_v24, _cse4, _fp64_g);
vec2 _v29 = df64_div(_cse3, df64_add(df64_sqr(_v27, _fp64_g), df64_sqr(_v28, _fp64_g), _fp64_g), _fp64_g);
vec2 _v30 = df64_mul(df64_add(df64_mul(_v25, _v27, _fp64_g), df64_mul(_v26, _v28, _fp64_g), _fp64_g), _v29, _fp64_g);
vec2 _v31 = df64_mul(df64_sub(df64_mul(_v26, _v27, _fp64_g), df64_mul(_v25, _v28, _fp64_g), _fp64_g), _v29, _fp64_g);
_v20 = df64_sub(df64_add(_v20, _licm0, _fp64_g), df64_add(_v30, _licm0, _fp64_g), _fp64_g);
_v21 = df64_sub(df64_add(_v21, _licm0, _fp64_g), df64_add(_v31, _licm0, _fp64_g), _fp64_g);
if ((df64_narrow(df64_add(df64_sqr(_v30, _fp64_g), df64_sqr(_v31, _fp64_g), _fp64_g)) > 1e-14)) {
_v7 = (_v7 + 1.0);
}
}
_v5 = df64_narrow(_v20);
_v6 = df64_narrow(_v21);
}
float _lc0 = (_v5 - 1.0);
float _v32 = ((_lc0 * _lc0) + (_v6 * _v6));
float _gv0 = (_v5 + 0.5);
float _lc2 = (_v6 - 0.8660254037844386);
float _gv1 = (_gv0 * _gv0);
float _v33 = (_gv1 + (_lc2 * _lc2));
float _lc4 = (_v6 + 0.8660254037844386);
float _v34 = (_gv1 + (_lc4 * _lc4));
vec3 _v35 = (((_v32 <= _v33) && (_v32 <= _v34)) ? vec3(0.91, 0.34, 0.22) : ((_v33 <= _v34) ? vec3(0.2, 0.66, 0.88) : vec3(0.98, 0.78, 0.22)));
float _v36 = (1.0 - (_v7 / 48.0));
_ret = vec4((_v35 * mix(0.25, 1.0, _v36)), 1.0);
}

이 예제를 움직이는 컨트롤에 페이지가 넣을 값이 없어서, 이 페이지에는 그림이 없습니다.

WGSL과 GLSL 탭은 커밋 c66579bf의 컴파일러가 직접 낸 출력입니다. 컴파일러의 출력 검사가 구워 둔 골든 파일에서 그대로 읽어 왔습니다(emit-goldens.test.ts).

이 예제는 fn() 빌더 API로 작성해서 Playground의 편집기가 받지 않습니다.

GitHub의 파일

이 페이지 편집 문제 보고