Plasma

Plasma

사인파를 여러 개 더해 만든 고전 플라스마에 RGB 팔레트로 색을 입혔습니다.

TypeScript로 쓰고 TypeShade가 컴파일한 Plasma 셰이더. 빌드할 때 렌더링함.
// ═══ typeshade example — a ShaderToy plasma, authored in the DSL ═══
//
// Ports the classic ShaderToy plasma (sum-of-sines → palette) to the DSL: a
// fullscreen-triangle vertex stage + a fragment stage driven by a {time,
// resolution} uniform. One DSL source emits WGSL (WebGPU) AND GLSL ES 3.00
// (WebGL2) plus its pipeline Reflection — the metadata a host needs to build the
// bind-group layout + pack the uniform. The /shader-dsl site page renders this live.
import { fn, module, vec3, vec4, sin } from '../src/index.js';
import { VsOut, vs, fullscreenUniforms } from './_fullscreen.js';
import type { ShaderExample } from './_shared.js';
const U = fullscreenUniforms();
// `vo` (vertex-out), NOT `in`: `in` is a reserved keyword in GLSL, so naming the
// fragment param `in` would emit `vec4 fs_impl(VsOut in)` — a hard WebGL2 compile error.
const fs = fn(
'fs',
{ vo: VsOut },
({ vo }) => {
const t = U.field.time;
const uv = vo.uv;
// sum-of-sines plasma field
const v = sin(uv.x.mul(10).add(t))
.add(sin(uv.y.mul(10).add(t)))
.add(sin(uv.x.add(uv.y).mul(10).add(t.mul(0.7))));
// map the field through an RGB palette
const col = vec3(sin(v), sin(v.add(2.094)), sin(v.add(4.188)))
.mul(0.5)
.add(0.5);
return vec4(col, 1);
},
{ stage: 'fragment', retAttr: '@location(0)' },
);
const plasmaModule = module({
structs: [U.struct, VsOut.decl],
bindings: [U.binding],
funcs: [vs, fs],
});
export const plasma: ShaderExample = {
id: 'plasma',
title: 'Plasma',
blurb:
'The classic sum-of-sines plasma folded through an RGB palette — the "hello shader". One DSL source, animated by a single time uniform.',
category: 'generic',
file: 'shadertoy-plasma.ts',
module: plasmaModule,
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>,
}
@group(0) @binding(0) var<uniform> U: Uniforms;
@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(vo: VsOut) -> @location(0) vec4<f32> {
let _cse0 = ((sin(((vo.uv.x * 10.0) + U.time)) + sin(((vo.uv.y * 10.0) + U.time))) + sin((((vo.uv.x + vo.uv.y) * 10.0) + (U.time * 0.7))));
return vec4<f32>(((vec3<f32>(sin(_cse0), sin((_cse0 + 2.094)), sin((_cse0 + 4.188))) * 0.5) + 0.5), 1.0);
}
#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;
layout(std140) uniform Uniforms {
float time;
vec2 resolution;
} U;
in vec2 uv;
layout(location = 0) out vec4 _ret;
void main() {
float _cse0 = ((sin(((uv.x * 10.0) + U.time)) + sin(((uv.y * 10.0) + U.time))) + sin((((uv.x + uv.y) * 10.0) + (U.time * 0.7))));
_ret = vec4(((vec3(sin(_cse0), sin((_cse0 + 2.094)), sin((_cse0 + 4.188))) * 0.5) + 0.5), 1.0);
}

Plasma. 빌드할 때 그린 화면입니다.

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

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

GitHub의 파일

이 페이지 편집 문제 보고