export default class Mesh extends Renderable { /** * @param {number} x - the x screen position of the mesh object * @param {number} y - the y screen position of the mesh object * @param {MeshSettings} settings - Configuration parameters for the Mesh object * @example * // create from OBJ + MTL (texture auto-resolved from material) * let mesh = new me.Mesh(0, 0, { * model: "fox", * material: "fox", * width: 200, * height: 200, * }); * * // create from OBJ with explicit texture (no MTL needed) * let mesh = new me.Mesh(0, 0, { * model: "cube", * texture: "cube_texture", * width: 200, * height: 200, * }); * * // create from raw geometry that already carries its own world scale * // (e.g. a glTF scene node) — keep real coordinates, no mirror * let node = new me.Mesh(0, 0, { * vertices: positions, // Float32Array of x,y,z triplets * uvs: texcoords, // Float32Array of u,v pairs * indices: tris, // Uint16Array of triangle indices * texture: baseColorImage, * width: 32, // pixels per unit * normalize: false, * rightHanded: true, * }); * * // material settings (WebGL) — usually set for you by the glTF/OBJ loader, * // but available directly on a hand-built mesh too * let sign = new me.Mesh(0, 0, { * vertices, uvs, indices, texture: "neon-sign", * width: 64, normalize: false, * textureFilter: "nearest", // crisp pixel-art upscaling * alphaCutoff: 0.5, // discard texels below 0.5 alpha (cutout) * emissive: [0.9, 0.2, 0.6], // glow, independent of scene lights * }); * * // 3D rotation using the standard rotate() API * mesh.rotate(Math.PI / 4, new me.Vector3d(0, 1, 0)); // rotate around Y axis * * // 2D rotation (Z axis, same as Sprite) * mesh.rotate(Math.PI / 4); */ constructor(x: number, y: number, settings: MeshSettings); /** * the original (untransformed) vertex positions as x,y,z triplets * @type {Float32Array} */ originalVertices: Float32Array; /** * texture coordinates as u,v pairs * @type {Float32Array} */ uvs: Float32Array; /** * number of vertices * @type {number} */ vertexCount: number; /** * the projected vertex positions. * * **Not refreshed on the retained `Camera3d` path.** There, geometry is * uploaded once in model space and placed by the GPU, so nothing * projects vertices per frame and this array holds whatever it last * did. It is still maintained by the Canvas renderer and by the 2D * camera path. Engine consumers that need current world positions — * {@link Mesh#getBounds3d}, {@link Mesh#toPolygon} — derive them on * demand instead of reading this; user code should do the same. * * To edit geometry, write to {@link Mesh#originalVertices} and set * {@link Mesh#needsUpdate}. * @type {Float32Array} */ vertices: Float32Array; /** * the source per-vertex normals (x,y,z triplets), or `undefined` if the * mesh was built without them. Supplied by the glTF loader; used for * lit shading under a `Camera3d` (see {@link Light3d}). * @type {Float32Array|undefined} */ originalNormals: Float32Array | undefined; /** * world-space normals for the current draw, recomputed from * {@link Mesh#originalNormals} along the Camera3d path. Empty (zero) when * the mesh has no source normals — the shader then ignores lighting. * * Carries the same caveat as {@link Mesh#vertices}: the WebGL * `Camera3d` path rotates normals on the GPU and leaves this array * untouched. * @type {Float32Array} */ normals: Float32Array; /** * Whether this mesh is lit by the active stage's {@link Light3d} lights. * When `true` it renders through the lit mesh batcher (diffuse shading * from the scene's lights, using {@link Mesh#originalNormals}); when * `false` (the default) it uses the lean unlit path and pays no lighting * cost. The glTF loader sets this on scene meshes when the scene has * lights. Only meaningful under a `Camera3d` on a GPU backend. * @type {boolean} * @default false */ lit: boolean; /** * Alpha cutout threshold. A fragment whose final alpha is below this * value is discarded — a hard-edged cutout (foliage, fences, chain-link, * decals) that needs no blending or back-to-front sorting. `0` (the * default) disables the cutout and the mesh renders fully opaque. Set by * the glTF loader from a material's `alphaMode: "MASK"` / `alphaCutoff`. * GPU mesh path only (the Canvas renderer ignores it). * @type {number} * @default 0 */ alphaCutoff: number; /** * Emissive (self-illumination) color as an `[r, g, b]` `Float32Array` * (0..1, may exceed 1 for HDR glow), added on top of the lit/unlit color * so the surface glows independently of the scene lights (neon, lava, * screens, glowing eyes). `undefined` (the default) means no emission and * keeps the mesh on the lean path. Set by the glTF loader from a material's * `emissiveFactor` (× `KHR_materials_emissive_strength`) and by the OBJ * loader from an MTL's `Ke`. GPU mesh path only (WebGL and WebGPU; the Canvas renderer ignores it). * @type {Float32Array|undefined} */ emissive: Float32Array | undefined; /** * Specular (highlight) color as an `[r, g, b]` `Float32Array`, or * `undefined` for a purely diffuse surface — which is the default, and * what every mesh rendered as before this existed. * * Drives a Blinn-Phong highlight on the **lit** mesh path, so it needs * `lit: true`, a `Light3d`, and normals. Set by the OBJ loader from an * MTL's `Ks`; paired with {@link Mesh#shininess}, which decides how * tight the highlight is. A `Ks` with no `Ns` produces nothing — the * exponent is what turns the term on. * @type {Float32Array|undefined} * @see Mesh#shininess */ specular: Float32Array | undefined; /** * Specular exponent — how tight the highlight is. The MTL `Ns` range * is 0..1000; higher is a smaller, harder highlight (polished metal), * lower is a broad sheen (satin). `0` (the default) disables the * specular term outright however bright {@link Mesh#specular} is, which * is what keeps a material declaring neither on the diffuse-only path. * @type {number} * @default 0 */ shininess: number; /** * Per-texel opacity map (MTL `map_d`), or `undefined`. Its red channel * multiplies the fragment's alpha before {@link Mesh#alphaCutoff} is * applied, so a single material can cut out per pixel — the shape of * a leaf, the holes in a chain-link fence — where `alphaCutoff` alone * can only threshold uniformly across the whole material. * * Only meaningful alongside a non-zero `alphaCutoff`: without one there * is nothing to discard against. GPU mesh path only. * @type {TextureAtlas|undefined} */ alphaMap: TextureAtlas | undefined; /** * Cast a soft dark ellipse — a "blob" shadow — on the ground beneath * this mesh (#1515). * * Not a simulated shadow, deliberately: what a 2.5D scene needs from * one is *contact* — where the object is standing, and how far off the * ground it is mid-jump. It costs one extra draw per shadowed object, * shares one geometry and one texture with every other shadow in the * scene, and is inert while `false`. * * Requires a GPU backend and a {@link Camera3d}: the shadow rides the * retained world-space path, so the Canvas renderer and the 2D-camera * path draw none. * * Left **unset** (`undefined`, the default) this follows the * application's `castGroundShadow` setting — with one safeguard: a * scene-wide opt-in skips meshes with no vertical extent, because a * flat plane lying on the floor is the floor, and shadowing it with * itself smears the whole ground. Setting the property here is an * explicit instruction and always obeyed, safeguard included. * @type {boolean|undefined} * @default undefined * @see Mesh#shadowGroundY */ castGroundShadow: boolean | undefined; /** * Whether this mesh is affected by the camera's distance fog * ({@link Camera3d#setFog}). * * Left **unset** (`undefined`, the default) the mesh fogs whenever the * camera drawing it has fog — which for a scene that never enables fog * means never. Set it to `false` and this mesh is never fogged, however * far away it is: the escape hatch for something that has to stay * readable at any distance, such as an objective marker or a waypoint. * `true` is accepted for symmetry and behaves as the default. * * It exempts the **mesh**, not the ground shadow it casts. A blob is a * mark on the floor and fogs with the floor it lies on — one staying * crisp under an object whose surroundings had dissolved would read as * a fault rather than as emphasis. The blob quad is also shared by * every caster in the scene, so it carries no per-object state to read. * * Emissive surfaces fog too — light travelling through fog is * attenuated like anything else — so a neon sign that should punch * through wants `fog: false` rather than a brighter emissive. * @type {boolean|undefined} * @default undefined * @see Camera3d#setFog * @example * // the world fogs; this waypoint stays readable at any distance * camera.setFog({ near: 1200, far: 7000 }); * * const marker = new Mesh(0, 0, { * ...beaconGeometry, * emissive: [1, 0.6, 0], * fog: false, * }); * // or afterwards, on anything already built * marker.fog = false; */ fog: boolean | undefined; /** * Whether this mesh draws in the **transparent pass** — blended, * back-to-front, writing no depth — instead of the opaque one. * * Left **unset** (`undefined`, the default) the mesh goes transparent * whenever the draw resolves to fractional alpha, so `setOpacity(0.5)` * simply fades it. That is the useful default because the opaque path * writes premultiplied colour with blending off: a faded mesh comes out * *darkened toward black* rather than see-through, which is a defect * rather than a contract — the fully transparent end of the same range * used to paint an opaque black silhouette until it was fixed. * * Set it **`true`** when the transparency lives in the TEXTURE rather * than in the opacity — a soft-edged glow, smoke, a glTF material with * `alphaMode: "BLEND"`. The automatic check reads the draw's alpha and * cannot see into the texture. The glTF loader does not set this for * you: one loaded mesh can merge several materials, and this flag * routes the whole mesh, so a `"BLEND"` material sharing geometry with * an opaque one would drag the opaque half into the transparent pass. * Note that `alphaCutoff` discards texels before blending sees them, so * a soft edge needs a low cutoff (see {@link Sprite3d}, which lowers * its default for exactly this). The cutoff thresholds the MATERIAL's * alpha, not the drawn alpha, so a fading cutout mesh keeps its shape * rather than disappearing at its own threshold. * * The pass composites premultiplied, which is what the mesh vertex * stage always emits. A texture uploaded with straight alpha and drawn * with `transparent: true` therefore reads slightly bright at its soft * texels; upload it premultiplied (the default) and it is exact. * * {@link Renderable#blendMode} is honoured per entry, with one limit: * the advanced modes (`"overlay"`, `"difference"`, and the rest that * need a compositing pass) fall back to `"normal"` here on both * backends, since the pass rasterizes directly into the target. * * Set it **`false`** to keep a mesh in the opaque pass however it is * faded — it will darken rather than fade, and it will keep writing * depth. * * Sorting is **per object**, by distance from the camera, so two * intersecting or mutually enclosing transparent meshes may pop as the * camera moves; split them, or accept it. Needs a GPU backend and a * {@link Camera3d} — the 2D-camera path is unaffected. * @type {boolean|undefined} * @default undefined * @see Renderable#blendMode * @example * // a ghost that fades in — nothing else needed * ghost.setOpacity(0.4); * * // a glow that blends at full opacity, and additively * const glow = new Mesh(0, 0, { * ...quad, * texture: glowTexture, * transparent: true, * blendMode: "additive", * alphaCutoff: 0, * }); */ transparent: boolean | undefined; /** * World Y of the floor the shadow lands on, or `undefined` (the * default) to mean "this object is standing on the ground" — the * shadow sits at the object's own base, at full strength, and does not * shrink or fade. * * Set it, and the shadow shrinks and fades as the object rises above * it: the readable part of a jump. The game already knows this value * from collision, which is why it is not derived — deriving it from the * object's live bounds would make the "ground" jump with the jumper, * so the height could never be anything but zero. * * Render space is Y-DOWN, so the floor is a **greater** Y than the * object above it. * @type {number|undefined} * @default undefined */ shadowGroundY: number | undefined; /** * Opacity of the shadow directly beneath the object, before any * height fade. * @type {number} * @default 0.45 */ shadowOpacity: number; /** * whether to cull back-facing triangles * @type {boolean} * @default true */ cullBackFaces: boolean; /** * Treat the source geometry as right-handed (Y-up, e.g. glTF) under * the Camera3d world path. The default (`false`) Y-up→Y-down bridge * negates Y only — a reflection, which mirrors the scene left/right. * When `true`, the bridge negates Y **and** Z (a 180° rotation about * X, determinant +1) so chirality is preserved and the result matches * the authoring tool (no mirror); triangle winding is left untouched * since a rotation doesn't invert it. * @type {boolean} * @default false */ rightHanded: boolean; /** * Uniform world-space scale (pixels per source unit) applied along the * Camera3d world path. Defaults to `width`. Scene loaders (e.g. glTF) * set this independently of `width` / `height` so those can describe * the renderable's world-space bounds (used for frustum culling) while * the geometry is still scaled by this factor — `width` alone can't * serve both roles for a non-normalized scene mesh. * @type {number} * @default settings.width */ meshScale: number; /** * Per-material submesh groups, populated when the OBJ * contains multiple `usemtl` directives AND a matching MTL * is bound via the `material` setting. Each entry slices * the shared `indices` buffer; field shape (`start`, * `count`, `materialName`) matches the glTF "groups" * convention. * * Under the per-vertex color baking path (tier 2), the * `tint` / `opacity` fields here are informational — the * actual rendered color is baked into `vertexColors` at * construction time. Mutating `groups[i].tint` after * construction has no visible effect; use `mesh.tint` for * runtime color multiplication, or rebuild the Mesh with * new material settings. * @type {Array<{materialName: string|null, start: number, * count: number, tint: Color, opacity: number, * texture: TextureAtlas|undefined}>} */ groups: Array<{ materialName: string | null; start: number; count: number; tint: Color; opacity: number; texture: TextureAtlas | undefined; }>; /** * Per-vertex color buffer (one packed Uint32 per vertex) * populated for multi-material meshes. The mesh batcher * reads from this when present, pushing the per-vertex * color as the `aColor` attribute — so multi-material * rendering needs no extra draw calls per material vs * single-material rendering (the batcher still chunks * very large meshes across multiple draws to fit its * vertex/index buffer limits, same as the single-material * path). Multiplied at render time by the global * `mesh.tint`, so runtime tint mutation still works as * expected (flash, fade, team color, etc.). * * Vertices were split per-material at parse time (each * material has its own dedup scope in the OBJ parser), so * every vertex belongs to exactly one material group and * carries that group's color unambiguously. * * This is also what `settings.vertexColors` and * {@link Mesh#setVertexColor} populate, so procedural geometry * can carry a gradient a per-object `tint` cannot express. * `undefined` when every vertex is plain white. * @type {Uint32Array|undefined} * @see Mesh#setVertexColor */ vertexColors: Uint32Array | undefined; texture: any; /** * Index ranges that each need their own diffuse texture bound, for a * multi-material model whose materials carry different `map_Kd` maps * (#1573) — `undefined` whenever one binding covers the whole mesh, * which is every single-material model and every `Kd`-only one. * * The GPU backends draw one indexed range per entry instead of one * range for the whole mesh; adjacent materials sharing a texture are * already merged here, so the list is the minimum number of draws the * model needs. An explicit `settings.texture` suppresses the split * entirely — asking for one texture is asking for one texture. * * The Canvas renderer ignores this: a multi-material mesh takes its * per-triangle solid-fill path there and never samples a texture at * all. * @type {Array<{texture: TextureAtlas, start: number, count: number}>|undefined} */ textureGroups: Array<{ texture: TextureAtlas; start: number; count: number; }> | undefined; /** * Per-mesh texture wrap mode (`"repeat"` / `"repeat-x"` / `"repeat-y"` * / `"no-repeat"`), or `undefined` to sample with the texture's own * wrap. Some assets author UVs outside the `[0, 1]` range and rely on * the sampler repeating the texture (this is the glTF default sampler * behavior); the mesh would otherwise clamp to the edge texels and * look flat / untextured. * * Kept on the mesh and threaded to the batcher at draw time — sampler * state per use, like a GL sampler object — so it never mutates the * per-image `TextureAtlas` shared with every other consumer of the * same image (#1503). Two meshes (or a mesh and a sprite) can point * at one image with different wrap modes; the texture cache keys GL * units by `(source, repeat)` so each wrap gets its own GL texture. * Applied only to a real texture — never the shared white-pixel * fallback, which is global and must stay `"no-repeat"`. * @type {string|undefined} */ textureRepeat: string | undefined; /** * Projection matrix applied automatically before the model transform in draw(). * Defaults to a perspective projection (45° FOV, camera at z=-2.5) suitable for * viewing unit-cube-sized geometry. Set to identity for orthographic (flat) projection. * Most users don't need to modify this — the default works for standard OBJ models. * @type {Matrix3d} */ projectionMatrix: Matrix3d; /** * Signal that this mesh's geometry itself has changed — its vertices, UVs, * indices, normals or per-vertex colours were edited in place. * * Placement is *not* geometry: moving, rotating, scaling or re-tinting a * mesh needs no signal, because those are applied when drawing rather than * stored in the geometry. Only reach for this after writing into * {@link Mesh#originalVertices} and friends directly. * @type {boolean} * @example * // deform the mesh, then tell it the shape moved * mesh.originalVertices[1] += 10; * mesh.needsUpdate = true; */ set needsUpdate(value: any); /** * Set one vertex's colour, multiplied into {@link Mesh#tint}. * * The mesh starts carrying per-vertex colour on the first call — every * other vertex is white until coloured, so a mesh built without * `settings.vertexColors` looks unchanged until you touch it. * * Out-of-range indices are ignored rather than throwing, matching * {@link InstancedMesh#setInstanceColor}. * * Bumps {@link Mesh#needsUpdate} for you: the retained `Camera3d` path * uploads geometry once and compares the version, so a colour written * without it would apply on the immediate path and silently not on the * retained one. * @param {number} index - the vertex to colour * @param {Color} color - the vertex colour * @example * // fade a procedural terrain toward the sky with distance * for (let i = 0; i < mesh.vertexCount; i++) { * const t = Math.min(1, mesh.originalVertices[i * 3 + 2] / 6000); * mesh.setVertexColor(i, haze.copy(ground).lerp(sky, t)); * } */ setVertexColor(index: number, color: Color): void; /** * The mesh's world-space 3D axis-aligned bounding box. This is the 3D analog * of {@link Renderable#getBounds} (which returns a flat 2D box from * `width`/`height` and so cannot describe a mesh's real extent). * * Computed on demand by bounding the model-space geometry through the * mesh's current placement, so it reflects the live transform and is valid * before the mesh has ever been drawn. Meaningful for the `Camera3d` path; * for the 2D path use {@link Renderable#getBounds}. * * The same {@link AABB3d} instance is returned each call (recomputed in * place), so copy it (`.clone()`) if you need to keep it. * @returns {AABB3d} the world-space bounding box (reused instance) */ getBounds3d(): AABB3d; /** * Render the mesh at its current state (transforms, projection, tint) to an offscreen canvas. * The returned canvas can be used with `renderer.drawImage()`, as a `Sprite` image source, * or converted to an ImageBitmap via `createImageBitmap()`. * @returns {HTMLCanvasElement} an offscreen canvas containing the rendered mesh * @example * // snapshot the mesh and create a Sprite from it * const canvas = mesh.toCanvas(); * const sprite = new me.Sprite(100, 100, { image: canvas }); * * // or draw directly * renderer.drawImage(mesh.toCanvas(), 100, 100); */ toCanvas(): HTMLCanvasElement; /** * Render the mesh at its current state to an ImageBitmap. * Useful for creating textures or sprites from the rendered mesh. * @returns {Promise} a promise that resolves to an ImageBitmap of the rendered mesh * @example * const bitmap = await mesh.toImageBitmap(); * const sprite = new me.Sprite(100, 100, { image: bitmap }); */ toImageBitmap(): Promise; } /** * Everything {@link Mesh} takes. * * Split out of the constructor's own `@param` list so a subclass that * forwards these wholesale — {@link InstancedMesh} does — can say so in its * type, instead of restating 27 entries that would then drift apart. */ export type MeshSettings = { /** * - name of a preloaded OBJ model (via loader.preload with type "obj"). Vertex normals come with it — authored `vn` when the file has them, generated from face geometry when it does not — so an OBJ model can be `lit`. */ model?: string; /** * - vertex positions as x,y,z triplets (alternative to `model`) */ vertices?: Float32Array | number[]; /** * - texture coordinates as u,v pairs (alternative to `model`) */ uvs?: Float32Array | number[]; /** * - triangle vertex indices (alternative to `model`). A `Uint32Array` is preserved as-is for meshes past 65535 vertices — which is what the glTF parser emits for them — while a plain array is materialized as `Uint16Array` */ indices?: Uint16Array | Uint32Array | number[]; /** * - the texture to apply (image name, HTMLImageElement, or TextureAtlas). If omitted and settings.material is provided, the texture is resolved from the MTL material's map_Kd. Passing this pins ONE binding over the whole model, which on a multi-material model suppresses the per-material texture split — see {@link Mesh#textureGroups}. */ texture?: HTMLImageElement | HTMLCanvasElement | Texture2d | TextureAtlas | string; /** * - name of a preloaded MTL material (via loader.preload with type "mtl"). When provided, the diffuse texture (map_Kd), tint color (Kd), and opacity (d) are automatically applied. On a multi-material model each material's own `map_Kd` is bound for its own slice of the geometry (#1573) and each `Kd` is baked per-vertex, so one `Mesh` renders the whole model. */ material?: string; /** * - display width in pixels. With normalization on (the default) the model is scaled to fit this size; with `normalize: false` this is the uniform pixels-per-unit scale applied to the raw geometry. With `normalize: false` and an explicit `scale`, an omitted `width`/`height` is derived from the GEOMETRY's own extent, the way a Sprite takes its size from its frame — a mesh that reports no extent misleads frustum culling, pointer picking and the physics broadphase alike. */ width: number; /** * - display height in pixels (normalized models only; ignored when `normalize: false`) */ height?: number; /** * - enable backface culling */ cullBackFaces?: boolean; /** * - fit the source geometry into a `[-0.5, 0.5]` unit cube before scaling, so `width`/`height` behave like a Sprite. Set `false` to keep the geometry's real-world coordinates — required when several meshes share one coordinate space (e.g. nodes of an imported glTF scene) so their relative scale and layout are preserved. */ normalize?: boolean; /** * - world-space scale (pixels per source unit) for the Camera3d path; defaults to `width`. Set this when `width`/`height` describe the renderable's world bounds (frustum culling) rather than the geometry scale — see {@link Mesh#meshScale}. */ scale?: number; /** * - treat the source as right-handed (Y-up, e.g. glTF) under the `Camera3d` world path. The default Y-up→Y-down bridge negates Y only (a reflection, which mirrors the scene left/right); `true` negates Y **and** Z (a rotation) so chirality is preserved and the result matches the authoring tool. See {@link Mesh#rightHanded}. */ rightHanded?: boolean; /** * - texture wrap mode (`"repeat"` / `"repeat-x"` / `"repeat-y"` / `"no-repeat"`) this mesh samples its texture with (per-mesh — it does not modify the shared texture, so other meshes/sprites using the same image are unaffected). Use `"repeat"` when the geometry's UVs fall outside the `[0, 1]` range and rely on the texture tiling (e.g. glTF assets, whose default sampler wrap is REPEAT) — otherwise the texture clamps to its edge texels and looks flat. Ignored for the white-pixel fallback. Note: REPEAT on a non-power-of-two texture requires WebGL 2. */ textureRepeat?: string; /** * - texture magnification filter (`"nearest"` for crisp pixel-art upscaling, `"linear"` for smooth) applied to the resolved texture. Omit to keep the renderer's global `antiAlias` default. On the mesh path, linear filtering also samples a generated mip chain with trilinear minification and 4× anisotropy (distant geometry stops shimmering) — `"nearest"` opts out, keeping crisp pixel-art models on hard level-0 sampling. GPU backends only (ignored by the Canvas renderer). */ textureFilter?: string; /** * - alpha cutout threshold. Fragments whose final alpha is below this value are discarded (hard-edged cutout — foliage, fences, decals — with no blending or sorting). `0` disables the cutout. Set automatically by the glTF loader from a material's `alphaMode: "MASK"`. GPU mesh path only (WebGL and WebGPU; the Canvas renderer ignores it). */ alphaCutoff?: number; /** * - emissive (self-illumination) color `[r, g, b]` (0..1, may exceed 1 for HDR glow) added on top of the lit/unlit color so the surface glows regardless of scene lights (neon, lava, screens). Omit / all-zero for no emission. Set automatically by the glTF loader (`emissiveFactor`) and OBJ loader (MTL `Ke`). GPU mesh path only (WebGL and WebGPU; the Canvas renderer ignores it). */ emissive?: number[] | Float32Array; /** * - shade this mesh with the scene's {@link Light3d} lights (the lit mesh pipeline) instead of rendering fullbright. Set automatically by the glTF importer when the scene carries a directional, point or spot light. With `lit` on and no lights present the batcher uploads a white ambient, so the result is indistinguishable from unlit. */ lit?: boolean; /** * - per-vertex colour, one entry per vertex, multiplied into {@link Mesh#tint}. Either packed RGBA8 (`Uint32Array`, the form the batchers read — no conversion) or one {@link Color} per vertex. Omit for plain white. Lets a single mesh carry a gradient — fading a terrain toward the sky with distance, darkening a crease — which a per-object `tint` cannot express. An explicit value wins over the colours a multi-material OBJ bakes from its MTL. */ vertexColors?: Uint32Array | Color[] | number[]; /** * - per-vertex normals for the lit path. An explicit value wins over the ones an OBJ or glTF source supplies; omit it and they are taken from the model, or generated from the geometry when the mesh is `lit`. Generated normals average per vertex where faces share vertices (smooth shading) and equal the face normal where they do not (flat shading) — the geometry decides, not a flag. */ normals?: number[] | Float32Array; /** * - specular color `[r, g, b]` (0..1) for the lit path. Set by the OBJ loader from MTL `Ks`, and derived from glTF metallic/roughness. */ specular?: number[] | Float32Array; /** * - specular exponent for the lit path (MTL `Ns`). `0` for a fully diffuse surface. */ shininess?: number; /** * - per-texel opacity map, sampled in addition to the diffuse texture (MTL `map_d`). */ alphaMap?: string | TextureAtlas | HTMLImageElement; /** * - give this mesh a blob ground shadow, overriding the application's `castGroundShadow` setting in both directions. Omit to inherit. Needs a GPU backend and a `Camera3d`. */ castGroundShadow?: boolean; /** * - draw in the transparent pass (blended, back-to-front, no depth write). Omit and a mesh goes transparent whenever its draw alpha is fractional; `true` for soft-alpha textures; `false` to stay opaque however faded */ transparent?: boolean; /** * - set `false` to exempt this mesh from the camera's distance fog ({@link Camera3d#setFog}); omit to fog whenever the camera does */ fog?: boolean; /** * - world Y of the floor the shadow lands on. Omit and the blob sits at the object's own base at full strength; set it and the blob shrinks and fades as the object rises. Render space is Y-down, so the floor is a **greater** Y than the object above it. */ shadowGroundY?: number; /** * - opacity of the shadow directly beneath the object, before any height fade. */ shadowOpacity?: number; }; import Renderable from "./renderable.js"; import { TextureAtlas } from "./../video/texture/atlas.js"; import { Color } from "../math/color.ts"; import { Matrix3d } from "../math/matrix3d.ts"; import { Vector2d } from "../math/vector2d.ts"; import { Polygon } from "../geometries/polygon.ts"; import { AABB3d } from "../physics/broadphase/aabb3d.ts"; import type WebGLRenderer from "./../video/webgl/webgl_renderer.js"; import Texture2d from "./../video/texture/texture2d.ts"; //# sourceMappingURL=mesh.d.ts.map