playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
751 lines (750 loc) • 25.4 kB
JavaScript
var __defProp = Object.defineProperty;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
import { Debug } from "../../core/debug.js";
import {
PIXELFORMAT_R32U,
PIXELFORMAT_RGBA16F,
PIXELFORMAT_RGBA16U,
PIXELFORMAT_RGBA32U,
PIXELFORMAT_RG32U
} from "../../platform/graphics/constants.js";
import { ShaderMaterial } from "../materials/shader-material.js";
import { GSplatFormat } from "../gsplat/gsplat-format.js";
import {
GSPLATDATA_COMPACT,
GSPLAT_RENDERER_AUTO,
GSPLAT_RENDERER_RASTER_CPU_SORT,
GSPLAT_RENDERER_COMPUTE,
GSPLAT_RENDERER_RASTER_GPU_SORT,
GSPLAT_DEBUG_NONE,
GSPLAT_DEBUG_LOD,
GSPLAT_DEBUG_SH_UPDATE,
GSPLAT_DEBUG_HEATMAP,
GSPLAT_DEBUG_AABBS,
GSPLAT_DEBUG_NODE_AABBS
} from "../constants.js";
import glslCompactRead from "../shader-lib/glsl/chunks/gsplat/vert/formats/containerCompactRead.js";
import glslCompactWrite from "../shader-lib/glsl/chunks/gsplat/frag/formats/containerCompactWrite.js";
import glslPackedRead from "../shader-lib/glsl/chunks/gsplat/vert/formats/containerPackedRead.js";
import glslPackedWrite from "../shader-lib/glsl/chunks/gsplat/frag/formats/containerPackedWrite.js";
import wgslCompactRead from "../shader-lib/wgsl/chunks/gsplat/vert/formats/containerCompactRead.js";
import wgslCompactWrite from "../shader-lib/wgsl/chunks/gsplat/frag/formats/containerCompactWrite.js";
import wgslPackedRead from "../shader-lib/wgsl/chunks/gsplat/vert/formats/containerPackedRead.js";
import wgslPackedWrite from "../shader-lib/wgsl/chunks/gsplat/frag/formats/containerPackedWrite.js";
class GSplatParams {
/**
* Creates a new GSplatParams instance.
*
* @param {GraphicsDevice} device - The graphics device.
*/
constructor(device) {
/**
* @type {ShaderMaterial}
* @private
*/
__publicField(this, "_material", new ShaderMaterial());
/**
* Format descriptor for work buffer streams.
*
* @type {GSplatFormat}
* @private
*/
__publicField(this, "_format");
/**
* @type {GraphicsDevice}
* @private
*/
__publicField(this, "_device");
/**
* @type {string}
* @private
*/
__publicField(this, "_dataFormat", GSPLATDATA_COMPACT);
/**
* Enables radial sorting based on distance from camera (for cubemap rendering). When false,
* uses directional sorting along camera forward vector. Defaults to false.
*
* Note: Radial sorting helps reduce sorting artifacts when the camera rotates (looks around),
* while linear sorting is better at minimizing artifacts when the camera translates (moves).
*/
__publicField(this, "radialSorting", false);
/**
* @type {number}
* @private
*/
__publicField(this, "_renderer", GSPLAT_RENDERER_AUTO);
/**
* @type {number}
* @private
*/
__publicField(this, "_currentRenderer", GSPLAT_RENDERER_RASTER_CPU_SORT);
/**
* Internal dirty flag to trigger update of gsplat managers when some params change.
*
* @ignore
*/
__publicField(this, "dirty", false);
/**
* @type {number}
* @private
*/
__publicField(this, "_debug", GSPLAT_DEBUG_NONE);
/** @private */
__publicField(this, "_enableIds", false);
/**
* Distance threshold in world units to trigger LOD updates for camera and gsplat instances.
* Defaults to 1.
*/
__publicField(this, "lodUpdateDistance", 1);
/**
* Angle threshold in degrees to trigger LOD updates based on camera rotation. Set to 0 to
* disable rotation-based updates. Defaults to 0.
*/
__publicField(this, "lodUpdateAngle", 0);
/** @private */
__publicField(this, "_lodBehindPenalty", 1);
/** @private */
__publicField(this, "_lodRangeMin", 0);
/** @private */
__publicField(this, "_lodRangeMax", 10);
/** @private */
__publicField(this, "_lodUnderfillLimit", 0);
/** @private */
__publicField(this, "_splatBudget", 0);
/**
* @type {import('../../platform/graphics/texture.js').Texture|null}
* @private
*/
__publicField(this, "_colorRamp", null);
/**
* Intensity multiplier for overdraw visualization mode. Value of 1 uses alpha of 1/32,
* allowing approximately 32 overdraws to reach full brightness with additive blending.
* Higher values increase brightness per splat. Defaults to 1.
*/
__publicField(this, "colorRampIntensity", 1);
/**
* Whether to apply scene fog to Gaussian splats. When false, splats ignore fog settings
* even if the scene or camera has fog configured. Defaults to true.
*/
__publicField(this, "useFog", true);
/**
* Viewing angle threshold in degrees for triggering spherical harmonics color updates.
* When the camera translates enough to change the viewing angle to an octree node or
* splat by this amount, its SH colors are re-evaluated. Distant nodes naturally update
* less frequently since they require more camera movement to reach the angle threshold.
* Set to 0 to update every frame where camera moves. Defaults to 10.
*/
__publicField(this, "colorUpdateAngle", 10);
/** @private */
__publicField(this, "_fisheye", 0);
/**
* Number of update ticks before unloading unused streamed resources. When a streamed resource's
* reference count reaches zero, it enters a cooldown period before being unloaded. This allows
* recently used data to remain in memory for quick reuse if needed again soon. Set to 0 to
* unload immediately when unused. Defaults to 100.
*/
__publicField(this, "cooldownTicks", 100);
this._device = device;
this._format = this._createFormat(GSPLATDATA_COMPACT);
this._material.setParameter("alphaClip", 0.3);
this._material.setParameter("alphaClipForward", 1 / 255);
this._material.setParameter("minPixelSize", 2);
this._material.setParameter("minContribution", 3);
}
/**
* @param {string} dataFormat - The data format constant.
* @returns {GSplatFormat} The created format.
* @private
*/
_createFormat(dataFormat) {
let format;
if (dataFormat === GSPLATDATA_COMPACT) {
format = new GSplatFormat(this._device, [
{ name: "dataColor", format: PIXELFORMAT_R32U },
{ name: "dataTransformA", format: PIXELFORMAT_RGBA32U },
{ name: "dataTransformB", format: PIXELFORMAT_R32U }
], {
readGLSL: glslCompactRead,
readWGSL: wgslCompactRead
});
format.setWriteCode(glslCompactWrite, wgslCompactWrite);
} else {
const colorFormat = this._device.getRenderableHdrFormat([PIXELFORMAT_RGBA16F]) || PIXELFORMAT_RGBA16U;
format = new GSplatFormat(this._device, [
{ name: "dataColor", format: colorFormat },
{ name: "dataTransformA", format: PIXELFORMAT_RGBA32U },
{ name: "dataTransformB", format: PIXELFORMAT_RG32U }
], {
readGLSL: glslPackedRead,
readWGSL: wgslPackedRead
});
format.setWriteCode(glslPackedWrite, wgslPackedWrite);
}
format.allowStreamRemoval = true;
return format;
}
/**
* Sets the rendering pipeline used for gaussian splatting. Can be:
*
* - {@link GSPLAT_RENDERER_AUTO}: Automatically selects the best pipeline for the platform.
* - {@link GSPLAT_RENDERER_RASTER_CPU_SORT}: Rasterization with CPU-side sorting.
* - {@link GSPLAT_RENDERER_COMPUTE}: Full compute pipeline (WebGPU only, experimental).
* - {@link GSPLAT_RENDERER_RASTER_GPU_SORT}: Rasterization with GPU-side sorting (WebGPU only,
* experimental).
*
* Defaults to {@link GSPLAT_RENDERER_AUTO}. Modes requiring WebGPU fall back to
* {@link GSPLAT_RENDERER_RASTER_CPU_SORT} on WebGL devices. The resolved mode actually used
* can be queried via {@link currentRenderer}.
*
* @type {number}
*/
set renderer(value) {
if (this._renderer !== value) {
this._renderer = value;
if (value === GSPLAT_RENDERER_AUTO) {
this._currentRenderer = GSPLAT_RENDERER_RASTER_CPU_SORT;
} else if ((value === GSPLAT_RENDERER_COMPUTE || value === GSPLAT_RENDERER_RASTER_GPU_SORT) && !this._device.isWebGPU) {
this._currentRenderer = GSPLAT_RENDERER_RASTER_CPU_SORT;
} else {
this._currentRenderer = value;
}
}
}
/**
* Gets the requested rendering pipeline for gaussian splatting. This may differ from
* {@link currentRenderer} when a WebGPU mode falls back on a WebGL device.
*
* @type {number}
*/
get renderer() {
return this._renderer;
}
/**
* The current rendering pipeline in effect after platform-based fallback resolution. When
* {@link renderer} is set to a mode requiring WebGPU on a WebGL device, this returns the
* fallback mode actually being used.
*
* @type {number}
*/
get currentRenderer() {
return this._currentRenderer;
}
/**
* Sets the debug rendering mode for Gaussian splats. Can be:
*
* - {@link GSPLAT_DEBUG_NONE}: Normal rendering (default).
* - {@link GSPLAT_DEBUG_LOD}: Colorize splats by their selected LOD level.
* - {@link GSPLAT_DEBUG_SH_UPDATE}: Random color per SH update pass to visualize update
* frequency.
* - {@link GSPLAT_DEBUG_HEATMAP}: Heatmap visualization of average splats processed per
* pixel in each tile. Only supported with {@link GSPLAT_RENDERER_COMPUTE}.
* - {@link GSPLAT_DEBUG_AABBS}: Draw world-space AABBs for each GSplat, colorized by LOD.
* - {@link GSPLAT_DEBUG_NODE_AABBS}: Draw world-space AABBs for each octree node of
* streamed GSplats, colorized by the currently selected LOD.
*
* Only one debug mode can be active at a time. Defaults to {@link GSPLAT_DEBUG_NONE}.
*
* @type {number}
*/
set debug(value) {
if (this._debug !== value) {
const prev = this._debug;
this._debug = value;
if (value === GSPLAT_DEBUG_LOD || prev === GSPLAT_DEBUG_LOD || value === GSPLAT_DEBUG_HEATMAP || prev === GSPLAT_DEBUG_HEATMAP) {
this.dirty = true;
}
}
}
/**
* Gets the debug rendering mode for Gaussian splats.
*
* @type {number}
*/
get debug() {
return this._debug;
}
/**
* @type {boolean}
* @deprecated Use {@link debug} with {@link GSPLAT_DEBUG_LOD} instead.
* @ignore
*/
set colorizeLod(value) {
Debug.deprecated("GSplatParams#colorizeLod is deprecated. Use GSplatParams#debug = GSPLAT_DEBUG_LOD instead.");
this.debug = value ? GSPLAT_DEBUG_LOD : GSPLAT_DEBUG_NONE;
}
/**
* @type {boolean}
* @deprecated Use {@link debug} with {@link GSPLAT_DEBUG_LOD} instead.
* @ignore
*/
get colorizeLod() {
return this._debug === GSPLAT_DEBUG_LOD;
}
/**
* @type {boolean}
* @deprecated Use {@link debug} with {@link GSPLAT_DEBUG_AABBS} instead.
* @ignore
*/
set debugAabbs(value) {
Debug.deprecated("GSplatParams#debugAabbs is deprecated. Use GSplatParams#debug = GSPLAT_DEBUG_AABBS instead.");
this.debug = value ? GSPLAT_DEBUG_AABBS : GSPLAT_DEBUG_NONE;
}
/**
* @type {boolean}
* @deprecated Use {@link debug} with {@link GSPLAT_DEBUG_AABBS} instead.
* @ignore
*/
get debugAabbs() {
return this._debug === GSPLAT_DEBUG_AABBS;
}
/**
* @type {boolean}
* @deprecated Use {@link debug} with {@link GSPLAT_DEBUG_NODE_AABBS} instead.
* @ignore
*/
set debugNodeAabbs(value) {
Debug.deprecated("GSplatParams#debugNodeAabbs is deprecated. Use GSplatParams#debug = GSPLAT_DEBUG_NODE_AABBS instead.");
this.debug = value ? GSPLAT_DEBUG_NODE_AABBS : GSPLAT_DEBUG_NONE;
}
/**
* @type {boolean}
* @deprecated Use {@link debug} with {@link GSPLAT_DEBUG_NODE_AABBS} instead.
* @ignore
*/
get debugNodeAabbs() {
return this._debug === GSPLAT_DEBUG_NODE_AABBS;
}
/**
* Enables or disables per-component ID storage in the work buffer. When enabled, each GSplat
* component gets a unique ID written to the work buffer. This ID is used by the picking
* system to identify which component was picked, but is also available to custom shaders for
* effects like highlighting, animation, or any per-component differentiation.
*
* @type {boolean}
*/
set enableIds(value) {
if (value && !this._enableIds) {
this._enableIds = true;
if (!this._format.getStream("pcId")) {
this._format.addExtraStreams([
{ name: "pcId", format: PIXELFORMAT_R32U }
]);
}
} else if (!value && this._enableIds) {
this._enableIds = false;
this._format.removeExtraStreams(["pcId"]);
}
}
/**
* Gets the ID storage enabled state.
*
* @type {boolean}
*/
get enableIds() {
return this._enableIds;
}
/**
* Multiplier applied to effective distance for nodes behind the camera when determining LOD.
* Value 1 means no penalty; higher values drop LOD faster for nodes behind the camera.
*
* Note: when using a penalty > 1, it often makes sense to set a positive
* {@link lodUpdateAngle} so LOD is re-evaluated on camera rotation, not just translation.
*
* @type {number}
*/
set lodBehindPenalty(value) {
if (this._lodBehindPenalty !== value) {
this._lodBehindPenalty = value;
this.dirty = true;
}
}
/**
* Gets behind-camera LOD penalty multiplier.
*
* @type {number}
*/
get lodBehindPenalty() {
return this._lodBehindPenalty;
}
/**
* Minimum allowed LOD index (inclusive). Defaults to 0.
*
* @type {number}
*/
set lodRangeMin(value) {
if (this._lodRangeMin !== value) {
this._lodRangeMin = value;
this.dirty = true;
}
}
/**
* Gets minimum allowed LOD index (inclusive).
*
* @type {number}
*/
get lodRangeMin() {
return this._lodRangeMin;
}
/**
* Maximum allowed LOD index (inclusive). Defaults to 10.
*
* @type {number}
*/
set lodRangeMax(value) {
if (this._lodRangeMax !== value) {
this._lodRangeMax = value;
this.dirty = true;
}
}
/**
* Gets maximum allowed LOD index (inclusive).
*
* @type {number}
*/
get lodRangeMax() {
return this._lodRangeMax;
}
/**
* Maximum number of LOD levels allowed below the optimal level when the optimal data is not
* resident in memory. The system may temporarily use a coarser LOD within this limit until the
* optimal LOD is available. Defaults to 0, which disables fallback (always load optimal).
* Higher values allow faster loading by using lower-quality data.
*
* @type {number}
*/
set lodUnderfillLimit(value) {
if (this._lodUnderfillLimit !== value) {
this._lodUnderfillLimit = value;
this.dirty = true;
}
}
/**
* Gets the maximum allowed underfill LOD range.
*
* @type {number}
*/
get lodUnderfillLimit() {
return this._lodUnderfillLimit;
}
/**
* Target number of splats across all GSplats in the scene. When set > 0,
* the system adjusts LOD levels globally to stay within this budget.
* Set to 0 to disable budget enforcement and use LOD distances only (default).
*
* @type {number}
*/
set splatBudget(value) {
if (this._splatBudget !== value) {
this._splatBudget = value;
this.dirty = true;
}
}
/**
* Gets the target number of splats across all GSplats in the scene.
*
* @type {number}
*/
get splatBudget() {
return this._splatBudget;
}
/**
* Gradient texture for elevation-based coloring in overdraw visualization mode.
* When set, enables overdraw mode with additive blending. When null, uses normal rendering.
* Texture should be (width x 1) size. World Y coordinate (0-20 range) maps to texture U coordinate.
* Defaults to null.
*
* @type {Texture|null}
*/
set colorRamp(value) {
if (this._colorRamp !== value) {
this._colorRamp = value;
this.dirty = true;
}
}
/**
* Gets the color ramp texture for overdraw visualization.
*
* @type {import('../../platform/graphics/texture.js').Texture|null}
*/
get colorRamp() {
return this._colorRamp;
}
/** @deprecated Use {@link debug} with {@link GSPLAT_DEBUG_SH_UPDATE} instead. */
set colorizeColorUpdate(value) {
Debug.deprecated("GSplatParams#colorizeColorUpdate is deprecated. Use GSplatParams#debug = GSPLAT_DEBUG_SH_UPDATE instead.");
this.debug = value ? GSPLAT_DEBUG_SH_UPDATE : GSPLAT_DEBUG_NONE;
}
/**
* @deprecated Use {@link debug} with {@link GSPLAT_DEBUG_SH_UPDATE} instead.
* @returns {boolean} Whether SH update colorization is enabled.
*/
get colorizeColorUpdate() {
return this._debug === GSPLAT_DEBUG_SH_UPDATE;
}
/** @ignore */
set colorUpdateDistance(value) {
Debug.removed("GSplatParams#colorUpdateDistance is removed. Use colorUpdateAngle instead.");
}
/** @ignore */
get colorUpdateDistance() {
Debug.removed("GSplatParams#colorUpdateDistance is removed. Use colorUpdateAngle instead.");
return 0;
}
/** @ignore */
set colorUpdateDistanceLodScale(value) {
Debug.removed("GSplatParams#colorUpdateDistanceLodScale is removed. Per-node distance scaling is now automatic.");
}
/** @ignore */
get colorUpdateDistanceLodScale() {
Debug.removed("GSplatParams#colorUpdateDistanceLodScale is removed. Per-node distance scaling is now automatic.");
return 0;
}
/** @ignore */
set colorUpdateAngleLodScale(value) {
Debug.removed("GSplatParams#colorUpdateAngleLodScale is removed. Per-node distance scaling is now automatic.");
}
/** @ignore */
get colorUpdateAngleLodScale() {
Debug.removed("GSplatParams#colorUpdateAngleLodScale is removed. Per-node distance scaling is now automatic.");
return 0;
}
/**
* Sets the alpha threshold for shadow, pick, and prepass rendering (not the main forward
* splat pass). Higher values create more aggressive clipping, while lower values preserve more
* translucent splats. Defaults to 0.3.
*
* @type {number}
*/
set alphaClip(value) {
this._material.setParameter("alphaClip", value);
this._material.update();
}
/**
* Gets the alpha threshold for shadow, pick, and prepass rendering.
*
* @type {number}
*/
get alphaClip() {
return this._material.getParameter("alphaClip")?.data ?? 0.3;
}
/**
* Sets the alpha threshold below which splats are culled or clipped in the **forward** splat
* rendering pass. Does not apply to shadow, pick, or prepass — use {@link GSplatParams#alphaClip}
* for those. Higher values improve performance by culling more low-opacity splats; lower values
* preserve more translucent splats. Defaults to 1 / 255.
*
* @type {number}
*/
set alphaClipForward(value) {
this._material.setParameter("alphaClipForward", value);
this._material.update();
}
/**
* Gets the forward-pass alpha threshold.
*
* @type {number}
*/
get alphaClipForward() {
return this._material.getParameter("alphaClipForward")?.data ?? 1 / 255;
}
/**
* Sets the minimum screen-space pixel size below which splats are discarded. Defaults to 2.
*
* @type {number}
*/
set minPixelSize(value) {
this._material.setParameter("minPixelSize", value);
this._material.update();
}
/**
* Gets the minimum pixel size threshold.
*
* @type {number}
*/
get minPixelSize() {
return this._material.getParameter("minPixelSize")?.data ?? 2;
}
/**
* Sets the minimum visual contribution threshold for the {@link GSPLAT_RENDERER_COMPUTE} renderer.
* Splats whose total screen contribution (opacity * projected area) falls below this value are
* discarded. Higher values cull more aggressively, improving performance at the cost of quality.
* Set to 0 to disable contribution culling. Defaults to 3.
*
* @type {number}
*/
set minContribution(value) {
this._material.setParameter("minContribution", value);
this._material.update();
}
/**
* Gets the minimum contribution threshold.
*
* @type {number}
*/
get minContribution() {
return this._material.getParameter("minContribution")?.data ?? 3;
}
/**
* Enables anti-aliasing compensation for Gaussian splats. Defaults to false.
*
* This option is intended for splat data that was generated with anti-aliasing
* enabled during training/export. It improves visual stability and reduces
* flickering for very small or distant splats.
*
* If the source splats were generated without anti-aliasing, enabling this
* option may slightly soften the image or alter opacity.
*
* @type {boolean}
*/
set antiAlias(value) {
this._material.setDefine("GSPLAT_AA", value);
this._material.update();
}
/**
* Gets whether anti-aliasing compensation is enabled.
*
* @type {boolean}
*/
get antiAlias() {
return !!this._material.getDefine("GSPLAT_AA");
}
/**
* Enables 2D Gaussian Splatting mode. Defaults to false.
*
* Renders splats as oriented 2D surface elements instead of volumetric 3D Gaussians.
* This provides a more surface-accurate appearance but requires splat data that
* was generated for 2D Gaussian Splatting.
*
* Enabling this with standard 3D splat data may produce incorrect results.
*
* @type {boolean}
*/
set twoDimensional(value) {
this._material.setDefine("GSPLAT_2DGS", value);
this._material.update();
}
/**
* Gets whether 2D Gaussian Splatting mode is enabled.
*
* @type {boolean}
*/
get twoDimensional() {
return !!this._material.getDefine("GSPLAT_2DGS");
}
/**
* Controls the fisheye projection strength for Gaussian splats. The value is in the
* range [0, 1]:
*
* - 0: Standard rectilinear (perspective) projection.
* - (0, 1]: Increasing barrel distortion, producing a wider field of view with a
* "little planet" effect at higher values.
*
* Enabling fisheye for the first time has a small one-off cost as new shaders are
* compiled. Subsequent switches between 0 and non-zero are instantaneous.
*
* Only supported with perspective cameras. Has no effect with orthographic projection.
*
* Note: This only affects Gaussian splat rendering. Other objects in the scene (meshes,
* sprites, etc.) continue to use the standard camera projection and are not distorted.
*
* For best results, enable {@link radialSorting} when using fisheye projection
* to avoid sorting artifacts caused by the wide field of view.
*
* Defaults to 0.
*
* @type {number}
*/
set fisheye(value) {
if (this._fisheye !== value) {
const wasEnabled = this._fisheye > 0;
this._fisheye = value;
const isEnabled = value > 0;
if (wasEnabled !== isEnabled) {
this._material.setDefine("GSPLAT_FISHEYE", isEnabled);
this._material.update();
}
}
}
/**
* Gets the fisheye projection strength.
*
* @type {number}
*/
get fisheye() {
return this._fisheye;
}
/**
* Work buffer data format. Controls the precision and bandwidth of the intermediate work buffer
* used during GSplat rendering. Can be set to {@link GSPLATDATA_COMPACT} (20 bytes/splat)
* or {@link GSPLATDATA_LARGE} (32 bytes/splat). Defaults to {@link GSPLATDATA_COMPACT}.
*
* @type {string}
*/
set dataFormat(value) {
if (this._dataFormat !== value) {
this._dataFormat = value;
const extraStreams = this._format.extraStreams.map((s) => ({
name: s.name,
format: s.format,
storage: s.storage
}));
this._format = this._createFormat(value);
if (extraStreams.length > 0) {
this._format.addExtraStreams(extraStreams);
}
this.dirty = true;
}
}
/**
* Gets the work buffer data format.
*
* @type {string}
*/
get dataFormat() {
return this._dataFormat;
}
/**
* A material template that can be customized by the user. Any defines, parameters, or shader
* chunks set on this material will be automatically applied to all GSplat components. After
* making changes, call {@link Material#update} to for the changes to be applied on the next
* frame.
*
* @type {ShaderMaterial}
* @example
* // Set a custom parameter on all GSplat materials
* app.scene.gsplat.material.setParameter('myCustomParam', 1.0);
* app.scene.gsplat.material.update();
*/
get material() {
return this._material;
}
/**
* Format descriptor for work buffer streams. Describes the textures used by the work buffer
* for intermediate storage during rendering. Users can add extra streams via
* {@link GSplatFormat#addExtraStreams} for custom per-splat data.
*
* @type {GSplatFormat}
* @example
* // Add a custom stream to store per-splat component IDs
* app.scene.gsplat.format.addExtraStreams([{
* name: 'splatId',
* format: pc.PIXELFORMAT_R32U
* }]);
*/
get format() {
return this._format;
}
/**
* Called at the end of the frame to clear dirty flags.
*
* @ignore
*/
frameEnd() {
this._material.dirty = false;
this.dirty = false;
}
}
export {
GSplatParams
};