Files
test/source/blender/io/collada/Materials.cpp
Iliya Katueshenock 75d17b1db5 Cleanup: Move BKE_node to namespace
Move all header file into namespace.
Unnecessary namespaces was removed from implementations file.
Part of forward declarations in header was moved in the top part
of file just to do not have a lot of separate namespaces.

Pull Request: https://projects.blender.org/blender/blender/pulls/121637
2024-05-13 16:07:12 +02:00

443 lines
13 KiB
C++

/* SPDX-FileCopyrightText: 2018-2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#include "Materials.h"
#include "BKE_node.hh"
#include "BKE_node_runtime.hh"
#include "BKE_node_tree_update.hh"
MaterialNode::MaterialNode(bContext *C, Material *ma, KeyImageMap &key_image_map)
: mContext(C), material(ma), effect(nullptr), key_image_map(&key_image_map)
{
bNodeTree *new_ntree = prepare_material_nodetree();
setShaderType();
if (new_ntree) {
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);
}
}
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)
{
prepare_material_nodetree();
setShaderType();
std::map<std::string, bNode *> 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) {
ntree = material->nodetree;
return nullptr;
}
blender::bke::ntreeAddTreeEmbedded(nullptr, &material->id, "Shader Nodetree", "ShaderNodeTree");
material->use_nodes = true;
ntree = material->nodetree;
return ntree;
}
void MaterialNode::update_material_nodetree()
{
BKE_ntree_update_main_tree(CTX_data_main(mContext), ntree, nullptr);
}
bNode *MaterialNode::add_node(int node_type, int locx, int locy, std::string label)
{
bNode *node = blender::bke::nodeAddStaticNode(mContext, ntree, node_type);
if (node) {
if (label.length() > 0) {
STRNCPY(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);
blender::bke::nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
}
void MaterialNode::add_link(bNode *from_node,
const char *from_label,
bNode *to_node,
const char *to_label)
{
bNodeSocket *from_socket = blender::bke::nodeFindSocket(from_node, SOCK_OUT, from_label);
bNodeSocket *to_socket = blender::bke::nodeFindSocket(to_node, SOCK_IN, to_label);
if (from_socket && to_socket) {
blender::bke::nodeAddLink(ntree, from_node, from_socket, to_node, to_socket);
}
}
void MaterialNode::set_reflectivity(COLLADAFW::FloatOrParam &val)
{
float reflectivity = val.getFloatValue();
if (reflectivity >= 0) {
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "Metallic");
((bNodeSocketValueFloat *)socket->default_value)->value = reflectivity;
material->metallic = reflectivity;
}
}
#if 0
/* needs rework to be done for 2.81 */
void MaterialNode::set_shininess(COLLADAFW::FloatOrParam &val)
{
float roughness = val.getFloatValue();
if (roughness >= 0) {
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "Roughness");
((bNodeSocketValueFloat *)socket->default_value)->value = roughness;
}
}
#endif
void MaterialNode::set_ior(COLLADAFW::FloatOrParam &val)
{
float ior = val.getFloatValue();
if (ior < 0) {
fprintf(stderr,
"IOR of negative value is not allowed for materials (using Blender default value "
"instead)\n");
return;
}
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "IOR");
((bNodeSocketValueFloat *)socket->default_value)->value = ior;
}
void MaterialNode::set_alpha(COLLADAFW::EffectCommon::OpaqueMode mode,
COLLADAFW::ColorOrTexture &cot,
COLLADAFW::FloatOrParam &val)
{
/* Handling the alpha value according to the Collada 1.4 reference guide
* see page 7-5 Determining Transparency (Opacity). */
if (effect == nullptr) {
return;
}
if (cot.isColor() || !cot.isValid()) {
/* transparent_cot is either a color or not defined */
float transparent_alpha;
if (cot.isValid()) {
COLLADAFW::Color col = cot.getColor();
transparent_alpha = col.getAlpha();
}
else {
/* no transparent color defined */
transparent_alpha = 1;
}
float transparency_alpha = val.getFloatValue();
if (transparency_alpha < 0) {
/* transparency is not defined */
transparency_alpha = 1; /* set to opaque */
}
float alpha = transparent_alpha * transparency_alpha;
if (mode == COLLADAFW::EffectCommon::RGB_ZERO) {
alpha = 1 - alpha;
}
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "Alpha");
((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
material->a = alpha;
}
else if (cot.isTexture()) {
int locy = -300 * (node_map.size() - 2);
add_texture_node(cot, -300, locy, "Alpha");
}
}
void MaterialNode::set_diffuse(COLLADAFW::ColorOrTexture &cot)
{
int locy = -300 * (node_map.size() - 2);
if (cot.isTexture()) {
bNode *texture_node = add_texture_node(cot, -300, locy, "Base Color");
if (texture_node != nullptr) {
add_link(texture_node, 0, shader_node, 0);
}
}
else {
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "Base Color");
float *fcol = (float *)socket->default_value;
if (cot.isColor()) {
COLLADAFW::Color col = cot.getColor();
fcol[0] = material->r = col.getRed();
fcol[1] = material->g = col.getGreen();
fcol[2] = material->b = col.getBlue();
fcol[3] = material->a = col.getAlpha();
}
else {
/* no diffuse term = same as black */
fcol[0] = material->r = 0.0f;
fcol[1] = material->g = 0.0f;
fcol[2] = material->b = 0.0f;
fcol[3] = material->a = 1.0f;
}
}
}
Image *MaterialNode::get_diffuse_image()
{
ntree->ensure_topology_cache();
const blender::Span<const bNode *> nodes = ntree->nodes_by_type("ShaderNodeBsdfPrincipled");
if (nodes.is_empty()) {
return nullptr;
}
const bNode *shader = nodes.first();
const bNodeSocket *in_socket = blender::bke::nodeFindSocket(shader, SOCK_IN, "Base Color");
if (in_socket == nullptr) {
return nullptr;
}
const bNodeLink *link = in_socket->link;
if (link == nullptr) {
return nullptr;
}
const 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)
{
int locy = -300 * (node_map.size() - 2);
if (cot.isColor()) {
COLLADAFW::Color col = cot.getColor();
bNode *node = add_node(SH_NODE_RGB, -300, locy, "Ambient");
set_color(node, col);
/* TODO: Connect node */
}
/* texture */
else if (cot.isTexture()) {
add_texture_node(cot, -300, locy, "Ambient");
/* TODO: Connect node */
}
}
void MaterialNode::set_reflective(COLLADAFW::ColorOrTexture &cot)
{
int locy = -300 * (node_map.size() - 2);
if (cot.isColor()) {
COLLADAFW::Color col = cot.getColor();
bNode *node = add_node(SH_NODE_RGB, -300, locy, "Reflective");
set_color(node, col);
/* TODO: Connect node */
}
/* texture */
else if (cot.isTexture()) {
add_texture_node(cot, -300, locy, "Reflective");
/* TODO: Connect node */
}
}
void MaterialNode::set_emission(COLLADAFW::ColorOrTexture &cot)
{
int locy = -300 * (node_map.size() - 2);
if (cot.isColor()) {
COLLADAFW::Color col = cot.getColor();
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "Emission Color");
float *fcol = (float *)socket->default_value;
fcol[0] = col.getRed();
fcol[1] = col.getGreen();
fcol[2] = col.getBlue();
fcol[3] = col.getAlpha();
}
// texture
else if (cot.isTexture()) {
bNode *texture_node = add_texture_node(cot, -300, locy, "Emission Color");
if (texture_node != nullptr) {
add_link(texture_node, "Color", shader_node, "Emission Color");
}
}
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "Emission Strength");
if (socket) {
*(float *)socket->default_value = 1.0f;
}
}
void MaterialNode::set_opacity(COLLADAFW::ColorOrTexture &cot)
{
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 */
}
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "Alpha");
((bNodeSocketValueFloat *)socket->default_value)->value = alpha;
}
/* texture */
else if (cot.isTexture()) {
add_texture_node(cot, -300, locy, "Alpha");
/* TODO: Connect node */
}
}
void MaterialNode::set_specular(COLLADAFW::ColorOrTexture &cot)
{
bool has_specularity = true;
int locy = -300 * (node_map.size() - 2);
if (cot.isColor()) {
COLLADAFW::Color col = cot.getColor();
if (col.getRed() == 0 && col.getGreen() == 0 && col.getBlue() == 0) {
has_specularity = false;
}
else {
bNode *node = add_node(SH_NODE_RGB, -300, locy, "Specular IOR Level");
set_color(node, col);
/* TODO: Connect node */
}
}
else if (cot.isTexture()) {
add_texture_node(cot, -300, locy, "Specular IOR Level");
/* TODO: Connect node */
}
else {
/* no specular term) */
has_specularity = false;
}
if (!has_specularity) {
/* If specularity is black or not defined reset the Specular value to 0
* TODO: This is a solution only for a corner case. We must find a better
* way to handle specularity in general. Also note that currently we
* do not export specularity values, see EffectExporter::operator() */
bNodeSocket *socket = blender::bke::nodeFindSocket(shader_node, SOCK_IN, "Specular IOR Level");
((bNodeSocketValueFloat *)socket->default_value)->value = 0.0f;
}
}
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 nullptr;
}
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;
}