Showing posts with label rainbow. Show all posts
Showing posts with label rainbow. Show all posts

A phong ramp (car paint?) OSL shader for Cycles

A phong ramp closure has been available for quite some time in Blenders OSL implementation (see the commit log) but this hasn't been exposed as a shader node yet. That is quite simple to do and in this post I present a bare bones implementation of such a shader node

I don't know much about car paint shaders, may be the reflection color changes as well with the view angle and not just the diffuse color but this might be a start for people wanting to implement such a fancy shader. This shader might be useful as well to implement soap bubble irridescence in a different way. (you might want to check the dicussion on Blender Artists).

surface phong_ramp(
 float Exp = 1,

 color C1=color(1,0,0),
 color C2=color(.8,.2,0),
 color C3=color(.6,0.4,0),
 color C4=color(.4,0.4,0.2),
 color C5=color(.2,0.4,0.4),
 color C6=color(0,0.4,0.6),
 color C7=color(0,0.2,0.8),
 color C8=color(0,0,1),
 
 output closure color Cout = 0
){
 color colors[8] = {C1,C2,C3,C4,C5,C6,C7,C8};
 Cout = phong_ramp(N, Exp, colors);
}
As you can see, all there is to this code is transfering the input values to the arguments of the built-in function. The function takes an array of eight colors so we have created eight input color sockets. I admit that it lacks elegance but it works.

Example node setup

the sphere in the example image was created with the following node setup:

A rainbow OSL shader for Blender Cycles

Here I present an OSL shader to render a simple, single rainbow in a scene.

The example image was generated using one of Bob Groothuis excellent HDRI maps from his Dutch Skies collection.
The aim here is to produce a believable but not necessarily completely realistic rendition of a rainbow. The theory behind rainbows is quite clear but we don't want to go as far as approximating Mie theory as this makes for very complex shaders indeed.
So what do we consider believable? The color progression and the angle of the arc should be correct of course but also we would like to be able to influence the intensity. Rainbows are most often seen against the backdrop of rain showers and the density of the distribution of the raindrops is not uniform and this has an effect on the visibility of the rainbow.

OSL limitations

In real life rainbows are seen when there is a very bright light behind you, most often the sun. The center of the rainbow arc is positioned in the direction of your shadow. Now we want to project the rainbow on a plane we can use a trick to find out the camera vector (by transforming the location of the object from world to camera space, see line 16 below) but there is currently no way to find out the location of objects other than the one being shaded. That means that to create a believable scene we must take care ourselves to position the plane with the rainbow opposite the sun, relative to the camera!
Another thing I found that although OSL has a wavelenght_oolor() function it was very difficult to create the washed out colors that we associate with rainbows. So instead of trying to mix colors and account for exact dispersion and stuff like the size of the disk of the sun, I opted for just calculating the angle an plugging the result into a color ramp.

#define INNER 0.766   // cos(40)
#define OUTER 0.743   // cos(42)
#define SPREAD (INNER - OUTER)

shader rainbow(
 output float T = 0 
){
    if( raytype("camera") ){
        point Pos = P;
     // vector from point being shaded to camera
        point cam = normalize(transform("common","camera",Pos));

        // vector from object center to camera
        point obj;
        getattribute("object:location",obj);
        obj=transform("world","camera",obj);
    
        obj=normalize(obj);
        
        float theta = dot(obj,cam);
     if (theta > OUTER && theta < INNER){
            theta = (theta-OUTER)/SPREAD ;
            T = theta;
    }
    }
}
So basically all that this shader does, is calculating the cosine of the angle between the vector pointing from the camera to the point being shaded and the vector pointing from the camera to the center of the object being shaded (line 20).

Example node setup


The trick used to create the example image is to multiply a suitable density (here a simple vertical gradient mapped to an appropriate position, shown on the left) to the the output color that we extract from a color ramp and input that into a diffuse shader that is added (not mixed) to a completely transparent shader. Note that the color ramp must start with an all black node (because T is zero outside the rainbow). The plane to which this material is added may be positioned at any distance from the camera so it is possible for example to position buildings that partially obscure the rainbow.