跳到主要内容

Varying 数据流

Varying 数据流从顶点阶段传递自定义逐单元值到片元阶段。值在 gsplatModifyVS 每单元计算一次,由 gsplatModifyPS 中每个片元读取。

典型用途是分类:先对单元判断一次,让逐像素阶段只在必要位置承担开销。

查看实时示例:动画盒裁剪,只有与盒表面相交的单元逐像素测试。

查看实时示例

添加数据流​

通过 app.scene.gsplat.varyings 管理:

app.scene.gsplat.varyings.add([
{ name: 'clipState', type: pc.TYPE_UINT32, components: 1 }
]);

// later, to remove
app.scene.gsplat.varyings.remove(['clipState']);

支持 TYPE_FLOAT32、TYPE_INT32、TYPE_UINT32,每项 1–4 分量。

每条流生成两个供代码块使用的函数:

函数使用位置用途
set<Name>(value)gsplatModifyVS写逐单元值,每单元一次
get<Name>()gsplatModifyPS为当前片元读取值

增删数据流会重建着色器,应启动时配置,避免运行时切换。

示例​

示例按动画世界空间盒分类:完全在盒内的整体裁掉;完全在外的设置标志,片元跳过工作;只有与表面相交的执行逐像素测试。

1. 顶点代码块写入逐单元值:

uniform vec3 uClipCenter;
uniform vec3 uClipHalf;

void modifySplatCenter(inout vec3 center) {
}

void modifySplatRotationScale(vec3 originalCenter, vec3 modifiedCenter, inout vec4 rotation, inout vec3 scale) {
// signed distance of the splat center from the clipping box surface (negative inside)
vec3 d = abs(modifiedCenter - uClipCenter) - uClipHalf;
float sdf = length(max(d, vec3(0.0))) + min(max(d.x, max(d.y, d.z)), 0.0);

// conservative splat radius
float radius = 2.0 * gsplatGetSizeFromScale(scale);

if (sdf < -radius) {
// fully inside the box - clip the whole splat
scale = vec3(0.0);
setClipState(1u);
} else if (sdf > radius) {
// fully outside the box - no per-pixel clipping needed
setClipState(1u);
} else {
// intersects the box surface - clip per pixel in the fragment shader
setClipState(0u);
}
}

void modifySplatColor(vec3 center, inout vec4 color) {
}

2. 片元读取并在昂贵操作前提前退出:

示例假设填满画布。内置 screen_size 提供尺寸,其他目标或局部视口需调整归一化。

uniform vec3 uClipCenter;
uniform vec3 uClipHalf;
uniform mat4 uInvViewProj;
uniform vec4 screen_size;

void modifySplatColor(vec2 gaussianUV, inout vec4 color) {
// splats fully inside or outside the box were already resolved per splat in the vertex stage
if (getClipState() == 1u) return;

// reconstruct the world position of this fragment (on the splat's depth plane)
vec3 ndc = vec3(gl_FragCoord.xy * screen_size.zw, gl_FragCoord.z) * 2.0 - 1.0;
vec4 world = uInvViewProj * vec4(ndc, 1.0);
vec3 worldPos = world.xyz / world.w;

// clip fragments inside the box
vec3 d = abs(worldPos - uClipCenter) - uClipHalf;
if (max(d.x, max(d.y, d.z)) < 0.0) {
color.a = 0.0;
}
}

按常规方式将两个代码块通过 gsplatModifyVS 和 gsplatModifyPS 应用到全局材质。

内存考虑​

部分平台将每分量保存在逐单元显存中,大小随渲染数量增长。应尽量紧凑,减少分量,将多个小值按位打包到一个 uint,避免独立数据流。

另请参见​