import { Expr } from '../../gpu/contract'; import { SurfaceFrame, SurfaceField } from './materials'; /** The line of sight through a shape's interior, from `interiorRay`. */ export interface InteriorRay { /** The depth at which the ray enters the shape. 0 for flat shapes. */ entry: Expr; /** How far the ray travels inside the shape, roughly 0–1. */ length: Expr; /** The position inside the shape at depth `z` along the ray. */ at(z: Expr): { x: Expr; y: Expr; }; } /** * The line of sight through a shape: where it enters, how far it travels inside, and where it is at any depth. * * Pass the material's `field` and `frame`, the point the ray enters at (`origin`, usually the * shape's centred placement coordinates) and optionally the `view` ray. `shear` (default 1) * sets how far deeper samples slide sideways along the view, which is what makes an interior * read as deep rather than flat. `lengthScale` stretches or shortens the travel. On a 3D shape * `length` is the real chord through it. On a flat shape it stands in for depth, growing * toward the middle of the shape. * * @example * ```ts * const ray = interiorRay(field, frame, {origin: interior, view, shear: 0.55}) * ``` * @tip Refract `origin` through the shell first (`shellRefract`) and the interior bends at the glass walls. * @see volumeMarch, parallaxPlane, turbulentMedium */ export declare function interiorRay(field: SurfaceField, frame: SurfaceFrame, opts: { origin: { x: Expr; y: Expr; }; view?: Expr; shear?: number; lengthScale?: number; }): InteriorRay; /** * A flat layer at a fixed depth inside the shape, like scenery seen through a window. * * `depth` is a fraction of the ray's length: 0 at the entry, 1 at the far side, beyond 1 for a * backdrop behind the shape. Give it a `pan` (the `rotationSensor` of the frame) and the layer * slides as the shape rotates, `panRate` times as far. Deeper layers with higher rates give * the parallax of real depth. Returns the position to sample content at, plus its depth `z`. * * @example * ```ts * const far = parallaxPlane(ray, {depth: 1.1, pan: rotationSensor(frame), panRate: 1.3, hint: 'far'}) * ``` * @tip Two planes at different depths and rates are enough to sell a starfield. * @see interiorRay, volumeMarch */ export declare function parallaxPlane(ray: InteriorRay, opts: { depth: number; pan?: { x: Expr; y: Expr; }; panRate?: number; hint?: string; }): { x: Expr; y: Expr; z: Expr; }; /** * A billowing cloud density at a point inside the shape. * * `frequency` sets how many cloud cells fit across the shape. `drift` is a time value that * moves the clouds. `seed` moves to a different part of the cloud so two instances differ. * `billow` (0–1) folds the clouds over themselves for a cumulus look. `density` is signed, * roughly −1 to 1: threshold it with `smoothstep` to make clouds with clear gaps. `mid` and * `fine` are two finer layers of the same cloud, free to use for dust bands or wisps. * * @example * ```ts * const gas = turbulentMedium({x: pos.x, y: pos.y, z}, {frequency: math.mul(u.gasScale, 3), drift: t, billow: math.float(0.4)}) * ``` * @tip Inside a `volumeMarch`, pass the step number as `hint` so each step gets its own values. * @see volumeMarch, interiorRay */ export declare function turbulentMedium(p: { x: Expr; y: Expr; z: Expr; }, opts: { frequency: Expr; drift?: Expr; seed?: Expr; billow?: Expr; hint?: string; }): { density: Expr; mid: Expr; fine: Expr; }; /** One sample along a `volumeMarch`, handed to its callback. */ export interface VolumeMarchStep { /** The step number, 0 first. A plain number, handy for naming per-step values. */ i: number; /** How far along the ray this step sits, 0–1. A plain number. */ t: number; /** The depth of this sample along the ray, to pass to `ray.at`. */ z: Expr; } /** * Walk a ray through the medium front to back, adding up what glows and what dims. * * `steps` is how many samples to take (4–8 is typical; it is fixed when the shader compiles). * `entry` and `length` come from `interiorRay`. For each step your callback returns `emit`, the * rgb light this sample gives off, and `absorb`, the rgb amount it blocks. Absorption is per * channel, so a medium can dim blue more than red. Returns the accumulated `color` and the * `transmittance` left at the far side: multiply anything behind the medium by it. `jitter` * is a small per-pixel offset along the ray, as a fraction of its length (a hash times * `1 / steps` works), that trades banding for fine grain. `emissionGain` scales every * sample's glow; use `k / steps` so brightness does not change with the step count. * * @example * ```ts * const march = volumeMarch({steps: 6, entry: ray.entry, length: ray.length, jitter}, ({z, i}) => ({emit: math.mul(rgb, dens), absorb: math.splat3(math.mul(dens, u.density))})) * ``` * @tip Fewer steps plus `jitter` beats more steps: the noise becomes grain instead of bands. * @see interiorRay, turbulentMedium, parallaxPlane */ export declare function volumeMarch(opts: { steps: number; entry: Expr; length: Expr; /** A per-pixel offset added to each step's position along the ray, as a fraction of the ray. */ jitter?: Expr; /** A multiplier on every sample's `emit`. */ emissionGain?: Expr; hint?: string; }, sample: (step: VolumeMarchStep) => { emit: Expr; absorb: Expr; }): { color: Expr; transmittance: Expr; }; //# sourceMappingURL=volume.d.ts.map