Warning, this page is outdated!

This page is about shader technical implementation in Blender, if you need to know a bit of theory perhaps you must search in the net about "illumination models" or "Bidireccional Reflectance Distribution Function (BDRF)" for example.

 

Make shaders for Blender is very easy. This tutorial will show you where and what to edit by adding the new illuminations models.

 

For this document we will use the Lommel-Seeligel illumination model by its simplicity. This illumination model is very similar to lambert illumination model, in fact is very easy to simulate with this last one, but for the intention of this tutorial is enough.

With this shader we can make dusty surfaces, but like this is a tutorial and it is not a real implementation we go to put the things more difficult. We will multiply the illumination model by a exponential elevate to a "k" factor, which will be in a [-2,2] range.

Files to edit

Good, we go to the cuestion. More or less you will need to modify 9 files to make your shader:

  • blender/source/blender/blenkernel/bad_level_call_stubs/stubs.c
  • blender/source/blender/blenkernel/intern/displist.c
  • blender/source/blender/blenkernel/intern/material.c
  • blender/source/blender/blenloader/intern/readfile.c
  • blender/source/blender/makesdna/DNA_material_types.h
  • blender/source/blender/render/extern/include/render.h
  • blender/source/blender/render/intern/source/rendercore.c
  • blender/source/blender/src/buttons_shading.c
  • blender/source/blender/src/previewrender.c

We will analyze every file to understand better the procedure.

1. rendercore.c :

This is the most important file due to that is where they are defined the illumination models. Therefore, here is where we need to add our Lommel-Seeliger illumination model function.

 

<ccode>

/* Lommel-Seeliger diffuse */

float LommSeel_Diff(float *n, float *l, float *v, float k)

{

  float nl, nv, i;

 

  /* dot product between surface normal and light vector */

  nl = n[0]*l[0] + n[1]*l[1] + n[2]*l[2];

  if (nl <= 0.0)

    return 0.0;

 

  /* dot product between surface normal and view vector */

  nv = n[0]*v[0] + n[1]*v[1] + n[2]*v[2];

  if (nv < 0.0)

    nv = 0.0;

 

  /* The illumination model */

  i = (nl / (nl + nv)) * exp(k);

 

  return i;

}

</ccode>

 

This part isn't as easy like I put here. If you want to make a good shader you will have to work hard for it. Perhaps you need to consult the source code of many shaders avalaible in the net.

 

One time we have done our function, the next step will be to use it in many places. In this file, in the function "void shade_lamp_loop(ShadeInput *shi, ShadeResult *shr)" we add in:

 

<ccode>

/* diffuse shaders (oren nayer gets inp from area light) */

if(ma->diff_shader==MA_DIFF_ORENNAYAR)

  is= OrenNayar_Diff_i(inp, vn, lv, view, ma->roughness);

else if(ma->diff_shader==MA_DIFF_TOON)

  is= Toon_Diff(vn, lv, view, ma->param[0], ma->param[1]);

else if(ma->diff_shader==MA_DIFF_MINNAERT)

  is= Minnaert_Diff(inp, vn, view, ma->darkness);

else if(ma->diff_shader==MA_DIFF_LOMMSEEL)

  is= LommSeel_Diff(vn, lv , view, ma->k);

else

  is= inp; // Lambert

</ccode>

2. DNA_material_types.h

Like we can see in the previous file, we need a new variable 'k' and a define 'MA_DIFF_LOMMSEEL'. This part is made in this file.

 

In first place we add the variable:

<ccode>/* shaders */

short diff_shader, spec_shader;

float roughness, refrac;

float param[4]; /* size, smooth, size, smooth, for toonshader */

float rms;

float darkness;

float k,pad8; /* <---------- Our new variables */

short texco, mapto;

</ccode>

and after the define:

<ccode>/* diff_shader */

#define MA_DIFF_LAMBERT 0

#define MA_DIFF_ORENNAYAR 1

#define MA_DIFF_TOON 2

#define MA_DIFF_MINNAERT 3

#define MA_DIFF_LOMMSEEL 4 /* <------- Our new define */

</ccode>

If you don't know why is used a 'pad' variable maybe you have to read this:

www.blender3d.org/cms/Notes_on_SDNA.436.0.html

3. render.h

To can use our new function in many places we need add it in the render.h include:

<ccode>/* ---------------------------------------------------------*/

/* rendercore (13) */

/* ---------------------------------------------------------*/

float Phong_Spec(float *n, float *l, float *v, int hard);

................

................

float Minnaert_Diff( float nl, float *n, float *v, float darkness);

float LommSeel_Diff(float *n, float *l, float *v, float k);

................

................

</ccode>

