godot
godot copied to clipboard
Parallax2D: strange behavior with images with transparency
Tested versions
v4.3.dev6.official.89850d553
System information
Mac OS 14.2.1 - Vulkan 1.2.275 - Forward Mobile - Using Device #0: Apple - Apple M1 Max
Issue description
When using images with transparency inside a Parallax2D with repeat config enabled, it seems to add the same image 2 times at same position. It can be noticed when using image with some transparency because it gets "darker".
On editor
Running:
Steps to reproduce
- Add sprite2D or ColorRect with some transparency
- Add it to a Parallax2D node
- Increase RepeatSize
Minimal reproduction project (MRP)
I'm not able to replicate this. When I run your project it's transparent and the repeat is as well. I tried with Mobile, Compatibility, and Forward+.
I'm not able to replicate this. When I run your project it's transparent and the repeat is as well. I tried with Mobile, Compatibility, and Forward+.
@markdibarry what is your OS?
Win 10. Perhaps it's a Mac issue?
In the MRP the repeat_size
saved in the main.tscn
is weird, the problematic part seems to be its near-zero x
value:
[node name="Parallax2D" type="Parallax2D" parent="."]
repeat_size = Vector2(2.08165e-12, 500)
@stephannv I'd say one question is how you've ended up with such value in there? :thinking:
Note that because of the limited precision of the inspector input fields, it's already shown as 0
, and thus trying to set it to actual 0
doesn't do anything as the input field thinks it's the same value already, and thus no change is made:
But by draging it out and back to 0
it's snapped properly, which gets rid of the issue:
After saving:
[node name="Parallax2D" type="Parallax2D" parent="."]
repeat_size = Vector2(0, 500)
@markdibarry Back to the Parallax2D repeating behavior, does this work as expected?
@stephannv I'd say one question is how you've ended up with such value in there? 🤔
I didn't change the X value, it was created with that value by default. I noticed that value on another scene on my project but I didn't give attention to it. I will try to replicate it
@kleonc I uploaded a video to issue description showing how I got that value.
It seems to be related to Vector2 property editor, on CollisionShape2D I got this problem too.
@kleonc Yeah that's the expected behavior since it'd never be overlapping with itself with normal use and wouldn't be centered. The repeat should be the same size as the image or larger in most scenarios unless you didn't prepare the image for use with parallax... then you'd need to base it off a region for the sprite. It also needs to be the same size or larger than the screen or the parallax effect is broken, same as ParallaxBackground
.
Though it is interesting that this is a Vector2
editor issue and not Parallx2D
specific.
@kleonc I uploaded a video to issue description showing how I got that value.
@stephannv This I can't replicate though (v4.3.dev6.official [89850d553], Windows). For me, it's being saved as Vector2(0, 500)
from the start.
So indeed could be Mac-specific issue. But could be something else. No clue what exactly, briefly looked at the code (EditorPropertyVectorN
, EditorSpinSlider
), haven't spotted anything obviously wrong or specific to Mac. Maybe some calculations end up slightly different because of the HiDPI / Retina display on Mac? :thinking:
Also in the video are you using mouse or trackpad? Again not sure if that's relevant but the more info the better. :slightly_smiling_face:
It seems to be related to Vector2 property editor, on CollisionShape2D I got this problem too.
Since it's not Parallax2D specific, it means you could potentially check whether the same happens for you in the previous versions. If we'd know since what exact version this started happening it would greatly narrow down where to look for the cause.
Also worth noting:
- Does this happen for Vector3 / Vector4 values?
- Does this happen for single floats?
- Does this not happen for some specific Vector2 properties?
Would need to be investigated / stepped through by someone who can reproduce the issue.
@kleonc
Maybe some calculations end up slightly different because of the HiDPI / Retina display on Mac? 🤔
I'm not sure, I did some tests today, and I noticed that "0.0...00208" is there before I change any value, just hovering the Vector2 on a newly created object and I already got that strange value, but it isn't saved on scene yet, this will be saved only if I change any property (x or y)
https://github.com/godotengine/godot/assets/3025661/9f6230c6-bceb-4fbd-b078-d300a26ee911
Also in the video are you using mouse or trackpad? Again not sure if that's relevant but the more info the better. 🙂
I'm using magic trackpad.
Since it's not Parallax2D specific, it means you could potentially check whether the same happens for you in the previous versions. If we'd know since what exact version this started happening it would greatly narrow down where to look for the cause.
I tried to replicate the issue and found the version where this problem started: 4.0-beta8 (PRs merged | Commits). Versions I tried and could not replicate the problem:
- 4.0-beta7
- 4.0-beta5
- 4.0-alpha17
- 4.0-alpha1
- 3.5.3
* Does this happen for Vector3 / Vector4 values?
Yes, I could reproduce the problem using Vector2, Vector3, Vector4, Transform2D and Transform3D. Here a video:
https://github.com/godotengine/godot/assets/3025661/eb698fac-64ed-4d65-8dbc-349bfd866e23
* Does this happen for single floats?
Yeah, I could reproduce the problem using @export var f : float
(I forget to add this property on video above).
* Does this _not_ happen for some specific Vector2 properties?
I will try to find some pattern, if I find, I will report here.
I'm not sure, I did some tests today, and I noticed that "0.0...00208" is there before I change any value, just hovering the Vector2 on a newly created object and I already got that strange value, but it isn't saved on scene yet, this will be saved only if I change any property (x or y)
Then I'd say it's rather unlikely to be input related.
I tried to replicate the issue and found the version where this problem started: 4.0-beta8. Versions I tried and could not replicate the problem:
* 4.0-beta7
That's great find, we're down to 150 commits. I've skimmed through the PRs and these catched my eye as potentially suspicious: #65101, #67660.
Still not sure why would they cause this issue for your specific setup though (I've tried v4.0.beta8.official [45cac42c0] as well, getting exact 0
with no problems).
Here's a simple EditorPlugin to output some brief debug info about EditorSpinSliders:
Plugin
@tool
extends EditorPlugin
var inspector: EditorInspector
func _enter_tree() -> void:
inspector = get_editor_interface().get_inspector()
inspector.property_selected.connect(on_property_selected)
func _exit_tree() -> void:
inspector.property_selected.disconnect(on_property_selected)
func on_property_selected(property: String) -> void:
var property_editor: EditorProperty = find_property_editor(inspector, property)
if not property_editor.get_class() in [
"EditorPropertyVector2",
]:
return
print("-".repeat(80))
print("property_selected(%s)" % [property])
var property_value: Vector2 = property_editor.get_edited_object().get(property)
print(" %s.x = 0x%s ≈ %50.40f" % [property, f64_to_hex_string(property_value.x), property_value.x])
print(" %s.y = 0x%s ≈ %50.40f" % [property, f64_to_hex_string(property_value.y), property_value.y])
print()
property_editor.print_tree_pretty()
var slider_props_to_list: Array = []
slider_props_to_list.append_array(ClassDB.class_get_property_list("Range", true))
slider_props_to_list.append_array(ClassDB.class_get_property_list("EditorSpinSlider", true))
var spin_sliders := property_editor.find_children("", "EditorSpinSlider", true, false)
for spin_slider: EditorSpinSlider in spin_sliders:
print()
print(spin_slider)
for prop in slider_props_to_list:
var value: Variant = spin_slider.get(prop.name)
if value is float:
print(" %-15s = 0x%s ≈ %50.40f" % [prop.name, f64_to_hex_string(value), value])
else:
print(" %-15s = %s" % [prop.name, value])
print("-".repeat(80))
func find_property_editor(node: Node, property: String) -> EditorProperty:
var to_check: Array[Node] = [node]
while not to_check.is_empty():
var current: Node = to_check.pop_back()
if current is EditorProperty and current.get_edited_property() == property:
return current
to_check.append_array(current.get_children())
return null
func f64_to_hex_string(value: float) -> String:
var bytes := PackedFloat64Array([value]).to_byte_array()
bytes.reverse()
return bytes.hex_encode()
Could you show what output you're getting from it e.g. after you select Parallax2D.repeat_size
property in the inspector?
Example output
--------------------------------------------------------------------------------
property_selected(repeat_size)
repeat_size.x = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
repeat_size.y = 0x407f400000000000 ≈ 500.0000000000000000000000000000000000000000
┖╴@EditorPropertyVector2@33339
┖╴@HBoxContainer@33338
┠╴@VBoxContainer@33332
┃ ┠╴@EditorSpinSlider@33334
┃ ┃ ┖╴@TextureRect@33333
┃ ┖╴@EditorSpinSlider@33336
┃ ┖╴@TextureRect@33335
┖╴@TextureButton@33337
@EditorSpinSlider@33334:<EditorSpinSlider#11762338437137>
min_value = 0xc0f869f000000000 ≈ -99999.0000000000000000000000000000000000000000
max_value = 0x40f869f000000000 ≈ 99999.0000000000000000000000000000000000000000
step = 0x3f50624dd2f1a9fc ≈ 0.0010000000000000000000000000000000000000
page = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
value = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
ratio = 0x3fe0000000000000 ≈ 0.5000000000000000000000000000000000000000
exp_edit = false
rounded = false
allow_greater = true
allow_lesser = true
label = x
suffix =
read_only = false
flat = true
hide_slider = true
@EditorSpinSlider@33336:<EditorSpinSlider#11762405543809>
min_value = 0xc0f869f000000000 ≈ -99999.0000000000000000000000000000000000000000
max_value = 0x40f869f000000000 ≈ 99999.0000000000000000000000000000000000000000
step = 0x3f50624dd2f1a9fc ≈ 0.0010000000000000000000000000000000000000
page = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
value = 0x407f400000000000 ≈ 500.0000000000000000000000000000000000000000
ratio = 0x3fe0147aeeb3b02e ≈ 0.5025000250002500400000000000000000000000
exp_edit = false
rounded = false
allow_greater = true
allow_lesser = true
label = y
suffix =
read_only = false
flat = true
hide_slider = true
--------------------------------------------------------------------------------
@kleonc I got:
On 4.3.dev6
--------------------------------------------------------------------------------
property_selected(repeat_size)
repeat_size.x = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
repeat_size.y = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
┖╴@EditorPropertyVector2@19591
┖╴@HBoxContainer@19590
┠╴@VBoxContainer@19584
┃ ┠╴@EditorSpinSlider@19586
┃ ┃ ┖╴@TextureRect@19585
┃ ┖╴@EditorSpinSlider@19588
┃ ┠╴@TextureRect@19587
┃ ┖╴@PopupPanel@19991
┃ ┠╴@Panel@19989
┃ ┖╴@Label@19990
┖╴@TextureButton@19589
@EditorSpinSlider@19586:<EditorSpinSlider#2168304248730>
min_value = 0xc0f869f000000000 ≈ -99999.0000000000000000000000000000000000000000
max_value = 0x40f869f000000000 ≈ 99999.0000000000000000000000000000000000000000
step = 0x3f50624dd2f1a9fc ≈ 0.0010000000000000000208166817117200000000
page = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
value = 0x3d824f7400000000 ≈ 0.0000000000020816473544904567916100000000
ratio = 0x3fe0000000000000 ≈ 0.5000000000000000000000000000000000000000
exp_edit = false
rounded = false
allow_greater = true
allow_lesser = true
label = x
suffix =
read_only = false
flat = true
hide_slider = true
@EditorSpinSlider@19588:<EditorSpinSlider#2168371357571>
min_value = 0xc0f869f000000000 ≈ -99999.0000000000000000000000000000000000000000
max_value = 0x40f869f000000000 ≈ 99999.0000000000000000000000000000000000000000
step = 0x3f50624dd2f1a9fc ≈ 0.0010000000000000000208166817117200000000
page = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
value = 0x3d824f7400000000 ≈ 0.0000000000020816473544904567916100000000
ratio = 0x3fe0000000000000 ≈ 0.5000000000000000000000000000000000000000
exp_edit = false
rounded = false
allow_greater = true
allow_lesser = true
label = y
suffix =
read_only = false
flat = true
hide_slider = true
--------------------------------------------------------------------------------
On 4.0-beta7
--------------------------------------------------------------------------------
property_selected(position)
position.x = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
position.y = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
┖╴@@17838
┖╴@@17837
┠╴@@17831
┃ ┠╴@@17833
┃ ┃ ┖╴@@17832
┃ ┖╴@@17835
┃ ┖╴@@17834
┖╴@@17836
@@17833:<EditorSpinSlider#1836534787637>
min_value = 0xc0f869f000000000 ≈ -99999.0000000000000000000000000000000000000000
max_value = 0x40f869f000000000 ≈ 99999.0000000000000000000000000000000000000000
step = 0x3f50624dd2f1a9fc ≈ 0.0010000000000000000208166817117200000000
page = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
value = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
ratio = 0x3fe0000000000000 ≈ 0.5000000000000000000000000000000000000000
exp_edit = false
rounded = false
allow_greater = true
allow_lesser = true
label = x
suffix = px
read_only = false
flat = true
hide_slider = true
@@17835:<EditorSpinSlider#1836601896456>
min_value = 0xc0f869f000000000 ≈ -99999.0000000000000000000000000000000000000000
max_value = 0x40f869f000000000 ≈ 99999.0000000000000000000000000000000000000000
step = 0x3f50624dd2f1a9fc ≈ 0.0010000000000000000208166817117200000000
page = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
value = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000
ratio = 0x3fe0000000000000 ≈ 0.5000000000000000000000000000000000000000
exp_edit = false
rounded = false
allow_greater = true
allow_lesser = true
label = y
suffix = px
read_only = false
flat = true
hide_slider = true
--------------------------------------------------------------------------------
On 4.3.dev6
step = 0.0010000000000000000208167 page = 0.0000000000000000000000000 value = 0.0000000000020816473544905
On 4.0-beta7 (Parallax2D doesn't exist, so I used the
position
property from CollisionShape2D):step = 0.0010000000000000000208167 page = 0.0000000000000000000000000 value = 0.0000000000000000000000000
@stephannv Thanks! I don't think 0.0010000000000000000208167
is actually representable, it might be just printed like that... :thinking: Aka your 0.0010000000000000000208167
could be the same as mine 0.0010000000000000000000000
. I've edited my previous comment with updated plugin (and its example output) so it also outputs the exact hex data for these 64-bit floats (they're double
in the source regardless of the build). Could you please edit/update your output as well?
https://github.com/godotengine/godot/blob/45cac42c0b511672240c1fcccecfd3cc0580edcb/scene/gui/range.h#L36-L44
@kleonc updated. I couldn't run on beta7 because get_edited_object
isn't available and I am not sure if the workaround I was trying was reliable.
@kleonc updated. I couldn't run on beta7 because
get_edited_object
isn't available and I am not sure if the workaround I was trying was reliable.
Oh, indeed EditorInspector.get_edited_object
is not available in there. But EditorProperty.get_edited_object
is, I've updated the plugin to use it instead.
But I'd say it already seems like your issue arised because of the changes in #65101.
On 4.3.dev6
-------------------------------------------------------------------------------- property_selected(repeat_size) repeat_size.x = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000 repeat_size.y = 0x4068000000000000 ≈ 192.0000000000000000000000000000000000000000
This tells us that the value within the object is just fine (until after a wrong value from the inspector is saved into the object). So the issue is likely about the EditorSpinSlider.
@EditorSpinSlider@20805:<EditorSpinSlider#2445765846133> min_value = 0xc0f869f000000000 ≈ -99999.0000000000000000000000000000000000000000 max_value = 0x40f869f000000000 ≈ 99999.0000000000000000000000000000000000000000 step = 0x3f50624dd2f1a9fc ≈ 0.0010000000000000000208166817117200000000 page = 0x0000000000000000 ≈ 0.0000000000000000000000000000000000000000 value = 0x3d824f7400000000 ≈ 0.0000000000020816473544904567916100000000
Here we can see that only the value
differs compared to my output (0x3d824f7400000000
vs 0x0000000000000000
).
The step
is exactly the same (0x3f50624dd2f1a9fc
). The fact it's printed differently I'd say is irrelevant here (the byte data used for the calculations seems to be the same :thinking:).
In fact your printed value is more accurate, as the exact decimal value corresponding to 0x3f50624dd2f1a9fc
is 0.001000000000000000020816681711721685132943093776702880859375
(you can use e.g. this site for checking).
If we'd use such exact step
value and val = 0.0
, min = -99999.0
(which both are exactly representable as doubles) to do this calculation:
https://github.com/godotengine/godot/blob/c4279fe3e0b27d0f40857c00eece7324a967285f/scene/gui/range.cpp#L102
Then the exact result would be 0.000000000002081647354490456791609176434576511383056640625
, pretty much what you're getting.
But of course the calculations are done with doubles and hence it's done with much less precision. Not sure why exactly would you get such result instead of 0.0
:thinking: (here's an example step by step producing 0.0
).
(Unless you're getting 0.0
there as well and the non-zero value comes from somewhere else. Then bad guessing by me. :smile:)
A kinda separate thing: should EditorSpinSlider's default min_value
/max_value
be so big (especially given allow_greater = true
, allow_lesser = true
)?
@kleonc I updated the logs in my previous comment including 4.0-beta7. I also ran your snippet (https://ideone.com/zBQtsj) and I got the same results:
clang++ -o test test.cpp && ./test
0x0 = 0.0000000000000000000000000000000000000000
0x3f50624dd2f1a9fc = 0.0010000000000000000208166817117216851329
0xc0f869f000000000 = -99999.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x4197d77460000000 = 99999000.0000000000000000000000000000000000000000
0x4197d77460000000 = 99999000.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
I ran some tests on my M1 Mac and found the step that messes up the calculation.
I ran some tests on my M1 Mac and found the step that messes up the calculation.
So it might be about the last part of the calculation being fused vs unfused multiply-add.
Kinda like:
- Unfused:
99999000.0 * 0.0010000000000000000208166817117216851329
Result:
99999.0000000000020816473544904567916048671
Fitted into double:
99999.0
99999.0 + (-99999.0)
Result:
0.0
Fitted into double:
0.0
- Fused:
99999000.0 * 0.0010000000000000000208166817117216851329 + (-99999.0)
Result:
0.0000000000020816473544904567916048671
Fitted into double:
0.0000000000020816473544904567916048671
Not sure about a solution. :thinking:
Potential workaround: prevent fused muliply-add (by adding a temp variable like in the snippet linked above?). Could it make other cases worse though?
I reported this issue to Apple as FB14253734, hopefully they will fix this before 4.3 is released
I ran some tests on my M1 Mac and found the step that messes up the calculation.
Yes, on my M1 Max (Mac OS 14.2.1) I got:
0x0 = 0.0000000000000000000000000000000000000000
0x3f50624dd2f1a9fc = 0.0010000000000000000208166817117216851329
0xc0f869f000000000 = -99999.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x4197d77460000000 = 99999000.0000000000000000000000000000000000000000
0x4197d77460000000 = 99999000.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
0x3d824f7400000000 = 0.0000000000020816473544904567916091764346
Result from ideone:
0x0 = 0.0000000000000000000000000000000000000000
0x3f50624dd2f1a9fc = 0.0010000000000000000208166817117216851329
0xc0f869f000000000 = -99999.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x4197d77460000000 = 99999000.0000000000000000000000000000000000000000
0x4197d77460000000 = 99999000.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
I have no knowledge on macOS dev, but perhaps passing -ffp-contract=off
to the compiler would fix this issue?
Edit - adding context: https://github.com/llvm/llvm-project/issues/91224
I reported this issue to Apple as FB14253734, hopefully they will fix this before 4.3 is released
@roydbt You reported the issue where? To which instance of Apple?
-ffp-contract=off
Interesting, using -ffp-contract=off
:
0x0 = 0.0000000000000000000000000000000000000000
0x3f50624dd2f1a9fc = 0.0010000000000000000208166817117216851329
0xc0f869f000000000 = -99999.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x4197d77460000000 = 99999000.0000000000000000000000000000000000000000
0x4197d77460000000 = 99999000.0000000000000000000000000000000000000000
0x40f869f000000000 = 99999.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
0x0 = 0.0000000000000000000000000000000000000000
How PHP solved this problem: https://github.com/php/php-src/pull/14162
This probably affects all aarch64 builds including Linux and Android, even x86 builds when targetting Haswell or newer.
On one hand I don't think disabling fp-contract is the right way to fix the issue, as it removes some optimizations. I think this specific problem can be worked around by breaking off the addition into a separate statement. But the better fix is to make Range
properly account for the fp precision error in its calculation.
On the other hand, disabling fp-contract would make floating point behaviour more consistent across platforms, which may be a good thing. (That is until Godot decides to drop support for architectures that does not support fma in official builds, if that ever happens.)