You can project an image from a point onto a surface using Vector Maths.
Start with two reference points - one for the source of the projection (L) and another for the centre of the plane (O).

The reference points can be defined in the material using a couple of Combine XYZ nodes to generate each as a Vector (representing the position in relating to the world origin). In addition, a third Combine XYZ node can be used to indicate the orientation of the image used in the projection. You can use Drivers to automatically set each of the XYZ elements of the vectors based on the location of an Empty positioned within the scene. In this way you can easily change the reference points simply by re-positioning those reference Emptys rather than having to manually adjust the vectors.

For each sample point on the surface we need to determine the vector of the ray from the projection source, through the image plane and to the surface. This can be achieved by subtracting the vector representing the source of the projection from the point on the surface. However, in order to calculate the vector of the ray we need to ensure that each of the points are in the same 'space'. The two reference points are in world space whereas the sample point Object output from the Texture Coordinate node) is in Object space. The Vector Transform node can be used to translate from Object space to World space and we can then simply Subtracting the vectors to calculate the vector of the ray.

Note : You must use the Vector Math Subtract node - not the Math Subtract node - for this.
To determine the point in the image texture that would be projected onto any particular point on the surface we need to be able to measure how far the ray travels in specific directions - in the Y direction of the image plane, in the X direction of the image plane, and also the distance travelled perpendicular to the image plane.
The vector between the two reference points (LO) can be used as the 'centreline' of the projection and this will be perpendicular to the image place. It can be calculated simply by subtracting one vector from the other.
The X and Y vectors need to both be perpendicular to the 'centreline' and to each other - to ensure they are independent (ie, at 90 degrees to each other, in the same way as for the the usual X,Y,Z axes in World or Object space). These can be generated by using the Cross Product Vector Math node; the Cross Product takes two vectors and generates a vector that is perpendicular to both of the input vectors. Passing the 'centreline' vector and the Orientation vector into a Cross Product will generate the X vector. Passing the generated X vector and the 'centreline' vector into another Cross Product wiil generate the Y vector.

Passing the X and Y vectors through a Vector Math Normalize node ensures they are of unit length (important to ensure the projection is not distorted).

To measure each ray we use the Dot Product to determine how far the ray travels in the direction of each of the 3 reference vectors (X,Y,centreline). ie, To measure the distance to the plane where the ray intersects the mesh we can combine the ray with the 'centreline' vector; in the X direction we combine with the X reference vector; in the Y direction we combine with the Y reference vector.

All that remains is to scale the measured distances based on the relative distances between the source, the projection plane, and the plane at the intersection of the mesh. ie, if the distance between the source and the plane (L->O) is 1/3 the distance from the source to the plane at the mesh (L->Q) then the vector in the texture plane (O->t) will be 1/3 the length of the equivalent vector (Q->P) at the mesh.

This can be achieved using maths nodes to calculate the ratio (the Dot Product and first Divide) and applying the ratio to the measured coordinates (the other Divide nodes). The results are combined into a Vector.

The resultant coordinates will be centred around 0,0 but the texture space is from 0.0 to 1.0 - so an additional MixRGB node set to Add is used to add 0.5,0.5,0.5 to the vector to adjust. The result can be used in a Texture node to apply the actual image to the projection.

The final material should look something like this :


In the attached Blend file, move the empties to move the reference points of the projection.
The material can be used to drive the surface for a surface projection as shown above, but can also be used to drive Volumetrics which can show the path of the projected rays.
