/* * ***** 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. * * Contributor(s): Gaia Clary. * * ***** END GPL LICENSE BLOCK ***** */ #include "Materials.h" MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map) : mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map) { ntree = prepare_material_nodetree(); setShaderType(); } MaterialNode::MaterialNode(bContext *C, COLLADAFW::EffectCommon *ef, Material *ma, UidImageMap &uid_image_map) : mContext(C), material(ma), effect(ef), uid_image_map(&uid_image_map) { ntree = prepare_material_nodetree(); setShaderType(); std::map nmap; #if 0 nmap["main"] = add_node(C, ntree, SH_NODE_BSDF_PRINCIPLED, -300, 300); nmap["emission"] = add_node(C, ntree, SH_NODE_EMISSION, -300, 500, "emission"); nmap["add"] = add_node(C, ntree, SH_NODE_ADD_SHADER, 100, 400); nmap["transparent"] = add_node(C, ntree, SH_NODE_BSDF_TRANSPARENT, 100, 200); nmap["mix"] = add_node(C, ntree, SH_NODE_MIX_SHADER, 400, 300, "transparency"); nmap["out"] = add_node(C, ntree, SH_NODE_OUTPUT_MATERIAL, 600, 300); nmap["out"]->flag &= ~NODE_SELECT; add_link(ntree, nmap["emission"], 0, nmap["add"], 0); add_link(ntree, nmap["main"], 0, nmap["add"], 1); add_link(ntree, nmap["add"], 0, nmap["mix"], 1); add_link(ntree, nmap["transparent"], 0, nmap["mix"], 2); add_link(ntree, nmap["mix"], 0, nmap["out"], 0); // experimental, probably not used. make_group(C, ntree, nmap); #else shader_node = add_node(SH_NODE_BSDF_PRINCIPLED, 0, 300, ""); output_node = add_node(SH_NODE_OUTPUT_MATERIAL, 300, 300, ""); add_link(shader_node, 0, output_node, 0); #endif } void MaterialNode::setShaderType() { #if 0 COLLADAFW::EffectCommon::ShaderType shader = ef->getShaderType(); // Currently we only support PBR based shaders // TODO: simulate the effects with PBR // blinn if (shader == COLLADAFW::EffectCommon::SHADER_BLINN) { ma->spec_shader = MA_SPEC_BLINN; ma->spec = ef->getShininess().getFloatValue(); } // phong else if (shader == COLLADAFW::EffectCommon::SHADER_PHONG) { ma->spec_shader = MA_SPEC_PHONG; ma->har = ef->getShininess().getFloatValue(); } // lambert else if (shader == COLLADAFW::EffectCommon::SHADER_LAMBERT) { ma->diff_shader = MA_DIFF_LAMBERT; } // default - lambert else { ma->diff_shader = MA_DIFF_LAMBERT; fprintf(stderr, "Current shader type is not supported, default to lambert.\n"); } #endif } bNodeTree *MaterialNode::prepare_material_nodetree() { if (material->nodetree == NULL) { material->nodetree = ntreeAddTree(NULL, "Shader Nodetree", "ShaderNodeTree"); material->use_nodes = true; } return material->nodetree; } bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label) { bNode *node = nodeAddStaticNode(mContext, ntree, node_type); if (node) { if (label.length() > 0) { strcpy(node->label, label.c_str()); } node->locx = locx; node->locy = locy; node->flag |= NODE_SELECT; } node_map[label] = node; return node; } void MaterialNode::add_link(bNode *from_node, int from_index, bNode *to_node, int to_index) { bNodeSocket *from_socket = (bNodeSocket *)BLI_findlink(&from_node->outputs, from_index); bNodeSocket *to_socket = (bNodeSocket *)BLI_findlink(&to_node->inputs, to_index); nodeAddLink(ntree, from_node, from_socket, to_node, to_socket); } void MaterialNode::set_reflectivity(float val) { material->metallic = val; bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_METALLIC); *(float *)socket->default_value = val; } void MaterialNode::set_ior(float val) { bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_IOR); *(float *)socket->default_value = val; } void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot, std::string label) { int locy = -300 * (node_map.size()-2); if (cot.isColor()) { COLLADAFW::Color col = cot.getColor(); material->r = col.getRed(); material->g = col.getGreen(); material->b = col.getBlue(); bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&shader_node->inputs, BC_PBR_DIFFUSE); float *fcol = (float *)socket->default_value; fcol[0] = col.getRed(); fcol[1] = col.getGreen(); fcol[2] = col.getBlue(); } else if (cot.isTexture()) { bNode *texture_node = add_texture_node(cot, -300, locy, label); if (texture_node != NULL) { add_link(texture_node, 0, shader_node, 0); } } } Image *MaterialNode::get_diffuse_image() { bNode *shader = ntreeFindType(ntree, SH_NODE_BSDF_PRINCIPLED); if (shader == nullptr) { return nullptr; } bNodeSocket *in_socket = (bNodeSocket *)BLI_findlink(&shader->inputs, BC_PBR_DIFFUSE); if (in_socket == nullptr) { return nullptr; } bNodeLink *link = in_socket->link; if (link == nullptr) { return nullptr; } bNode *texture = link->fromnode; if (texture == nullptr) { return nullptr; } if (texture->type != SH_NODE_TEX_IMAGE) { return nullptr; } Image *image = (Image *)texture->id; return image; } static bNodeSocket *set_color(bNode *node, COLLADAFW::Color col) { bNodeSocket *socket = (bNodeSocket *)BLI_findlink(&node->outputs, 0); float *fcol = (float *)socket->default_value; fcol[0] = col.getRed(); fcol[1] = col.getGreen(); fcol[2] = col.getBlue(); return socket; } void MaterialNode::set_ambient(COLLADAFW::ColorOrTexture &cot, std::string label) { int locy = -300 * (node_map.size() - 2); if (cot.isColor()) { COLLADAFW::Color col = cot.getColor(); bNode *node = add_node(SH_NODE_RGB, -300, locy, label); set_color(node, col); // TODO: Connect node } // texture else if (cot.isTexture()) { add_texture_node(cot, -300, locy, label); // TODO: Connect node } } void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot, std::string label) { int locy = -300 * (node_map.size() - 2); if (cot.isColor()) { COLLADAFW::Color col = cot.getColor(); bNode *node = add_node(SH_NODE_RGB, -300, locy, label); set_color(node, col); // TODO: Connect node } // texture else if (cot.isTexture()) { add_texture_node(cot, -300, locy, label); // TODO: Connect node } } void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot, std::string label) { int locy = -300 * (node_map.size() - 2); if (cot.isColor()) { COLLADAFW::Color col = cot.getColor(); bNode *node = add_node(SH_NODE_RGB, -300, locy, label); set_color(node, col); // TODO: Connect node } // texture else if (cot.isTexture()) { add_texture_node(cot, -300, locy, label); // TODO: Connect node } } void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot, std::string label) { if (effect == nullptr) { return; } int locy = -300 * (node_map.size() - 2); if (cot.isColor()) { COLLADAFW::Color col = effect->getTransparent().getColor(); float alpha = effect->getTransparency().getFloatValue(); if (col.isValid()) { alpha *= col.getAlpha(); // Assuming A_ONE opaque mode } if (col.isValid() || alpha < 1.0) { // not sure what to do here } bNode *node = add_node(SH_NODE_RGB, -300, locy, label); set_color(node, col); // TODO: Connect node } // texture else if (cot.isTexture()) { add_texture_node(cot, -300, locy, label); // TODO: Connect node } } void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot, std::string label) { int locy = -300 * (node_map.size() - 2); if (cot.isColor()) { COLLADAFW::Color col = cot.getColor(); material->specr = col.getRed(); material->specg = col.getGreen(); material->specb = col.getBlue(); bNode *node = add_node(SH_NODE_RGB, -300, locy, label); set_color(node, col); // TODO: Connect node } // texture else if (cot.isTexture()) { add_texture_node(cot, -300, locy, label); // TODO: Connect node } } bNode *MaterialNode::add_texture_node(COLLADAFW::ColorOrTexture &cot, int locx, int locy, std::string label) { if (effect == nullptr) { return nullptr; } UidImageMap &image_map = *uid_image_map; COLLADAFW::Texture ctex = cot.getTexture(); COLLADAFW::SamplerPointerArray& samp_array = effect->getSamplerPointerArray(); COLLADAFW::Sampler *sampler = samp_array[ctex.getSamplerId()]; const COLLADAFW::UniqueId& ima_uid = sampler->getSourceImage(); if (image_map.find(ima_uid) == image_map.end()) { fprintf(stderr, "Couldn't find an image by UID.\n"); return NULL; } Image *ima = image_map[ima_uid]; bNode *texture_node = add_node(SH_NODE_TEX_IMAGE, locx, locy, label); texture_node->id = &ima->id; return texture_node; }