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 Vector3.project_on_plane() #8173

Closed
esklarski opened this issue Oct 17, 2023 · 16 comments
Closed

Add Vector3.project_on_plane() #8173

esklarski opened this issue Oct 17, 2023 · 16 comments

Comments

@esklarski
Copy link

esklarski commented Oct 17, 2023

Describe the project you are working on

I'm new to Godot, but I'm immediately missing a project on plane method for Vector3's. This is easy enough to implement in GdScript but I think it should be a core Vector3 method.

Ie:

Vector3  project_on_plane( Vector3 surface_normal )

I'm willing to make the code changes, but I've also never written C++ code before this and have never tried to build and test the engine. Consider this a work in progress, needing some mentoring.

Describe the problem or limitation you are having in your project

No limitation really, more a quality of life thing.

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

I'd like to be able to write:
var projected_vector = my_vector.project_on_plane(surface_normal)

This would keep all the calculation on the C++ side, improving performance (I assume)

It would also help newcomers to vector math. Instead of needing to understand the calculations they can move on with the vector they needed.

Describe how your proposal will work, with code, pseudo-code, mock-ups, and/or diagrams

GdScript: (tested)

static func project_on_plane(vector: Vector3, surface_normal: Vector3) -> Vector3:
	var axis1 = vector.cross(surface_normal).normalized()
	var axis2 = axis1.cross(-surface_normal).normalized()
	
	return vector.project(axis1) + vector.project(axis2)

C++: (I think)

In godot/core/math/vector3.h: (I think)

Vector3 Vector3::project_on_plane(const Vector3 &v_to_p, const Vector3 &s_n) const {
	Vector3 axis1 = v_to_p.cross(s_n)
	Vector3 axis2 = axis1.cross(s_n * -1)
	
	return vector.project(axis1) + vector.project(axis2)
}

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

I'm surprised that this does not exist. But I'm also completely unaware of how often this might get used, I only know this was a core method for Vector3 in Unity, and that I liked it :-)

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

I guess it could be an addon but that kinda keeps it from helping newcomers.

@AThousandShips
Copy link
Member

What would the difference between this and Plane.project be?

@esklarski
Copy link
Author

I do not know... I did not know about Plane

I will check that out.

@AThousandShips
Copy link
Member

Since Vector3 already has a project method it can't be added to it, as GDScript doesn't support overriding methods

@esklarski
Copy link
Author

esklarski commented Oct 17, 2023

Looked into 'Plane.project()' and I can get it to do the same thing as my proposed method. But I'm still feeling a project_on_plane for the Vector3 class would be semantically clearer:

These two produce the same result:

	var test1: Vector3 = project_on_plane(linear_velocity, -current_gravity) #see above comment
	var test2: Vector3 = Plane(-current_gravity.normalized()).project(linear_velocity)

But also maybe this is a documentation issue. A hint in the Vector3 class would also have helped me out.

@AThousandShips
Copy link
Member

In this case if you're looking at operating on a Plane and a Vector3 then looking at both documentations would be good, and I don't think it's a good idea to duplicate the code, and it makes more sense under Plane just like intersections and other code fit there

@esklarski
Copy link
Author

esklarski commented Oct 17, 2023

But that was my problem, I wasn't working with Planes. I wanted to flatten a vector on a surface normal to get the velocity perpendicular to the surface. What I have to work with are Vector3's, and what I wanted was the same.

Is creating a Plane like this every frame performant? I might try to test a bit.

@AThousandShips
Copy link
Member

AThousandShips commented Oct 17, 2023

Oh my bad missed the part without the plane, you can simply create a plane with a default position, but I don't think projecting onto a normal like this is a normal operation in this case

It's been a while since I did linear algebra so I don't entirely recall

@esklarski
Copy link
Author

esklarski commented Oct 17, 2023

I think it is more that for this purpose the location and dimensions of the plane are irrelevant; it can be anywhere and infinite in size. I'm looking for the magnitude and directional components of a vector that is perpendicular to another vector (parallel to the plane) so the surface normal is the only data needed.

I'm satisfied that Godot has this functionality, but I'd leave my suggestion as is. I think it would be an improvement still.

@AThousandShips
Copy link
Member

That can be done with a plane constructor I think simply with no cost AFAIK, you take a look at the constructors

@Calinou
Copy link
Member

Calinou commented Oct 17, 2023

Plane.project() could be mentioned in Camera3D's project_position() description (and vice versa).

@esklarski
Copy link
Author

Plane.project() could be mentioned in Camera3D's project_position() description (and vice versa).

I'd also advocate for a mention of Plane.project() in Vector3.project()

@theraot
Copy link

theraot commented Oct 18, 2023

I believe this is Vector3.slide. Valid geometric interpretations of Vector3.slide are:

  • Getting the vector minus its projection on another vector.
  • Getting the vector rejection from another vector.
  • Getting the projection of a vector on a plane that (crosses the origin and) has the other vector as normal.

Documentation on Vector3.slide currently says:

Returns a new vector slid along a plane defined by the given normal.


Like this:

image
Picture taken from Wikipedia

Given vectors a and b:

a1 = a.project(b)
a2 = a.slide(b)

@esklarski
Copy link
Author

// slide returns the component of the vector along the given plane, specified by its normal vector.

Never heard of sliding a Vector, but that sure sounds like the thing I'm looking for.

@theraot
Copy link

theraot commented Oct 18, 2023

Never heard of sliding a Vector, but that sure sounds like the thing I'm looking for.

And you won't be alone on that. I'm only aware of Godot calling it that way. And renaming it would be a breaking change.

Anyway, I'd be in favor of changing the documentation on slide to mention the word projection. That, at least, would make it easier to find.

@esklarski
Copy link
Author

esklarski commented Oct 18, 2023

It seems Godot is correct in it's use of vector "projection", and while "rejection" seems the correct term for what I want "slide" is clearer once I know what it is.

rejected_vector = linear_velociy.reject(-current_gravity)

would only confuse me more, lol.

I can confirm that these three methods produce the same result:

	var test: Vector3 = project_on_plane(linear_velocity, -current_gravity)
	var test2: Vector3 = Plane(-current_gravity.normalized()).project(linear_velocity)
	var test3: Vector3 = linear_velocity.slide(-current_gravity.normalized())

So, I would agree that adding mention of projection in the Vector3.slide() documentation would be helpful.

@esklarski
Copy link
Author

I've opened an issue on the document git here: godotengine/godot-docs#8286

Therefore I'll close this issue and move on to editing the documentation.

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

No branches or pull requests

4 participants