Custom WebGL code

Hi Cesium team,

1. A concise explanation of the problem you’re experiencing.

I am trying to pass custom vertex shader code to a material. I know you can pass in fragment shader code in the fabric json under the “source” field. But I also need pass in a vertex shader because I am creating an animation.

2. A minimal code example. If you’ve found a bug, this helps us reproduce and repair it.

I attached an image of what I have. I am passing in the fragment shader using fabrics like the ones from here: https://github.com/AnalyticalGraphicsInc/cesium-materials-pack.

I am also using tweens to update a time parameter to create the animation (Like the erosion example from the link).

3. Context. Why do you need to do this? We might know a better way to accomplish your goal.

I am trying to visualize wind data similar to what they have here: https://earth.nullschool.net/ . I need to update the location of the wind particles from frame to frame in order to run the animation. I can’t update them using a fragment shader so I am trying a find a way to make the particles move.

The work around I have now is that I am using tweens to update a time parameter (a uniform in the fragment shader). The fragment shader uses this to calculate which pixels should be shaded to simulate the wind movements. However, this method is inefficient because I essentially have to backtrack through 100 frames to calculate the new position of the wind particles at each frame.

4. The Cesium version you’re using, your operating system and browser.

Windows 10, Cesium 1.50, Chrome

Thanks for your help

Capture1.PNG

Capture2.PNG

You can create a custom frag/vertex shader by using a custom Appearance:

https://cesiumjs.org/Cesium/Build/Documentation/Appearance.html?classFilter=Appear

This is a good reference on appearances in general:

I think the good news is that the WebGL wind simulation you linked to is open source. It might be worth looking at it to see how they set up the simulation:

I imagine the simulation logic is done in the shader itself, and it renders onto a frame buffer that is passed back as input in the next frame. If so, this can be done in Cesium but rendering to a texture isn’t very well documented right now since it’s a less common use case.

If you make progress on this it’d be great to post a demo or your tips here! I know this is something that’s often requested.

Thank you so much for your help Omar. I’ll definitely post a demo if I make good progress.

The problem I have now is that I can’t pass the wind data to the vertex shader if I use Appearances. Before, when I only used a fragment shader, I could pass an image that had the wind data encoded in it through the fabric json of the Material. So I just specified the variable name and the image location under the uniforms field (like in the screenshot of my code). Then, I had “uniform sampler2D WindSpeed;” in the fragment shader which stored the texture.

Do you know how I can pass the data to the vertex shader if I use a custom Appearance? I can’t find any examples so I haven’t been able to figure it out.

I think zwcloud had a similar issue here:

https://groups.google.com/forum/#!topic/cesium-dev/t1huyGykzO4

Thanks

Also, the data that I am passing in is the wind direction at each coordinate. As of now, I have the data encoded as an image where the red and green pixels depict the wind direction. But the data doesn’t have to be formatted as an image as long as I can somehow pass it in.

An Appearance does take a vertexShaderSource in the same way that it takes a fragmentShaderSource. This is the most recent forum post I can think of that has an example of using both a custom vertex shader and a fragment shader:

https://groups.google.com/d/msg/cesium-dev/PWMu8pehSPw/z5rrN0jTCAAJ

You should be able to specify the uniforms and pass in the wind data as an image as well, which I think is the most efficient way to do it (it would be too much to send a giant array of numbers instead).

I was under the assumption that you can only pass in uniforms using fabrics if you use a Material (when the fragment shader code is passed through the “source” parameter of the fabrics json). But not if you use an Appearance.

I’ll look into it more carefully today. I’ll post what I find.

Thanks Omar.

Hi Omar. I wasn’t able to pass in Uniforms to the fragment/vertex shaders using Appearances. I can only do that with Materials (like the example from my code).

Do you know of any other examples using custom shaders for Appearances that I can refer to? Thanks.

Can you post a Sandcastle example of the attempt(s) you’ve made? I’d be happy to take a look.

Here is an example of what I have when I only use the shader supplied to the material in the fabric json. I am just passing a float (sampleColor) as a uniform and it is used by the shader to set the value of the green pixels. This method works fine but I also need a vertex shader.

Here is what I am trying to do using an Appearance. For this example, I took the vertex and fragment shaders from EllipsoidSurfaceAppearance. I then try to pass in the same uniform like I did with the first example but I get an error. I don’t get the error if I don’t read the uniform in the shaders.

My goal is to get cesium to render the vertex shader and fragment shader while passing in uniforms.

Thank you so much Omar.

Thanks for the code examples! So here’s what’s going on. When you create a uniform, CesiumJS does a lot of setup for you, including figuring out the uniform’s type and assigning a name. In this case, it’s appending “_0” to the name of the uniform:

https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Scene/Material.js#L937

So in order to use your uniform in your shader, you just have to remove your own declaration of it (since Cesium injects it for you) and then just use it as sampleColor_0. Here’s a working example. This is an area of Cesium that isn’t very well documented, so I appreciate you asking this question and providing your code samples. I’m sure others in the community will find this very helpful.

Thank you so much Omar. I wouldn’t have been able to figure it out without your help.

Now I am trying to update the position of the wind particles from frame to frame. My plan is to to render onto a frame buffer and pass it back as input to the next frame like you mentioned last week. Do you know of any examples or documentation that I can refer to? Thanks Omar.

I’ve been trying to put together an example of that for a while now. Doing this is rather tricky at the time of writing. I think you’d have to either create your own DrawCommand (https://github.com/AnalyticalGraphicsInc/cesium/blob/master/Source/Renderer/DrawCommand.js) or pass in a flag to make the Primitive modify the draw command it sends to draw to a custom framebuffer. There’s not a lot of documentation on this, but this blog post is a helpful reference:

And possibly this one too:

Thanks Omar. I really appreciate you taking the time trying to create an example. If I end up getting it to work, I’ll put together a Sandcastle example and post it here.

Just out of curiosity, do you think I would have to modify Cesium’s source code to do what you described?

You’d have to modify the source code in order to pass in this new flag to a Primitive to make it modify its draw command, but I do think it’s the easiest way to do this (and it might be a great contribution to open a PR back into CesiumJS!)

That way I think relieves the burden from having to figure out how to construct the DrawCommand and send it to the renderer yourself, and leverages the existing pipeline.