Shader.SetGlobalColor works but Material.SetColor doesn't when working with custom shaders

We have a custom shader we’ve been using for a while with a number of custom values that are set through Shader.SetGlobalFloat, Shader.SetGlobalVectorArray, Shader.SetGlobalInt, etc. Recently, I tried simplifying this by creating a compute buffer that combines a number of these into a single list. That part works, however we’re also using multiple Cesium 3D tilesets and that’s where I’m running into issues.

My solution was to use Material.SetBuffer instead of Shader.SetGlobalBuffer so that each tileset could have different parameters but it seemed to not update the values. I tried simplifying things, just setting a color on each material using Material.SetColor and even that doesn’t work.

Here’s an example where I set a section of the tileset to green using Shader.SetGlobalColor (which works). I then tried setting it to red with Material.SetColor, but the color didn’t update:

The code works when I apply the material to other GameObjects, it only doesn’t work for Cesium. Any idea why that would be?

Been playing around with it some more, and it looks like some of the tiles will update but not others – here I updated from black to red and you can see patches of red:

What’s even weirder is I put the material on a plane and it works properly, but if I disable the plane it all goes black:

I’m assuming that the material gets copied at some point but maybe the buffer doesn’t get copied with it?

Hi @abliss86, welcome back to the community!

One initial guess I have for your situation has to do with how materials are handled in a given Cesium3DTileset. Each tile mesh has its own material, and thus its own shader parameters, so changing a value on the tileset’s opaqueMaterial will not propagate the changes to any existing tiles. Here’s an older thread with a similar situation that might be helpful for your use case:

If this looks to be different from what you’re talking about, though, it would help if you provided a minimal example for us to reproduce so we could observe that behavior. I admit I’ve never tried to use the Shader.Set___ approach with the tileset material. Perhaps other community members can chime in with their experience?

Hey @janine thanks, that’s actually very helpful. Your UpdateExistingTiles function did what I wanted – the only change was renderer.sharedMaterial.SetVectorArray instead of renderer.sharedMaterial.color since after some tinkering the VectorArray was the only thing I need to set per-material.

However now I’m running into a related issue that maybe you can help with… I’m using the per-material settings to allow me to hide one tileset but show another one. The issue is if the two tilesets overlap, it seems like the one that’s supposed to be visible only shows up in pieces:

I’m guessing maybe something to do with the depth buffer or something? But it’s really weird – if I turn off either tileset, the other one shows up fine:

Heh, it looks like you posted while I was responding, @abliss86 . I’ll delete my response since that issue was resolved.

Hi @abliss86 . I’m not certain of the use case, but is it possible to achievable by using a CesiumCartographicPolygon? If not, understanding why not might help us better diagnose.

If the CesiumCartographicPolygon isn’t the right tool, does tileset A always take precedence over tileset B? If that’s the case, you might be able to fix the issue by setting the Renderer’s sortingOrder integer.

Let us know if any of the above work. If not, we should have some additional insight to find a solution.

Thanks!

1 Like

Hey thanks for the feedback. This is something we use in addition to Cartographic Polygons to clip out small objects like trees, as well as floating objects like bridges when we want to leave the ground underneath. It does seem like the sort order thing fixed it, thanks for all your help!