跳到主要内容

程序化高斯泼溅

GSplatContainer 可通过程序创建数据而非从文件加载,适合动态可视化、程序化效果和其他数据转换。

备注

此功能基于渲染架构。

概览​

GSplatContainer 是由 CPU 填充的容器,搭配定义纹理流与属性读取方式的 GSplatFormat。GSplatProcessor 也可从 GPU 写入。

主要特点:

  • 固定大小:创建时设容量,不能更改。
  • CPU 填充:JavaScript 写入纹理数据。
  • GPU 填充:可通过 GSplatProcessor 写入。
  • 格式驱动:GSplatFormat 定义布局和代码。

数据格式​

文件资源自动确定格式,程序化数据则需显式创建。引擎为常见用途提供内置格式。

内置格式​

默认格式​

GSplatFormat.createDefaultFormat(device) 包含完整数据:

数据流格式内容
dataColorRGBA16F半浮点 r、g、b、a
dataCenterRGBA32F浮点 x、y、z 位置
dataScaleRGBA16F半浮点 x、y、z 缩放
dataRotationRGBA16F半浮点 x、y、z、w 四元数
const format = pc.GSplatFormat.createDefaultFormat(device);

简化格式​

GSplatFormat.createSimpleFormat(device) 创建无旋转、统一缩放的轻量格式:

数据流格式内容
dataCenterRGBA32Fxyz 位置,w 保存统一尺寸
dataColorRGBA16F半浮点 r、g、b、a
const format = pc.GSplatFormat.createSimpleFormat(device);

适合 GsplatMesh、GsplatImage、GsplatLines 等辅助脚本。

自定义格式​

高级用途可自行定义数据流和代码。

构造函数​

const format = new pc.GSplatFormat(device, streams, options);

参数:

  • device:图形设备。
  • streams:{ name: string, format: number } 描述符数组。
  • options.readGLSL:WebGL 所需 GLSL。
  • options.readWGSL:WebGPU 所需 WGSL。

必需着色器函数​

读取代码必须定义:

函数返回类型说明
getCenter()vec3局部空间位置
getColor()vec4r、g、b、a 颜色
getScale()vec3x、y、z 缩放
getRotation()vec4x、y、z、w 四元数

getCenter() 始终最先执行,可在其中采样纹理、保存共享全局值,供其他函数使用。

加载函数​

每条流生成 load{StreamName}(),首字母大写。例如 data 生成 loadData()。

示例:带染色 uniform 的自定义格式​

用单张 RGBA8 纹理和自定义 uniform 创建逐实例颜色渐变:

const format = new pc.GSplatFormat(device, [
{ name: 'data', format: pc.PIXELFORMAT_RGBA8 }
], {
readGLSL: `
uniform vec3 uTint;
uniform vec3 uTint2;
vec4 splatData; // Global variable to avoid sampling texture twice

vec3 getCenter() {
// getCenter always executes first - sample texture here
splatData = loadData();
return (splatData.rgb - 0.5) * 5.0;
}

vec4 getColor() {
vec3 tint = mix(uTint2, uTint, splatData.a);
return vec4(tint, 1.0);
}

vec3 getScale() { return vec3(0.15); }
vec4 getRotation() { return vec4(0.0, 0.0, 0.0, 1.0); }
`,
readWGSL: `
uniform uTint: vec3f;
uniform uTint2: vec3f;
var<private> splatData: vec4f; // Global variable to avoid sampling texture twice

fn getCenter() -> vec3f {
// getCenter always executes first - sample texture here
splatData = loadData();
return (splatData.rgb - 0.5) * 5.0;
}

fn getColor() -> vec4f {
let tint = mix(uniform.uTint2, uniform.uTint, splatData.a);
return vec4f(tint, 1.0);
}

fn getScale() -> vec3f { return vec3f(0.15); }
fn getRotation() -> vec4f { return vec4f(0.0, 0.0, 0.0, 1.0); }
`
});

基本用法​

1. 创建格式​

使用内置或自定义格式:

// Simple format for uniform-scale splats (no rotation)
const format = pc.GSplatFormat.createSimpleFormat(device);

// Or default format with full splat data
const format = pc.GSplatFormat.createDefaultFormat(device);

2. 创建容器​

const maxSplats = 1000;
const container = new pc.GSplatContainer(device, maxSplats, format);

3. 填充纹理​

锁定、填数据、解锁:

// Get textures by stream name
const centerTex = container.getTexture('dataCenter');
const colorTex = container.getTexture('dataColor');

// Lock for writing
const centerData = centerTex.lock(); // Float32Array for RGBA32F
const colorData = colorTex.lock(); // Uint16Array for RGBA16F

// Fill data for each splat
for (let i = 0; i < numSplats; i++) {
// Center position (x, y, z) + size in w
centerData[i * 4 + 0] = x;
centerData[i * 4 + 1] = y;
centerData[i * 4 + 2] = z;
centerData[i * 4 + 3] = size;

// Color as half-floats (use FloatPacking helper)
colorData[i * 4 + 0] = pc.FloatPacking.float2Half(r);
colorData[i * 4 + 1] = pc.FloatPacking.float2Half(g);
colorData[i * 4 + 2] = pc.FloatPacking.float2Half(b);
colorData[i * 4 + 3] = pc.FloatPacking.float2Half(a);
}

// Unlock when done
centerTex.unlock();
colorTex.unlock();

4. 设置中心与包围盒​

中心用于排序,包围盒用于剔除:

// Fill centers array (xyz per splat, Float32Array)
const centers = container.centers;
for (let i = 0; i < numSplats; i++) {
centers[i * 3 + 0] = x;
centers[i * 3 + 1] = y;
centers[i * 3 + 2] = z;
}

// Set bounding box
container.aabb = new pc.BoundingBox(
new pc.Vec3(centerX, centerY, centerZ),
new pc.Vec3(halfExtentX, halfExtentY, halfExtentZ)
);

5. 更新并加入场景​

// Update container with number of splats to render (can be less than maxSplats)
container.update(numSplats);

// Add to scene via gsplat component
entity.addComponent('gsplat', {
resource: container
});

numSplats 可小于等于 maxSplats,只渲染容器一部分。

更新数据​

创建后更新:

  1. 锁定纹理,修改,解锁。
  2. 中心变化时更新 container.centers。
  3. 调用 container.update(numSplats, centersUpdated)。
// Update color texture
const colorTex = container.getTexture('dataColor');
const colorData = colorTex.lock();
// ... modify colorData ...
colorTex.unlock();

// Update count (centersUpdated=false if centers didn't change)
container.update(numSplats, false);

辅助脚本​

以下现成脚本封装容器,覆盖常见用途:

脚本说明
GsplatMesh转换网格
GsplatImage每可见像素一个单元
GsplatLines线、箭头、包围盒
GsplatText渲染文本

脚本负责容器创建和数据填充。

实时示例​

Procedural Instanced 演示自定义容器、格式及逐实例 uniform。

程序化实例示例

另请参见​