# How to make a holographic reticle shader in cycles

Does anyone have a lead on how to set up a shader in cycles to mimic the behavior of hologhraphic sights in blender, as shown in this image?

I don't want to have to try and figure out exactly how to get the lenses and reflectors etc. physically correct because there seems to be no public knowledge of how exactly it's done. I'm thinking it will probably have to involve some vector math, but I don't know how to do it.

• Please don't use link shorteners. You can link the image directly or rehost it on imgur. May 6, 2018 at 19:54

Hey look, high-school maths does have a purpose......

From what I could understand with a little research, holographic/reticle sights display a holograph that appears (when looking through the sights glass) to be fixed to a spatial position a certain distance (d) from the glass. Basically, we need to work out the x,y coordinates of the point d distance down the camera ray for each point we render on our sight. We can then use that to map our texture.

This would be a piece of cake if we had matrices in cycles nodes (in particular, the transform matrices of the sight object and the camera, as well as the projection matrix). We don't, so lets improvise.

The camera data node (which is where you'd expect to find the view and projection matrices) is a good starting place. While we don't see any juicy matrices, we do get one vector.

### The View Vector

• Location: Camera Data Node
• Age... No idea when it was added
• Height: ....Dude, this is a node
• Weakness: Its normalized

The view vector provides a vector representing the ray that was shot out to hit that point of our mesh. This direction is in camera space. Therefore Z is always forwards, x is always left/right, and y is always up down. Each vector is normalized, so they always have a length of one.

Lets visualize this a bit. We'll do this in 2D because I can't draw this in 3D it will be easier for you to understand.

Looking at our camera top down in camera space, z is forwards (now up relative to our view), and x is left to right. This is drawn with the dark colored axis. If we look at our ray (in yellow) which has a length of 1, you will see that it can be broken up into an x and a z component (light colored axis). This is the ratio of x to z movement needed to travel down the ray.

I am available to illustrate geometry textbooks.

Do you remember when I said

Basically, we need to work out the x,y coordinates of the point d distance down the camera ray for each point we render on our sight.

If we multiply the View Vector by d, we will get the x,y coordinates of a point d distance from the camera in that direction. Progress!

However, our sight is now fixed to the camera. We can improve this, using the vector transform node.

### Vector Transform

• Strength: Secret sauce that makes everything work
• Weakness: Doesn't seem to understand the idea of location

Obviously, our hologram should not always be d distance infront of the camera. It should be d distance in front of our sight. To do this, we will need to go from camera space to object space. The vector transform does exactly this:

To explain exactly how this space conversion works, we will need to understand object space. Object space is where the origin of our space is the origin of the object, and all the axis (plural) line up with the objects local axis (plural). Pretty simple. Our sight just needs to be d distance down the z axis is object space.

So how does this space conversion work?

If you will direct your eyes to my next graphic (again drawn looking top down), you will see that a plane as been added (our sight), and the camera has been rotated. In light colors are the axis of the object space, and in dark the axis of the camera space.

If we ignore position for a moment, and overlay the two spaces, we can see how the axis don't align:

If we line the axis up as such:

We can see that the ray, which is in camera space, is pointing the wrong way. If we apply the inverse of the camera's rotation to the data, the ray will go back to pointing the correct direction.

This is what the vector transform does.

However, this space transformation does not take the relative positions of the camera and the object into account. Therefore, if we move the camera, our sight slips:

To fix this, we need to take position into account.

### Object Texture Coordinate

• Location: Texture Coordinate node
• Weakness: Weird positions for object origins

The object texture coordinate give the object space location of the ray/mesh intersection. Since our rays are traveling at the right angle, all they need is to start at the right place. If we take the object space coordinate, and travel d distance along the ray direct (in object space), we will get our desired x,y coordinates. This can be achieve simply be Adding the two vectors together (using the vector math node).

Now it works:

Lets re-cap.

We take the view vector, transform it to object space, multiply it by the distance d (scalar multiplication). We then add it to the object texture coordinate.

Since we sample textures in 0,1 space, and our xy coordinates range between --25 and + 25, we then divide by d, and add .5 to the xy coordinates, Clamp to avoid the texture repeating, then sample it. The whole setup looks like this:

I created my own vector clamp and scalar multiply node groups. Those can be obtained in the provided blend file.

### Denormalizing the View Vector

The view vector travels out from the camera, which is a point in space. We adjust the position, transforming it to the origin of the object. Because the vector is normalize, our "projection" plane is actually a sphere d distance from the origin of the object.

In the examples, we view a very small slice of the sphere, so the curvature is not very noticeable

However, if we were to place a camera with a very wide FOV very close to the glass, we would see a much greater amount of curvature:

Which would produce very visible distortion (clamping is turned off because the repeating pattern makes to distortion more visible):

To fix this we need project the point represented by the normalize view vector (Yellow) onto a abstract plane (Teal) that is one unit away from the camera along the z (depth) axis.

The target point is in magenta. RGB lines represent components of the view vector. Also, 2.8 grease pencil improvements are awesome.

This diagram is a little confusing, a top down view provides some more clarity:

If we scale the vector's components by the ratio of the distance to the plane and the z components 1.0/z (big purple bracket divided by little purple bracket) We can extend the vector to the plane.

Implemented in nodes:

And now the warping is gone:

The center target is still roughly the same size. They appear to have shrunk since the spherical projection was moving the outer targets closer.

## Author's Notes

This is a pretty robust shader. It handles object rotation, scaling moving, and zooming (focal length changes) in stride. The scope texture will always be centered around the object origin, and be visible when looking down the z axis of the object. Because the output of view vector is normalized, the output x,y coordinates used to map the texture will be projected along a sphere d distance from the objects origin, rather than a plane. This shouldn't be too noticeable. Pity they don't let the user decide whether it should be normalized.

• Upvoted purely for the MS paint diagram!!! :) May 7, 2018 at 13:27
• You should be able to use trigonometry to project the view vector onto a plane and not a sphere, but, you're right, it's unnoticeable.
– HTNW
May 7, 2018 at 19:47
• Just out of curiosity, why the hell don't we get access to matrices of things. May 7, 2018 at 20:09
• @joojaa No idea really. Kind of a shame. TBH, alot of improvements could be made to the cycles nodes. There are oodles of procedural texture patterns that we don't have, and lots of math features that are downright missing, or a pain in the neck to use. Best solution would be to remove OSL, and allow users to add their own SVM shaders for GPU rendering (although I am willing to be there is a technical reason as to why this hasn't happened). Doing that would allow a massive amount of community nodes to appear, which in turn could be added to blender proper, fixing many issues. May 11, 2018 at 7:22

## Objects

You will need two objects. Lens and sight. Place them as you will do it for gun without holographic sight.

## Materials

For lens use just Glass Shader.

For sight use mix between sight material (could be anything, I've used just Emission Shader) and Transparent by Light Path > Transmission Depth. This will create material that will be visible only trough glass.

Note: Do NOT shoot innocent monkey!