Open Nolkaloid opened 4 years ago
You can look at my VectorResource
plugin (AssetLib link, but I recommend downloading from GitHub as it contains some recent fixes), see "vector swizzling syntax" in the examples section.
It doesn't support overloaded operators though (nor GDScript: godotengine/godot#23488), so the way you show it in the snippet (namely *=
, only =
operator is supported being the _set
method) is not completely possible, but it's indeed possible to get any combination of a vector (not sure about the performance though). The vector used internally is always Vector3
because it can contain Vector2
representation within itself quite nicely.
Of course it's equally cumbersome if you need to perform this kind of operation frequently enough, because you'd basically have to instantiate an entire Resource
just for the vector math:
var velocity = VectorResource.new()
velocity.xyz = Vector3(6, 1, 6)
velocity.xz = velocity.xz * 2
So see for yourself, this has mostly editing/storage purpose.
The plugin originates from #397.
Thanks for linking the plugin! It's great that there is at least a way to achieve "vector swizzling syntax" right now. But it's again rather cumbersome to use a plugin for something like that. My proposal is just a "small improvement" to gdScript and it's just a question of "quality of life".
Yeah I'm just showcasing the hurdles as a plugin writer. Having this implemented in core would certainly make plugin development much easier in this regard.
Related to https://github.com/godotengine/godot/issues/6861.
How difficult would this be to implement? Would it just be a matter of adding xz
, xy
and yz
properties to Vector3 with setters and getters that return Vector2
?
@Calinou In essence, yes.
This get more contrived since we should probably add zx
, yx
and zy
as well.
Then, the swizzles xzy
, yzx
, yxz
, zxy
, and zyx
are a natural extension of it.
Then on Vector2, we would want to have yx
for feature parity.
And for converting a vector2 into a vector3 we might also want to have xyo
, xoy
, oxy
, yxo
, yox
, and oyx
.
(for feature parity, it might be worth adding swizzles with o
to vector3 as well, but those are around 18)
@bojidar-bg Are swizzles featuring all components really useful though (like zyx
)?
Indeed, I can't think of a use for three-component swizzles right now.
Maybe someone else can suggest some usecases for those? :smiley:
It could be useful if you want to change the orientation of your frame. Let's say I have
var =Vector3(1, 4, 1)
and then I change it's orientation like this :
var = var.xzy
What about:
enum Component {
ZERO,
AXIS_X,
AXIS_Y,
AXIS_Z
}
Vector2 Vector3::swizzle2( Component x, Component y );
Vector3 Vector3::swizzle3( Component x, Component y, Component z );
It is slightly clumsier than .xyz()
, but still adds a fair bit of convenience without exploding the API with 27 new properties :)
We could even append ZERO
to enum Axis
but it might not make sense in the other contexts it is used.
Could this be done ~using a union
access to the Vector's components as an array and~ using an overloaded access([]
) operator/new function (granted it's confusing for people who use mutlidimensional array index operators, like in C#)?
var vec3: Vector3
var vec2: Vector2
vec3[X] = 1
vec3[Y, Z] = Vector2(2, 1) # or [2, 1] since both are iterators of some kind
vec2 = vec3[Z, Y]
Then introducing the syntactic sugar vec3.zy
for this new operator/function? I have seen rorre's implementation and it felt quite cumbersome in comparison.
@ShivamMukherjee I believe that would be a more significant change, as:
X
and Y
in your example? In that context they will be interpreted as variables, not symbols. Unless we add X
Y
Z
constants to the global namespace, it would be more like vec3[Vector3.AXIS_Y, Vector3.AXIS_Z]
@ShivamMukherjee I believe that would be a more significant change, as:
- gdscript doesn't have a multi-element indexing operator (that I'm aware of)
- What are
X
andY
in your example? In that context they will be interpreted as variables, not symbols. Unless we addX
Y
Z
constants to the global namespace, it would be more likevec3[Vector3.AXIS_Y, Vector3.AXIS_Z]
They're constants basically, could very well be the respective class's AXIS_* constants. The ordering of the constants in this function/operator call will matter. The bottom line is that a notation which is fairly uniform may be easily macro'd from the respective shader swizzle notation.
I suggest an operator since a function call, as far as I understand, can't appear on the left-side of an assignment operator. Again, this could be a setter function kinda thing as well.
For reference, here are links to PRs discussing this same topic: https://github.com/godotengine/godot/pull/39674 https://github.com/godotengine/godot/pull/51165 https://github.com/godotengine/godot/pull/55220 https://github.com/godotengine/godot/pull/93012
My take is that because converting is usually not as simple as just getting multiple coordinates in a swizzle (ex: converting between 2D and 3D you need to negate the Y axis and scale by 100, or whatever pixels-per-meter your project is using), and due to the inevitable combinatorial explosion (imagine doing this for Vector4), the engine should not provide these functions/properties.
the engine should not provide these functions/properties.
I agree this would be better implemented at a GDScript level, although I wonder how this would be done in C#. This is likely how GLSL compilers handle it internally (maybe look at Mesa for answers 🙂).
@Calinou In C#, this feature is needed in the engine even less because C# has a feature called extension methods. These are defined in users' own code, saving the engine from bloat, but behave the same way as a built-in method, providing a seamless user experience. For example:
// Define this anywhere in your project.
public static Vector2 to_2d(this Vector3 v) {
return new Vector2(v.X, -v.Y) * 100.0f;
}
// Then use it like this:
Vector2 v2 = v3.to_2d();
for starters having just the three xy
, yz
and xz
would be nice and we can discuss the other swizzles later.
or we can get a function with 27 enums,like so:
var vector_three := vector3.ONE
vector_three.get_axis(vector3.AXIS_XY)
or a function that get a string like get_axis("XY")
or someting like these,
but even so i suggest the xy
,yz
and xz
still be added as properties to the vector3 as i think these are more usefull.
Describe the project you are working on: 3D top down shooter
Describe the problem or limitation you are having in your project: Operations on different vectors become rather cumbersome when working separately on coordinates:
Describe the feature / enhancement and how it helps to overcome the problem or limitation: It would be really useful to be able to access multiple coordinates at the same time like in GLSL: