I have solved this and I figured I’d post the solution for anyone dumb enough to want to do this who might stumble upon this thread and come to the wrong conclusion based on the discussion.
Restating the Problem.
Create a planar UV projection in Object space that is always aligned to the camera. No matter how the object is oriented or where it is in the world, a planar projection generates a set of UVs that are attached to the object and face the camera. With the result, a projected texture will look similar to a screen UV projection, however the scaling and sliding that happens with screen space projections will be minimized.
Solution
My initial instinct I think is the only way to achieve this. The UVs or Pixels need to be rotated and the projection applied. No common space transform can solve this. The projection has to happen in the object’s space and the vector the projection aligns to is the vector between the object position and the camera position. View space comes close, however the camera view vector and the desired projection vector become divergent when the camera is rotated away from the object and the projection will appear to rotate away from the view point. No matter what space you attempt to do this in, you will be three rotations away from lining up the projection coordinates correctly, so it’s easiest and cheapest to not use a transform node and just work in world coordinates. The planar projection must be defined explicitly. Using a BB function to define the extents of the projection scales the projection with the object’s animation.
The solution is to rotate the object position->camera position vector to a cardinal axis and apply the projection It’s important to note you are not actually rotating the object. You can do all the rotations you want and as long as you don’t feed them into World position offset, the model will not physically change shape or orientation.
You will need to define 6 vectors and do three rotations. You are trying to rotate about an arbitrary axis. I found it easiest to use Transform3x3Matrix functions and not have the additional expense and headache of dealing with offsets generated by rotate about axis.
Some useful links.
[This explains rotations about an arbitrary axis](https://www.siggraph.org/education/materials/HyperGraph/modeling/mod_tran/3drota.htm#Rotation about an Arbitrary Axis)
This has a clearly explained solution for calculating rotations and dealing with axis flipping on rotations.
I found it easiest to rotate the object->camera vector to align with World Y and apply the projection, so that is what this explanation will do.
Steps
-
Define your vectors. Three unit vectors representing the world, X (1,0,0), Y (0,1,0), and Z(0,0,1). Your Projection Vector (object position - camera position). Using the projection vector and World X, create orthogonal vectors for your projection space with the Create Third Orthogonal Vector node. This will produce normalized orthogonal vectors representing your projection axis. I refer to them as Projection, Up and Right.
-
Subtract the actor position from the Absolute world space position from the outset. I’ll call this UV Position.
-
Create a seventh vector you will use to start aligning your projection vector with World Y. You can refer to Pythagoras to generate this vector, or cheat. The vector should be a projection of your Projection vector in the XZ plane. To cheat, just grab the Projection vector break out it’s components and make a new float 3 substituting 0 for it’s Z value. I will refer to this as XY Projection.
-
First rotation. Get the angle between XY Projection and World Y. Rotate UV Position on World Z using the angle between XY Projection and World Y. This and all subsequent rotations use 0,0,0 as their base position or pivot.
-
Apply the same rotation to Projection and Up vectors. You can additionally rotate Right vector if needed but it’s not required for this example.
-
Using the angle between the Projection vector generated in step 5 and World Y, rotate UV Position on X Axis.
-
Apply the same rotation to the Up vector generated in step 5. Again, you can rotate Projection and Right from step 5 as well to ensure all your vectors are where they should be, but it is not required for this example.
-
Using the angle between World Z and the Up vector generated in step 7, rotate UV position on the World X Axis.
At this point you can build a planar projection in the XZ plane. Use the X and Z coordinates for your U and V.
The result here is a sphere with a planar projection of a pattern. No matter how the object is transformed in world space or where the camera is positioned or aimed, the result looks like the image. The texture will appear to slide when the camera orbits the object, but is quite stable when compared to using screen UVs.
This method is not cheap. The vertex program comes in around 190 instructions and includes three acos functions just to rotate the UVs and build the projection.
You can also use this method to apply a displacement. Do the rotations above, displace on Y, reverse the rotations, and plug it into world position offset. This comes in around 225 instructions. You will notice in the image the texture does not appear perfectly flat like a screen projection. By rotating the UVs, scaling on Y, and rotating the UVs back, then feeding the result to World Offset, you can flatten the object on it’s Projection vector and get a perfectly flat appearance. Flattening the model works well but is not suitable for environments with a free perspective camera.