Godot-proposals: Allow to get multiple coordinates of vectors at the same time (swizzling)

Created on 18 Apr 2020  路  13Comments  路  Source: godotengine/godot-proposals

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:

velocity = Vector3(6, 1, 6)
velocity.x *= 2
velocity.z *= 2

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:

velocity = Vector3(6, 1, 6)
velocity.xz *= 2
core gdscript

Most helpful comment

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".

All 13 comments

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.

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:

  • gdscript doesn't have a multi-element indexing operator (that I'm aware of)
  • What are 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 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]

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

IllusiveS picture IllusiveS  路  3Comments

Torguen picture Torguen  路  3Comments

wijat picture wijat  路  3Comments

PLyczkowski picture PLyczkowski  路  3Comments

SpyrexDE picture SpyrexDE  路  3Comments