import { GpuComputeNode, GpuFragmentParams, KitTexture, Expr } from '../../gpu/contract'; import { DirectionFrame } from '../frames'; /** * Evaluates an expression only where a condition holds, and a cheap fallback everywhere else. * * Use it to skip a material's whole body for pixels outside the shape. Any value you build * inside `inner` and also read after the guard must be listed in `deps`. * * @example * ```ts * return guarded(insideShape(field.sdf, field.pxH), vec4(rgb, silhouette(field, u.edgeSoftness)), vec4(0, 0, 0, 0), 'plastic') * ``` * @tip Values first made inside the guard are not visible after it. Put shared locals in `deps`. * @see insideShape, silhouette */ export declare function guarded(cond: Expr, inner: Expr, fallback: Expr, hint?: string, deps?: Expr[]): Expr; export { reflect, refract, exp2 } from '../math'; /** * True inside the shape and up to two pixels outside it. * * Pass the signed distance and pixel size from `surfaceField`. The two-pixel margin keeps the * anti-aliased edge inside the shaded region. The usual condition for `guarded`. * * @example * ```ts * guarded(insideShape(field.sdf, field.pxH), shaded, vec4(0, 0, 0, 0)) * ``` * @see guarded, silhouette */ export declare function insideShape(sdf: Expr, pxH: Expr): Expr; /** * What `shapedSurface` hands your `surface` function: the shape's distance field, sampled and * ready to shade. * * Read the taps through `surfaceField` rather than directly. `volumetric` tells you at build * time whether the shape is a 3D one (a sphere, a cube, an extruded SVG) or a flat one. */ export interface SurfaceFrame { /** Placement coordinates: the shape's own 0–1 square after center, scale and rotation. Absent with `stencil: 'none'`. */ sdfUV?: Expr; /** The field at this pixel. `.x` is the signed distance (negative inside), `.y/.z` pattern coordinates, `.w` depth. */ surf0?: Expr; /** The field one step right and one step down, when the stencil took them. */ surfX?: Expr; surfY?: Expr; /** The field one step left and one step up. Only with `stencil: {kind: 'central'}`. */ surfL?: Expr; surfD?: Expr; /** Sample the field at any placement coordinate, at full quality. */ sampler: (uv: Expr) => Expr; /** Sample the field at any placement coordinate, cheaply. Use it for neighbour taps. */ gradSampler: (uv: Expr) => Expr; /** Sample one texel without filtering, for discrete data packed into the field. */ texelSampler: (uv: Expr) => Expr; /** True when the shape is 3D or extruded. Known at build time, so you can branch in TypeScript. */ volumetric: boolean; /** `volumetric` as a 0/1 number, for use inside an expression. */ volFlag: Expr; /** True when `.y/.z` already hold the field's gradients instead of pattern coordinates. Skip your own slope taps. */ bakedGradients: boolean; /** The layer inside, as a texture. Present with `child: 'required'`. */ childTexture?: KitTexture; } /** The options `shapedSurface` takes. Only `surface` is required. */ export interface ShapedSurfaceSpec { /** Bake surface coordinates for 3D shapes so a pattern sticks to them (default 'none'). 'raw' follows the surface without seams, 'triplanar' projects from three sides. */ pattern?: 'none' | 'raw' | 'triplanar'; /** How thickness is measured through a 3D shape (default 'span'). 'firstLobe' measures the front wall only. */ chord?: 'span' | 'firstLobe'; /** Quality of the neighbour taps (default 'fast'). 'same' uses the full-quality sampler for them too. */ gradSampler?: 'fast' | 'same'; /** Let the field carry its own gradients in `.y/.z` (default 'none'). Check `frame.bakedGradients` before taking slopes. */ bakedGradients?: 'none' | 'volumetric' | 'all'; /** Which taps to take for you (default a right-and-down pair, `eps` 0.01 in placement units). 'none' takes none, 'centre' this pixel only, 'central' adds left and up. */ stencil?: 'none' | 'centre' | { kind: 'forward' | 'central'; eps: number; }; /** * Which sampler takes the centre tap (default 'quality'). 'fast' is cheaper on 3D shapes * when the centre tap only gates coverage and the material takes its own quality tap * where it needs one. */ centreTap?: 'quality' | 'fast'; /** Displace the canvas uv before placement, to wobble or warp the whole shape. */ placeUV?: (params: GpuFragmentParams) => Expr; /** Require the layer inside and expose it as `frame.childTexture`. Without a child the effect draws nothing. */ child?: 'required'; /** Your material: shade the frame and return the color at this pixel. */ surface: (frame: SurfaceFrame, params: GpuFragmentParams) => Expr; } /** The three fields `shapedSurface` returns. Spread them into your definition. */ export interface ShapedSurfaceEffect { extraFields: Record; compute: GpuComputeNode; gpu: { fragment: (params: GpuFragmentParams) => Expr; }; } /** * Turns a shape prop into a surface your material shades. * * Spread the result into a definition that declares the `center`, `scale`, `rotation` and * `shape` props (copy them from any shape effect). Your `surface` function receives a * `SurfaceFrame` and returns the color at this pixel. Flat shapes, SVG shapes and 3D shapes * all arrive through the same frame. * * @example * ```ts * ...shapedSurface({ * pattern: 'raw', * surface: (frame, params) => { * const u = params.uniforms * const field = surfaceField(frame, params, {scale: u.scale}) * const n = geometricNormal(frame, field, {bevelWidth: u.bevelWidth, bevelShape: u.bevelShape}) * const key = keyLightAt(direction(u.lightAngle), -0.7) * const rgb = mul(u.color.member('rgb'), lambert(n, key.member('L'), {wrap: 0.3})) * return guarded(insideShape(field.sdf, field.pxH), vec4(rgb, silhouette(field, u.edgeSoftness)), vec4(0, 0, 0, 0)) * }, * }), * ``` * @tip Start from `surfaceField`, end with `guarded` around `insideShape`. Everything between is the look. * @see surfaceField, geometricNormal, silhouette, guarded */ export declare function shapedSurface(spec: ShapedSurfaceSpec): ShapedSurfaceEffect; /** The field values a material reads, bound once: the taps, the signed distance and the pixel size. */ export interface SurfaceField { /** The field at this pixel, and one step right and one step down when the stencil took them. */ s0: Expr; sX?: Expr; sY?: Expr; /** Signed distance to the shape's edge: negative inside, zero on the edge. */ sdf: Expr; /** One pixel, as a fraction of the canvas height. */ pxH: Expr; /** Canvas width divided by height. */ aspect: Expr; } /** * The first line of a material: the field taps, the signed distance and the pixel size, bound once. * * Pass `scale` (the shape's scale prop) to divide the distance by it, as the library's metals * and plastics do, so edge softness and pixel tests track the shape's size. Leave it out for * `continuedField`. * * @example * ```ts * const field = surfaceField(frame, params, {scale: params.uniforms.scale}) * ``` * @see shapedSurface, geometricNormal, silhouette, insideShape */ export declare function surfaceField(frame: SurfaceFrame, params: GpuFragmentParams, opts?: { scale?: Expr; }): SurfaceField; /** * The surface normal of the shape, whichever kind of shape is active. * * A 3D shape takes its normal from the marched depth. A flat shape takes a normal that tilts * away from the face near the edge, over `bevelWidth` (in the units of `field.sdf`) with the * profile `bevelShape` (0 round, 1 machined). `sharpness` clamps the 3D slope (default 5, lower * is calmer). `eps` must match the stencil step (default 0.01). Needs a stencil with neighbour taps. * * @example * ```ts * const n = geometricNormal(frame, field, {bevelWidth: u.bevelWidth, bevelShape: u.bevelShape}) * ``` * @tip Add relief with `nudgeNormal` or `tiltNormal` after this, never before. * @see marchedNormal, nudgeNormal, tiltNormal, fieldSlope */ export declare function geometricNormal(frame: SurfaceFrame, field: SurfaceField, opts: { bevelWidth: Expr; bevelShape: Expr; sharpness?: number; eps?: number; hint?: string; }): Expr; /** * Coordinates for a pattern that sticks to the shape's surface. * * On a flat shape they are the placement coordinates centred on the shape (0,0 at its centre). * On a 3D shape they follow the surface as it rotates, when the effect declares * `pattern: 'raw'` or `'triplanar'`. * * @example * ```ts * const pat = surfacePattern(frame, field) * ``` * @see shapedSurface, rotationSensor, surfaceNoiseAt */ export declare function surfacePattern(frame: SurfaceFrame, field: SurfaceField, opts?: { uv?: Expr; }): Expr; /** * The direction the shape's distance grows in: a 2D vector pointing outward at this pixel. * * Its length is about 1 on a flat shape. `eps` is the tap step (default 0.01) and must match * the stencil step. * * @example * ```ts * const grad = fieldSlope(field) * ``` * @see nearestEdge, geometricNormal, tiltAlong */ export declare function fieldSlope(field: SurfaceField, eps?: number): Expr; /** * The direction the viewer looks along at this pixel, for reflections that sweep across a face. * * A unit 3D vector pointing into the canvas. `fov` sets how much it leans off-axis toward * the edges (0.6 is the usual value, 0.55 flatter). * * @example * ```ts * const view = viewRay(params, field) * ``` * @see grazingOf, reflect, studioSoftboxes */ export declare function viewRay(params: GpuFragmentParams, field: Pick, fov?: number): Expr; /** * How edge-on the surface is to the viewer: 0 face-on, 1 grazing. * * The input the fresnel words take when you have a view ray. Without one, use `grazingFlat`. * * @example * ```ts * const grazing = grazingOf(n, viewRay(params, field)) * ``` * @see grazingFlat, fresnelBoost, schlickFresnel */ export declare function grazingOf(n: Expr, view: Expr): Expr; /** * Tilts a normal along and across a direction, for brushed or woven relief. * * `frame` is a `directionFrame` (from `frames`). `along` and `across` are slope amounts; a * few tenths is a visible relief. * * @example * ```ts * const n = tiltNormal(nGeo, brush, {across: reliefAcross, along: reliefAlong}) * ``` * @see nudgeNormal, tiltAlong, grainNoise */ export declare function tiltNormal(n: Expr, frame: DirectionFrame, slopes: { along?: Expr; across?: Expr; }, hint?: string): Expr; /** * The brightness of a five-light studio seen in a reflected direction. * * Pass the x and y of a reflected view ray. `rotation` is a `direction()` vector that turns * the studio. `keyRadius` sizes the main light (0.16 crisp, 0.42 soft), `drift` slides it, * `strength` scales the whole bank and `skyGain` the floor-to-sky gradient behind it (0.3–0.4). * * @example * ```ts * const env = studioSoftboxes(R.member('x'), R.member('y'), {rotation: direction(u.envRotation), keyRadius: 0.3, drift: 0, strength: u.environment, skyGain: 0.38}) * ``` * @tip Smear it with `smearAlong` for a brushed look. * @see smearAlong, reflect, viewRay */ export declare function studioSoftboxes(x: Expr, y: Expr, opts: { /** A `direction()` vector that rotates the studio. */ rotation: Expr; keyRadius: Expr | number; drift: Expr | number; strength: Expr | number; skyGain: number; }): Expr; /** * One octave of smooth signed noise along and across a direction, for grain. * * `coords` come from `directionFrame(...).coordsOf(p)`. `freq` sets the feature density per * axis (a high across value gives fine streaks). Returns roughly −1 to 1. Sum octaves and * apply gains at the call site. * * @example * ```ts * const sheen = grainNoise(brush.coordsOf(pat), {freq: [1.3, 6.5], drift: driftA}) * ``` * @see surfaceNoise, tiltNormal, smearAlong */ export declare function grainNoise(coords: { along: Expr; across: Expr; }, opts: { freq: [Expr | number, Expr | number]; offset?: [number, number]; drift?: Expr; }): Expr; /** * Blurs any 2D lookup along a direction, for streaked reflections and motion smear. * * Samples `taps` points (default 9) spread `spread` either side of `center` along the unit * vector `axis`, weighted by a bell curve, and sums them. `sample` receives an x and a y. * * @example * ```ts * const env = smearAlong({center: R, axis: brush.tangent, spread: 0.3}, (x, y) => studioSoftboxes(x, y, studio)) * ``` * @see studioSoftboxes, grainNoise */ export declare function smearAlong(opts: { center: Expr; axis: Expr; spread: Expr; taps?: number; sigma?: number; hint?: string; }, sample: (x: Expr, y: Expr) => Expr): Expr; /** * A 3D light direction from a `direction()` vector and an elevation. * * `z` is negative for a light on the viewer's side of the surface (−0.6 raking to −0.9 * frontal). Use it where a word wants a unit light vector. `keyLightAt` also gives the half * vector for highlights. * * @example * ```ts * const L = lightVec3(direction(u.lightAngle), -0.7) * ``` * @see keyLightAt, anisoSpecular, lambert */ export declare function lightVec3(dir: Expr, z: number, hint?: string): Expr; /** * Turns roughness and anisotropy sliders (0–1 each) into the two lobe widths `anisoSpecular` takes. * * Higher roughness widens the highlight. Higher anisotropy stretches it along the grain and * squeezes it across. * * @example * ```ts * alphas: wardAlphas(u.roughness, u.anisotropy) * ``` * @see anisoSpecular */ export declare function wardAlphas(roughness: Expr | number, anisotropy: Expr | number): { along: Expr; across: Expr; }; /** * A highlight stretched along a grain, as on brushed metal or carbon fibre. * * `tangent` is the 2D grain direction, `light` a unit 3D light vector, `view` the view ray * and `alphas` the widths from `wardAlphas`. Pass `gain` or scale the result yourself. * * @example * ```ts * const spec = anisoSpecular({normal: n, tangent: brush.tangent, light: lightVec3(direction(u.lightAngle), -0.7), view, alphas: wardAlphas(rough, aniso), gain: u.specular}) * ``` * @see wardAlphas, lightVec3, sharpGlint, dualLobeGlint */ export declare function anisoSpecular(opts: { normal: Expr; /** The 2D grain direction. */ tangent: Expr; /** A unit 3D light direction (see `lightVec3`). */ light: Expr; view: Expr; alphas: { along: Expr; across: Expr; }; gain?: Expr | number; }): Expr; /** * Tilts a normal along one 2D direction by a slope amount. * * `axis` is a unit 2D vector such as `direction()` or `fieldSlope`. A few tenths is a * visible tilt. * * @example * ```ts * const n = tiltAlong(nGeo, weaveDir, mul(crown, 0.3)) * ``` * @see tiltNormal, nudgeNormal */ export declare function tiltAlong(n: Expr, axis: Expr, amount: Expr, hint?: string): Expr; /** * A multiplier that brightens grazing edges: 1 face-on, up to `1 + amount` at the rim. * * `grazing` comes from `grazingOf` or `grazingFlat`. `power` (default 3) sets how tightly * the lift hugs the rim. * * @example * ```ts * const lit = mul(env, fresnelBoost(grazingOf(n, view), {amount: 0.6})) * ``` * @see schlickFresnel, grazingOf, grazingFlat */ export declare function fresnelBoost(grazing: Expr, opts: { power?: number; amount: Expr | number; }): Expr; /** * Maps a lighting value (0 dark, 1 light) onto two colors. * * Takes color props and returns rgb. The final tint of a material lit in grey. * * @example * ```ts * const rgb = tintRamp(lit, u.darkColor, u.lightColor) * ``` * @see neutralTone, cosineRainbow */ export declare function tintRamp(t: Expr, dark: Expr, light: Expr): Expr; /** * The shape's coverage at this pixel: 1 inside, 0 outside, soft across the edge. * * `edgeSoftness` is the softness prop; at 0 the edge is still anti-aliased over 1.5 pixels. * Use it as the alpha of the color you return. * * @example * ```ts * return guarded(insideShape(field.sdf, field.pxH), vec4(rgb, silhouette(field, u.edgeSoftness)), vec4(0, 0, 0, 0)) * ``` * @see insideShape, guarded */ export declare function silhouette(field: SurfaceField, edgeSoftness: Expr): Expr; /** * Compresses bright color back into range without shifting its hue. * * The last step of a metal or glass look that adds reflection on top of a base color. * `exposureTone` is the cousin for emitted light. * * @example * ```ts * const rgb = neutralTone(mul(env, u.tint.member('rgb'))) * ``` * @see exposureTone */ export declare function neutralTone(rgb: Expr): Expr; /** * Tilts a normal by a slope in x and y, turning a height field into relief. * * Feed it the `dx`/`dy` of `fdSlope` or `perlinSlope`, scaled by how strong you want the * relief. Works on a flat `vec3(0, 0, -1)` normal as well as a shape's normal. * * @example * ```ts * const n = nudgeNormal(vec3(0, 0, -1), mul(relief.dx, 0.08), mul(relief.dy, 0.08)) * ``` * @see fdSlope, perlinSlope, tiltNormal, geometricNormal */ export declare function nudgeNormal(n: Expr, dx: Expr, dy: Expr, hint?: string): Expr; /** * The surface normal of a 3D shape, from the marched depth. * * Only meaningful when `frame.volumetric` is true. `geometricNormal` chooses between this * and the flat-shape normal for you. `sharpness` clamps the slope (default 5; 4 is calmer, * 6 crisper). * * @example * ```ts * const n = frame.volumetric ? marchedNormal(field, 4) : flatNormal * ``` * @see geometricNormal */ export declare function marchedNormal(field: SurfaceField, sharpness?: number, hint?: string): Expr; /** * A key light from an angle: the light direction `.L` and the half vector `.H` for highlights. * * `dir` is a `direction()` vector (from `frames`). `elevation` is how far the light sits * toward the viewer: −0.6 raking, −0.9 frontal. Read `.L` with `member('L')` for `lambert` * and `.H` for a glint. * * @example * ```ts * const key = keyLightAt(direction(u.lightAngle), -0.7) * ``` * @tip Elevation is negative in this engine. A positive value lights the surface from behind. * @see keyLightXY, lightVec3, lambert, dualLobeGlint, sharpGlint */ export declare function keyLightAt(dir: Expr, elevation: number, hint?: string): Expr; /** * A key light from explicit x and y components, for a second or a crossed light. * * Same result as `keyLightAt`: `.L` and `.H`. * * @example * ```ts * const fill = keyLightXY(mul(ly, -1), lx, -0.4, 'fill') * ``` * @see keyLightAt */ export declare function keyLightXY(x: Expr, y: Expr, elevation: number, hint?: string): Expr; /** * How edge-on the surface is to a straight-on viewer: 0 face-on, 1 grazing. * * Use it when the material has no `viewRay`. The fresnel input for plastics, frost and water. * * @example * ```ts * const grazing = grazingFlat(n) * ``` * @see grazingOf, schlickFresnel, fresnelBoost */ export declare function grazingFlat(n: Expr): Expr; /** * A highlight whose tightness follows a sharpness slider. * * `ndh` is the dot of the normal and the key light's `.H`. `sharpness` runs 0–1 and slides * the exponent from `cfg.x` to `cfg.y` and the gain from `cfg.z` to `cfg.w`. Pass `cfg` as * `vec4(soft exponent, sharp exponent, soft gain, sharp gain)`. * * @example * ```ts * const spec = sharpGlint(dot(n, key.member('H')), u.sharpness, vec4(60, 900, 0.4, 1.4)) * ``` * @see dualLobeGlint, anisoSpecular, keyLightAt */ export declare function sharpGlint(ndh: Expr, sharpness: Expr, cfg: Expr): Expr; /** * The slope of smooth noise at a point, for wavy or molten relief. * * Returns a 2D slope scaled by `gain` and clamped to ±4, so relief never spikes into seams. * Feed its x and y to `nudgeNormal`. * * @example * ```ts * const hg = perlinSlope(pat, 0.62) * const n = nudgeNormal(nGeo, mul(hg.member('x'), -0.5), mul(hg.member('y'), -0.5)) * ``` * @see nudgeNormal, fdSlope, flowWarp */ export declare function perlinSlope(q: Expr, gain: Expr | number): Expr; /** * How much material the view passes through at this pixel: 0 at the edge, up to about 1.2 deep inside. * * Multiply by a density prop and feed `beerLambert` for glass, ice and water. * * @example * ```ts * const thickness = mul(opticalThickness(field, frame), u.density) * ``` * @see beerLambert */ export declare function opticalThickness(field: SurfaceField, frame: SurfaceFrame): Expr; /** * How much light survives a thickness of tinted material, per channel. * * `absorb` is an rgb absorption; higher absorbs more. Returns rgb transmission 0–1. * Multiply the color behind by it. * * @example * ```ts * const transmit = beerLambert(mul(opticalThickness(field, frame), u.density), absorb) * ``` * @see opticalThickness */ export declare function beerLambert(thickness: Expr, absorb: Expr): Expr; /** * A slowly folding 2D offset to add to pattern coordinates, for molten or wind-blown motion. * * `warpInput` is the pattern coordinate scaled by about 0.6, `flowT` the layer's clock times a * speed. Add the result to the coordinate before sampling noise. * * @example * ```ts * const q = add(pat, mul(flowWarp(mul(pat, 0.6), flowT), u.warp)) * ``` * @see surfaceNoiseAt, perlinSlope */ export declare function flowWarp(warpInput: Expr, flowT: Expr): Expr; /** * Smooth signed noise at a 2D point, roughly −1 to 1, with features about one unit wide. * * The basis for grain, crumple and frost. Scale the inputs to set the feature size. * * @example * ```ts * const grain = surfaceNoise(mul(pat.member('x'), 140), mul(pat.member('y'), 140)) * ``` * @see surfaceNoiseAt, valueNoise, hashNoise, grainNoise */ export declare function surfaceNoise(x: Expr | number, y: Expr | number): Expr; /** * `surfaceNoise` at a 2D point you already hold. * * @example * ```ts * const n = surfaceNoiseAt(mul(pat, 6)) * ``` * @see surfaceNoise, volumeNoiseAt, cellNoiseAt */ export declare function surfaceNoiseAt(p: Expr): Expr; /** * Smooth signed noise at a 3D point, roughly −1 to 1. * * For anything sampled through a body rather than across its surface: gas, smoke, * inclusions, density. * * @example * ```ts * const density = volumeNoiseAt(vec3(pos.member('x'), pos.member('y'), t)) * ``` * @see surfaceNoiseAt */ export declare function volumeNoiseAt(p: Expr): Expr; /** * A smooth rainbow color from a value that wraps every 1. * * `phases` offset the red, green and blue cycles; `[0, 1/3, 2/3]` is the full spectrum. The * color behind holographic foil and thin-film iridescence. * * @example * ```ts * const rgb = cosineRainbow(mul(grazing, 3), [0, 1 / 3, 2 / 3]) * ``` * @see tintRamp */ export declare function cosineRainbow(t: Expr, phases: [number, number, number]): Expr; /** * Cellular noise at a 2D point: 0 at each cell's seed point, rising toward the cell walls. * * The value is a squared distance in cell units. Use it for facets and cracks, or as the * field `fdSlope` differentiates for faceted relief. * * @example * ```ts * const facet = fdSlope(cellNoiseAt, mul(pat, 6), 0.002) * ``` * @see fdSlope, surfaceNoiseAt, pointStars */ export declare function cellNoiseAt(p: Expr): Expr; /** * The value and slope of any field at a point: `value`, `dx` and `dy`. * * `sampleAt` is the field as a function of a 2D point, `eps` the tap distance in that point's * units (a few thousandths in uv). The bridge from a height field to a normal: feed `dx` and * `dy` to `nudgeNormal`. * * @example * ```ts * const relief = fdSlope((at) => heightField(params, at), uv, 0.0035) * ``` * @tip Three taps of the field per pixel. Keep the field cheap or `share` it. * @see nudgeNormal, perlinSlope, cellNoiseAt */ export declare function fdSlope(sampleAt: (p: Expr) => Expr, p: Expr, eps: number, hint?: string): { value: Expr; dx: Expr; dy: Expr; }; /** * The value, slope and curvature of any field at a point: `value`, `dx`, `dy` and `curvature`. * * `fdSlope` with two more taps. The slopes are centred, so they sit on the point rather than * half a step past it, and `curvature` is the field's Laplacian: negative on a crest, positive * in a crease, zero on a flat or a plane. Scale it by a gain for a cavity shade that darkens * creases and lifts crests. `eps` is the tap distance in the point's units. * * @example * ```ts * const relief = fdCurvature(cloth, q, 0.004) * const cavity = clamp(sub(1, mul(relief.curvature, 0.005)), 0.6, 1.1) * ``` * @tip Five taps of the field per pixel. Keep the field cheap. * @see fdSlope, nudgeNormal */ export declare function fdCurvature(sampleAt: (p: Expr) => Expr, p: Expr, eps: number, hint?: string): { value: Expr; dx: Expr; dy: Expr; curvature: Expr; }; /** * Random 0–1 per point, with no smoothness between neighbours. * * For grain, flicker and per-pixel jitter. Feed it large coordinates so every pixel differs. * * @example * ```ts * const grain = hashNoise(mul(uv.member('x'), 991.3), mul(uv.member('y'), 787.7)) * ``` * @see interleavedNoise, valueNoise, sensorGrain */ export declare function hashNoise(x: Expr | number, y: Expr | number): Expr; /** * A 0–1 dither pattern over device pixels where neighbours differ as much as possible. * * Better than `hashNoise` for jittering sample positions, which would otherwise clump into * visible grain. `pixel` is the pixel coordinate (uv times the viewport size). `clock` * shifts the pattern each frame. * * @example * ```ts * const jitter = interleavedNoise(mul(uv, viewport), frame) * ``` * @see hashNoise, sensorGrain */ export declare function interleavedNoise(pixel: Expr, clock?: Expr | number): Expr; /** * Smooth noise 0–1 at a 2D point, softer and blockier than `surfaceNoise`. * * @example * ```ts * const wobble = sub(valueNoise(mul(x, 4), mul(y, 3)), 0.5) * ``` * @see surfaceNoise, hashNoise */ export declare function valueNoise(x: Expr | number, y: Expr | number): Expr; /** * How far a 3D shape has rotated, as a 2D pan you can move content by. * * Zero on flat shapes and on any shape at rest, growing as the shape turns. Constant across * the frame, so it pans a star field or a backdrop without shearing it. Needs `pattern: 'raw'`. * * @example * ```ts * const pan = rotationSensor(frame) * ``` * @see shellRefract, surfacePattern */ export declare function rotationSensor(frame: SurfaceFrame): { x: Expr; y: Expr; }; /** * Coordinates for what sits inside a glass shell, bent where the shell curves. * * Returns `x` and `y` centred on the shape and displaced by the normal's tilt times * `amount`, plus the unbent `centered` pair for anything fixed to the container. The bend is * strongest at bevels and silhouettes, where real glass bends its interior. * * @example * ```ts * const interior = shellRefract(frame, n, u.bend) * ``` * @see rotationSensor, refract */ export declare function shellRefract(frame: SurfaceFrame, n: Expr, amount: Expr): { x: Expr; y: Expr; centered: { x: Expr; y: Expr; }; }; /** * How mirror-like a surface is at this pixel: `r0` face-on, rising to `r0 + gain` at the rim. * * `grazing` comes from `grazingOf` or `grazingFlat`. Glass is `{r0: 0.04, gain: 0.96}`. Lower * the gain to keep the rim from turning into a full mirror over an interior. * * @example * ```ts * const fresnel = schlickFresnel(grazingOf(n, view), {gain: 0.6}) * ``` * @see fresnelBoost, grazingOf, reflect */ export declare function schlickFresnel(grazing: Expr, opts: { r0?: number; gain: Expr | number; power?: number; }): Expr; /** * A brightness factor that shimmers over time, different for each element. * * Ranges from `1 − 2·amount` to 1. `phase` is a per-element value (a noise or a hash) that * keeps the elements out of step; `rate` is how fast, `spread` how differently they flicker. * * @example * ```ts * shimmer: (v) => twinkle(t, v, {amount: 0.3, rate: 1.7, spread: 40}) * ``` * @see pointStars */ export declare function twinkle(t: Expr, phase: Expr, opts: { amount: Expr; rate: number; spread: number; }): Expr; /** * A plane of sparse glinting points: stars, glitter, dust. * * `p` is the plane coordinate; scale it to set density. Returns the glint intensity, the slow * per-point `variation` field, and `rgb` when `tint` is given. Radii are in the cellular * noise's squared-distance units, so they are small (0.004–0.02). * * @example * ```ts * const stars = pointStars(mul(pat, 40), {variationFreq: 0.13, radius: [0.004, 0.013], keep: [0.35, 0.75], brightness: [0.3, 1.2], gain: u.stars, tint: {from: [0.72, 0.82, 1], to: [1, 0.92, 0.82], gain: 1.6}}) * ``` * @see twinkle, cellNoiseAt */ export declare function pointStars(p: Expr, opts: { /** Frequency of the per-point variation field relative to `p` (slow, about 0.1). */ variationFreq: number; /** Point radius as `[base, jitter]`: base plus variation times jitter. */ radius: [number, number]; /** The band of the variation field that keeps a point at all. Narrower is sparser. */ keep: [number, number]; /** Brightness as `[base, gain]`: base plus variation squared times gain. */ brightness: [number, number]; /** A per-point shimmer factor built from the variation field (see `twinkle`). */ shimmer?: (variation: Expr) => Expr; /** Overall gain. */ gain: Expr; /** Color the glints: variation mixes `from` to `to`, scaled by the glint times `gain`. */ tint?: { from: [number, number, number]; to: [number, number, number]; gain: number; }; hint?: string; }): { glint: Expr; variation: Expr; rgb?: Expr; }; /** * A position prop in the shape's own coordinates, so you can compare it with the field. * * Takes a `transformPosition` prop and applies the same center, scale and rotation the shape * has. Distances from it are in placement units, not canvas units. * * @example * ```ts * const lightUV = placementPoint(params, params.uniforms.lightPosition) * ``` * @see pointLightFrom, nearestEdge */ export declare function placementPoint(params: GpuFragmentParams, position: Expr, hint?: string): Expr; /** * The distance field extended past the edge of an SVG shape's texture. * * An SVG field stops at its 0–1 square, so a far-reaching glow or shadow would see a plateau * beyond it. Returns the extended distance here, an `outward` push to add to any slope taken * near the border, and `at(uv)` for the distance anywhere. Pass an unscaled `surfaceField`. * Flat and 3D shapes pass through unchanged. * * @example * ```ts * const far = continuedField(frame, field, params) * ``` * @see nearestEdge, fieldSlope */ export declare function continuedField(frame: SurfaceFrame, field: SurfaceField, params: GpuFragmentParams): { sdf: Expr; outward: Expr; at: (uv: Expr) => Expr; }; /** * The closest point on the shape's edge to this pixel, and the outward normal there. * * Where a rim glow or contact shadow comes from for pixels outside the shape. `slope` is * `fieldSlope`; its length is guarded. * * @example * ```ts * const edge = nearestEdge(frame.sdfUV!, field.sdf, fieldSlope(field)) * ``` * @see fieldSlope, pointLightFrom, continuedField */ export declare function nearestEdge(sdfUV: Expr, sdf: Expr, slope: Expr, hint?: string): { point: Expr; normal: Expr; }; /** * A point light as seen from a point on the shape: the 3D light vector `L`, the 2D direction `toLight` and the `distance`. * * `position` is in placement coordinates (see `placementPoint`). `height` lifts the light * toward the viewer, in the same units. Feed `L` to `lambert` and `distance` to `inverseSquare`. * * @example * ```ts * const onBody = pointLightFrom({position: lightUV, height: u.lightHeight}, frame.sdfUV!) * ``` * @see placementPoint, lambert, inverseSquare, keyLightAt */ export declare function pointLightFrom(light: { position: Expr; height: Expr | number; }, at: Expr, hint?: string): { L: Expr; toLight: Expr; distance: Expr; }; /** * How much a light falls on a surface: 0 facing away, 1 facing it. * * `normal` and `light` are unit vectors, both 2D or both 3D. `wrap` lets light reach around * the shape: 0 is a hard terminator, 1 lights it all the way round. * * @example * ```ts * const diffuse = lambert(n, key.member('L'), {wrap: 0.3}) * ``` * @see keyLightAt, pointLightFrom, dualLobeGlint */ export declare function lambert(normal: Expr, light: Expr, opts?: { wrap?: Expr | number; }): Expr; /** * How a point light fades with distance: 1 at the source, half at `range`. * * @example * ```ts * const lit = mul(lambert(n, onBody.L), inverseSquare(onBody.distance, u.lightRange)) * ``` * @see pointLightFrom, lambert */ export declare function inverseSquare(distance: Expr, range: Expr | number): Expr; /** * Turns light that piles past 1 into a soft burn toward white, like film. * * Apply it to summed emitted light before output. `neutralTone` is the cousin for a lit, * tinted surface. * * @example * ```ts * const glow = exposureTone(add(irradiance, emitter)) * ``` * @see neutralTone, sensorGrain */ export declare function exposureTone(rgb: Expr): Expr; /** * Adds a fine per-pixel brightness jitter, so rendered light reads as photographed. * * Each pixel is scaled by up to half of `amount` either way. `pixel` is the pixel coordinate * (uv times the viewport size); `clock` re-rolls the grain each frame. * * @example * ```ts * const rgb = sensorGrain(glow, {amount: 0.08, pixel: mul(uv, viewport), clock: t}) * ``` * @see hashNoise, interleavedNoise, exposureTone */ export declare function sensorGrain(rgb: Expr, opts: { amount: Expr | number; pixel: Expr; clock: Expr | number; }): Expr; /** * A highlight with a tight hot core and a wide dim halo. * * `ndh` is the dot of the normal and the key light's `.H`. `core` and `halo` are * `[exponent, gain]` pairs. `softness` (0–1, 0.5 neutral) widens or tightens both lobes. * * @example * ```ts * const spec = dualLobeGlint(dot(n, key.member('H')), {core: [140, 1.3], halo: [22, 0.14], softness: u.highlightSoftness, gain: u.highlight}) * ``` * @see sharpGlint, keyLightAt, lambert */ export declare function dualLobeGlint(ndh: Expr, opts: { /** `[exponent, gain]` of the hot core lobe. */ core: [number, number]; /** `[exponent, gain]` of the wide halo lobe. */ halo: [number, number]; softness?: Expr; gain: Expr; }): Expr; /** * The soft glow of light scattered off fibres where a surface turns edge-on to the viewer: * the velvet sheen on the flanks of satin, velour and wool. * * `normal` and `light` are unit 3D vectors and `view` the view ray (`viewRay`, or a constant * `vec3(0, 0, 1)`). It is zero on a face-on surface and rises along each fold's flank, so it * never washes a flat sheet. `roughness` (0–1) widens it: low is a thin bright rim, high a * broad soft bloom. The lobe peaks at 1 and is held back by a wrapped lambert so unlit flanks * stay dark; pass `gain` or scale the result yourself. Pair it with `anisoSpecular` for a * satin finish: the streak is the shine, the sheen is the body. * * @example * ```ts * const velvet = sheenLobe({normal: n, light: L, view, roughness: 0.5, gain: u.sheen}) * ``` * @see anisoSpecular, lambert, grazingOf */ export declare function sheenLobe(opts: { normal: Expr; light: Expr; view: Expr; roughness: Expr | number; gain?: Expr | number; }): Expr; //# sourceMappingURL=materials.d.ts.map