I'm trying to generate a planet's shape from code.
I'm using Sprite for the image and CollisionPolygon2D for the collision.
But the Sprite and the CollisionPolygon2D don't exactly line up. ``````vec2 st = (UV-0.5);
float r = length(st)*2.;
float angle = atan(st.x, st.y)*1./(PI*2.);
float r_a = r;
r_a *= (1.+hills_1_a*sin((angle)*round(hills_1_d)*2.*PI));
r_a *= (1.+hills_2_a*sin((angle)*round(hills_2_d)*2.*PI));
r_a *= (1.+hills_3_a*sin((angle)*round(hills_3_d)*2.*PI));
``````

Where `hills_[1-3]_[a,d]` are just float scalars.

For the CollisionPolygon2D the code looks like this:

``````var arr:PoolVector2Array = PoolVector2Array()
var angle:float = 0
var angle_delta = 2*PI/shape_points
while angle <= 2*PI:
r *= (1+hills_1_a*sin((angle)*round(hills_1_d)));
r *= (1+hills_2_a*sin((angle)*round(hills_2_d)));
r *= (1+hills_3_a*sin((angle)*round(hills_3_d)));
var p = Vector2.UP.rotated(angle) * r
angle += angle_delta
arr.append(p)
\$CollisionPolygon2D.polygon = arr
``````

The `hills_[1-3]_[a,d]` variables are the same values as in the shader (they are passed as uniform in other part of the code). `shape_points` is the number of points in the polygon (I use around 1000 but it doesn't affect the difference)
So as you can see the code is essentially the same. But as seen on the image above the values are off. I'll admit, it's pretty zoomed in. Here's how it looks zoomed out: But since it's going to be a planet, I need it to be accurate when zoomed in.

What's the reason behind this? (I'm guessing cpu vs gpu rounding difference, but I hope I'm wrong)
Is there a way to fix this?
If not, how can I work around it? How can I get accurate procedurally generated planet that has same sprite and collision?
I'm okay with having to write a lot more code if needed, even modifying the engine/writing cpp modules.

Godot version 3.2.3
in Engine
edited

Your case seems to be consistent with that ~5 mm (?) thick white line, is it the same all around? How big is a pixel compared to the white line? I mean, if you zoom to 1:1 (did you take the screenshot in the editor?) how many pixels is that approximately? It doesn't look like rounding error, because it wouldn't be that consistent. I'd try artificially making the collision a bit bigger maybe, and see if it's closer to the sprite. Or, first try making the planet 10× or 20× bigger (as in not zooming in, but making its size bigger) and the line thickness should remain the same, while everything is scaled up, possibly scaling the problem down, maybe that works. (also try keeping the collision as simple as possible, it may be bad for the performance, but you'll see that if it is or not)

I forgot to mention that the inaccuracy isn't consistent. At some points it lines up perfectly, while at others it's as seen on the pictures. So scaling up the collision would create "gaps" in different parts. Here's the "transition". (This picture is taken 100% editor zoom)
Using bigger texture and thus smaller Sprite scale yielded same results. Scaling both the polygon and the Sprite also yielded same results.
I will worry about performance later, if I get it to work.

Ahh yeah, I understand it better now. And if you make the radius parameter bigger, while keeping the bumpssize-to-radius the same, so it's effectively scaling up, but without scaling up (that's what I meant, sorry I wasn't clear)?
If that doesn't work, maybe you could figure out which one is the imprecise.
Another thing I can think of, maybe try calculating simpler stuff, like a rectangle or circle, and see if they have the same problem, or add the calculations one at a time and see which one adds the inconsistency?

I'm not sure what exactly you mean by that scaling, but I've tried every combination I could think of and got the same results.
Not sure how to figure out which one is the imprecise, since I can't get numerical values out of the shader (unless I would render it to a texture and save it and do something with it, but then there is a lot of things on the way that could change the measurements).
It seems that with lower amplitudes (`hills_[1-3]_a` in my code) there is no difference (or at least not noticeable), but it makes sense, since the bigger the amplitude the bigger the difference. Maybe I'll find a "magic number" that when I multiply the wave function by it, it will line up. But I'm not sure.

Oh so the sin part is bad? It'd make sense for the GPU to calculate trigonometry differently, maybe it uses a lookup table or an approximation formula...
(I'm not sure that that's the case, but it seems like a good guess)
in that case.. well I know very little about shaders so idk if you can force it to calculate sin more precisely
or maybe you can try to replicate the inconsistency with gdscript but that seems like a bad idea and it may even be different with different GPUs

you could replace sine with something else that is consistent (with both implementations), maybe a sine approximation? (I just googled this, idk if it's good) https://en.wikipedia.org/wiki/Bhaskara_I%27s_sine_approximation_formula

Using the Bhaskara I approximation in both the shader and GDScript gave exactly (I think) same results.
I've tried multiplying one of them by some value, or adding some values, but it seems that whenever I "fix" it in one place, at another it breaks.
I think I'll have to find other way to achieve what I want.
(Unless I find out why is there a difference).
Thanks.