[3Delight] Blender Material Shader Emulator

Hi All,

One of the immediate set backs to switching from Blender Internal to 3Delight or any Renderman based exporter is the immediate lack of the basics. All of a sudden it becomes a chore to get an image map to work…or to make specularity appear on a surface. All these things we take for granite are really just small pieces of code used to calculate the surface.

So I thought having a Renderman Shader that emulates Blender Internal would be nice thing for noobs or anyone who just wants to get a quick render out of 3Delight and not necessarily dig into shader writing.

This what I have so far…


/* 
    Blender Surface Shader.
    Version 1.0
    By Atom 09-12-2011
    
    An attempt at emulating the Blender material as a Renderman shader.
    The goal is to offer up at least one image slot 
    for each main aspect of shading that we take for granted as Blender users.
    
    Option Supported:
        DIFFUSE color.
        SPECULAR color.
        SPECULAR ROUGHNESS.
        DIFFUSE IMAGE MAP.
        ALPHA IMAGE MAP.
        SPECULAR IMAGE MAP.
        BUMP MAP.
        REFLECTION MAP.
        ROTATE TEXTURE BY 90 degree increments. (90,180,270,0)
 */
 
surface blender_surface (
    uniform float flip_S=0;
    uniform float flip_T=0;
    uniform float swap_ST=0;
    
    string diffuse_map_name = "";
    string alpha_map_name = "";
    uniform float diffuse_use_alpha = 1.0;
    uniform float diffuse_intensity = 0.81;
    
    string bump_map_name = "";
    uniform float bump_scale = 1;
 
    string reflection_ENV_map_name = "";
    uniform float reflection_intensity = 0.311;
   
    uniform float Ka = 0.5;
    uniform float Kd = 0.85;
    uniform float Ks = 1;
    uniform float roughness = 0.2;
    string specularity_map_name = "";
    color specular_color = color(1,1,1);
    uniform float specular_intensity = 0.311;
)

{
    // Offer up a simple way to roate image by 90 degrees via flipping s and t.
    float ss = s, tt = t;
    if (swap_ST == 1) {
        ss = t;
        tt = s;
    }
    if (flip_S == 1)
        ss = 1-ss;
    if (flip_T == 1)
        tt = 1-tt;

    // DIFFUSE.
    Ci = Oi * Cs;   // Default the diffuse color.
    Oi = Os;        // Default alpha. 
   
    // Begin analysis of what maps need to be included in our surface calculation.
    float result_type = 0;
    if (diffuse_map_name != "") {
        if (diffuse_use_alpha == 1)
            // Use the alpha from the diffuse map.
            result_type = 2;
        else
            result_type = 1;
    }
    
    if (alpha_map_name != "") {
        if (diffuse_map_name == "")
           result_type = 3;
        else
           result_type = 4;
    }
   
    // Generate the surface color and opacity based upon our result_type.
    color diffuse_color = color(0,0,0);
    color alpha_color = color(0,0,0);
    color specular_color = color(0,0,0);
    color reflection_color = color(0,0,0);
    
    if (result_type == 1) {
        // Diffuse map only, no Alpha implied.
        diffuse_color = diffuse_intensity * color texture(diffuse_map_name, ss, tt);
    }
    if (result_type == 2) {
        // Diffuse map with an alpha channel from the same diffuse map.
        color Ct = diffuse_intensity * color texture(diffuse_map_name,ss,tt);
        float a = float texture(diffuse_map_name[3],ss,tt);
        //Ci = Oi * (Cs + a*(Ct-Cs));
        diffuse_color = Cs + a * (Ct-Cs);
    }

    if (result_type == 3) {
        // Alpha map with no diffuse map supplied, just use diffuse color.
        // Deterimine if alpha map is 3 or 4 channels?
        // i.e. Do I nned to convert RGB intensity to Alpha or is the 4th channel available?
        float a = float texture(alpha_map_name[3],ss,tt);
        //Ci = Oi * (Cs + a);
        diffuse_color = Cs + a;
    }
    if (result_type ==4) {
        // Use the diffuse map for color and alpha map for alpha.
        color Ct = diffuse_intensity * color texture(diffuse_map_name,ss,tt);
        float a = float texture(alpha_map_name[3],ss,tt);
        //Ci = Oi * (Cs + a*(Ct-Cs));
        diffuse_color = Cs + a * (Ct-Cs);
    }

    // SPECULAR.
    if(specularity_map_name != "") {
        specular_color = specular_intensity * color texture(specularity_map_name, ss, tt);
    }

    // BUMP.
    normal Nf;
    vector V, D;
    point PP;
    float bmp;
    if( bump_map_name != "" ) {
        bmp = bump_scale * float texture( bump_map_name, ss, tt);
        PP = transform("shader", P);
        Nf = normalize( ntransform("shader", N) );
        PP += bmp * Nf;
        PP = transform("shader", "current", PP);
        Nf = calculatenormal(PP);

        /*
        if (abUseNormals == 1) {
            normal deltaN = normalize(N) - normalize(Ng);
            Nf = normalize(Nf) + deltaN;
        }

        if( abDoDisplacement == 1.0 )
            P = PP;
        */
    } else {
        Nf = N;
    }

    Nf = faceforward( normalize(Nf), I );
    V = -normalize(I);
    
    // REFLECTION.
    if( reflection_ENV_map_name != "" )
    {
        D = reflect(-V, Nf);
        D = vtransform("worldspace", D);
        /*
        if( abReflectionUp != 0 )
        {
            D = vector(-zcomp(D), xcomp(D), ycomp(D));
        }
        */
        reflection_color = reflection_intensity * color environment(reflection_ENV_map_name, D);
    }
    else
        reflection_color = color(0);

    // Final calculation.
    Ci = diffuse_color * (ambient() + diffuse(Nf)) + (specular_color * (specular(Nf, V, roughness) + reflection_color));
}

