You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WGSL数组用变量索引报错,求Bevy 0.12计算着色器解决办法

在Bevy 0.12的WGSL计算着色器中使用变量索引固定大小数组的问题

我正在为Bevy 0.12编写计算着色器,使用WGSL语言。编写了如下is_boxed_in函数,尝试通过变量索引固定大小数组array<ShaderVoxel, 4096>:

fn is_boxed_in(x: u32, y: u32, z: u32, voxels: array<ShaderVoxel, 4096>) -> bool {
    if check_for_voxel(voxels[voxel_to_1d(min(CHUNK_SIZE - 1u, x + 1u), y, z)])
        && check_for_voxel(voxels[voxel_to_1d(max(0u, x - 1u), y, z)])
        && check_for_voxel(voxels[voxel_to_1d(x, min(CHUNK_SIZE - 1u, y + 1u), z)])
        && check_for_voxel(voxels[voxel_to_1d(x, max(0u, y - 1u), z)])
        && check_for_voxel(voxels[voxel_to_1d(x, y, min(CHUNK_SIZE - 1u, z + 1u))])
        && check_for_voxel(voxels[voxel_to_1d(x, y, max(0u, z - 1u))])
    {
        return true;
    }

    return false;
}

但触发了如下错误:

Function [6] 'is_boxed_in' is invalid.

WithSpan {
    inner: Function {
        handle: [6],
        name: "is_boxed_in",
        source: Expression {
            handle: [10],
            source: IndexMustBeConstant(
                [4],
            ),
        },
    },
    spans: [
        (
            Span {
                start: 2094,
                end: 2700,
            },
            "naga::Function [6]",
        ),
        (
            Span {
                start: 2201,
                end: 2256,
            },
            "naga::Expression [10]",
        ),
    ],
}

该函数的调用代码如下:

@compute @workgroup_size(16, 16, 1)
fn init(@builtin(global_invocation_id) global_id: vec3<u32>){
    let index = voxel_to_1d(global_id.x, global_id.y, global_id.z);

    var iter = 0u;
    while iter < arrayLength(&chunks.chunks) {
        var chunk = chunks.chunks[iter];
        var voxels = chunk.voxels;
        for (var i = 0; i < 4096; i += 1){
            var voxel = voxels[i];
            if voxel.id != 0u && !is_boxed_in(voxel_to_3d(i).x, voxel_to_3d(i).y, voxel_to_3d(i).z, voxels){
                //gen normal
            }
        }
        iter += 1u;
    }
}

请问是否可以使用变量索引该数组?若可行,正确的实现方式是什么?


解答

可以使用变量索引固定大小数组,当前报错是因为WGSL中直接传递固定大小数组作为函数参数时,编译器会将其视为值传递的常量大小数组,要求索引必须是编译期常量,而你的索引是运行时计算的,因此Naga(Bevy使用的WGSL编译器)抛出错误。

推荐两种解决方法:

方法1:将数组参数改为指针类型

把is_boxed_in的voxels参数从array<ShaderVoxel, 4096>改为指针类型,调用时传递数组的指针:

修改后的is_boxed_in函数:

fn is_boxed_in(x: u32, y: u32, z: u32, voxels: ptr<function, array<ShaderVoxel, 4096>>) -> bool {
    if check_for_voxel((*voxels)[voxel_to_1d(min(CHUNK_SIZE - 1u, x + 1u), y, z)])
        && check_for_voxel((*voxels)[voxel_to_1d(max(0u, x - 1u), y, z)])
        && check_for_voxel((*voxels)[voxel_to_1d(x, min(CHUNK_SIZE - 1u, y + 1u), z)])
        && check_for_voxel((*voxels)[voxel_to_1d(x, max(0u, y - 1u), z)])
        && check_for_voxel((*voxels)[voxel_to_1d(x, y, min(CHUNK_SIZE - 1u, z + 1u))])
        && check_for_voxel((*voxels)[voxel_to_1d(x, y, max(0u, z - 1u))])
    {
        return true;
    }

    return false;
}

调用时修改为传递指针:

if voxel.id != 0u && !is_boxed_in(voxel_to_3d(i).x, voxel_to_3d(i).y, voxel_to_3d(i).z, &voxels){
    //gen normal
}

这种方式让编译器明确数组是外部分配的,允许使用运行时变量索引。

方法2:将数组包装成结构体

如果指针方式不匹配你的代码结构,可以把数组放到结构体中传递:

首先定义结构体:

struct VoxelArray {
    data: array<ShaderVoxel, 4096>,
};

修改is_boxed_in参数:

fn is_boxed_in(x: u32, y: u32, z: u32, voxels: VoxelArray) -> bool {
    if check_for_voxel(voxels.data[voxel_to_1d(min(CHUNK_SIZE - 1u, x + 1u), y, z)])
        && check_for_voxel(voxels.data[voxel_to_1d(max(0u, x - 1u), y, z)])
        && check_for_voxel(voxels.data[voxel_to_1d(x, min(CHUNK_SIZE - 1u, y + 1u), z)])
        && check_for_voxel(voxels.data[voxel_to_1d(x, max(0u, y - 1u), z)])
        && check_for_voxel(voxels.data[voxel_to_1d(x, y, min(CHUNK_SIZE - 1u, z + 1u))])
        && check_for_voxel(voxels.data[voxel_to_1d(x, y, max(0u, z - 1u))])
    {
        return true;
    }

    return false;
}

调用时确保chunk.voxels是VoxelArray类型,直接传递即可。


内容的提问来源于stack exchange,提问作者NewUser69420

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.29 22:31:01