A complex approach - Iridescence in cycles

Just checked the .blend, it’s by far the most complex node group I’ve ever seen.

Usually, this would be the type of thing that should be hardcoded as a genuine node type (like an advanced version of the glossy node much like the anisotropic node is), but the fact that it’s doable at all shows the sheer power of the Cycles node system in and of itself (as demonstrated many times before).

cmon, all we need in Cycles for such things just make another sampling dimension and expose wave length as optional input.

Thx see360.

@Ace Dragon… most of the complexity it’s dued to the fact that we don’t have loops in the node editor.
basically everything can be reduced to this pseudo code (which will not work, but it’s an idea ;)):

for (wl=400, wl<720, wl+=wlstep)
{
for(order=-OrderMax, order<=OrderMax, order++){
N’=Normalsolver(Dist, wl, order, N, T);
Cl+=reflect(N’)*wavelenght(wl);
}
}

But you are totally right, this should be hardcoded as a new BRDF… And i’d like to do it, but everytime i try to look to Cycles code, i feel completly lost!
Eitherway this is just a proof of concept. But I’m very happy that it works in Cycles, and that anyone can really have this kind of power on their fingertips :slight_smile:

@storm_st :confused: hummm… how would that work??

here are two more examples:




1 Like

Fantastic proof of concept…I’ll definitely have to have a play with this. Love the sequin cloth. Any chance you could post the blends for your material examples.

(it would also be a wonderful addition to the current BRDFs).

Yes moony, give it a try. If possible give it a push!! :slight_smile:
I’ve shared it so people could enhance it.

I haven’t even tried to get my head around your nodes yet - I fear they may be well beyond me. My experimentation in this area has (as you know) tended to be rather less complex :smiley:

:slight_smile: i’m also probing from this side…
but here is the shader you asked sequins.blend (1.87 MB), and i’ve forgot to post it before…

the magenta nodes are previous to my rotation2tangent, just to know.

basically i’ve splitted up the UV map in to tiny little pieces, each has a circular gradient as as mask, a radial gradient as a rotation map, and a noise gradient that is rounded ( in osl i’d use floor(), but here i needed to add 0.5) to make a variation in the normals of each sequin. the rest is quite trivial.

Had a play. Still trying to get my head around it - although it’s not as complex as I first thought - a lot of repetition going on. Thanks for the sequins blend - looks good.

On thing that did occur to me. In your Diffraction Example shader - the final mixing of the “Order Solver” nodes…have you thought about using the add node rather than the mix node. Generally when I do color separation - I tend to recombine using add (although to be fair - it tends to be when i’m only recombining RGB).

I did had a play replacing mix with add - and the colours seem a lot brighter. It may be an option when you are aiming for brighter holographic type iridescence - rather than more subtle soap bubble type effects.

Another thing that occured to me. Currently you are treating the wavelengths separately. Would it be possible to use a colour gradient instead - so you get a continuation of colour rather than discrete bands. I’m not sure how feasible this would be given that you are currently feeding these colours into discrete glossy shaders.

I have been working on my own holographic wrapping paper material over the past week or so - and did manage to get colour gradient within a single glossy/anisotropic shader that varies based on viewing angle - could this approach be adapted to your setup?



The reason for not using the Add Shader, it’s because in Diffraction, RGB are not separated. The light still gets reflected, in the same quantities, but the wave is simply destroyed. Allthough in my examples i’ve been using a more subtle effect, it’s very easy to get a brighter result (though not physically accurated), by setting the color to a brighter then white (something like [4,4,4]). This way it’s possible to have realistic and artistic control! :slight_smile:

About the repetition in the nodes… I’d try to use a noise as an input for having different values automatically, but it turned out that the Noise node doesn’t give me uniform values in the range [0,1]. After reading about it, and looking to the Noise code, I found that only the cellnoise function is capable of uniform values. I’m writing an OSL version of the shader, using the cellnoise, and to be honest, the results are really nice, without wavelenght separations :slight_smile: hope to have it finished today.

About your setup… Wow. I wouldn’t have thought of that!! :slight_smile: I was planning to create another shader, but this time not so physically based, for faster renders… and that can be very usefull. I’ll give it a try.

With regards to using a colour gradient - I was thinking something like this (the gradient contains 1st to -4th order reflections).

If you feed in the correct angles - the glossy should pick up the colour (obviously my angles are wrong - just wanted to show the effect). The stripes dance across the surface when you change the viewing angle. No idea if it would work in your setup though - just brain dumping.


here’s an OSL script that does (allmost) the same job as the nodes…


/*
 * Diffraction Grating Reflection
 */



#include "stdosl.h"