Here is the command I used to compile the above shader on Windows.

shaderdl.exe "blender_surface.sl"

Attachments


I started blender material -> sl shader code some time ago but didn’t have time to work on it. I used some diffuse and specular shaders from Advanced Renderman, the plan was to tweak them to look like blender’s. The plan was to look at the blender shading source some time… Here what I’ve got so far, it prints the code in the console. I think it compiles but with warnings.

import bpy
material = bpy.context.active_object.active_material
diffCall = ""
diffCol = material.diffuse_color
diffInt = material.diffuse_intensity
specCol = material.specular_color
specInt = material.specular_intensity
specHard = material.specular_hardness
header = "surface " + material.name + "("
shaderF = ""
diffVar = ""
#header
if material.use_shadeless == True:
    header += "color surface_color = ("
    header += str(diffCol[0])
    header += ","  
    header += str(diffCol[1])
    header += ","
    header += str(diffCol[2])
    header += ";"
    code = "{
"
    code += "	Oi = Os;
"
    code += "	Ci = Cs * Oi * surface_color;
"
    code += "}
"

else:
    if material.diffuse_shader == "LAMBERT":
        diffVar = "normal n = normalize(N);
"
        diffCall = "diffuse_light(n)"
        #shader arguments
        header += "color diffuse_color = ("   
        header += str(diffCol[0])
        header += ","  
        header += str(diffCol[1])
        header += ","
        header += str(diffCol[2])   
        header += ");" 
        header += " float diffuse_intensity = "  
        header += str(diffInt)   
        header += ";"
        #shader functions
        shaderF += "color diffuse_light(normal n)
"
        shaderF += "{
"
        shaderF += "	color C = 0;
"
        shaderF += "	illuminance(P, n, PI/2)
"
        shaderF += "	{
"
        shaderF += "		C += Cl * n.normalize(L);
"
        shaderF += "	}
"
        shaderF += "	return C;
"
        shaderF += "}
"
    elif material.diffuse_shader == "OREN_NAYAR":
        diffVar = "	normal n = normalize(N);
	vector V = - normalize(I);
"
        diffCall = "diffuse_light(n, V, roughness)"
        #shader arguments
        header += "color diffuse_color = ("   
        header += str(diffCol[0])
        header += ","  
        header += str(diffCol[1])
        header += ","
        header += str(diffCol[2])   
        header += ");" 
        header += " float diffuse_intensity = "  
        header += str(diffInt)   
        header += ";"
        header += " float roughness = "
        header += str(material.roughness)
        header += ";"
        #shader functions
        shaderF += "color diffuse_light(normal n; vector V; float roughness;)
"
        shaderF += "{
"
        shaderF += "	float sigma2 = roughness * roughness;
"
        shaderF += "	float A = 1 - 0.5 * sigma2/ (sigma2 + 0.33);
"
        shaderF += "	float B = 0.45 * sigma2/ (sigma2 + 0.09);
"
        shaderF += "	float theta_r = acos(V.N);
"
        shaderF += "	vector V_perp_N = normalize(V-N*(V.N));
"
        shaderF += "	color C = 0;
"
        shaderF += "	illuminance(P, N, PI/2)
"
        shaderF += "	{
"
        shaderF += "		vector LN = normalize(L);
"
        shaderF += "		float cos_theta_i = LN.N;
"
        shaderF += "		float cos_phi_diff = V_perp_N.normalize(LN - N * cos_theta_i);
