Color based on an angle between camera and object's origin?


(Okavango) #1

Hi guys, here’s a fun experiment:

Would anyone know how to get a material to change it’s colour based on an angle of the line connecting that object’s origin and the camera that is watching it?

Basically, the colour of an object would suddenly change if the camera is moved around the object and the angle between the object’s origin and the camera exceeds a certain amount. Let’ say the colour of the shown plane would flip from red to green every 15 degrees the camera ‘lurks’ around the plane:

Been trying to do that for some time, but to no success…


(ruslan k) #2

played a bit ) achieved a color dependency on camera (view) position this way

camera-to-color.blend (498.5 KB)


(sundialsvc4) #3

In this thread – Switching between materials on linked library objects ... easily – one respondent talked about using “color ramp” nodes and provided an illustration. In like manner, if you could obtain the angle as a number, then scale it and clamp it into the range-of-values needed by that node as the respondent did, and feed that into a “color ramp,” it just might get you to where you want to be.


(Okavango) #4

Wow, what an elegant solution, i would’ve never thought of Vector Transform node. Thank you!

With a little modification for an instant colour ‘flipping’, here’s what i got:

And it worked :slight_smile:


(Okavango) #5

Ah, great! I will check it out. That might be helpful for the next step - make the plane have one colour for the frontal and +/-45 degree angles, and other colour when it comes near to side view, as seen from the camera.


(Lumpengnom) #6

Yes, you´d probably want something like the following. Note that the y output of the separate node does nothing because it is plugged into the second input of a tangent math node. This second input has no function if set to tangent.


(ruslan k) #7

the update to initial proposal:

  1. ensure initial vector is normalized and pointing Y axis (look-to direction in camera space)
  2. just a note: transforming vector into object space makes behavior dependent on object orientation
    within a world space, if you don’t want the object rotation impact the final color then update the
    target space to “world”
  3. output as vector

The math is fixed to actually provide linear dependency on angle to camera

below is the math description (for those who’s interested):

the Vector Transform output represents the vector with a normalized (=1) length aligned to camera;
the X value is a projection of this vector to X axis (within object space), which value may vary
(depending on angle) from -1 to 1. The acos() calculates actual angle relative to X axis (in radians) which requires to be divided by Pi for normalization (to fit -1…1 range). The abs() just makes negative
values being positive, due to factor input (subsequent node) expects values in range 0…1.

camera-to-color-updated.blend (480.4 KB)


(Okavango) #8

Thanks for the updates guys. Couldn’t spend a significant time on this but will try to get to what i want. Yes, i noticed that i have some problems when orbiting camera around the plane, although the colour flip is brisk and on every 90 degrees, the change pace is not quite predictive, especially when you multiply the number of planes. I will try these different settings that you proposed @roolic and report back.

I think you will like the final purpose of this little experiment, if we succeed in this it could help in one aspect of rendering large scenes :wink: The goal is actually to have multiple planes in the scene, scattered around and with different rotations and when the camera looks at them frontally (with a margin of ±45 degrees) the planes would acquire a certain aspect of the material.


(moony) #9

Does this thread help?


(Okavango) #10

Hi guys! Thanks for the support, here’s what i have so far:

This first screen-shot is what i got when applying the updated node set proposed by @roolic (with the addition of constant colour ramp for instant flipping between colours and a transparent shader to see what is going on the rear side):

At first it seemed that it worked, this is actually what i was trying to get when the camera looks at the group of planes!

There should be 3 planes in an assembly (i decided to go for 60 degree difference angle instead of 45) which have the same material. When the camera looks at an assembly, only the most frontal plane of the 3 would have the green colour and the two other would have the red colour. This should remain the same no matter from which position the camera looks at this group, only one of the three planes should be painted in green. As you move the camera around, the green colour would instantly flip to the most frontally oriented plane, and other two should go red at the exact same moment, so only one plane is green at all times.

Unfortunately, the nodeset gives unpredictable behaviour, when i walked the camera around, this is what happened:


(Okavango) #11

