Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Vector4 to the engine #629

Closed
aaronfranke opened this issue Aug 11, 2018 · 22 comments · Fixed by godotengine/godot#63219
Closed

Add Vector4 to the engine #629

aaronfranke opened this issue Aug 11, 2018 · 22 comments · Fixed by godotengine/godot#63219
Milestone

Comments

@aaronfranke
Copy link
Member

aaronfranke commented Aug 11, 2018

Describe the project you are working on:

Many projects can benefit from this feature, this is mostly for discussion.

Describe the feature / enhancement and how it helps to overcome the problem or limitation:

A Vector4 class would be similar to Vector2 and Vector3, but with four components: X, Y, Z, and W.

Potential use cases for a Vector4 class that I can think of:

There's likely many more uses for Vector4 than I'm thinking of. I'm not desperate for it, but I would find a Vector4 class useful. What matters is what Godot users would need it to do. It would be engine bloat implementing Vector4 "just because". So I'm opening this discussion to ask around about if users would find Vector4 useful and what kind of things they would use it for.

If you can think of a use case for Vector4 that you'd use, feel free to post it here.

If this enhancement will not be used often, can it be worked around with a few lines of script?:

Yes-ish. I have a C# implementation here. It's not really feasible to make within GDScript, but the real solution there would be to allow custom structs in GDScript: #279

Is there a reason why this should be core and not an add-on in the asset library?:

Having Vector4 in core would allow engine functions to use it as a built-in type whenever it's necessary to work with four numbers. An analysis of how many engine functions could benefit from this would be a good idea first. Again, this proposal is mostly for discussion.

It might indeed be a better idea for this to be an add-on, but this isn't possible in GDScript.

@joleeee
Copy link

joleeee commented Aug 11, 2018

You mentioned shaders, the shading language has vec4. Although it could be useful in GDScript as well.

@Chaosus Chaosus changed the title [Discussion] Vector4, and other 4D math types Vector4, and other 4D math types Sep 14, 2018
@aaronfranke
Copy link
Member Author

@AndreaCatania Bullet has btVector4. Are there physics use cases for Vector4 in core?

@AndreaCatania
Copy link

In bullet I didn't used it, but I used it for the Flex Engine implementation

@groud
Copy link
Member

groud commented Oct 7, 2018

I don't think this deserves to be in the core. The need for them is very limited, as even in the core we don't need them (we have the quaternion class for case 3)

@Illiander
Copy link

I don't really see why this isn't core.

Just for linking with the shader language vec4s if nothing else.

Unless Quats already do this, and can be passed to shaders, etc... as arbitrary 4-tuples.

@syskrank
Copy link

That would be really useful for many cases.
Besides, Vector4 is a core type in many engines and (could be) used directly for producing more effects with shaders, storing complex data and scripting fancy math stuff.

It won't hurt anyone or anything to have this implemented.

@Jummit
Copy link

Jummit commented May 31, 2019

It won't hurt anyone or anything to have this implemented.

Reduz stated that submissions will be refused by default and that bloat accumulates quickly, and this doesn't seem like a feature that is needed (follow the diagram here).

@aaronfranke
Copy link
Member Author

aaronfranke commented Jun 1, 2019

While the debate for the usefulness of Vector4 continues, if anyone is interested in having Vector4 in their own projects, I created a C# math library which includes Vector4 among other things. You still won't be able to use it as a parameter for Godot's built-in methods, at least not directly, but it can be used for manual math or storing the values for later.

@aaronfranke aaronfranke transferred this issue from godotengine/godot Mar 24, 2020
@fire
Copy link
Member

fire commented Mar 25, 2020

Currently Godot Engine uses plane or color for vec4.

@aaronfranke
Copy link
Member Author

aaronfranke commented Mar 28, 2020