"
        shaderF += "		float theta_i = acos(cos_theta_i);
"
        shaderF += "		float alpha = max(theta_i, theta_r);
"
        shaderF += "		float beta = min(theta_i, theta_r);
"
        shaderF += "		C += Cl * cos_theta_i * (A + B * max(0, cos_phi_diff) * sin(alpha) * tan(beta));
"
        shaderF += "	}
"
        shaderF += "	return C;
"
        shaderF += "}
"
    if material.specular_shader == "PHONG":
        #shader inputs
        header += " color specular_color = ("
        header += str(specCol[0]) + ","  + str(specCol[1]) + "," + str(specCol[2]) + ");" 
        header += " float specular_intensity = "
        header += str(material.specular_intensity)
        header += "; float roughness = "
        header += str(specHard)
        shaderF += "specular_light(float roughness, normal n, H)
" //blender have "hardness", needs investigation
        shaderF += "{
"
        shaderF += return pow(max(0, n.H), 1/roughness);

        shaderF += "}
"
    elif material.specular_shader == "BLINN":
        header += " color specular_color = ("
        header += str(specCol[0]) + ","  + str(specCol[1]) + "," + str(specCol[2]) + ");" 
        header += " float specular_intensity = "
        header += str(material.specular_intensity)
        header += "; float roughness = " //blender have hardness...
        header += str(specHard)
        shaderF += "float specularLight(float w, roughness; normal n, H)
"
        shaderF += "{
"
        shaderF += "return smoothstep(.72 - w, .72 + w, pow(max(0, n.H), 1/roughness));
" //.72 probably needs tweaking
        shaderF += "}
"
    #shader
        header += ")
"
    code = "{
"
    code += diffVar
    code += "	Oi = Os;
"
    code += "	Ci = Cs * Oi * diffuse_intensity * " + diffCall + " * diffuse_color;
"
    code += "}
"
print(shaderF)
print(header)
print(code)

Thanks for the contribution, I had not thought too much about specularity emulation. You code seems to cover that well.

I am still working on getting MAP to work the way I am used to in Blender Internal.
The thought is this…If you supply a diffuse map to the diffuse slot and the diffuse map contains an alpha channel it will automatically assume that you want to make use of that alpha channel. But if you supply another image to the alpha slot you override that assumption. and the alpha is calculated based upon whether the alpha map supplied is RGB or RGBA. If the map is RGB the alpha will be calculated based upon luminosity. If RGBA the fourth channnel will be used as the alpha. If an alpha map is supplied and no diffuse map is supplied you should see the silhouette of the alpha in the diffuse color modified by diffuse intensity.


/* 
    Blender Surface Shader.
    Version 1.0
    By Atom 09-12-2011
    
    An attempt at emulating the Blender material as a Renderman shader.
    The goal is to offer up at least one image slot 
    for each main aspect of shading that we take for granted as Blender users.
    
    Option Supported:
        DIFFUSE color.
        SPECULAR color.
        SPECULAR ROUGHNESS.
        DIFFUSE IMAGE MAP.
        ALPHA IMAGE MAP.
        SPECULAR IMAGE MAP.
        BUMP MAP.
        REFLECTION MAP.
        ROTATE TEXTURE BY 90 degree increments. (90,180,270,0)
 */

// From 3Delight developer Oliver on public forum.
// http://www.3delight.com/en/modules/PunBB/viewtopic.php?id=3053
float luminance( color i_color ) {
        return
                0.3 * comp(i_color, 0) + 
                0.59 * comp(i_color, 1) + 
                0.11 * comp(i_color, 2);
}

// Begin Shader.
surface blender_surface (
    uniform float flip_S=0;
    uniform float flip_T=0;
    uniform float swap_ST=0;
    
    string diffuse_map_name = "";
    string alpha_map_name = "";
    uniform float diffuse_use_alpha = 1.0;
    uniform float diffuse_intensity = 0.81;
    
    string bump_map_name = "";
    uniform float bump_scale = 1;
 
    string reflection_ENV_map_name = "";
    uniform float reflection_intensity = 0.311;
   
    uniform float Ka = 0.5;
    uniform float Kd = 0.85;
    uniform float Ks = 1;
    uniform float roughness = 0.2;
    string specularity_map_name = "";
    color specular_color = color(1,1,1);
    uniform float specular_intensity = 0.311;
)