Now you have to understand, i really have no idea what math is going on behind those nodes and i have hard time visualizing those vectors, but after some random meddling i got this:

Now this is not what i was looking for, obviously, but an interesting thing happened when i turned the camera around:

It behaved flawlessly - as i turned around, the planes exchanged colours with a swift flip and always facing in the same direction. Unfortunately, as you can see, the backsides of the planes are half - half coloured and the green colour facing to the right, but there might be some inspiration in this… What do you guys think?


(Okavango) #12

Hi, thanks for the link, it’s a very interesting approach. Unfortunately, this node set colours different parts of the same object in different colours and with a gradient. What i need is an instant colour change to a whole object, based on an angle between the object’s local coordinate system and the view vector of the camera.


(ruslan k) #13

camera-to-planes

important: all planes should have locally rotated by 60 degrees (do not apply rotation)

the ColorRamp handles (white area) angle change at 60 and 120 degrees to local X axes (while input
indicates 0 to 180, the points are set at 0.333 and 0.666, also constant mode used ColorRamp node)
doing same for ranges 0-60 degrees or 120-180 degrees doesn’t work, unfortunately
due to abs(), proper logic is a bit complicated and seems can be resolved only via custom shader (script).

anyway can be resolved (workaround) by plane rotation in edit mode (keeping same local orientation)

camera-to-planes.blend (490.1 KB)


(Okavango) #14

Wow, seems you’ve got something there! Thanks, i will report back.


(Okavango) #15

Yup, it looks like you solved it :smiley: I even managed to rotate the plan in edit mode, so that the green plane is the only one and facing the camera.

However… Blender wouldn’t be what it is if it wouldn’t give you some hard time occasionally. I tried to reproduce your material in my own file, and believe or not I COULD NOT.

I made my own planes, i followed what you’ve said, reproduced the exact same nodeset and it kind - of - but - not - really - worked. I then imported your planes to my file and it worked flawlessly. I put it next to my object and transferred your material to my object and it worked. I put my material back to my object and it did not work! My material irregularly lags when flipping colours and timing overlap is often the case.

Since i don’t quite like computers making jokes on me, i went to your own file, made a duplicate of your plane assembly in your file and imported my material reproduction with the exact same nodeset. I applied my material to one of the objects and you can see the result below.

Now, could someone, in the name of human mental health, explain to me - how are these two nodesets different:

camera-to-planes_001.blend.zip (86.9 KB)

Just to be clear, this is your original file, your original and duplicated object, your original material and my discriminated reproduction of your material.


(ruslan k) #16

the initial vector

initial-vector

expected to be oriented in a direction camera looks to (0,1,0), it’s in this comment )


(Okavango) #17

BARGH! I somehow knew i would look stupid at the end of this thread :smiley:

Thanks man, i corected it and it worked. I will try to perfect it and to bring it to it’s final purpose. I think it is time for the SOLUTION mark :slight_smile:

Will report with the final results, thanks guys.


(Okavango) #18

Ok, here is the final run-down of the procedure. I tried to see if i can replicate the effect in a completely new file:

First, you make a plane in upright position, or rotate a horizontal plane of required dimensions to upright position and apply transformation. Make sure it’s local z axis is upright, it’s x is to the right and it’s y going behind it.

Next, reproduce this exact nodeset with given parameters and values 0.333 and 0.666 for positions 1 and 2 in the colour ramp.

Now simply duplicate the plane two times, each duplicate rotated by +60 degrees from the previous one.

Multiply the assembly to your liking, stretch, scale…

No matter where you look from or which camera you turn on, the most frontal plane in each assembly will be marked. Thanks for the help guys.


(KWD) #19

By the way, you can get the cosine of the angle between two vectors by taking their dot products. So if you take the dot product between a polygon’s normal and the camera view, you have the cosine of the angle between them. The cosine will be between -1 and 1, with values < 0 meaning the polygon is facing away.

Here’s my take on it:

If you want the sine of the angle, you would need to use the length of the cross product instead of the dot product.