|
Blender
V2.59
|
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