"Canvas" Shader Graph - Looks correct in Scene view but wrong in Game view. Can't figure out why

I am making a card game, and I’m working on creating a dissolve effect for the cards.
The cards are prefabs that have multiple Images that are pieced together to create the whole card (background, main-art, text-background, frame, etc).

For the dissolve effect, what I’m working towards doing is setting it up so that the effect has the card dissolve ‘as a whole’ (meaning the ‘noise’ for the dissolve effect is sampled in some sort of “space” that each of the Images can use to make it look correct). I’m doing this by applying a material to each of the Images, and then sending in some shader parameters to each one (card centerpoint & card scale).

I’m using a Canvas Shader Graph (the dissolve effect is a sub graph). This is how I am sampling the noise node:

So what I am doing is:

  1. Getting the World Space position
  2. Subtracting the position of the centerpoint of the card prefab (which is a parameter that is passed into the shader. I am sending in the cardPrefab.transform.position for this). This gives me the ‘position relative to the centerpoint of the card’
  3. Then I divide by the scale of the card (which is a parameter that is passed into the shader. I am sending in the cardPrefab.transform.lossyScale for this).
  4. Sample the noise

In my scene I have two cards, one has its transform’s scale set to 4, and the other one has its transform’s scale set to 8.

In Scene view they look correct. The bigger card should just look like a bigger version of the smaller card:

But in Game view, the bigger card looks different than the smaller card (something is wrong with how the noise being sampled):

Here is a video showing the problem - I adjust the scale in Scene view and it looks correct, but then I adjust it in Game view and its wrong:

Also just to show this - moving the cards around does properly move the effect ‘along with the card’, so that part is working:

I feel like the problem has something to do with trying to use the World space position with a UI Canvas shader, or maybe a mismatch between using the world-positions and the cardPrefab.transform scale? I’ve tried playing around with trying different “spaces” for the position but haven’t found one that works. I feel like there isn’t much info on how the “spaces” work with the Canvas Shader Graph since its relatively new (2023?).

Would really appreciate any help with this or suggestions on what to try.

Thanks a lot!

It looks like an issue with lossyScale to me, seeing as the noise pattern is always remaining at the same scale. How are you setting the scale material property? Are you doing it on Update? Try debug logging the value to see if it’s actually changing. And maybe try using localScale instead and see if that works, in case lossyScale doesn’t work well with Rect Tranforms possibly? Just some ideas.

Hey, thanks for the reply. I’ve tested it with both local and lossy scale (in this test case, they are the same) and have logged the value I’m setting as the shader parameter to verify it (scale = 4 for the smaller card and scale = 8 for the bigger card). Yeah, I’m applying the shader parameters in Update.

The fact that it works in Scene view but not in Game view is making me try to figure out what the difference is between the two, which might lead me towards a fix. I think it probably has something to do with the Canvas being “screen space - overlay”, versus the Scene view just using whatever sort of Camera setup Scene view uses. But I haven’t been able to figure out specifically whats going on, and there isn’t much info about the Canvas Shader Graph online

I think I found the issue:

  • “World Space” in a Canvas Shader Graph has the origin point 0,0 at the center of the canvas.
  • For my “card centerpoint” I was sending in the transform.position - but that is using a coordinates system that has 0,0 at the physical world centerpoint, not the canvas’ centerpoint.

I just tried switching over to using the rectTransform.anchoredPosition for my “card centerpoint” and it seems to have fixed the issue. The anchoredPosition uses coordinates based on the centerpoint of its coordinates/anchor system, and my test setup just has the Card as a direct child of the Canvas, so that made both the “world position” and my “card centerpoint” position jive together.

So now all I’ll need to do is make sure that when I have my Card way deeper in the Canvas hierarchy, that I’m still calculating/sending the appropriate position value that jives with the Canvas’ “global” coordinates system

This seems to be the solution for that - not sure how efficient it is though:

canvas.transform.InverseTransformPoint(cardCenterRect.position)