{
    // Offer up a simple way to roate image by 90 degrees via flipping s and t.
    float ss = s, tt = t;
    if (swap_ST == 1) {
        ss = t;
        tt = s;
    }
    if (flip_S == 1)
        ss = 1-ss;
    if (flip_T == 1)
        tt = 1-tt;

    // DIFFUSE.
    float a = float luminance(color(0,0,0));
    color Ct = diffuse_intensity * Cs;
    Ci = Oi * Ct;   // Default the diffuse color.
    Oi = Os;        // Default alpha. 
   
    // Begin analysis of what maps need to be included in our surface calculation.
    uniform float result_type = 0;
    uniform float diffuse_channel_count = 0;
    uniform float alpha_channel_count = 0;
    if (diffuse_map_name != "") {
        textureinfo ( diffuse_map_name, "channels" , diffuse_channel_count);   // Fetch information about how many channels are in this map.
        if (diffuse_channel_count == 4)
            // Use the alpha from the diffuse map.
            result_type = 2;
        else
            result_type = 1;
    }
    
    if (alpha_map_name != "") {
        textureinfo ( alpha_map_name, "channels" , alpha_channel_count);   // Fetch information about how many channels are in this map.
        if (diffuse_map_name == "")
           result_type = 3;
        else
           result_type = 4;
    }
   
    // Generate the surface color and opacity based upon our result_type.
    color diffuse_color = color(0,0,0);
    color alpha_color = color(0,0,0);
    color specular_color = color(0,0,0);
    color reflection_color = color(0,0,0);
    
    if (result_type == 1) {
        // Diffuse map only, no Alpha implied.
        Ct = diffuse_intensity * color texture(diffuse_map_name, ss, tt);
        a = 1.0;
    }
    if (result_type == 2) {
        // Diffuse map with an alpha channel from the same diffuse map.
        Ct = diffuse_intensity * color texture(diffuse_map_name,ss,tt);
        a = float texture(diffuse_map_name[3],ss,tt);
    }

    if (result_type == 3) {
        // Alpha map with no diffuse map supplied, just use diffuse color.
        //color Ct = diffuse_intensity * Cs;
        if (alpha_channel_count == 4)
            a = float texture(alpha_map_name[3],ss,tt);
        else
            a = float luminance(color texture(alpha_map_name,ss,tt));
    }
    if (result_type ==4) {
        // Use the diffuse map for color and alpha map for alpha.
        Ct = diffuse_intensity * color texture(diffuse_map_name,ss,tt);
        if (alpha_channel_count == 4)
            a = float texture(alpha_map_name[3],ss,tt);
        else
            a = float luminance(color texture(alpha_map_name,ss,tt));
    }
    Ci = Oi * (Cs + a*(Ct-Cs));
}

In this image the panel is in the diffuse slot and a torn image is in the alpha slot. The diffuse color is pink.

The next step is to make the pink part truly transparent so the light can cast the correct shadow. Any tips on how to achieve this?

Attachments



I have the diffuse, alpha and bump slots working now.

These images show some of the possible combinations from using three different maps while mixing in a diffuse color.


/* 
    Blender Surface Shader.
    Version 1.0
    By Atom 09-12-2011
    Update 09-17-2011
    
    An attempt at emulating the Blender material as a Renderman shader.
    The goal is to offer up at least one image slot 
    for each main aspect of shading that we take for granted as Blender users.
    
    Option Supported:
        DIFFUSE color.
        SPECULAR color.
        SPECULAR ROUGHNESS.
        DIFFUSE IMAGE MAP.
        ALPHA IMAGE MAP.
        SPECULAR IMAGE MAP.
        BUMP MAP.
        REFLECTION MAP.
        ROTATE TEXTURE BY 90 degree increments. (90,180,270,0)
 */

// From 3Delight developer Oliver on public forum.
// http://www.3delight.com/en/modules/PunBB/viewtopic.php?id=3053
float luminance( color i_color ) {
        return
                0.3 * comp(i_color, 0) + 
                0.59 * comp(i_color, 1) + 
                0.11 * comp(i_color, 2);
}
float intensity (color i_color) {
    return
        (comp(i_color, 0)+
        comp(i_color, 1)+
        comp(i_color, 2))/3;
}

// A way of relaying a parameter description to the host application
#pragma annotation flip_S "gadgettype=floatfield;label=Mirror Y;hint=Set to 1.0 to flip image verticaly."
#pragma annotation flip_T "gadgettype=floatfield;label=Mirror X;hint=Set to 1.0 to flip image horizontaly."
#pragma annotation swap_ST "gadgettype=floatfield;label=Swap XY;hint=Set to 1.0 to rotate image 90 degrees."

#pragma annotation diffuse_map_name "gadgettype=inputfile;label=Diffuse Map;hint=Filename of image map."
#pragma annotation diffuse_intensity "gadgettype=floatfield;label=Difuse Intensity;hint=Use to mix color of diffuse chit with color in image map."

