[Bf-blender-cvs] [1cd052f469f] soc-2019-fast-io: [Fast import/export] OBJ exports materials and animations

Hugo Sales noreply at git.blender.org
Sun Jun 23 15:58:03 CEST 2019


Commit: 1cd052f469f17c9b366f3a0301c459b8c50869b0
Author: Hugo Sales
Date:   Sun Jun 23 14:57:44 2019 +0100
Branches: soc-2019-fast-io
https://developer.blender.org/rB1cd052f469f17c9b366f3a0301c459b8c50869b0

[Fast import/export] OBJ exports materials and animations

===================================================================

A	release/scripts/modules/obj_export.py
M	source/blender/editors/io/CMakeLists.txt
M	source/blender/editors/io/intern/iterators.hpp
M	source/blender/editors/io/intern/obj.cpp
M	source/blender/editors/io/io_common.c
M	source/blender/editors/io/io_common.h

===================================================================

diff --git a/release/scripts/modules/obj_export.py b/release/scripts/modules/obj_export.py
new file mode 100644
index 00000000000..9125aa85c76
--- /dev/null
+++ b/release/scripts/modules/obj_export.py
@@ -0,0 +1,130 @@
+# ##### 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.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8 compliant>
+
+import os
+
+import bpy
+from mathutils import Matrix, Vector, Color
+from bpy_extras import io_utils, node_shader_utils
+
+def write_mtl(filepath, materials):
+    C = bpy.context
+    scene = C.scene
+    world = scene.world
+    world_amb = Color((0.8, 0.8, 0.8))
+
+    source_dir = os.path.dirname(bpy.data.filepath)
+    dest_dir = os.path.dirname(filepath)
+
+    with open(filepath, "w", encoding="utf8", newline="\n") as f:
+        fw = f.write
+
+        fw('# Blender MTL File: %r\n' % (os.path.basename(bpy.data.filepath) or "None"))
+        fw('# Material Count: %i\n' % len(materials))
+
+        for material in materials:
+            fw('newmtl %s\n' % material)
+            mat = bpy.data.materials[material]
+            mat_wrap = node_shader_utils.PrincipledBSDFWrapper(mat) if mat else None
+
+            if mat_wrap:
+                use_mirror = mat_wrap.metallic != 0.0
+                use_transparency = mat_wrap.alpha != 1.0
+
+                # XXX Totally empirical conversion, trying to adapt it
+                #     (from 1.0 - 0.0 Principled BSDF range to 0.0 - 900.0 OBJ specular exponent range)...
+                spec = (1.0 - mat_wrap.roughness) * 30
+                spec *= spec
+                fw('Ns %.6f\n' % spec)
+
+                # Ambient
+                if use_mirror:
+                    fw('Ka %.6f %.6f %.6f\n' % (mat_wrap.metallic, mat_wrap.metallic, mat_wrap.metallic))
+                else:
+                    fw('Ka %.6f %.6f %.6f\n' % (1.0, 1.0, 1.0))
+                    fw('Kd %.6f %.6f %.6f\n' % mat_wrap.base_color[:3])  # Diffuse
+                    # XXX TODO Find a way to handle tint and diffuse color, in a consistent way with import...
+                fw('Ks %.6f %.6f %.6f\n' % (mat_wrap.specular, mat_wrap.specular, mat_wrap.specular))  # Specular
+                # Emission, not in original MTL standard but seems pretty common, see T45766.
+                fw('Ke 0.0 0.0 0.0\n')           # XXX Not supported by current Principled-based shader.
+                fw('Ni %.6f\n' % mat_wrap.ior)   # Refraction index
+                fw('d %.6f\n' % mat_wrap.alpha)  # Alpha (obj uses 'd' for dissolve)
+
+                # See http://en.wikipedia.org/wiki/Wavefront_.obj_file for whole list of values...
+                # Note that mapping is rather fuzzy sometimes, trying to do our best here.
+                if mat_wrap.specular == 0:
+                    fw('illum 1\n')  # no specular.
+                elif use_mirror:
+                    if use_transparency:
+                        fw('illum 6\n')  # Reflection, Transparency, Ray trace
+                    else:
+                        fw('illum 3\n')  # Reflection and Ray trace
+                elif use_transparency:
+                    fw('illum 9\n')  # 'Glass' transparency and no Ray trace reflection... fuzzy matching, but...
+                else:
+                    fw('illum 2\n')  # light normally
+
+                #### And now, the image textures...
+                image_map = {
+                    "map_Kd": "base_color_texture",
+                    "map_Ka": None,  # ambient...
+                    "map_Ks": "specular_texture",
+                    "map_Ns": "roughness_texture",
+                    "map_d": "alpha_texture",
+                    "map_Tr": None,  # transmission roughness?
+                    "map_Bump": "normalmap_texture",
+                    "disp": None,  # displacement...
+                    "refl": "metallic_texture",
+                    "map_Ke": None  # emission...
+                }
+
+                for key, mat_wrap_key in sorted(image_map.items()):
+                    if mat_wrap_key is None:
+                        continue
+                    tex_wrap = getattr(mat_wrap, mat_wrap_key, None)
+                    if tex_wrap is None:
+                        continue
+                    image = tex_wrap.image
+                    if image is None:
+                        continue
+
+                    filepath = io_utils.path_reference(image.filepath, source_dir, dest_dir,
+                                                       'AUTO', "", None, image.library)
+                    options = []
+                    if key == "map_Bump":
+                        if mat_wrap.normalmap_strength != 1.0:
+                            options.append('-bm %.6f' % mat_wrap.normalmap_strength)
+                    if tex_wrap.translation != Vector((0.0, 0.0, 0.0)):
+                        options.append('-o %.6f %.6f %.6f' % tex_wrap.translation[:])
+                    if tex_wrap.scale != Vector((1.0, 1.0, 1.0)):
+                        options.append('-s %.6f %.6f %.6f' % tex_wrap.scale[:])
+                    if options:
+                        fw('%s %s %s\n' % (key, " ".join(options), repr(filepath)[1:-1]))
+                    else:
+                        fw('%s %s\n' % (key, repr(filepath)[1:-1]))
+
+            else:
+                # Write a dummy material here?
+                fw('Ns 500\n')
+                fw('Ka 0.8 0.8 0.8\n')  # Ambient
+                fw('Kd 0.8 0.8 0.8\n')  # Diffuse
+                fw('Ks 0.8 0.8 0.8\n')  # Specular
+                fw('d 1\n')             # No alpha
+                fw('illum 2\n')         # light normally
diff --git a/source/blender/editors/io/CMakeLists.txt b/source/blender/editors/io/CMakeLists.txt
index 35b3f892ac6..a7f6d77dfc4 100644
--- a/source/blender/editors/io/CMakeLists.txt
+++ b/source/blender/editors/io/CMakeLists.txt
@@ -88,6 +88,11 @@ if(WITH_INTERNATIONAL)
   add_definitions(-DWITH_INTERNATIONAL)
 endif()
 
