Particle won't scale(change size) with camera distance,how can I realize this feature in my shader

I investigate this problem for two days, but most closely search result is “size attenuation” in WebGL(maybe)?

Someone told me It has something to do with “Perspective-Correct Interpolation”, I haven’t experience deep Graphic, so I don’t think it’s related…

The effect is like ParticleSystem - Renderer - Min Particle size and max Particle size both set to 0.1.

I know It’s about PosVS.z or PosCS.w or some thing like these( depth? ), but all I can figure out is simply

v.posVS.xy*=-v.posVS.z;

The object do not scale with camera distance indeed, but its position is changing in scene…

I’m insane…Any one can save me…

Your intuition is correct, this isn’t related.

The correct way to do this is to scale the mesh based on the depth from the camera. Here’s an example shader that takes the default quad mesh and rotates it towards the camera while keeping it a constant view size.
https://discussions.unity.com/t/745529/3

But there are some big caveats. When scaling the mesh, we’re assuming a few details. One, that we’re scaling the mesh in local space where the mesh’s pivot is at the center of the mesh.

If you take the shader and apply it to two quads, it stops working. Why? Because by default Unity batches simple meshes, meaning it combines them into a single mesh pre-transformed into world space. You no longer know where the center pivot of each quad is to scale around. Meaning when scaling the mesh you’re not scaling each quad in-place, but scaling the entirely particle system around the world origin.

If you’re trying to do this to an actual particle system, the particle system’s mesh is usually batched just like the above example, meaning you don’t know where the particles are, and scaling it will again be scaling it around the world origin.

The ways around this would be to use an instanced mesh particle system instead of the default batched mesh particles, as these do retain their individual pivot positions.

Alternatively you can use custom vertex streams to pass the particle’s world position to the shader via unused UV channels. You can then subtract that pivot position from the vertex positions, do the scaling, and add the pivot position back.

Either way these require slightly more complex shaders than the linked example.

Do you mean GPU instance? I’m not familiar to particle system. Actually I’m not going to create particles, just want to add some “UI”(signs?) in scene(world space?) but not on screen.

I’ve found the thread you provided the day before yesterday, it did save my life, I owe you my best thanks.

Then I received new demands yesterday.

  1. Change the anchor point of quad in shader. According to my observation, the quad rotates according to origin. Does this mean I need to change the origin of object space? Should I mul translation matrix? 'cause I think it’s a coordinate transformation, like the second statement in the following pic. The effect is wrong.

2.Rotate the quad in shader. I also use matrix like the first statement in the following pic.It looks not bad.

  1. Always show the quad above all the objects. Can I simply “ZTest off”?

I find another problem(maybe very foolish). Is float4 in shader a row vector? Matrix is row matrix? Then why
mul(UNITY_MATRIX_V, float4(worldPos, 1.0));
is right? mul((4x4) , (1x4)), this looks not right in math?

9449828--1326509--upload_2023-11-4_17-52-44.png

This can be accomplished by offsetting the local vertex position before scaling it. But there are some things to be weary of when doing this, as it means the mesh will be getting pushed outside of its CPU side bounds, meaning it might be culled by occlusion or the camera frustum too early.

The only real solution to this is to expand the bounds, which you can do by scaling the game object up, and inversely scaling the mesh down in the shader. Though this will be an issue even when rotating around the pivot due to the mesh not actually rotating and the quad mesh having a nearly flat AABB that can be easily culled.

Are you trying to rotate around the axis pointed towards the camera? Then again you can do this by rotating the local vertex position, after applying any offset for the pivot, and either before or after the scaling. You can also construct a full transform matrix if you want, but it’s not actually any faster on modern GPUs to do that vs doing it step by step.

Yes. …ish. You also will also likely want to change the SubShader’s Tags to include "Queue" = "Overlay" so it also renders after everything else.

1 Like