Page MenuHome

Attribute Vector Math Projection does not behave in a mathematically sensible way
Confirmed, NormalPublic

Description

System Information
Operating system: Linux Mint 19
Graphics card: GTX 1660

Blender Version
Broken: 2.93
Worked: ?

Short description of error
Projection of one vector onto another traditionally results in a scalar; but Blender's Attribute Vector Math Geometry Node, in its Project mode, returns another vector. Additionally, I have no idea where this vector is coming from, as it does not seem to relate to the projection at all.

An alternative possibility is that it represents the less commonly referred to vector projection; but in the attached file, which I have edited (check inside Geometry Nodes.001) to project position onto itself, the z-coordinate of the result is consistently zero. By vector projection, it should be parallel to position; which it clearly can't be if it isn't even on the same ray.

In the meanwhile, I'm going to try defining my own scalar projection; but this behavior is undocumented and likely a bug. (The documentation on Attribute Vector Math describes Project as "the projection of A onto B", which is not helpful at all.)

Exact steps for others to reproduce the error
In the event that this is a runtime bug, I'm also enclosing a screen shot.

My expected behavior is that Project returns (AB / BB), or the component of A in the direction of B. It's been a while since I worked with linear algebra directly, and there's a very mild chance I'm mangling it in my head; but I can't figure out how z could ever be zero.

Event Timeline

Richard Antalik (ISS) changed the task status from Needs Triage to Confirmed.Tue, Jun 8, 11:16 AM

Current math is: if (A • B) > 0, result is B, otherwise {0,0,0}. I would also expect component of A to be returned.

That's very counter-intuitive. I wouldn't expect a default zero vector at all. A project is simply defined as (A • B)/(B • B), possibly times B if you want a vector, isn't it? Since a dot product is simply |A||B|cos θ, and I don't believe that either vector is ever (or at least, always) zero, and lastly they should only rarely be at 90°, I'm not sure how that would realistically apply here.

(I admit that I'm still not convinced that I'm not just pulling a PEBKaC here; this is part of what has been a very big project and I'm a little jaded. This feels real though.)

@Charlie Jolly (charlie), would you like to check if this is working as expected or if something is wrong and whether it only affects geometry nodes?

Below is the implementation of the Project function. This was added when Cycles was first implemented. This appears to be correct in regard to Vector Projection as defined here: https://en.wikipedia.org/wiki/Vector_projection. It maybe that you want the other function under Scalar Projection?

Geo nodes:

case NODE_VECTOR_MATH_PROJECT:
      return dispatch([](float3 a, float3 b) {
        float length_squared = float3::dot(a, b);
        return (length_squared != 0.0) ? (float3::dot(a, b) / length_squared) * b : float3(0.0f);
      });
Eevee:

void vector_math_project(
    vec3 a, vec3 b, vec3 c, float scale, out vec3 outVector, out float outValue)
{
  float lenSquared = dot(b, b);
  outVector = (lenSquared != 0.0) ? (dot(a, b) / lenSquared) * b : vec3(0.0);
}
Cycles:

    case NODE_VECTOR_MATH_PROJECT:
      *vector = project(a, b);
      break;

ccl_device_inline float3 project(const float3 v, const float3 v_proj)
{
  float len_squared = dot(v_proj, v_proj);
  return (len_squared != 0.0f) ? (dot(v, v_proj) / len_squared) * v_proj : zero_float3();
}
OSL:

vector project(vector v, vector v_proj)
{
  float lenSquared = dot(v_proj, v_proj);
  return (lenSquared != 0.0) ? (dot(v, v_proj) / lenSquared) * v_proj : vector(0.0);
}

I agree that this may well have been a PEBKaC. (I'd been working on that project for several weeks.) I may have been expecting the more familiar (to me, at least) scalar version. To be fair, it might be a good idea to separate operations into "Vector Project" and "Scalar Project", as they're named similarly but, in implementation, are very different.

I agree that this may well have been a PEBKaC. (I'd been working on that project for several weeks.) I may have been expecting the more familiar (to me, at least) scalar version. To be fair, it might be a good idea to separate operations into "Vector Project" and "Scalar Project", as they're named similarly but, in implementation, are very different.

If you can provide a clear use case and example, I can prepare a patch to add scalar projection.

Sure. When I use scalar projection, I'm usually trying to see how far a vector (or color) displaces along an arbitrary axis. The mathematical definition (in LaTeX) is thus:

Where the dot is the dot product, and the double bars are the length of the vector. I would expect this to take two vectors as inputs and provide a floating point output (or possibly a floating point and a vector, parallel to B, of the length of that floating point).

It isn't difficult at all to throw together a group that does this; but it feels a little excessive to have to, so thank you very much for considering adding it. (I'm trying to contribute to the code, but I've got an animation job taking up my time right now and am totally lost in the C++ at the moment.)

Peace.