Freeciv3D - port shader from WebGL to WebGPU Shader Language (WGSL)


As part of updating Freeciv3D to WebGPU, I am going to port the WebGL shader to WebGPU Shader Language (WGSL).

Are there any relevant examples of WGSL shaders for Three.js that I can use in order to understand how to do this? The shader can be simple initially showing only the game map terrain tiles, and eventually also support shadows, rendering borders and fog of war.

Freeciv3D Github project: GitHub - fciv-net/fciv-net: the 3D version of the Freeciv strategy game

This is the existing shader which I will be porting to WGSL:

I will be reading this: WebGPU Shading Language

Screenshot from the game:

I once did this as an example for someone. In it you can see how you can use wgsl in 3js.

Since I’ve been working with the webgpu renderer for some time now, I can explain a few things to you if you have any questions.

I saw a vertex and fragment shader in the app. The topic with the varyings is currently in development and there will be an extension to it with r159.
Most or even all of what I saw in the vertex and fragment shader in the app could be implemented without varyings.


If your geometry has (position, normal, uv) attributes, you can also use them in the node system in the fragment stage (colorNode) analogous to my example in the link, as long as you don’t change them in the vertex shader and don’t need the changed positions and normals. Since it is a landscape, I am assuming that you do not reposition the vertices in the vertex shader and do not recalculate the normal vectors. I mean I had seen the vertex shader, it was pretty small. That makes it much easier.
My recommendation would be to first create a very simple fragment stage wgsl shader that initially only outputs a color of your choice. If you see this on the screen, you know it’s running. Then you can gradually incorporate all the uniforms, arrtibutes, constants and keep checking whether you can still see your control color. Then gradually integrate the functions etc. This is how I was able to port my original webgl project well.

A simple example:

const vertexStageParams = {
   position: attribute("position"),
const vertexStageWGSL = wgslFn(`
    fn mainFn(
       position: vec3<f32>,	  
    ) -> vec4<f32> {

	   return vec4<f32>(position, 1);						

const fragmentStageParams = {
   vPosition: attribute("position"),
   vNnormal: attribute("normal"),
   vUv: uv() //or attribute("uv"),
const fragmentStageWGSL = wgslFn(`
    fn mainFn(
       position: vec3<f32>,
       normal: vec3<f32>,
       vUv: vec2<f32>	  
    ) -> vec4<f32> {

	   return vec4<f32>(1, 0, 1, 1);   //testcolor						

    //Place constants and other functions below the main function. 
    //The main function must be at the top

    const PI: f32 = 3.1415; //example for a constant


const material = new MeshBasicNodeMaterial();
material.positionNode = vertexStageWGSL(vertexStageParams);
material.colorNode = fragmentStageWGSL(fragmentStageParams);

If you don’t change anything about the vertices, you can save yourself the vertexStage shader. The node system will then take care of that automatically


Try asking Chat GPT. It does 90% of the work

1 Like

As far as I know, the free version of chatGPT doesn’t yet know that three.js has a webGPURenderer. And since there is no documentation of the node system yet, ChatGPT can only shrug its shoulders :man_shrugging:

Seems to do a pretty good job.

Unfortunately, it won’t do the whole thing in one go yet. But with small enough chunks it can help with the bulk of the work.

1 Like

I get this error when trying this code:

Uncaught ReferenceError: attribute is not defined

How should I define this attribute?

This is because it is just a blunt webgl to wgsl port without taking the 3js api into account. But chatGPT has no idea about the webgpu api in 3js :exploding_head: :wink:
I have a few posts about wgsl here in the forum. With webgpu, 3js took the opportunity to introduce a more powerful node-based material system and things work differently.

Here is a simple example that shows how you can use an attribute