void rng_seed(output int rng, int seed)
{
    int chash = seed;
    if (chash == 0) chash = 1;
    rng = chash * 891694213;
}

float rng_uniform(output int rng)
{
    float res = rng / float(2137483647) * 0.5 + 0.5;
    rng *= 891694213;
    return res;
}

float randomInterval(float minval, float maxval, int seed, point ipt)
{
    int rng;
    float f=0;
    float delta=maxval-minval;
    f = fmod(cellnoise(ipt*12345.0), 1.0);
    rng_seed(rng, int(f * 2137483647)+seed);

    return delta*rng_uniform(rng)+minval;
}

void rotateVector(vector v, vector axis, float angle)
{
    float sf=0, cf=0;
    sincos(angle, sf, cf);
    v=(normalize(cross(axis,v))*sf)+(v*cf);
}


shader Diffraction
(
color Color=1.0,
float Distance=1200,
float Roughness=0.0,
float Rotation=0.0,
normal Normal = N,
normal Tangent = normal(0.0,0.0,0.0),
int samples=1,
output closure color BRDF=reflection(N)
)

{
    float Rg=clamp(Roughness,0,1);
    float Rt=clamp(Rotation,0,1);
    int smps=clamp(samples,1,32);
    
    /* setup Tangent direction */
    normal Tg=Tangent;
    if (Tangent==normal(0.0,0.0,0.0))
    {
        normal Zaxis=normal(0.0,0.0,1.0);
        Zaxis = transform("object", "world", Zaxis);
        Tg=normalize(cross(Zaxis,Normal));
    }
    rotateVector(Tg, Normal, Rotation*M_2PI);
    
    
    /* setup max order */
    float maxorder=Distance/190;
    
    
    /* setup loop */
    normal NN;
    color cl;
    BRDF=0;
    
    /* do sampling */
    for(int i=1; i&lt;=smps;i++){
        
        /* setup random samples */
        float wave=randomInterval(380, 780, i*19, P);
        float order=round(randomInterval(1,maxorder,i*17,P));
        float sgl=randomInterval(-1,1,i*13,P);
                 
        /* calculate angle */
        float sTheta=sin(acos(dot(Normal,I)));
        float wfac=sTheta-wave*order/Distance;
        float angle= asin(wfac);
        
        if (sgl&gt;0){angle=-angle;}

        /*  rotate normal  */
        NN=Normal;
        rotateVector(NN, Tg, angle);
        
        cl=Color*wavelength_color(wave)/smps;

        if(Roughness==0.0)
        {
            BRDF= BRDF + (cl * reflection(NN));
        } else {
            BRDF= BRDF + (cl * microfacet_beckmann(NN,Roughness));
        }
    }
}

And @moony, when I saw your setup, I thought in some kind of shader that do not need to be precise with the Light/Incoming relation… something like opals or other types of half chaotic iridescence… I’m going to play a bit with your ideas, and see what will come out :wink:

1 Like

Really impressive results, nice work!

Whoa, that’s amazing! Especially the one in post 41.

post #50 has the file with it :wink:

This looks great! Now if only there was a way to get it working in Mitsuba… :wink:

Oh… I don’t use Mitsuba… :frowning:
If it’s possible to create random pairs of [Normal, Color] and add them all up, then I don’t see why not. After all I’m only using the beckmann reflection (which also comes with Mitsuba).

Wow that shader in post #46 would be perfect to use to create Ford’s ‘Tuxedo Black’ car paint! Good work in this thread guys! :yes:

Secrop, I was looking into if it would be possible to implement a more optimised way of doing quaternion multiplication since your method involves decomposing the quaternion into its base coefficients and doing various multiplications and sums, and so to that end I found that the quaternion multiplication can be expressed as the sum of a vector cross and dot product plus the product of the scalar components.

So I implemented exactly that, which in theory should work, but then I discovered that if I take the cross product of two vectors that produce a zero vector and add a non-zero vector to it I still end up with a zero vector. At least using the vector math nodes that seems to be the case which is quite surprising. I was wondering if this was related to my computer and/or blender build so if you’re interested I can post the .blend file.

Besides that, this is brilliant. I was thinking along these lines and here there is a fantastic implementation of it. I’m hoping this can be implemented as a separate bsdf because that would be incredibly useful :smiley:

Thanks moony :wink:

@Microno… that sounds strange… and I doubt is a problem of your computer (post the file in pasteall and send me the link, so I can check)…

Anyway, I’ve changed the Vector rotation node, so now it doesn’t use Quaternions anymore (much simpler now!!). I think it only works with normalized vectors :confused:, but it’s all I need. :slight_smile: