클래스

클래스

클래스는 함수를 두른 구조체입니다. 디스패치가 정적이라 상속과 믹스인과 제네릭은 파일을 컴파일하는 동안 다 정해집니다.

  • 기반 타입 자리에 쓰는 파생 값

    기반 타입으로 읽기만 하며 메서드 선택이 같다고 입증하면 기반 표현을 한 번 구성합니다. 메서드 재정의, 수신 객체의 변경이나 별칭을 통한 관찰 가능한 변경은 이 입증 범위 밖입니다.

    TypeScript
    class Material {
    color: f32 = 0.5;
    response(): f32 { return this.color; }
    }
    class LeafMaterial extends Material {
    thickness: f32 = 1.;
    }
    function response(material: Material): f32 {
    return material.response();
    }
    export function leafResponse(): f32 {
    const material = new LeafMaterial();
    return response(material);
    }
    생성된 WGSL
    struct Material {
    color: f32,
    }
    struct LeafMaterial {
    color: f32,
    thickness: f32,
    }
    fn response(material: Material) -> f32 {
    return Material_response(material);
    }
    fn leafResponse() -> f32 {
    let material = LeafMaterial_new();
    return response(LeafMaterial_as_Material(material));
    }
  • 필드 없는 클래스

    인스턴스 필드 없이도 생성하고 메서드를 호출할 수 있습니다. 호스트 값은 {}이며, GPU에는 소스 값에 없는 내부 저장 멤버를 둡니다.

    TypeScript
    class Counter {
    next(value: f32): f32 { return value + 1.; }
    }
    export function next(value: f32): f32 {
    return new Counter().next(value);
    }
    생성된 WGSL
    struct Counter {
    _empty: u32,
    }
    fn Counter_new() -> Counter {
    var self_: Counter = Counter(0u);
    return self_;
    }
    fn Counter_next(self_: Counter, value: f32) -> f32 {
    return (value + 1.0);
    }
    fn next(value: f32) -> f32 {
    return Counter_next(Counter_new(), value);
    }
  • constructor와 new

    new는 Ray_new 호출입니다. 구조체를 지어 돌려줍니다.

    TypeScript
    class Ray {
    origin: vec3
    dir: vec3
    constructor(origin: vec3, dir: vec3) {
    this.origin = origin
    this.dir = dir
    }
    }
    생성된 WGSL
    fn Ray_new(origin: vec3<f32>, dir: vec3<f32>) -> Ray {
    let _cse0 = vec3<f32>(0.0, 0.0, 0.0);
    var self_: Ray = Ray(_cse0, _cse0);
    self_.origin = origin;
    self_.dir = dir;
    return self_;
    }
  • 메서드

    첫 매개변수가 구조체인 함수가 되고, this는 그 매개변수로 읽힙니다.

    TypeScript
    class Ray {
    origin: vec3
    dir: vec3
    at(t: f32): vec3 {
    return this.origin + this.dir * t
    }
    }
    생성된 WGSL
    fn Ray_at(self_: Ray, t: f32) -> vec3<f32> {
    return (self_.origin + (self_.dir * t));
    }
    fn hit(r: Ray) -> vec3<f32> {
    return Ray_at(r, 1.0);
    }
  • static 메서드

    수신자가 없는 함수가 되며, 클래스 이름을 앞에 답니다.

    TypeScript
    class Ray {
    origin: vec3
    dir: vec3
    static up(): vec3 {
    return vec3(0., 1., 0.)
    }
    }
    생성된 WGSL
    fn Ray_up() -> vec3<f32> {
    return vec3<f32>(0.0, 1.0, 0.0);
    }
  • this를 바꾸는 메서드

    객체를 바꾸는 메서드는 WGSL에서 포인터로, GLSL ES 3.00에서 inout으로 객체를 받습니다. orbit-inout

    TypeScript
    class Body {
    pos: vec3
    vel: vec3
    step(dt: f32): void {
    this.pos = this.pos + this.vel * dt
    }
    }
    생성된 WGSL
    fn Body_step(self_: ptr<function, Body>, dt: f32) {
    (*self_).pos = ((*self_).pos + ((*self_).vel * dt));
    }
  • extends와 super

    기반 클래스의 필드가 앞에 오고, 물려받은 메서드는 다시 하향 변환됩니다. super는 자기 함수가 됩니다. shape-inheritance

    TypeScript
    class Ring extends Circle {
    width: f32
    sdf(p: vec2): f32 {
    return abs(super.sdf(p)) - this.width
    }
    }
    생성된 WGSL
    struct Ring {
    center: vec2<f32>,
    radius: f32,
    width: f32,
    }
    fn Ring_sdf(self_: Ring, p: vec2<f32>) -> f32 {
    return (abs(Ring_super_Circle_sdf(self_, p)) - self_.width);
    }
  • abstract 클래스

    abstract 클래스에는 구조체가 없습니다. 하위 클래스가 저마다 필드와 메서드 복사본을 가집니다.

    TypeScript
    abstract class Shape {
    center: vec2
    abstract sdf(p: vec2): f32
    offset(p: vec2): vec2 {
    return p - this.center
    }
    }
    생성된 WGSL
    struct Disc {
    center: vec2<f32>,
    radius: f32,
    }
    fn Disc_offset(self_: Disc, p: vec2<f32>) -> vec2<f32> {
    return (p - self_.center);
    }
  • implements

    TypeScript만 검사합니다. 구조체는 그 클래스 자신의 필드입니다.

    TypeScript
    class Disc implements Placed {
    center: vec2
    radius: f32
    }
    생성된 WGSL
    struct Disc {
    center: vec2<f32>,
    radius: f32,
    }
  • 접근 제어자

    받아들이지만 셰이더에는 아무 뜻이 없습니다. 강제하는 쪽은 TypeScript입니다.

    TypeScript
    class Sphere {
    private center: vec3
    readonly radius: f32
    public hit(p: vec3): f32 {
    return length(p - this.center) - this.radius
    }
    }
    생성된 WGSL
    struct Sphere {
    center: vec3<f32>,
    radius: f32,
    }
    fn Sphere_hit(self_: Sphere, p: vec3<f32>) -> f32 {
    return (length((p - self_.center)) - self_.radius);
    }
  • 게터와 세터

    각각 모듈의 함수 Disc_get_area와 Disc_set_area가 되고, 읽기와 쓰기가 그 함수를 부릅니다. class-syntax

    TypeScript
    class Disc {
    radius: f32
    get area(): f32 {
    return this.radius * this.radius
    }
    }
    생성된 WGSL
    struct Disc {
    radius: f32,
    }
    fn Disc_get_area(self_: Disc) -> f32 {
    return (self_.radius * self_.radius);
    }
  • 믹스인 함수

    함수는 컴파일하는 동안 실행됩니다. 멤버는 클래스에 끼워 넣고, Tinted는 어디에도 생성되지 않습니다. mixin-surface

    TypeScript
    function Tinted<T extends AnyClass>(Base: T) {
    return class extends Base {
    tint: vec3
    lit(cover: f32): vec3 {
    return this.tint * cover
    }
    }
    }
    class TintedDisc extends Tinted(Disc) {
    }
    생성된 WGSL
    struct TintedDisc {
    center: vec2<f32>,
    radius: f32,
    tint: vec3<f32>,
    }
    fn TintedDisc_lit(self_: TintedDisc, cover: f32) -> vec3<f32> {
    return (self_.tint * cover);
    }
  • 제네릭 함수

    프로그램이 쓰는 타입 인자 조합마다 함수가 하나씩 생기고, pick이라는 이름은 없습니다. generic-helpers

    TypeScript
    function pick<T>(a: T, b: T, c: bool): T {
    return c ? a : b
    }
    생성된 WGSL
    fn pick_f32(a: f32, b: f32, c: bool) -> f32 {
    return select(b, a, c);
    }
    fn pick_vec3(a: vec3<f32>, b: vec3<f32>, c: bool) -> vec3<f32> {
    return select(b, a, c);
    }
  • 제네릭 클래스

    타입 인자 조합마다 구조체가 하나씩 생기고, 메서드도 조합마다 따로 생깁니다. generic-class

    TypeScript
    class Slot<T> {
    a: T
    b: T
    first(): T {
    return this.a
    }
    }
    생성된 WGSL
    struct Slot_f32 {
    a: f32,
    b: f32,
    }
    struct Slot_vec3 {
    a: vec3<f32>,
    b: vec3<f32>,
    }

이 페이지 편집 문제 보고