##pragma annotation alpha_map_name "gadgettype=inputfile;label=Alpha Map;hint=Filename of image map."

#pragma annotation specularity_map_name "gadgettype=inputfile;label=Specular Map;hint=Filename of image map."
#pragma annotation specular_intensity "gadgettype=floatfield;label=Specular Intensity;hint=Use to mix color of diffuse chit with color in image map."
#pragma annotation specular_color "gadgettype=floatfield;label=Specular Color;hint=Colour for specular highlights."

#pragma annotation bump_map_name "gadgettype=inputfile;label=Bump Map;hint=Filename of image map."
#pragma annotation bump_scale "gadgettype=floatfield;label=Bump Size;hint=Use to set amount of bump map influence."

#pragma annotation reflection_ENV_map_name "gadgettype=inputfile;label=Reflection Map;hint=Filename of image map."
#pragma annotation reflection_intensity "gadgettype=floatfield;label=Reflection Intensity;hint=Use to mix color of diffuse chit with color in image map."


// Begin Shader.
surface blender_surface (
    uniform float flip_T=0;
    uniform float flip_S=0;
    uniform float swap_ST=0;
    
    string diffuse_map_name = "";
    uniform float diffuse_intensity = 0.81;
    
    string alpha_map_name = "";

    string specularity_map_name = "";
    color specular_color = color(1,1,1);
    uniform float specular_intensity = 0.311;
    uniform float roughness = 0.2;

    string bump_map_name = "";
    uniform float bump_scale = 1;
 
    string reflection_ENV_map_name = "";
    uniform float reflection_intensity = 0.311;
    
    /*   
    uniform float Ka = 0.5;
    uniform float Kd = 0.85;
    uniform float Ks = 1;
    */
)

{
    // Offer up a simple way to roate image by 90 degrees via flipping s and t.
    float ss = s, tt = t;
    if (swap_ST == 1) {
        ss = t;
        tt = s;
    }
    if (flip_S == 1)
        ss = 1-ss;
    if (flip_T == 1)
        tt = 1-tt;

    // DIFFUSE.
    float a = float intensity(color(1,1,1));
    Oi = a;                                 // Default alpha. 
    color Ct = diffuse_intensity * Cs;    // Calculate initial color modified by intensity.
    //normal Nn = normalize(N);
    //color Ct = diffuse(Nn);
    Ci = Oi * Ct;                           // Default the diffuse color.
   
    // Begin analysis of what maps need to be included in our surface calculation.
    uniform float result_type = 0;
    uniform float diffuse_channel_count = 0;
    uniform float alpha_channel_count = 0;
    if (diffuse_map_name != "") {
        textureinfo ( diffuse_map_name, "channels" , diffuse_channel_count);   // Fetch information about how many channels are in this map.
        if (diffuse_channel_count == 4)
            // Use the alpha from the diffuse map.
            result_type = 2;
        else
            result_type = 1;
    }
    
    if (alpha_map_name != "") {
        textureinfo ( alpha_map_name, "channels" , alpha_channel_count);   // Fetch information about how many channels are in this map.
        if (diffuse_map_name == "")
           result_type = 3;
        else
           result_type = 4;
    }
   
    // Generate the surface color and opacity based upon our result_type.
    color diffuse_color = color(0,0,0);
    color alpha_color = color(0,0,0);
    color specular_color = color(0,0,0);
    color reflection_color = color(0,0,0);
    
    // Special case processing based upon result_type.
    if (result_type == 1) {
        // Diffuse map only, no Alpha implied.
        Ct = Ct + diffuse_intensity * color texture(diffuse_map_name, ss, tt);
        a = 1.0;
        Oi = a;
    }
    if (result_type == 2) {
        // Diffuse map with an alpha channel from the same diffuse map.
        Ct = Ct + diffuse_intensity * color texture(diffuse_map_name,ss,tt);
        a = float texture(diffuse_map_name[3],ss,tt);
        Oi = a;
    }
    if (result_type == 3) {
        // Alpha map with no diffuse map supplied, just use diffuse color.
        // No need to calculate diffuse, just use initial default from above.
    }
    if (result_type ==4) {
        // Use the diffuse map for color and alpha map for alpha.
        Ct = Ct + diffuse_intensity * color texture(diffuse_map_name,ss,tt);
    }
    diffuse_color = Ct;
    
    // Final alpha decision is based upon the channel count of the alpha map.
    if ((result_type == 3) || (result_type ==4)) {
        // Some kind of map was supplied for the alpha.
        //Determine how to calculate the alpha.
        if (alpha_channel_count == 1)
            a *= float texture(alpha_map_name[0],ss,tt);
        else if (alpha_channel_count == 3)
            a *= luminance( texture(alpha_map_name,ss,tt) );
        else if (alpha_channel_count >= 4)
            a *= float texture(alpha_map_name[3],ss,tt);
        Oi = a;    
    }
    
    
    //Ci = Oi * (Ct + a*(Ct-Cs));


    // SPECULAR.
    if(specularity_map_name != "") {
        specular_color = specular_intensity * color texture(specularity_map_name, ss, tt);
    }

    // BUMP.
    normal Nf;
    vector V, D;
    point PP;
    float bmp;
    if( bump_map_name != "" ) {
        bmp = bump_scale * float texture( bump_map_name, ss, tt);
        PP = transform("shader", P);
        Nf = normalize( ntransform("shader", N) );
        PP += bmp * Nf;
        PP = transform("shader", "current", PP);
        Nf = calculatenormal(PP);
    } else {
        Nf = N;
    }

    Nf = faceforward( normalize(Nf), I );
    V = -normalize(I);
    
    // REFLECTION.
    if( reflection_ENV_map_name != "" )
    {
        D = reflect(-V, Nf);
        D = vtransform("worldspace", D);
        reflection_color = reflection_intensity * color environment(reflection_ENV_map_name, D);
    }
    else
        reflection_color = color(0);

    // Final calculation.
    //Ci = Oi * Ct;
    Ci = Oi * diffuse_color * (ambient() + diffuse(Nf)) + (specular_color * (specular(Nf, V, roughness) + reflection_color));


}

