import * as THREE from 'three/webgpu'; import type { ComputeNode, Mesh, Renderer, SkinnedMesh, StorageBufferAttribute, StorageInstancedBufferAttribute } from 'three/webgpu'; import type { TSLUniformNode } from '../types/tsl.js'; export interface ComputeMeshSurfaceSamplerOptions { seed?: number | undefined; useVertexNormals?: boolean | undefined; } export interface ComputeMeshSurfaceSamplerComputeOptions { resampleIndex?: number | undefined; trackTimestamp?: boolean | undefined; } /** * GPU mesh surface sampler using TSL. * * **Overview** * This class implements a high-performance surface sampling algorithm that runs entirely on the GPU. * It is designed to generate thousands or millions of instances distributed on the surface of a mesh. * * **Algorithm** * 1. **CPU Pre-processing**: Builds a weighted distribution (CDF) and Alias Table based on triangle areas. * 2. **GPU Sampling**: Uses the Alias Method (O(1)) to select triangles and Blue Noise to pick barycentric coordinates. * 3. **Output**: Writes transformation matrices to a storage buffer, ready for `InstancedMesh`. * * **Features** * - **Blue Noise**: Ensures samples are well-distributed (low discrepancy) and temporally stable. * - **Alias Method**: Efficient O(1) selection of weighted triangles. * - **Normal Alignment**: Aligns instance Y-axis to the surface normal. * * **Example: Grass distribution on terrain** * * ```js * import { ComputeMeshSurfaceSampler } from 'three-blocks'; * import * as THREE from 'three/webgpu'; * * // Load terrain mesh * const terrain = await loadTerrain(); * * // Create sampler for 100,000 grass blades * const sampler = new ComputeMeshSurfaceSampler(terrain, renderer, 100000, { * seed: 42, * useVertexNormals: true * }); * * // Run sampling on GPU * await sampler.compute(); * * // Create instanced grass using the sampled transforms * const grassGeometry = new THREE.PlaneGeometry(0.1, 0.5); * const grassMaterial = new THREE.MeshStandardNodeMaterial({ color: 0x3d9140 }); * const grass = new THREE.InstancedMesh(grassGeometry, grassMaterial, 100000); * * // Assign the GPU-generated transforms directly * grass.instanceMatrix = sampler.output; * scene.add(grass); * ``` * * **Example: Resampling specific instances** * * ```js * // Resample only instance 42 (e.g., for respawning) * await sampler.compute({ resampleIndex: 42 }); * * // Measure GPU performance * const timestamp = await sampler.compute({ trackTimestamp: true }); * console.log(`Sampling took ${timestamp}ms`); * ``` * * @class ComputeMeshSurfaceSampler * @short GPU mesh surface sampler using alias table + blue noise to output instance matrices/normals for instancing. * @category Compute * @tags WebGPU */ export declare class ComputeMeshSurfaceSampler { renderer: Renderer; count: number; indexSSBO: StorageBufferAttribute | null; positionSSBO: StorageBufferAttribute | null; normalSSBO: StorageBufferAttribute | undefined; cdfSSBO: StorageBufferAttribute | null; aliasPackedSSBO: StorageBufferAttribute | null; outMatrixSSBO: StorageInstancedBufferAttribute | null; outNormalSSBO: StorageBufferAttribute | null; computeNode: ComputeNode | null; _compiled: boolean; _disposed: boolean; _isSkinned: boolean; _skinnedMesh: SkinnedMesh | null; skinIndexSSBO: StorageBufferAttribute | null; skinWeightSSBO: StorageBufferAttribute | null; boneMatrixSSBO: StorageBufferAttribute | null; uBindMatrix: TSLUniformNode<'mat4', THREE.Matrix4>; uBindMatrixInverse: TSLUniformNode<'mat4', THREE.Matrix4>; uObjectMatrix: TSLUniformNode<'mat4', THREE.Matrix4>; uResampleIndex: TSLUniformNode<'int', number>; uSeed: TSLUniformNode<'float', number>; /** * Create a new mesh surface sampler. * * @param {THREE.Mesh} mesh - Source mesh to sample from. * @param {THREE.WebGPURenderer} renderer - WebGPU renderer instance. * @param {number} count - Number of samples/instances to generate. * @param {Object} [options] - Configuration options. * @param {number} [options.seed=1337] - Random seed for sampling. * @param {boolean} [options.useVertexNormals=true] - If true, interpolates vertex normals; if false, uses geometric face normal. */ constructor(mesh: Mesh, renderer: Renderer, count: number, options?: ComputeMeshSurfaceSamplerOptions); /** * Returns the GPU storage buffer containing instance transformation matrices. * Can be directly assigned to InstancedMesh.instanceMatrix. * @returns {THREE.StorageInstancedBufferAttribute} */ get output(): StorageInstancedBufferAttribute; /** * Returns the GPU storage buffer containing world-space surface normals per instance. * @returns {THREE.StorageBufferAttribute|null} */ get outputNormal(): StorageBufferAttribute | null; /** * Recompute on GPU. Pass {resampleIndex} to update just one instance. * @param {Object} [options] - Options * @param {number} [options.resampleIndex] - If provided, updates only this instance index; otherwise all instances are recomputed. * @param {boolean} [options.trackTimestamp] - If true, returns the GPU timestamp. * @returns {Promise} GPU timestamp if {trackTimestamp} is true, otherwise null. */ compute(options?: ComputeMeshSurfaceSamplerComputeOptions): Promise; /** * (optional) Read back transformation matrices to CPU * @returns {Promise} Array of mat4 matrices (16 floats per instance) */ readback(): Promise>; /** Release the sampler's compute pipeline and owned storage buffers. */ dispose(): void; }