When it comes to shoehorning existing types for usage as a Vector4, here's a quick overview:

  • Color: This type is not ideal because it uses float rather than real_t, which would mean it has less precision than vector types when real_t is double. Color also generally expects its values to be on a range of 0 to 1, but it can go above 1. There are also some issues with automatic color space conversions that can mess things up. Overall Color is the least suitable option out of everything here.

  • Plane: This type expects its x, y, and z values to form a normalized vector.

  • Quat: This type expects its values to be on a range of -1 to 1, and form a valid rotation.

  • Rect2: This type has no restrictions on its position, but expects the size to be non-negative (EDIT: well, it allows negative sizes for now, but it doesn't work properly in a lot of cases). This might be the most annoying to use since it's built out of two Vector2 values, but it also has the least restrictions on what kind of values produce a "valid" Rect2.

A Vector4 type would have no expectations, and all numbers would make up valid Vector4s.

I would suggest using Rect2 if you need to transfer around data with 4 values, if not that then Plane, if not that then Quat.

@bojidar-bg
Copy link

Rect2: […] but expects the size to be non-negative.

I do not remember this being the case, especially since issues like godotengine/godot#23711 are reproduced when using rect2 with negative size.

@Calinou Calinou changed the title Vector4, and other 4D math types Add Vector4 and other 4D math types Apr 7, 2020
@seocwen
Copy link

seocwen commented Feb 23, 2021

As someone who's not a good programmer, I don't understand what's expected of me when I'm trying to get a Vector4 into a shader. If I'm supposed to use Plane, or Color, of Quat, or whatever, that's really something that needs to be documented. How do I know nothing's going to break when I'm passing one of these between the CPU and GPU using a value outside their normal range - say, due to normalization, or filtering? And how easy and intuitive can you explain to a shader newbie how and why these other types are to be used as a Vector4? Likewise, when someone goes looking for this information, finding it should be straightforward.

I'm not sure it makes life easier for those looking for standard functionality like this to be expected to look for something other than "Vector4" - seems like they're going to end up having to ask someone for help figuring out the expected workaround.

On the other hand, in shaders themselves, vectors and colors are the same datatype, which makes a lot of sense. If Color had the same functionality as a Vec4 (maybe with x, y, z, and w property aliases) and you explained up front it was for the sake of interoperability between the CPU and GPU, I think you could justify that to anyone who's learning about shaders anyway. Of course, some reassurance in the documentation that Color and Vec4 really will have the same value after being passed and operate the same way on either side would be helpful. There's a lot that's not obvious about shader programming and no one want's to "experiment" with what works right now and end up with inscrutable bugs later.

@aaronfranke aaronfranke changed the title Add Vector4 and other 4D math types Add Vector4 to the engine Jan 7, 2022
@lawnjelly
Copy link
Member

Hardware support - SIMD, alignment, cache lines

Just to mention one of the reasons that Vector4 is so ubiquitous in high performance software like graphics / games / audio - hardware support.

Nearly all modern CPUs and GPUs have SIMD support for 4 floats (in the form of e.g. _m128). In addition, these structures can be aligned (to e.g. 16 bytes) and conveniently fit on e.g. 64 byte cache lines...

This therefore makes it a special case - it is a hardware supported type.

One argument against a Vector4 might be that users might want to create any random interleaved structure, rather than just an e.g. 128 bit struct. Well they can do this, but in most cases it will not be so aligned to the hardware. Interleaving different types in a struct will not work directly with SIMD without jiggery pokery, and unaligned structures can run slower or even flat out crash on some hardware (e.g. some ARM) in some situations.

Generic SIMD sized structure

There are thus a large number of data structures in programming that are fitted into these 4 floats, rather than the more generalized case of non-aligned structs. Indeed these are so efficient that you will often find that smaller structs like Vector3s are actually stored as 128 bit for efficiency, even if they waste memory. There are likely so many of these variations in use that it may not be practical for Godot to have a specialized type in each case.

This has led to the current situation where users (and contributors) have had to shoehorn other types into e.g. Plane, or Color, or Quaternion.
As @aaronfranke says this isn't ideal both in terms of:

  • Code clarity
  • Restrictions due to the parent type

This does create an argument for a generic type that can either be used directly or to transfer data to / from faster native forms (be these shaders, packed SIMD capable arrays etc).

Integer operations

One thing I would consider, if we were to make a generic type, would be to ask whether we can make it truly generic, as in the ability to address it either as floats or uint32_t or uint8_t etc, equivalent to the SIMD intrinsics.

This could potentially future proof things and maybe we would only need 1 struct, instead of having to create umpteen variant versions, and conversions between them etc. (Data is data, a CPU essentially doesn't care whether you treat 32 bits as a float or an int).

I thought this was worth mentioning, as this is how SIMD code works, but it may be deemed too complex for users to understand in terms of any bound functions. And there is a slight complication here is the compiling the engine real_t as 32 or 64 bit. Both are pretty easy to use either as a single 128 bit or 2x128 bits (or single 256 bit if the CPU supports), but integer bit depths tend to need to be more exact.

C++ or Variant or both

I will say that I'm primarily interested in the c++ side of this myself in terms of engine code, modules and extensions, but there is also a decent argument for binding this, whether or not part of Variant I can't say.

@lyuma
Copy link

lyuma commented Apr 8, 2022

I would argue against adding another type for a few reasons.
Yes, Color, Rect2 and Quat all have drawbacks because of their intended usecases and what they enforce.

However, Plane already exists and is a reasonable choice as a standard Vector4 type. It does not check for being unit length. As evidence of this, all vec4 types currently declared in shaders (other than :hint_color) are already passed as Plane without any problem in both Godot 3 and Godot 4.

Furthermore, Plane already has x, y and z. Only d needs to be renamed to w, so it would be very easy to migrate code using Plane. Plane-specific operations can be kept on Vector4 but prefixed with plane_

Therefore, rather than add yet another type, I would propose that either the status quo be kept, or Plane be renamed to Vector4.

t might also be nice to add a PackedVector4Array, since the alternatives are PackedFloat64Array (or PackedFloat32Array presently used for passing data to shader arrays) and PackedColorArray neither of which are ideal.

As for native formats, we already have PackedByteArray and various packed types which can be made from this. But I agree, it's not all-encompassing and both misses many formats and requires copying between types. I really appreciate Javascript's TypedArray system, where there is an ArrayBuffer (like a PackedByteArray) which backs the data, and then any number of Uint8Array etc typed arrays can be created as views over the backing ArrayBuffer. Godot could also enforce alignment such that SIMD operations can always be safely used.

I tried writing conversion code in GDScript for various vertex buffer formats here: https://github.com/V-Sekai/Unidot-Importer/blob/main/aligned_byte_buffer.gd supporting various strides and types (i needed to pass these to mesh APIs, so I wanted to minimize overhead in GDScript). Some of the conversions were clean but others were extremely messy.

I feel like the discussion about a generic type and/or SIMD / integer operations is interesting but might belong in its own proposal. I'm kind of scared about making things too generic just to solve the Vector4 problem because that creates complexity everywhere in the type system.

Edit: I'm not opposed to making Plane or Vector4 backed by _m128, but I feel like that can be made an implementation detail rather than redesigning the whole type system.

@Zireael07
Copy link

Plane -> Vector4 isn't a bad idea, and ditto for PackedVector4Array

@Listwon
Copy link

Listwon commented Apr 8, 2022

Plane -> Vector4 isn't a bad idea,

It is a bad idea, because there's no reason for Vector4 to have methods specific to Plane (like Vector3 project(const Vector3 &p_point), bool is_point_over(const Vector3 &p_point) etc.).

I really can't grasp what is the real problem of having such basic data type in 3D game engine core.

@Zireael07
Copy link

@Listwon: You have a point. Maybe have the Plane inherit from V4?

@aaronfranke
Copy link
Member Author

@Zireael07 That wouldn't make much sense. There are also methods that would be on Vector4 that don't make sense on Plane, such as length and distance methods, actually I think most methods wouldn't make sense.

@Zireael07
Copy link

  • scratches head kinda sheepishly* right...

@nathanfranke
Copy link
Contributor

As mentioned in godotengine/godot#59125 (comment), Vector4 can be used to link the values of sides/corners (e.g. stylebox borders top/bottom/left/right) using a property hint.

image

@philomelus
Copy link

This has been closed, even though Vector4 and Vector4i have not been implemented in the mono classes. Isn't making the mono classes part of "implementing" the new feature? If so, this is incomplete.

@aaronfranke
Copy link
Member Author

@philomelus This is already being worked on. These new types not existing in the Mono module prevents compiling the Mono module, so it's not as if this could be forgotten.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Status: Implemented
Development

Successfully merging a pull request may close this issue.