+if(WITH_PYTHON)
+  list(APPEND INC ../../python)
+  add_definitions(-DWITH_PYTHON)
+endif()
+
 if(CMAKE_COMPILER_IS_GNUCC)
   add_definitions(-Wfatal-errors) # Temporary, for development
 endif()
diff --git a/source/blender/editors/io/intern/iterators.hpp b/source/blender/editors/io/intern/iterators.hpp
index cbd825d37f4..422c658d2f9 100644
--- a/source/blender/editors/io/intern/iterators.hpp
+++ b/source/blender/editors/io/intern/iterators.hpp
@@ -10,6 +10,7 @@ extern "C" {
 #include "BKE_library.h"
 #include "BKE_customdata.h"
 #include "BKE_scene.h"
+#include "BKE_material.h"
 
 #include "DNA_layer_types.h"
 #include "DNA_meshdata_types.h"
@@ -43,6 +44,7 @@ struct pointer_iterator_base {
   using iterator_category = Tag;
   pointer_iterator_base(pointer p, size_t size) : first(p), curr(p), size(size) {}
   pointer_iterator_base(const pointer_iterator_base &pib) : first(pib.first), curr(pib.curr), size(pib.size) {}
+  // Conversion to base pointer
   operator pointer() const { return curr; }
   pointer_iterator_base &operator=(const pointer_iterator_base &p) {
     // Placement new: construct a new object in the position of `this`
@@ -55,8 +57,8 @@ struct pointer_iterator_base {
   pointer_iterator_base & operator++() { ++curr; return *this; }
   pointer_iterator_base & operator--() { --curr; return *this; }
   pointer_iterator_base & operator+(difference_type n) { curr += n; return *this; }
-  ptrdiff_t operator-(const pointer_iterator_base &other) const { return other.curr - curr; }
-  bool operator==(const pointer_iterator_base &other)     const { return curr == other.curr; }
+  difference_type operator-(const pointer_iterator_base &other) const { return other.curr - curr; }
+  bool operator==(const pointer_iterator_base &other) const { return curr == other.curr; }
   pointer first;
   pointer curr;
   size_t size;
@@ -82,6 +84,14 @@ struct list_iterator : pointer_iterator_base<SourceT, Tag> {
   inline const ResT operator*() const { return *this->curr; }
 };
 
+// Represents an offset into an array (base for iterators like material_iter)
+template<typename T>
+struct offset_iterator : pointer_iterator_base<T, std::random_access_iterator_tag> {
+  offset_iterator(size_t size)
+    : pointer_iterator_base<T, std::random_access_iterator_tag>(0, size) {}
+  size_t offset() const { return ((size_t) this->curr) / sizeof(T); }
+};
+
 // Iterator over the polygons of a mesh
 struct poly_iter : pointer_iterator<MPoly> {
   poly_iter(const Mesh *const m) : pointer_iterator(m->mpoly, m->totpoly) {}
@@ -191,6 +201,25 @@ struct loop_of_poly_iter : pointer_iterator<MLoop> {
   // loop_of_poly_iter(pointer_iterator &&p) : pointer_iterator(std::move(p)) {}
 };
 
+struct material_iter : offset_iterator<Material *> {
+  material_iter(const Object * const ob)
+    : offset_iterator(ob->totcol), ob(ob), mdata(*give_matarar((Object *) ob)) {}
+  material_iter begin() const { return material_iter(ob); }
+  material_iter end()   const { material_iter mi(ob); mi.curr = mi.first + mi.size; return mi; }
+  const Material * operator*() {
+    const size_t off = offset();
+    if (ob->matbits && ob->matbits[off]) {
+      // In Object
+      return ob->mat[off];
+    } else {
+      // In Data
+      return mdata[off];
+    }
+  }
+  const Object * const ob;
+  const Material * const * const mdata;
+};
+
 // Iterator over the UVs of a mesh (as `const std::array<float, 2>`)
 struct uv_iter : pointer_iterator_base<MLoopUV> {
   uv_iter(const Mesh *const m) : pointer_iterator_base(m->mloopuv, m->totloop) {}

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list