One time we have defined our illumination model and we can use it from many places, we are going to start to integrate it in Blender.

4. buttons_shading.c

In this file we add the graphical interface to access to the shader. We need add two things:

- The LommSeel item to the diffuse shader list:

- The 'k' slider:

This can be done as follow:

<ccode>

char *str1= "Diffuse Shader%t|Lambert %x0|Oren-Nayar %x1|Toon %x2|

  Minnaert %x3|LommSeel %x4"; /* <----- List new model*/

char *str2= "Specular Shader%t|CookTorr %x0|Phong %x1|Blinn %x2|

  Toon %x3|WardIso %x4";

 

/* diff shader buttons */

uiDefButS(block, MENU, B_MATPRV_DRAW, str1, 9, 180,78,19,

  &(ma->diff_shader), 0.0, 0.0, 0, 0, "Creates a diffuse shader");

.....................

.....................

.....................

else if(ma->diff_shader==MA_DIFF_MINNAERT)

  uiDefButF(block, NUMSLI, B_MATPRV, "Dark:",90,160, 150,19,

    &(ma->darkness), 0.0, 2.0, 0, 0, "Sets Minnaert darkness");

else if(ma->diff_shader==MA_DIFF_LOMMSEEL)

  uiDefButF(block, NUMSLI, B_MATPRV, "K:",90,160, 150,19, &(ma->k),

    -2.0, 2.0, 0, 0, "Sets k factor");

uiBlockEndAlign(block);

</ccode>

5. material.c

Now we have a new 'k' parameter but we can't put it a default value. This is done in this file as follow:

<ccode>

void init_material(Material *ma)

{

......................

......................

  ma->rms=0.1;

  ma->darkness=1.0;

  ma->k=0.1; /* <---------- init new shader var */

.....................

.....................

}

</ccode>

6. readfile.c

To can use our Blend file saved with the new shader (with the parameter modified) without problems we have to put this:

<ccode>

if(main->versionfile <= 236) { /* A minor version than you are */

.....................

.....................

  // init new shader var

  for (ma= main->mat.first; ma; ma= ma->id.next) {

    ma->k=0.1;

  }

....................

....................

}

</ccode>

7. previewrender.c

To can see the new shader in the preview material windows we have to add the illumination function to this file:

<ccode>static void shade_preview_pixel(ShadeInput *shi, float *vec, int x,

  int y,char *rect, int smooth){

....................

....................

....................

/* diffuse shaders */

if(mat->diff_shader==MA_DIFF_ORENNAYAR)

  is=OrenNayar_Diff(shi->vn, lv, shi->view, mat->roughness);

else if(mat->diff_shader==MA_DIFF_TOON)

  is=Toon_Diff(shi->vn, lv, shi->view, mat->param[0], mat->param[1]);

else if(mat->diff_shader==MA_DIFF_MINNAERT)

  is=Minnaert_Diff(is, shi->vn, shi->view, mat->darkness);

else if(mat->diff_shader==MA_DIFF_LOMMSEEL)

  is=LommSeel_Diff(shi->vn, lv, shi->view, mat->k);

// else Lambert

inp= (shi->refl*is + shi->emit);

</ccode>

8. displist.c

This file is the one responsible to render the new shader in the 3d window as well. We need to add this in the next function:

<ccode>

static void fastshade(float *co, float *nor, float *orco,

  Material *ma, char *col1, char *col2, char *vertcol){

...................

...................

..................

if(fl->mode & LA_NO_DIFF) is= 0.0;

else {

  is= nor[0]*lv[0]+ nor[1]*lv[1]+ nor[2]*lv[2];

  if(ma->diff_shader==MA_DIFF_ORENNAYAR)

    is= OrenNayar_Diff(nor, lv, shi.view, ma->roughness);

  else if(ma->diff_shader==MA_DIFF_TOON)

    is= Toon_Diff(nor, lv, shi.view, ma->param[0], ma->param[1]);

  else if(ma->diff_shader==MA_DIFF_MINNAERT)

    is= Minnaert_Diff(is, nor, shi.view, ma->darkness);

  else if(ma->diff_shader==MA_DIFF_LOMMSEEL)

    is= LommSeel_Diff(nor, lv, shi.view, ma->k);

}</ccode>

9. stubs.c

To resolve linking of a stand-alone Blender Player (game engine), we need add to this file the following:

<ccode>

/* displist.c */

#include "DNA_world_types.h" /* for render_types */

#include "render_types.h"

....................

....................

float Minnaert_Diff(float nl, float *n, float *v, float a){return 0;}

float LommSeel_Diff(float *n, float *l, float *v, float k){return 0;}

...................

...................

</ccode>

Now we can compile, run blender, set the new shader and F12!!!