The specular and reflection stuff is pretty much untested at this point. That is next is on the list.

Attachments




Made some more progress, but I have run into a problem with calculating specularity.
Mainly, how do I factor in the alpha map?
Also, notice that my specularity calculation seems to use facted normals. Is there a way to avoid this as well and just use the state of the normals in the mesh?

Attachments


Atom, to factor in teh opacity for specular you must multiply the specular lighting by the opacity… Also for the reflection …

change this:



  Ci = Oi * diffuse_color * (ambient() + diffuse(Nf)) + Oi* (specular_color * (specular(Nf, V, roughness) + Oi * reflection_color));

Obviously glass etc will want spec and reflection opaque so your original is best for that.

@MichaelW: Thank you very much, that worked like like a charm! I have been fussing with variations for Ci all day. Then I popped your code in and it worked.


I have added diffuse tinting and halftoning as well.

This shaders source code is officially too big to post as text so I am attaching it in a text document of this BLEND file.

Attachments

25_blender_surface_code.blend (421 KB)

I made a little more progress on reflection. In this image all meshes have the same material type applied (the blender_surface), the leaves have an environment map assigned to the reflection slot. The floor, has the same material, but with the environment slot empty, the shader calculates reflection from the scene instead of the map. I think I can add a Glossiness fader into the mix as well. Like we are already used to in Blender Internal.

Attachments


25_blender_surface_code.blend (425 KB)

I was going to do one of these too.

Personally I never liked teh blender way of handling alpha channels for controlling all parameters and being forced to use the “rgb to alpha” checkbox,…
I do like that each “map” has an “influence” slider in blender though. It’d solve your specular problem by just adding the alpha texture to the specular intesnsity map and would be more flexible for glass etc…

Atom, i hope you don’t mind me posting in this thread here, but I think it might be useful for your blender shader.

I have a “fresnel” shader that replicates the reflections setups I used to make with nodes in blender internal and blender’s built in raytrace functionality.

I’m not completely sure I got the “eta” setting right, but at 0 you get a full reflection and 1 is completely diffuse with values in between giving a fresnel “rolloff”.

the reflections can be environment mapped (add an environment texture), raytraced (turn on teh raytracing checkbox) or both (do both) where the stuff that gets reflected is composited over the environment map reflection.

I love being able to “over crank” the specular.

Anyway, here’s the listing:


/******************************************************************************/
/*                                                                            */
/*      mike's fresnel shader                                                 */
/*                                                                            */
/*                                                                            */
/******************************************************************************/

#pragma annotation raytrace "gadgettype=checkbox; label=Raytrace;hint=enable Raytraced reflections"


color SampleEnvironment(
    point P;  vector R;  float blur, raysamples;  string envname;)
{
   /* First trace a ray and then composite the environment on top if
      the transmission != 0 */
    color transmission;
    color ray = trace( P, R,
        "samples", raysamples,
        "samplecone", blur,
        "transmission", transmission );

    if( transmission == 0 || envname == "" )
        return ray;

    /* NOTE: should apply correct blur here */
    color env = environment(envname, vtransform("world",R),"blur", blur
     );
    return ray + transmission * env;
}




