Why UtilityFunctions::print("vector: ", Vector3(0, 1, 0)) got "vector: (0.0, 0.0, 0.0)"?

Godot Version

Godot 4.4 or 4.5

Question

I’m using GDExtension.

void AlwaysLookAt::_process(double delta) {
Node3D *parentNode = Object::cast_to(get_parent());
Node3D *target = getTarget();
if(parentNode && target) {
Vector3 p = parentNode->get_global_position();
const Vector3 tgtP = target->get_global_position();
Vector3 dir = tgtP - p;
Vector3 up{0.0, 1.0, 0.0};
UtilityFunctions::print("vector: ", up);
parentNode->look_at(tgtP, up);
}
}

the parentNode is a Camera3D object.
the vector “up” is always (0.0, 0.0, 0.0).
so the look_at(…) always failed.

Does it work correctly if you use Vector3 up(0.0, 1.0, 0.0);? The two are not equivalent I’d say

2 Likes

I feel like you need an equal sign in there

Vector3 up = {0.0, 1.0, 0.0};

That’s not required the initialization is valid, and that shouldn’t make any difference, but using initializer declaration might not be supported for this or might behave differently

1 Like

Any warnings from the compiler?

Looking into source, Vector3 data members are declared as a union of a struct and an array:

union {
		// NOLINTBEGIN(modernize-use-default-member-init)
		struct {
			real_t x;
			real_t y;
			real_t z;
		};

		real_t coord[3] = { 0 };
		// NOLINTEND(modernize-use-default-member-init)
	};

So it should probably be:

Vector3 up{ {0.0, 1.0, 0.0} };

But I’d just use a constructor instead of list initialization.

1 Like

Code looks fine and absolutely should work. There are zero problems regarding initialiser list Vs constructor here.

Indeed I just tested:

	Vector3 foo{0.0, 1.0, 0.0};
	print_line("foo = ", foo);
	print_line("bar = ", Vector3{0.0, 1.0, 0.0});

and I got:

foo = (0.0, 1.0, 0.0)
bar = (0.0, 1.0, 0.0)

No idea what is going on sorry, but it is definitely not what other people are suggesting.

@normalized Initiliaser list with union will populate the first listed member (the struct in this case) unless you do fancy stuff with very modern lang features (i.e. your compiler probably doesn’t support it). You do not need an outer brace pair for it, and indeed that then won’t match anything and will be a compile error.

Which c++ standard were you compiling with?

Did a couple more tests.

Looks like both {0.0, 1.0, 0.0} and {{0.0, 1.0, 0.0}} will work as expected with C++14 onward if the class hasn’t got any constructors defined. If there is a 3 argument constructor, {0.0, 1.0, 0.0} will always call that constructor.

{0.0, 1.0, 0.0} won’t compile with C++11 if there is no matching constructor but if there is - it will use that constructor.

In any case, {0.0, 1.0, 0.0} should work with Godot’s Vector3 class unless the OP is using some obscure compiler setup that somehow ignores the initializer list and uses the default constructor which nullifies the components.

3 Likes

Interesting. I had (after I made the post) tested in isolation and discovered I was wrong and both worked, which seemed strange as it didn’t work with godot::Vector3, but given I was looking at an apparent bug someone else was reporting and I could not repro, I moved on to something more productive (or something else, at the least ;)).

Adding a 3 param ctor to that test breaks the {{...}} init with the same error I got in Godot. Thanks for sharing your more thorough testing!

2 Likes

抱歉占用大家的时间。

我后来试过 UtilityFunctions::print("vector: ", up.x, up.y, up.z); 结果就完全正确。
我也试过其它的浮点数组合,print("vector: ", up) 显示的完全是另外一些奇怪的数值。
于是我猜测,由于 Vector3 是一个 union ,有没有可能传递对象时把它当成了 double[3] 数组,而复制时只读取了 double[3] 的前面 12 个字节?
那么很有可能是由于 float/double 编译配置的问题。

我用的是 CMake 工具链,习惯手写 CMake 脚本。
后来我去参考了 godot-cpp-template 的源代码,发现我的 CMake 中的 add_subdirectory 调用漏掉了 “SYSTEM” 参数。
修正了这个错误之后就一切正常了。

我的英文水平有限,但现在翻译软件非常强大,希望能帮助到其他人。
感谢大家的时间!