Blender  V2.59
SHD_material.c
Go to the documentation of this file.
00001 /*
00002  * $Id: SHD_material.c 38268 2011-07-09 19:16:32Z campbellbarton $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2005 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): none yet.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include "../SHD_util.h"
00036 
00037 /* **************** MATERIAL ******************** */
00038 
00039 static bNodeSocketType sh_node_material_in[]= {
00040         {       SOCK_RGBA, 1, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00041         {       SOCK_RGBA, 1, "Spec",           0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00042         {       SOCK_VALUE, 1, "Refl",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00043         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
00044         {       -1, 0, ""       }
00045 };
00046 
00047 static bNodeSocketType sh_node_material_out[]= {
00048         {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00049         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
00050         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
00051         {       -1, 0, ""       }
00052 };
00053 
00054 /* **************** EXTENDED MATERIAL ******************** */
00055 
00056 static bNodeSocketType sh_node_material_ext_in[]= {
00057         {       SOCK_RGBA, 1, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00058         {       SOCK_RGBA, 1, "Spec",           0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00059         {       SOCK_VALUE, 1, "Refl",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00060         {       SOCK_VECTOR, 1, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
00061         {       SOCK_RGBA, 1, "Mirror",         0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00062         {       SOCK_VALUE, 1, "Ambient",       0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00063         {       SOCK_VALUE, 1, "Emit",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00064         {       SOCK_VALUE, 1, "SpecTra",       0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00065         {       SOCK_VALUE, 1, "Ray Mirror",    0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
00066         {       SOCK_VALUE, 1, "Alpha",         0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00067         {       SOCK_VALUE, 1, "Translucency",  0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00068         {       -1, 0, ""       }
00069 };
00070 
00071 static bNodeSocketType sh_node_material_ext_out[]= {
00072         {       SOCK_RGBA, 0, "Color",          0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00073         {       SOCK_VALUE, 0, "Alpha",         1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f},
00074         {       SOCK_VECTOR, 0, "Normal",       0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f},
00075         {       SOCK_RGBA, 0, "Diffuse",                0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00076         {       SOCK_RGBA, 0, "Spec",           0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00077         {       SOCK_RGBA, 0, "AO",             0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f},
00078         {       -1, 0, ""       }
00079 };
00080 
00081 static void node_shader_exec_material(void *data, bNode *node, bNodeStack **in, bNodeStack **out)
00082 {
00083         if(data && node->id) {
00084                 ShadeResult shrnode;
00085                 ShadeInput *shi;
00086                 ShaderCallData *shcd= data;
00087                 float col[4];
00088                 bNodeSocket *sock;
00089                 char hasinput[NUM_MAT_IN]= {'\0'};
00090                 int i;
00091                 
00092                 /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
00093                  * the constant input stack values (e.g. in case material node is inside a group).
00094                  * we just want to know if a node input uses external data or the material setting.
00095                  * this is an ugly hack, but so is this node as a whole.
00096                  */
00097                 for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i)
00098                         hasinput[i] = (sock->link != NULL);
00099                 
00100                 shi= shcd->shi;
00101                 shi->mat= (Material *)node->id;
00102                 
00103                 /* copy all relevant material vars, note, keep this synced with render_types.h */
00104                 memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
00105                 shi->har= shi->mat->har;
00106                 
00107                 /* write values */
00108                 if(hasinput[MAT_IN_COLOR])
00109                         nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
00110                 
00111                 if(hasinput[MAT_IN_SPEC])
00112                         nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
00113                 
00114                 if(hasinput[MAT_IN_REFL])
00115                         nodestack_get_vec(&shi->refl, SOCK_VALUE, in[MAT_IN_REFL]);
00116                 
00117                 /* retrieve normal */
00118                 if(hasinput[MAT_IN_NORMAL]) {
00119                         nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
00120                         normalize_v3(shi->vn);
00121                 }
00122                 else
00123                         VECCOPY(shi->vn, shi->vno);
00124                 
00125                 /* custom option to flip normal */
00126                 if(node->custom1 & SH_NODE_MAT_NEG) {
00127                         shi->vn[0]= -shi->vn[0];
00128                         shi->vn[1]= -shi->vn[1];
00129                         shi->vn[2]= -shi->vn[2];
00130                 }
00131                 
00132                 if (node->type == SH_NODE_MATERIAL_EXT) {
00133                         if(hasinput[MAT_IN_MIR])
00134                                 nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]);
00135                         if(hasinput[MAT_IN_AMB])
00136                                 nodestack_get_vec(&shi->amb, SOCK_VALUE, in[MAT_IN_AMB]);
00137                         if(hasinput[MAT_IN_EMIT])
00138                                 nodestack_get_vec(&shi->emit, SOCK_VALUE, in[MAT_IN_EMIT]);
00139                         if(hasinput[MAT_IN_SPECTRA])
00140                                 nodestack_get_vec(&shi->spectra, SOCK_VALUE, in[MAT_IN_SPECTRA]);
00141                         if(hasinput[MAT_IN_RAY_MIRROR])
00142                                 nodestack_get_vec(&shi->ray_mirror, SOCK_VALUE, in[MAT_IN_RAY_MIRROR]);
00143                         if(hasinput[MAT_IN_ALPHA])
00144                                 nodestack_get_vec(&shi->alpha, SOCK_VALUE, in[MAT_IN_ALPHA]);
00145                         if(hasinput[MAT_IN_TRANSLUCENCY])
00146                                 nodestack_get_vec(&shi->translucency, SOCK_VALUE, in[MAT_IN_TRANSLUCENCY]);                     
00147                 }
00148                 
00149                 shi->nodes= 1; /* temp hack to prevent trashadow recursion */
00150                 node_shader_lamp_loop(shi, &shrnode);   /* clears shrnode */
00151                 shi->nodes= 0;
00152                 
00153                 /* write to outputs */
00154                 if(node->custom1 & SH_NODE_MAT_DIFF) {
00155                         VECCOPY(col, shrnode.combined);
00156                         if(!(node->custom1 & SH_NODE_MAT_SPEC)) {
00157                                 sub_v3_v3(col, shrnode.spec);
00158                         }
00159                 }
00160                 else if(node->custom1 & SH_NODE_MAT_SPEC) {
00161                         VECCOPY(col, shrnode.spec);
00162                 }
00163                 else
00164                         col[0]= col[1]= col[2]= 0.0f;
00165                 
00166                 col[3]= shrnode.alpha;
00167                 
00168                 if(shi->do_preview)
00169                         nodeAddToPreview(node, col, shi->xs, shi->ys, shi->do_manage);
00170                 
00171                 VECCOPY(out[MAT_OUT_COLOR]->vec, col);
00172                 out[MAT_OUT_ALPHA]->vec[0]= shrnode.alpha;
00173                 
00174                 if(node->custom1 & SH_NODE_MAT_NEG) {
00175                         shi->vn[0]= -shi->vn[0];
00176                         shi->vn[1]= -shi->vn[1];
00177                         shi->vn[2]= -shi->vn[2];
00178                 }
00179                 
00180                 VECCOPY(out[MAT_OUT_NORMAL]->vec, shi->vn);
00181                 
00182                 /* Extended material options */
00183                 if (node->type == SH_NODE_MATERIAL_EXT) {
00184                         /* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
00185                          * a node tree :( */
00186                         VECCOPY(out[MAT_OUT_DIFFUSE]->vec, shrnode.diff);
00187                         VECCOPY(out[MAT_OUT_SPEC]->vec, shrnode.spec);
00188                         VECCOPY(out[MAT_OUT_AO]->vec, shrnode.ao);
00189                 }
00190                 
00191                 /* copy passes, now just active node */
00192                 if(node->flag & NODE_ACTIVE_ID) {
00193                         float combined[4], alpha;
00194 
00195                         copy_v4_v4(combined, shcd->shr->combined);
00196                         alpha= shcd->shr->alpha;
00197 
00198                         *(shcd->shr)= shrnode;
00199 
00200                         copy_v4_v4(shcd->shr->combined, combined);
00201                         shcd->shr->alpha= alpha;
00202                 }
00203         }
00204 }
00205 
00206 
00207 static void node_shader_init_material(bNode* node)
00208 {
00209         node->custom1= SH_NODE_MAT_DIFF|SH_NODE_MAT_SPEC;
00210 }
00211 
00212 /* XXX this is also done as a local static function in gpu_codegen.c,
00213  * but we need this to hack around the crappy material node.
00214  */
00215 static GPUNodeLink *gpu_get_input_link(GPUNodeStack *in)
00216 {
00217         if (in->link)
00218                 return in->link;
00219         else
00220                 return GPU_uniform(in->vec);
00221 }
00222 
00223 static int gpu_shader_material(GPUMaterial *mat, bNode *node, GPUNodeStack *in, GPUNodeStack *out)
00224 {
00225         if(node->id) {
00226                 GPUShadeInput shi;
00227                 GPUShadeResult shr;
00228                 bNodeSocket *sock;
00229                 char hasinput[NUM_MAT_IN]= {'\0'};
00230                 int i;
00231                 
00232                 /* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
00233                  * the constant input stack values (e.g. in case material node is inside a group).
00234                  * we just want to know if a node input uses external data or the material setting.
00235                  */
00236                 for (sock=node->inputs.first, i=0; sock; sock=sock->next, ++i)
00237                         hasinput[i] = (sock->link != NULL);
00238 
00239                 GPU_shadeinput_set(mat, (Material*)node->id, &shi);
00240 
00241                 /* write values */
00242                 if(hasinput[MAT_IN_COLOR])
00243                         shi.rgb = gpu_get_input_link(&in[MAT_IN_COLOR]);
00244                 
00245                 if(hasinput[MAT_IN_SPEC])
00246                         shi.specrgb = gpu_get_input_link(&in[MAT_IN_SPEC]);
00247                 
00248                 if(hasinput[MAT_IN_REFL])
00249                         shi.refl = gpu_get_input_link(&in[MAT_IN_REFL]);
00250                 
00251                 /* retrieve normal */
00252                 if(hasinput[MAT_IN_NORMAL]) {
00253                         GPUNodeLink *tmp;
00254                         shi.vn = gpu_get_input_link(&in[MAT_IN_NORMAL]);
00255                         GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp);
00256                 }
00257                 
00258                 /* custom option to flip normal */
00259                 if(node->custom1 & SH_NODE_MAT_NEG)
00260                         GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
00261 
00262                 if (node->type == SH_NODE_MATERIAL_EXT) {
00263                         if(hasinput[MAT_IN_AMB])
00264                                 shi.amb= gpu_get_input_link(&in[MAT_IN_AMB]);
00265                         if(hasinput[MAT_IN_EMIT])
00266                                 shi.emit= gpu_get_input_link(&in[MAT_IN_EMIT]);
00267                         if(hasinput[MAT_IN_ALPHA])
00268                                 shi.alpha= gpu_get_input_link(&in[MAT_IN_ALPHA]);
00269                 }
00270 
00271                 GPU_shaderesult_set(&shi, &shr); /* clears shr */
00272                 
00273                 /* write to outputs */
00274                 if(node->custom1 & SH_NODE_MAT_DIFF) {
00275                         out[MAT_OUT_COLOR].link= shr.combined;
00276 
00277                         if(!(node->custom1 & SH_NODE_MAT_SPEC)) {
00278                                 GPUNodeLink *link;
00279                                 GPU_link(mat, "vec_math_sub", shr.combined, shr.spec, &out[MAT_OUT_COLOR].link, &link);
00280                         }
00281                 }
00282                 else if(node->custom1 & SH_NODE_MAT_SPEC) {
00283                         out[MAT_OUT_COLOR].link= shr.spec;
00284                 }
00285                 else
00286                         GPU_link(mat, "set_rgb_zero", &out[MAT_OUT_COLOR].link);
00287 
00288                 GPU_link(mat, "mtex_alpha_to_col", out[MAT_OUT_COLOR].link, shr.alpha, &out[MAT_OUT_COLOR].link);
00289 
00290                 out[MAT_OUT_ALPHA].link = shr.alpha; //
00291                 
00292                 if(node->custom1 & SH_NODE_MAT_NEG)
00293                         GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
00294                 out[MAT_OUT_NORMAL].link = shi.vn;
00295 
00296                 if (node->type == SH_NODE_MATERIAL_EXT) {
00297                         out[MAT_OUT_DIFFUSE].link = shr.diff;
00298                         out[MAT_OUT_SPEC].link = shr.spec;
00299                 }
00300 
00301                 return 1;
00302         }
00303 
00304         return 0;
00305 }
00306 
00307 void register_node_type_sh_material(ListBase *lb)
00308 {
00309         static bNodeType ntype;
00310 
00311         node_type_base(&ntype, SH_NODE_MATERIAL, "Material", NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
00312                 sh_node_material_in, sh_node_material_out);
00313         node_type_size(&ntype, 120, 80, 240);
00314         node_type_init(&ntype, node_shader_init_material);
00315         node_type_exec(&ntype, node_shader_exec_material);
00316         node_type_gpu(&ntype, gpu_shader_material);
00317 
00318         nodeRegisterType(lb, &ntype);
00319 }
00320 
00321 
00322 void register_node_type_sh_material_ext(ListBase *lb)
00323 {
00324         static bNodeType ntype;
00325 
00326         node_type_base(&ntype, SH_NODE_MATERIAL_EXT, "Extended Material", NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW,
00327                 sh_node_material_ext_in, sh_node_material_ext_out);
00328         node_type_size(&ntype, 120, 80, 240);
00329         node_type_init(&ntype, node_shader_init_material);
00330         node_type_exec(&ntype, node_shader_exec_material);
00331         node_type_gpu(&ntype, gpu_shader_material);
00332 
00333         nodeRegisterType(lb, &ntype);
00334 }
00335 
00336