surface 
fresnel(
    float Ka = 1;
    float Kd = .1;
    string texturename = ""; 



    color specularcolor = 1;
    float Ks = 1;
    string spec_int_map ="";
    float roughness = .2; 



    string envname = "";
    color envcolor = 1;
    float eta = 1.3;
    float Kenv =1;
    float blur =0;
    float raytrace = 0;
    float samples = 1;

    )
    
    
    
{
    normal Nf;
    vector V;
    vector rRay;
    color Ct;
    color env = 0;
    float Kr,Kt,Si = 0;
    
    Nf = faceforward(normalize(N), I);
    V = normalize(-I);
    rRay =  -1 * reflect(V,Nf);
    
    Ct = ( texturename != "" ) ?
        texture( texturename, "filter", "gaussian" ) : 1.0;

    Si = ( spec_int_map != "" ) ?
        float texture( spec_int_map, "filter", "gaussian" ) : 1.0;

    /* environment  */
    if (raytrace <0.5)          /* just envmap */
        {
        env =( envname != "" ) ?
            environment( envname, vtransform("world",rRay),"blur", blur) : 1.0;
        }
    else
        {
        env = SampleEnvironment(P, rRay, blur, samples, envname);
        }


    fresnel(I,N,eta, Kr,Kt);


    Oi = Os;
    Ci = (Cs * Ct * (Ka * ambient() + Kt * Kd * diffuse(Nf)) 
        + Si * specularcolor * Ks * specular(Nf, V, roughness) 
        + Kr * envcolor * env * Kenv);

    Ci *= Oi;
}


And of course some examples:
note the raytracing picking up the “bounce cards” They heve been set on teh “object” tab not to cast shadows and I would normally also exclude them from the camera view there… It’s a great lighting tool!

NB, this is just the shader with local illumination, no photons or point based GI used.

http://www.cowtoolsmedia.co.uk/assets/sphere.jpg

and here it’s used as a basic car paint shader… though I’m currently modifying it more for that purpose (flecks, damage, dirt etc)
NB I use a bluish “bounce card” to tweak the reflection on teh far side of the car here. (still a wip!)

http://www.cowtoolsmedia.co.uk/assets/carfresnel.jpg

Mike, your renders are the most impresssive 3delight renders I ve seen in this forum. That’s great, I hope Aqsis 2.0 will reach this level and be a real alternative to BI.
Atom, your code seems to be cool, but right know, I m searching a good shader which allow me to use SSS + diffuse-spec-bump-displace map. just like the blender way.
I have tested the simple_ss (in the shader folder of 3delight by default), it’s works, but I can’t add a diffuse and spec map. Would be grat to do this for code allergenic like me :wink:

kala_ndo, thanks!

It wouldn’t be too hard to do what you’re after using raytraced SSS… I may have a look when I get time.

Ideally you’d want the option to use a pointcloud for 2pass SSS… THAT will need looking into further!

I’m trying to find some docs for the rib syntax for creating environment maps… to do a hack for point (omni) light shadow maps and of course more accurate environment maps for individual objects…

Hi,

Could I ask anyone what their feelings are regarding Vray or 3Delight as a BI alternative? I’m looking for a fast good quality renderer (that won’t break the bank) but don’t have tonnes of time to invest learning yet another workflow. I’m not interested in an unbiased solution since I’ll be using for motion graphics/design.

Any suggestions?

Yp

A bit off topic !
Vray is excellent and works in a familiar way with the blender integration.
It’s missing a couple of nodes so you can’t do all you could with max

It comes with 12 rendernodes so although commercial is very low cost when the standalone is around 350euros…
it’s very good at fast gi.

If you can get by with the shader examples that come with 3 delight (and the blender material Atom is writing here) then the learning curve is fine with Matt ebbs exporter and 3delight.

The free version of 3delight only allows 2cores for rendering… a.d then you have to licence on a per machine basis…$600 for 4 cores or $1000 for a multicore system… gets pricey quickly!

Aqsis and pixie both support less than 3delight… so its a more expensive option with a steep learning curve… choose renderman for fast motion blur, Dof and hugely detailed displacements… gi and raytracing gets expensive… so instead you end up managing environment maps and pointclouds for fast approximation…

Only you know what you need, so try the demos…
It takes time and experimentation anyway, so you’ll quickly get an idea about learning curve.

I thought so to, but figured it’s better to ask this question to people that are going through the same process as well.

thanks! that was very helpful.

For GI, Occlusion, SSS and raytracing, point clouds are very useful. Once they have been generated you can reuse them, like shadow maps.

Thank you!

