How to display triangles with WebGPU + WGSL?

Below is a sample triangle using GLSL in Babylon.js. This does not seem to be a problem.

BABYLON.ShaderStore.ShadersStore["customTriangleVertexShader"] = `#version 300 es
    in  vec3 position;
    in  vec4 color;
    out vec4 vColor;

    void main() {
        vColor = color;
        gl_Position = vec4(position, 1.0);
    }
`;

Next I tried the above sample with WebGPU + WGSL.

BABYLON.ShaderStore.ShadersStoreWGSL["customTriangleVertexShader"] = `   
    attribute position : vec3<f32>;
    attribute color : vec4<f32>;
    varying vColor : vec4<f32>;

    @vertex
    fn main(input : VertexInputs) -> FragmentInputs {
        vColor = color;
        gl_Position = vec4<f32>(position, 1.0);
    }
`;

However, the following error occurred and could not be displayed.

Attribute shader location (1) is used more than once.

Can someone tell me what is wrong?

Something has been broken in the WGSL support, looking into thatā€¦

2 Likes

BTW, it was displayed without problems when vertex colors were not used.

Ok, so the position and color attributes are handled automatically by the system (as well as normal and uv), you donā€™t need to list them in the attributes property when creating a ShaderMaterial instance:

If you do pass some attributes to the constructor, you should still donā€™t pass color because this one is automatically added as long as there is a ā€œcolorā€ vertex buffer attached to the mesh. So, you should only pass position:

Itā€™s a bit weird, but thatā€™s how ShaderMaterial works and we canā€™t change it to avoid breaking backwards compatibility.

2 Likes

What do you think about using GitHub - brendan-duncan/wgsl_reflect: A WebGPU Shading Language parser and reflection library for Javascript. to automate this?

We could not use it because we are using our own parser to parse some specific constructs not available in WGSL (ā€œattributeā€ / ā€œvaryingā€ for eg).

Itā€™s a little strange, but I understand that it is not necessary to specify the position and color attributes when using ShaderMaterial.
I thought it would be nice to have some additional information about vertex colors in the documentation.

Doc updated:

2 Likes

Thank you for adding to the documentation.
I made some samples using Babylon.js and WGSL. It seems fine for now.

Colored Cube

Textured Cube

Teapot

2 Likes

BTW, before I knew it, the previous sample stopped working. This was a sample before the official specifications were released, so the specifications may have changed.
I have attached the modified code for your reference.

Colored Cube

BABYLON.ShaderStore.ShadersStoreWGSL["customCubeVertexShader"] = `   
    #include<sceneUboDeclaration>
    #include<meshUboDeclaration>

    attribute position : vec3<f32>;
    attribute color : vec4<f32>;

    varying vColor : vec4<f32>;

    @vertex
    fn main(input : VertexInputs) -> FragmentInputs {
        vertexOutputs.vColor = vertexInputs.color;
        vertexOutputs.position =  scene.viewProjection * mesh.world * vec4<f32>(vertexInputs.position, 1.0);
    }
`;

BABYLON.ShaderStore.ShadersStoreWGSL["customCubeFragmentShader"] =`
    varying vColor : vec4<f32>;

    @fragment
    fn main(input : FragmentInputs) -> FragmentOutputs {
        fragmentOutputs.color = fragmentInputs.vColor;
    }
`;

Textured Cube

BABYLON.ShaderStore.ShadersStoreWGSL["customCubeVertexShader"] = `   
    #include<sceneUboDeclaration>
    #include<meshUboDeclaration>

    attribute position : vec3<f32>;
    attribute uv: vec2<f32>;

    varying vUV : vec2<f32>;

    @vertex
    fn main(input : VertexInputs) -> FragmentInputs {
        vertexOutputs.vUV =vertexInputs.uv;
        vertexOutputs.position =  scene.viewProjection * mesh.world * vec4<f32>(vertexInputs.position, 1.0);
    }
`;

BABYLON.ShaderStore.ShadersStoreWGSL["customCubeFragmentShader"] =`
    varying vUV : vec2<f32>;

    var diffuse : texture_2d<f32>;
    var mySampler : sampler;

    @fragment
    fn main(input : FragmentInputs) -> FragmentOutputs {
        fragmentOutputs.color = textureSample(diffuse, mySampler, fragmentInputs.vUV);
    }
`;

Teapot

BABYLON.ShaderStore.ShadersStoreWGSL["teapotVertexShader"] = `   
    #include<sceneUboDeclaration>
    #include<meshUboDeclaration>

    attribute position : vec3<f32>;
    attribute normal : vec3<f32>;
    attribute uv: vec2<f32>;

    varying vPosition : vec3<f32>;
    varying vNormal : vec3<f32>;
    varying vUV : vec2<f32>;

    @vertex
    fn main(input : VertexInputs) -> FragmentInputs {
        vertexOutputs.position =  scene.viewProjection * mesh.world * vec4<f32>(vertexInputs.position, 1.0);
        vertexOutputs.vPosition = vertexOutputs.position.xyz;
        vertexOutputs.vNormal = vertexInputs.normal;
        vertexOutputs.vUV = vertexInputs.uv;
    }
`;

BABYLON.ShaderStore.ShadersStoreWGSL["teapotFragmentShader"] =`
    uniform uPointLightingLocation : vec3<f32>;

    varying vPosition : vec3<f32>;
    varying vNormal : vec3<f32>;
    varying vUV : vec2<f32>;

    var diffuse : texture_2d<f32>;
    var mySampler : sampler;

    @fragment
    fn main(input : FragmentInputs) -> FragmentOutputs {
        var lightDirection: vec3<f32> = normalize(uniforms.uPointLightingLocation - fragmentInputs.vPosition.xyz);
        var normal: vec3<f32> = normalize(fragmentInputs.vNormal);
        var lightWeighting: f32 = max(dot(normal, lightDirection), 0.0);
        var fragmentColor: vec4<f32> = textureSample(diffuse, mySampler, fragmentInputs.vUV);
        fragmentOutputs.color = vec4<f32>(fragmentColor.rgb * lightWeighting, fragmentColor.a);
    }
`;
2 Likes