Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/io/wavefront_obj/importer/obj_import_mtl.cc')
-rw-r--r--source/blender/io/wavefront_obj/importer/obj_import_mtl.cc301
1 files changed, 161 insertions, 140 deletions
diff --git a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
index f39def0a4af..0922a71979e 100644
--- a/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
+++ b/source/blender/io/wavefront_obj/importer/obj_import_mtl.cc
@@ -5,18 +5,19 @@
*/
#include "BKE_image.h"
+#include "BKE_main.h"
#include "BKE_node.h"
#include "BLI_map.hh"
#include "BLI_math_vector.h"
+#include "BLI_path_util.h"
#include "DNA_material_types.h"
#include "DNA_node_types.h"
#include "NOD_shader.h"
-/* TODO: move eMTLSyntaxElement out of following file into a more neutral place */
-#include "obj_export_io.hh"
+#include "obj_export_mtl.hh"
#include "obj_import_mtl.hh"
#include "obj_import_string_utils.hh"
@@ -27,12 +28,12 @@ namespace blender::io::obj {
* Only float value(s) can be set using this method.
*/
static void set_property_of_socket(eNodeSocketDatatype property_type,
- StringRef socket_id,
+ const char *socket_id,
Span<float> value,
bNode *r_node)
{
BLI_assert(r_node);
- bNodeSocket *socket{nodeFindSocket(r_node, SOCK_IN, socket_id.data())};
+ bNodeSocket *socket{nodeFindSocket(r_node, SOCK_IN, socket_id)};
BLI_assert(socket && socket->type == property_type);
switch (property_type) {
case SOCK_FLOAT: {
@@ -60,136 +61,124 @@ static void set_property_of_socket(eNodeSocketDatatype property_type,
}
}
-static bool load_texture_image_at_path(Main *bmain,
- const tex_map_XX &tex_map,
- bNode *r_node,
- const std::string &path)
+static Image *load_image_at_path(Main *bmain, const std::string &path, bool relative_paths)
{
- Image *tex_image = BKE_image_load(bmain, path.c_str());
- if (!tex_image) {
+ Image *image = BKE_image_load_exists(bmain, path.c_str());
+ if (!image) {
fprintf(stderr, "Cannot load image file: '%s'\n", path.c_str());
- return false;
+ return nullptr;
}
fprintf(stderr, "Loaded image from: '%s'\n", path.c_str());
- r_node->id = reinterpret_cast<ID *>(tex_image);
- NodeTexImage *image = static_cast<NodeTexImage *>(r_node->storage);
- image->projection = tex_map.projection_type;
- return true;
+ if (relative_paths) {
+ BLI_path_rel(image->filepath, BKE_main_blendfile_path(bmain));
+ }
+ return image;
}
-/**
- * Load image for Image Texture node and set the node properties.
- * Return success if Image can be loaded successfully.
- */
-static bool load_texture_image(Main *bmain, const tex_map_XX &tex_map, bNode *r_node)
+static Image *create_placeholder_image(Main *bmain, const std::string &path)
+{
+ const float color[4] = {0, 0, 0, 1};
+ Image *image = BKE_image_add_generated(bmain,
+ 32,
+ 32,
+ BLI_path_basename(path.c_str()),
+ 24,
+ false,
+ IMA_GENTYPE_BLANK,
+ color,
+ false,
+ false,
+ false);
+ STRNCPY(image->filepath, path.c_str());
+ image->source = IMA_SRC_FILE;
+ return image;
+}
+
+static Image *load_texture_image(Main *bmain, const MTLTexMap &tex_map, bool relative_paths)
{
- BLI_assert(r_node && r_node->type == SH_NODE_TEX_IMAGE);
+ Image *image = nullptr;
/* First try treating texture path as relative. */
std::string tex_path{tex_map.mtl_dir_path + tex_map.image_path};
- if (load_texture_image_at_path(bmain, tex_map, r_node, tex_path)) {
- return true;
+ image = load_image_at_path(bmain, tex_path, relative_paths);
+ if (image != nullptr) {
+ return image;
}
/* Then try using it directly as absolute path. */
std::string raw_path{tex_map.image_path};
- if (load_texture_image_at_path(bmain, tex_map, r_node, raw_path)) {
- return true;
+ image = load_image_at_path(bmain, raw_path, relative_paths);
+ if (image != nullptr) {
+ return image;
}
/* Try removing quotes. */
std::string no_quote_path{tex_path};
auto end_pos = std::remove(no_quote_path.begin(), no_quote_path.end(), '"');
no_quote_path.erase(end_pos, no_quote_path.end());
- if (no_quote_path != tex_path &&
- load_texture_image_at_path(bmain, tex_map, r_node, no_quote_path)) {
- return true;
+ if (no_quote_path != tex_path) {
+ image = load_image_at_path(bmain, no_quote_path, relative_paths);
+ if (image != nullptr) {
+ return image;
+ }
}
/* Try replacing underscores with spaces. */
std::string no_underscore_path{no_quote_path};
std::replace(no_underscore_path.begin(), no_underscore_path.end(), '_', ' ');
- if (no_underscore_path != no_quote_path && no_underscore_path != tex_path &&
- load_texture_image_at_path(bmain, tex_map, r_node, no_underscore_path)) {
- return true;
+ if (no_underscore_path != no_quote_path && no_underscore_path != tex_path) {
+ image = load_image_at_path(bmain, no_underscore_path, relative_paths);
+ if (image != nullptr) {
+ return image;
+ }
}
-
- return false;
-}
-
-ShaderNodetreeWrap::ShaderNodetreeWrap(Main *bmain, const MTLMaterial &mtl_mat, Material *mat)
- : mtl_mat_(mtl_mat)
-{
- nodetree_.reset(ntreeAddTree(nullptr, "Shader Nodetree", ntreeType_Shader->idname));
- bsdf_ = add_node_to_tree(SH_NODE_BSDF_PRINCIPLED);
- shader_output_ = add_node_to_tree(SH_NODE_OUTPUT_MATERIAL);
-
- set_bsdf_socket_values(mat);
- add_image_textures(bmain, mat);
- link_sockets(bsdf_, "BSDF", shader_output_, "Surface", 4);
-
- nodeSetActive(nodetree_.get(), shader_output_);
-}
-
-/**
- * Assert if caller hasn't acquired nodetree.
- */
-ShaderNodetreeWrap::~ShaderNodetreeWrap()
-{
- if (nodetree_) {
- /* nodetree's ownership must be acquired by the caller. */
- nodetree_.reset();
- BLI_assert(0);
+ /* Try taking just the basename from input path. */
+ std::string base_path{tex_map.mtl_dir_path + BLI_path_basename(tex_map.image_path.c_str())};
+ if (base_path != tex_path) {
+ image = load_image_at_path(bmain, base_path, relative_paths);
+ if (image != nullptr) {
+ return image;
+ }
}
-}
-bNodeTree *ShaderNodetreeWrap::get_nodetree()
-{
- /* If this function has been reached, we know that nodes and the nodetree
- * can be added to the scene safely. */
- return nodetree_.release();
+ image = create_placeholder_image(bmain, tex_path);
+ return image;
}
-bNode *ShaderNodetreeWrap::add_node_to_tree(const int node_type)
-{
- return nodeAddStaticNode(nullptr, nodetree_.get(), node_type);
-}
+/* Nodes are arranged in columns by type, with manually placed x coordinates
+ * based on node widths. */
+const float node_locx_texcoord = -880.0f;
+const float node_locx_mapping = -680.0f;
+const float node_locx_image = -480.0f;
+const float node_locx_normalmap = -200.0f;
+const float node_locx_bsdf = 0.0f;
+const float node_locx_output = 280.0f;
-std::pair<float, float> ShaderNodetreeWrap::set_node_locations(const int pos_x)
+/* Nodes are arranged in rows; one row for each image being used. */
+const float node_locy_top = 300.0f;
+const float node_locy_step = 300.0f;
+
+/* Add a node of the given type at the given location. */
+static bNode *add_node(bNodeTree *ntree, int type, float x, float y)
{
- int pos_y = 0;
- bool found = false;
- while (true) {
- for (Span<int> location : node_locations) {
- if (location[0] == pos_x && location[1] == pos_y) {
- pos_y += 1;
- found = true;
- }
- else {
- found = false;
- }
- }
- if (!found) {
- node_locations.append({pos_x, pos_y});
- return {pos_x * node_size_, pos_y * node_size_ * 2.0 / 3.0};
- }
- }
+ bNode *node = nodeAddStaticNode(nullptr, ntree, type);
+ node->locx = x;
+ node->locy = y;
+ return node;
}
-void ShaderNodetreeWrap::link_sockets(bNode *from_node,
- StringRef from_node_id,
- bNode *to_node,
- StringRef to_node_id,
- const int from_node_pos_x)
+static void link_sockets(bNodeTree *ntree,
+ bNode *from_node,
+ const char *from_node_id,
+ bNode *to_node,
+ const char *to_node_id)
{
- std::tie(from_node->locx, from_node->locy) = set_node_locations(from_node_pos_x);
- std::tie(to_node->locx, to_node->locy) = set_node_locations(from_node_pos_x + 1);
- bNodeSocket *from_sock{nodeFindSocket(from_node, SOCK_OUT, from_node_id.data())};
- bNodeSocket *to_sock{nodeFindSocket(to_node, SOCK_IN, to_node_id.data())};
+ bNodeSocket *from_sock{nodeFindSocket(from_node, SOCK_OUT, from_node_id)};
+ bNodeSocket *to_sock{nodeFindSocket(to_node, SOCK_IN, to_node_id)};
BLI_assert(from_sock && to_sock);
- nodeAddLink(nodetree_.get(), from_node, from_sock, to_node, to_sock);
+ nodeAddLink(ntree, from_node, from_sock, to_node, to_sock);
}
-void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat)
+static void set_bsdf_socket_values(bNode *bsdf, Material *mat, const MTLMaterial &mtl_mat)
{
- const int illum = mtl_mat_.illum;
+ const int illum = mtl_mat.illum;
bool do_highlight = false;
bool do_tranparency = false;
bool do_reflection = false;
@@ -255,21 +244,21 @@ void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat)
/* Approximations for trying to map obj/mtl material model into
* Principled BSDF: */
/* Specular: average of Ks components. */
- float specular = (mtl_mat_.Ks[0] + mtl_mat_.Ks[1] + mtl_mat_.Ks[2]) / 3;
+ float specular = (mtl_mat.Ks[0] + mtl_mat.Ks[1] + mtl_mat.Ks[2]) / 3;
if (specular < 0.0f) {
specular = do_highlight ? 1.0f : 0.0f;
}
/* Roughness: map 0..1000 range to 1..0 and apply non-linearity. */
float roughness;
- if (mtl_mat_.Ns < 0.0f) {
+ if (mtl_mat.Ns < 0.0f) {
roughness = do_highlight ? 0.0f : 1.0f;
}
else {
- float clamped_ns = std::max(0.0f, std::min(1000.0f, mtl_mat_.Ns));
+ float clamped_ns = std::max(0.0f, std::min(1000.0f, mtl_mat.Ns));
roughness = 1.0f - sqrt(clamped_ns / 1000.0f);
}
/* Metallic: average of Ka components. */
- float metallic = (mtl_mat_.Ka[0] + mtl_mat_.Ka[1] + mtl_mat_.Ka[2]) / 3;
+ float metallic = (mtl_mat.Ka[0] + mtl_mat.Ka[1] + mtl_mat.Ka[2]) / 3;
if (do_reflection) {
if (metallic < 0.0f) {
metallic = 1.0f;
@@ -279,7 +268,7 @@ void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat)
metallic = 0.0f;
}
- float ior = mtl_mat_.Ni;
+ float ior = mtl_mat.Ni;
if (ior < 0) {
if (do_tranparency) {
ior = 1.0f;
@@ -288,89 +277,121 @@ void ShaderNodetreeWrap::set_bsdf_socket_values(Material *mat)
ior = 1.5f;
}
}
- float alpha = mtl_mat_.d;
+ float alpha = mtl_mat.d;
if (do_tranparency && alpha < 0) {
alpha = 1.0f;
}
- float3 base_color = {mtl_mat_.Kd[0], mtl_mat_.Kd[1], mtl_mat_.Kd[2]};
+ float3 base_color = {mtl_mat.Kd[0], mtl_mat.Kd[1], mtl_mat.Kd[2]};
if (base_color.x >= 0 && base_color.y >= 0 && base_color.z >= 0) {
- set_property_of_socket(SOCK_RGBA, "Base Color", {base_color, 3}, bsdf_);
+ set_property_of_socket(SOCK_RGBA, "Base Color", {base_color, 3}, bsdf);
/* Viewport shading uses legacy r,g,b base color. */
mat->r = base_color.x;
mat->g = base_color.y;
mat->b = base_color.z;
}
- float3 emission_color = {mtl_mat_.Ke[0], mtl_mat_.Ke[1], mtl_mat_.Ke[2]};
+ float3 emission_color = {mtl_mat.Ke[0], mtl_mat.Ke[1], mtl_mat.Ke[2]};
if (emission_color.x >= 0 && emission_color.y >= 0 && emission_color.z >= 0) {
- set_property_of_socket(SOCK_RGBA, "Emission", {emission_color, 3}, bsdf_);
+ set_property_of_socket(SOCK_RGBA, "Emission", {emission_color, 3}, bsdf);
}
- if (mtl_mat_.texture_maps.contains_as(eMTLSyntaxElement::map_Ke)) {
- set_property_of_socket(SOCK_FLOAT, "Emission Strength", {1.0f}, bsdf_);
+ if (mtl_mat.tex_map_of_type(MTLTexMapType::Ke).is_valid()) {
+ set_property_of_socket(SOCK_FLOAT, "Emission Strength", {1.0f}, bsdf);
}
- set_property_of_socket(SOCK_FLOAT, "Specular", {specular}, bsdf_);
- set_property_of_socket(SOCK_FLOAT, "Roughness", {roughness}, bsdf_);
+ set_property_of_socket(SOCK_FLOAT, "Specular", {specular}, bsdf);
+ set_property_of_socket(SOCK_FLOAT, "Roughness", {roughness}, bsdf);
mat->roughness = roughness;
- set_property_of_socket(SOCK_FLOAT, "Metallic", {metallic}, bsdf_);
+ set_property_of_socket(SOCK_FLOAT, "Metallic", {metallic}, bsdf);
mat->metallic = metallic;
if (ior != -1) {
- set_property_of_socket(SOCK_FLOAT, "IOR", {ior}, bsdf_);
+ set_property_of_socket(SOCK_FLOAT, "IOR", {ior}, bsdf);
}
if (alpha != -1) {
- set_property_of_socket(SOCK_FLOAT, "Alpha", {alpha}, bsdf_);
+ set_property_of_socket(SOCK_FLOAT, "Alpha", {alpha}, bsdf);
}
- if (do_tranparency) {
+ if (do_tranparency || (alpha >= 0.0f && alpha < 1.0f)) {
mat->blend_method = MA_BM_BLEND;
}
}
-void ShaderNodetreeWrap::add_image_textures(Main *bmain, Material *mat)
+static void add_image_textures(Main *bmain,
+ bNodeTree *ntree,
+ bNode *bsdf,
+ Material *mat,
+ const MTLMaterial &mtl_mat,
+ bool relative_paths)
{
- for (const Map<const eMTLSyntaxElement, tex_map_XX>::Item texture_map :
- mtl_mat_.texture_maps.items()) {
- if (texture_map.value.image_path.empty()) {
+ float node_locy = node_locy_top;
+ for (int key = 0; key < (int)MTLTexMapType::Count; ++key) {
+ const MTLTexMap &value = mtl_mat.texture_maps[key];
+ if (!value.is_valid()) {
/* No Image texture node of this map type can be added to this material. */
continue;
}
- bNode *image_texture = add_node_to_tree(SH_NODE_TEX_IMAGE);
- if (!load_texture_image(bmain, texture_map.value, image_texture)) {
- /* Image could not be added, so don't add or link further nodes. */
+ Image *image = load_texture_image(bmain, value, relative_paths);
+ if (image == nullptr) {
continue;
}
+ bNode *image_node = add_node(ntree, SH_NODE_TEX_IMAGE, node_locx_image, node_locy);
+ BLI_assert(image_node);
+ image_node->id = &image->id;
+ static_cast<NodeTexImage *>(image_node->storage)->projection = value.projection_type;
+
/* Add normal map node if needed. */
bNode *normal_map = nullptr;
- if (texture_map.key == eMTLSyntaxElement::map_Bump) {
- normal_map = add_node_to_tree(SH_NODE_NORMAL_MAP);
- const float bump = std::max(0.0f, mtl_mat_.map_Bump_strength);
+ if (key == (int)MTLTexMapType::bump) {
+ normal_map = add_node(ntree, SH_NODE_NORMAL_MAP, node_locx_normalmap, node_locy);
+ const float bump = std::max(0.0f, mtl_mat.map_Bump_strength);
set_property_of_socket(SOCK_FLOAT, "Strength", {bump}, normal_map);
}
/* Add UV mapping & coordinate nodes only if needed. */
- if (texture_map.value.translation != float3(0, 0, 0) ||
- texture_map.value.scale != float3(1, 1, 1)) {
- bNode *mapping = add_node_to_tree(SH_NODE_MAPPING);
- bNode *texture_coordinate = add_node_to_tree(SH_NODE_TEX_COORD);
- set_property_of_socket(SOCK_VECTOR, "Location", {texture_map.value.translation, 3}, mapping);
- set_property_of_socket(SOCK_VECTOR, "Scale", {texture_map.value.scale, 3}, mapping);
-
- link_sockets(texture_coordinate, "UV", mapping, "Vector", 0);
- link_sockets(mapping, "Vector", image_texture, "Vector", 1);
+ if (value.translation != float3(0, 0, 0) || value.scale != float3(1, 1, 1)) {
+ bNode *texcoord = add_node(ntree, SH_NODE_TEX_COORD, node_locx_texcoord, node_locy);
+ bNode *mapping = add_node(ntree, SH_NODE_MAPPING, node_locx_mapping, node_locy);
+ set_property_of_socket(SOCK_VECTOR, "Location", {value.translation, 3}, mapping);
+ set_property_of_socket(SOCK_VECTOR, "Scale", {value.scale, 3}, mapping);
+
+ link_sockets(ntree, texcoord, "UV", mapping, "Vector");
+ link_sockets(ntree, mapping, "Vector", image_node, "Vector");
}
if (normal_map) {
- link_sockets(image_texture, "Color", normal_map, "Color", 2);
- link_sockets(normal_map, "Normal", bsdf_, "Normal", 3);
+ link_sockets(ntree, image_node, "Color", normal_map, "Color");
+ link_sockets(ntree, normal_map, "Normal", bsdf, "Normal");
}
- else if (texture_map.key == eMTLSyntaxElement::map_d) {
- link_sockets(image_texture, "Alpha", bsdf_, texture_map.value.dest_socket_id, 2);
+ else if (key == (int)MTLTexMapType::d) {
+ link_sockets(ntree, image_node, "Alpha", bsdf, tex_map_type_to_socket_id[key]);
mat->blend_method = MA_BM_BLEND;
}
else {
- link_sockets(image_texture, "Color", bsdf_, texture_map.value.dest_socket_id, 2);
+ link_sockets(ntree, image_node, "Color", bsdf, tex_map_type_to_socket_id[key]);
}
+
+ /* Next layout row: goes downwards on the screen. */
+ node_locy -= node_locy_step;
}
}
+
+bNodeTree *create_mtl_node_tree(Main *bmain,
+ const MTLMaterial &mtl,
+ Material *mat,
+ bool relative_paths)
+{
+ bNodeTree *ntree = ntreeAddTreeEmbedded(
+ nullptr, &mat->id, "Shader Nodetree", ntreeType_Shader->idname);
+
+ bNode *bsdf = add_node(ntree, SH_NODE_BSDF_PRINCIPLED, node_locx_bsdf, node_locy_top);
+ bNode *output = add_node(ntree, SH_NODE_OUTPUT_MATERIAL, node_locx_output, node_locy_top);
+
+ set_bsdf_socket_values(bsdf, mat, mtl);
+ add_image_textures(bmain, ntree, bsdf, mat, mtl, relative_paths);
+ link_sockets(ntree, bsdf, "BSDF", output, "Surface");
+ nodeSetActive(ntree, output);
+
+ return ntree;
+}
+
} // namespace blender::io::obj