This repository has been archived on 2023-10-09. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
blender-archive/source/blender/nodes/shader/nodes/node_shader_material.c
Thomas Dinges 2ed2226ee7 Node UI:
* After PyNodes merge, many node sockets had sliders, instead of the arrow buttons (as the PROP_FACTOR subtype now actually was used). Change those back now, after artists feedback.
2013-04-06 12:07:42 +00:00

340 lines
11 KiB
C

/*
* ***** BEGIN GPL LICENSE BLOCK *****
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2005 Blender Foundation.
* All rights reserved.
*
* The Original Code is: all of this file.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/nodes/shader/nodes/node_shader_material.c
* \ingroup shdnodes
*/
#include "node_shader_util.h"
/* **************** MATERIAL ******************** */
static bNodeSocketTemplate sh_node_material_in[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_RGBA, 1, N_("Spec"), 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Refl"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
{ SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
{ -1, 0, "" }
};
static bNodeSocketTemplate sh_node_material_out[] = {
{ SOCK_RGBA, 0, N_("Color")},
{ SOCK_FLOAT, 0, N_("Alpha")},
{ SOCK_VECTOR, 0, N_("Normal")},
{ -1, 0, "" }
};
/* **************** EXTENDED MATERIAL ******************** */
static bNodeSocketTemplate sh_node_material_ext_in[] = {
{ SOCK_RGBA, 1, N_("Color"), 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_RGBA, 1, N_("Spec"), 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Refl"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
{ SOCK_VECTOR, 1, N_("Normal"), 0.0f, 0.0f, 0.0f, 1.0f, -1.0f, 1.0f, PROP_DIRECTION},
{ SOCK_RGBA, 1, N_("Mirror"), 0.0f, 0.0f, 0.0f, 1.0f},
{ SOCK_FLOAT, 1, N_("Ambient"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
{ SOCK_FLOAT, 1, N_("Emit"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
{ SOCK_FLOAT, 1, N_("SpecTra"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
{ SOCK_FLOAT, 1, N_("Ray Mirror"), 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, PROP_NONE},
{ SOCK_FLOAT, 1, N_("Alpha"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_UNSIGNED},
{ SOCK_FLOAT, 1, N_("Translucency"), 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, PROP_NONE},
{ -1, 0, "" }
};
static bNodeSocketTemplate sh_node_material_ext_out[] = {
{ SOCK_RGBA, 0, N_("Color")},
{ SOCK_FLOAT, 0, N_("Alpha")},
{ SOCK_VECTOR, 0, N_("Normal")},
{ SOCK_RGBA, 0, N_("Diffuse")},
{ SOCK_RGBA, 0, N_("Spec")},
{ SOCK_RGBA, 0, N_("AO")},
{ -1, 0, "" }
};
static void node_shader_exec_material(void *data, int UNUSED(thread), bNode *node, bNodeExecData *execdata, bNodeStack **in, bNodeStack **out)
{
if (data && node->id) {
ShadeResult shrnode;
ShadeInput *shi;
ShaderCallData *shcd= data;
float col[4];
bNodeSocket *sock;
char hasinput[NUM_MAT_IN] = {'\0'};
int i, mode;
/* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
* the constant input stack values (e.g. in case material node is inside a group).
* we just want to know if a node input uses external data or the material setting.
* this is an ugly hack, but so is this node as a whole.
*/
for (sock = node->inputs.first, i=0; sock; sock = sock->next, ++i)
hasinput[i] = (sock->link != NULL);
shi= shcd->shi;
shi->mat= (Material *)node->id;
/* copy all relevant material vars, note, keep this synced with render_types.h */
memcpy(&shi->r, &shi->mat->r, 23*sizeof(float));
shi->har= shi->mat->har;
/* write values */
if (hasinput[MAT_IN_COLOR])
nodestack_get_vec(&shi->r, SOCK_VECTOR, in[MAT_IN_COLOR]);
if (hasinput[MAT_IN_SPEC])
nodestack_get_vec(&shi->specr, SOCK_VECTOR, in[MAT_IN_SPEC]);
if (hasinput[MAT_IN_REFL])
nodestack_get_vec(&shi->refl, SOCK_FLOAT, in[MAT_IN_REFL]);
/* retrieve normal */
if (hasinput[MAT_IN_NORMAL]) {
nodestack_get_vec(shi->vn, SOCK_VECTOR, in[MAT_IN_NORMAL]);
normalize_v3(shi->vn);
}
else
copy_v3_v3(shi->vn, shi->vno);
/* custom option to flip normal */
if (node->custom1 & SH_NODE_MAT_NEG) {
negate_v3(shi->vn);
}
if (node->type == SH_NODE_MATERIAL_EXT) {
if (hasinput[MAT_IN_MIR])
nodestack_get_vec(&shi->mirr, SOCK_VECTOR, in[MAT_IN_MIR]);
if (hasinput[MAT_IN_AMB])
nodestack_get_vec(&shi->amb, SOCK_FLOAT, in[MAT_IN_AMB]);
if (hasinput[MAT_IN_EMIT])
nodestack_get_vec(&shi->emit, SOCK_FLOAT, in[MAT_IN_EMIT]);
if (hasinput[MAT_IN_SPECTRA])
nodestack_get_vec(&shi->spectra, SOCK_FLOAT, in[MAT_IN_SPECTRA]);
if (hasinput[MAT_IN_RAY_MIRROR])
nodestack_get_vec(&shi->ray_mirror, SOCK_FLOAT, in[MAT_IN_RAY_MIRROR]);
if (hasinput[MAT_IN_ALPHA])
nodestack_get_vec(&shi->alpha, SOCK_FLOAT, in[MAT_IN_ALPHA]);
if (hasinput[MAT_IN_TRANSLUCENCY])
nodestack_get_vec(&shi->translucency, SOCK_FLOAT, in[MAT_IN_TRANSLUCENCY]);
}
/* make alpha output give results even if transparency is only enabled on
* the material linked in this not and not on the parent material */
mode = shi->mode;
if (shi->mat->mode & MA_TRANSP)
shi->mode |= MA_TRANSP;
shi->nodes= 1; /* temp hack to prevent trashadow recursion */
node_shader_lamp_loop(shi, &shrnode); /* clears shrnode */
shi->nodes= 0;
shi->mode = mode;
/* write to outputs */
if (node->custom1 & SH_NODE_MAT_DIFF) {
copy_v3_v3(col, shrnode.combined);
if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
sub_v3_v3(col, shrnode.spec);
}
}
else if (node->custom1 & SH_NODE_MAT_SPEC) {
copy_v3_v3(col, shrnode.spec);
}
else
col[0] = col[1] = col[2] = 0.0f;
col[3] = shrnode.alpha;
if (shi->do_preview)
BKE_node_preview_set_pixel(execdata->preview, col, shi->xs, shi->ys, shi->do_manage);
copy_v3_v3(out[MAT_OUT_COLOR]->vec, col);
out[MAT_OUT_ALPHA]->vec[0] = shrnode.alpha;
if (node->custom1 & SH_NODE_MAT_NEG) {
shi->vn[0] = -shi->vn[0];
shi->vn[1] = -shi->vn[1];
shi->vn[2] = -shi->vn[2];
}
copy_v3_v3(out[MAT_OUT_NORMAL]->vec, shi->vn);
/* Extended material options */
if (node->type == SH_NODE_MATERIAL_EXT) {
/* Shadow, Reflect, Refract, Radiosity, Speed seem to cause problems inside
* a node tree :( */
copy_v3_v3(out[MAT_OUT_DIFFUSE]->vec, shrnode.diff);
copy_v3_v3(out[MAT_OUT_SPEC]->vec, shrnode.spec);
copy_v3_v3(out[MAT_OUT_AO]->vec, shrnode.ao);
}
/* copy passes, now just active node */
if (node->flag & NODE_ACTIVE_ID) {
float combined[4], alpha;
copy_v4_v4(combined, shcd->shr->combined);
alpha= shcd->shr->alpha;
*(shcd->shr)= shrnode;
copy_v4_v4(shcd->shr->combined, combined);
shcd->shr->alpha= alpha;
}
}
}
static void node_shader_init_material(bNodeTree *UNUSED(ntree), bNode *node)
{
node->custom1= SH_NODE_MAT_DIFF|SH_NODE_MAT_SPEC;
}
/* XXX this is also done as a local static function in gpu_codegen.c,
* but we need this to hack around the crappy material node.
*/
static GPUNodeLink *gpu_get_input_link(GPUNodeStack *in)
{
if (in->link)
return in->link;
else
return GPU_uniform(in->vec);
}
static int gpu_shader_material(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), GPUNodeStack *in, GPUNodeStack *out)
{
if (node->id) {
GPUShadeInput shi;
GPUShadeResult shr;
bNodeSocket *sock;
char hasinput[NUM_MAT_IN] = {'\0'};
int i;
/* note: cannot use the in[]->hasinput flags directly, as these are not necessarily
* the constant input stack values (e.g. in case material node is inside a group).
* we just want to know if a node input uses external data or the material setting.
*/
for (sock = node->inputs.first, i=0; sock; sock = sock->next, ++i)
hasinput[i] = (sock->link != NULL);
GPU_shadeinput_set(mat, (Material*)node->id, &shi);
/* write values */
if (hasinput[MAT_IN_COLOR])
shi.rgb = gpu_get_input_link(&in[MAT_IN_COLOR]);
if (hasinput[MAT_IN_SPEC])
shi.specrgb = gpu_get_input_link(&in[MAT_IN_SPEC]);
if (hasinput[MAT_IN_REFL])
shi.refl = gpu_get_input_link(&in[MAT_IN_REFL]);
/* retrieve normal */
if (hasinput[MAT_IN_NORMAL]) {
GPUNodeLink *tmp;
shi.vn = gpu_get_input_link(&in[MAT_IN_NORMAL]);
GPU_link(mat, "vec_math_normalize", shi.vn, &shi.vn, &tmp);
}
/* custom option to flip normal */
if (node->custom1 & SH_NODE_MAT_NEG)
GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
if (node->type == SH_NODE_MATERIAL_EXT) {
if (hasinput[MAT_IN_AMB])
shi.amb= gpu_get_input_link(&in[MAT_IN_AMB]);
if (hasinput[MAT_IN_EMIT])
shi.emit= gpu_get_input_link(&in[MAT_IN_EMIT]);
if (hasinput[MAT_IN_ALPHA])
shi.alpha= gpu_get_input_link(&in[MAT_IN_ALPHA]);
}
GPU_shaderesult_set(&shi, &shr); /* clears shr */
/* write to outputs */
if (node->custom1 & SH_NODE_MAT_DIFF) {
out[MAT_OUT_COLOR].link= shr.combined;
if (!(node->custom1 & SH_NODE_MAT_SPEC)) {
GPUNodeLink *link;
GPU_link(mat, "vec_math_sub", shr.combined, shr.spec, &out[MAT_OUT_COLOR].link, &link);
}
}
else if (node->custom1 & SH_NODE_MAT_SPEC) {
out[MAT_OUT_COLOR].link= shr.spec;
}
else
GPU_link(mat, "set_rgb_zero", &out[MAT_OUT_COLOR].link);
GPU_link(mat, "mtex_alpha_to_col", out[MAT_OUT_COLOR].link, shr.alpha, &out[MAT_OUT_COLOR].link);
out[MAT_OUT_ALPHA].link = shr.alpha; //
if (node->custom1 & SH_NODE_MAT_NEG)
GPU_link(mat, "vec_math_negate", shi.vn, &shi.vn);
out[MAT_OUT_NORMAL].link = shi.vn;
if (node->type == SH_NODE_MATERIAL_EXT) {
out[MAT_OUT_DIFFUSE].link = shr.diff;
out[MAT_OUT_SPEC].link = shr.spec;
}
return 1;
}
return 0;
}
void register_node_type_sh_material(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_MATERIAL, "Material", NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW);
node_type_compatibility(&ntype, NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_material_in, sh_node_material_out);
node_type_size(&ntype, 120, 80, 240);
node_type_init(&ntype, node_shader_init_material);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_material);
node_type_gpu(&ntype, gpu_shader_material);
nodeRegisterType(&ntype);
}
void register_node_type_sh_material_ext(void)
{
static bNodeType ntype;
sh_node_type_base(&ntype, SH_NODE_MATERIAL_EXT, "Extended Material", NODE_CLASS_INPUT, NODE_OPTIONS|NODE_PREVIEW);
node_type_compatibility(&ntype, NODE_OLD_SHADING);
node_type_socket_templates(&ntype, sh_node_material_ext_in, sh_node_material_ext_out);
node_type_size(&ntype, 120, 80, 240);
node_type_init(&ntype, node_shader_init_material);
node_type_exec(&ntype, NULL, NULL, node_shader_exec_material);
node_type_gpu(&ntype, gpu_shader_material);
nodeRegisterType(&ntype);
}