Blender V2.61 - r43446

node_shader_material.c

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