@MichaelW: I compiled your fresnel shader and it works. But I am not sure how to use it? For instance, I have a specular map (I converted using tmake) and I type the name in the spec_int_map field but I don’t get the results like your sphere. (Yes I have my map path set). I have unwrapped my sphere using spherical projection.

How did you get that bumpy shine?

Attachments


Atom, I had the roughness at 0.2 which enlarges the size of the specular highlight, and i overcranked Ks to “2”… as I was just using the colour map as a specular map (declaring float texture rather than colour texture automatically converts it to the “value” of teh rgb texture map)

Because the texture is sort of a mid grey on average it would halve the specular amount (as I just multiply in the shader) which is why cranking the specular Ks higher than 1 is safe and desirable! I used to do that all the time in Lightwave back in teh day!

My Kd is lowered to around 0.1… hardly any so that I get mostly specular.

I have a “fill” spot light cranked right up to “50” from left of and behind the camera and The “key light” is a sun set at 1 intensity shining in from over the right shoulder of the cameraman

eta was set at 0.7 so we just get the base “plastic” specular and diffuse for facing stuff.

I also over-cranked Kenv!

i used a modified “bumpy” displacement shader for the bumps (modified to have a user defined mid value so that it can displace both in and out). Whilst it’s called “bumpy” it’s actually a true displacement.

(declaring float texture rather than colour texture automatically converts it to the “value” of teh rgb texture map)
So if I use this method of fetching from a texture…

Ct = color texture(diffuse_map_name, ss,tt);

I get the RGB or RGBA color from the map.

If I use this method…

Ct = float texture(diffuse_map_name, ss, tt);

I get the value (V from HSV) from the map.

If I use this method…

a = float texture(diffuse_map_name[3], ss, tt);

I can get any channels value (V from HSV) by altering the array index, in this case for alpha. Assuming the provided map is an actual RGBA map.

So extracting H or S can be achieved by passing the color value to a function that returns such a value.

I am having some problems as this Blender Surface shader grows in size and complexity.

So I have taken a step back to try and solidify basic features. This is a dual map shader I am calling image. It allows you to supply a diffuse map and an alpha map. You can also fade the entire image out via the main Alpha slider of the material. It has the image mirror/flip code from the above shader.


/* 
    An image shader.
    Version 1.0
    By Atom 09-23-2011
    
    Option Supported:
        DIFFUSE color.
        ALPHA IMAGE MAP.
 */
 
 
// luminance from 3Delight developer Oliver on public forum.
// http://www.3delight.com/en/modules/PunBB/viewtopic.php?id=3053
float luminance( color i_color ) {
        return
                0.3 * comp(i_color, 0) + 
                0.59 * comp(i_color, 1) + 
                0.11 * comp(i_color, 2);
}

#pragma annotation flip_S "gadgettype=floatfield;label=Mirror Y;hint=Set to 1.0 to flip image verticaly."
#pragma annotation flip_T "gadgettype=floatfield;label=Mirror X;hint=Set to 1.0 to flip image horizontaly."
#pragma annotation swap_ST "gadgettype=floatfield;label=Swap XY;hint=Set to 1.0 to rotate image 90 degrees."

#pragma annotation Ka "gadgettype=floatfield;label=Ambient;hint=Multiplier for ambient contribution."
#pragma annotation Kd "gadgettype=floatfield;label=Diffuse;hint=Multiplier for diffuse contribution. Increase to contribute emission to Point Cloud."

// Begin Shader.
surface image (
    uniform float flip_T=0;
    uniform float flip_S=0;
    uniform float swap_ST=0;
    
    uniform float Ka = 1;
    uniform float Kd = 1;
    
    string diffuse_map_name = "";
    string alpha_map_name = "";
)

{
    // Define variables here.
    color Ct = Cs;
    float alpha_channel_count = 0;
    float a = 0;
    
    // Offer up a simple way to roate image by 90 degrees via flipping s and t.
    float ss = s, tt = t;
    if (swap_ST == 1) {
        ss = t;
        tt = s;
    }
    if (flip_S == 1)
        ss = 1-ss;
    if (flip_T == 1)
        tt = 1-tt;
    
    // DIFFUSE.
    if (diffuse_map_name != "")
        Ct = color texture(diffuse_map_name,ss,tt);
    else
        Ct = Cs;
        
    // Final alpha decision is based upon the channel count of the alpha map.
    if (alpha_map_name != "") {
        // Some kind of map was supplied for the alpha.
        a = luminance( texture(alpha_map_name,ss,tt) );
        Oi = a * Os;    
    } else {
        Oi = Os;
    }

    // Final calculation.
    normal Nf;

    Nf = faceforward( normalize(N), I );
    Ci = Oi * Ct * (Ka * ambient() + Kd * diffuse(Nf));

}

Attachments