Discard cutout
가운데 원 바깥에서는 픽셀을 버리고 안쪽에서는 채움 색을 돌려주는 프래그먼트 헬퍼입니다. 프래그먼트 IO 구조체 생성자에 인자로 한 번 넣습니다.
// ═══ typeshade example — discard cutout (#1840 GLSL-legalize coverage) ═══//// A fragment helper discards outside a centred circle and returns the fill colour;// the fragment stage calls it ONCE, as the sole argument of the fragment IO-struct's// `.construct({...})` — the exact shape ANGLE's D3D11 backend miscompiles when the// discarding call is left inline in a GLSL struct constructor (glsl-legalize.ts,// #1840). This example's GLSL golden pins the `_dh0` local the legalize pass// hoists it into; the WGSL golden stays the untouched inline call (WGSL has no// such backend bug, so it is byte-untouched by design).
import { fn, module, ioStruct, vec3, vec4, location, vec2fT, vec4fT, If, Discard, Let, length, mix,} from '../src/index.js';import { VsOut, vs, fullscreenUniforms, screenCoords } from './_fullscreen.js';import type { ShaderExample } from './_shared.js';
const U = fullscreenUniforms();
const FsOut = ioStruct('FsOut', { color: location(0, vec4fT) });
// Discards outside the unit circle; inside, a radial gradient from a bright// centre to a dim rim.const discardOutsideCircle = fn('discard_outside_circle', { p: vec2fT }, ({ p }) => { const r = Let(length(p)); If(r.gt(1), () => { Discard(); }); return vec4(mix(vec3(1, 1, 1), vec3(0.06, 0.1, 0.35), r), 1);});
const fs = fn( 'fs', { vo: VsOut }, ({ vo }) => { const p = screenCoords(vo.uv, U.field.resolution); return FsOut.construct({ color: discardOutsideCircle({ p }) }); }, { stage: 'fragment' },);
const discardCutoutModule = module({ structs: [U.struct, VsOut.decl, FsOut.decl], bindings: [U.binding], funcs: [vs, fs],});
export const discardCutout: ShaderExample = { id: 'discard-cutout', title: 'Discard cutout', blurb: "A fragment helper discards outside a centred circle and returns the fill colour, called once as the fragment IO-struct's constructor argument — the exact shape ANGLE's D3D11 backend miscompiles when left inline (#1840). Renders a clean circular cutout with a radial centre-to-rim gradient.", category: 'generic', file: 'discard-cutout.ts', module: discardCutoutModule, renderable: true, controls: { time: { kind: 'time' }, resolution: { kind: 'resolution' }, },};struct Uniforms { time: f32, resolution: vec2<f32>,}
struct VsOut { @builtin(position) pos: vec4<f32>, @location(0) uv: vec2<f32>,}
struct FsOut { @location(0) color: vec4<f32>,}
@group(0) @binding(0) var<uniform> U: Uniforms;
fn discard_outside_circle(p: vec2<f32>) -> vec4<f32> { let _v0 = length(p); if ((_v0 > 1.0)) { discard; } return vec4<f32>(mix(vec3<f32>(1.0, 1.0, 1.0), vec3<f32>(0.06, 0.1, 0.35), _v0), 1.0);}
@vertexfn 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)));}
@fragmentfn fs(vo: VsOut) -> FsOut { return FsOut(discard_outside_circle(vec2<f32>((((vo.uv.x * 2.0) - 1.0) * (U.resolution.x / U.resolution.y)), ((vo.uv.y * 2.0) - 1.0))));}#version 300 esprecision 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 esprecision highp float;precision highp int;
layout(std140) uniform Uniforms { float time; vec2 resolution;} U;vec4 discard_outside_circle(vec2 p) { float _v0 = length(p); if ((_v0 > 1.0)) { discard; } return vec4(mix(vec3(1.0, 1.0, 1.0), vec3(0.06, 0.1, 0.35), _v0), 1.0);}in vec2 uv;layout(location = 0) out vec4 color;
void main() { vec4 _dh0 = discard_outside_circle(vec2((((uv.x * 2.0) - 1.0) * (U.resolution.x / U.resolution.y)), ((uv.y * 2.0) - 1.0))); color = _dh0;}Discard cutout. 빌드할 때 그린 화면입니다.
WGSL과 GLSL 탭은 커밋 c66579bf의 컴파일러가 직접 낸 출력입니다. 컴파일러의 출력 검사가 구워 둔 골든 파일에서 그대로 읽어 왔습니다(emit-goldens.test.ts).
이 예제는 fn() 빌더 API로 작성해서 Playground의 편집기가 받지 않습니다.