Package kawa_scripts
kawa_scripts
is an addon and package of useful methods for Blender 2.8x+
made by Kawashirov.
It's designed to use mostly form Python interactive console or from Python scripts.
Basically this addon provides powerful tool for making fully-automated script for preparing, finalizing and baking lots of raw parts (Objects, Meshes, Modifiers, Materials) into few export-ready assets.
Besides internal API for building, there is a few useful operators,
especially for editing Shape Keys (see kawa_scripts.shapekeys
) and applying Modifiers (see kawa_scripts.modifiers
).
Documentation is not yet finished, sorry. My English is not very good, also sorry.
Downloads, Installation and Contacts
You can find everything related to this on a Github page.
kawa_scripts
distributed as Blender addon.
Addon should work on all verisons of Blender from 2.80, but 2.9x is recommended.
You can find ready-to-install zipped addon on Releases page.
To install you should go Edit > Preferences > Add-ons, click "Install" and select downloaded .zip
archive.
There is no any auto-updaters, if you want to upgrade kawa_scripts
,
you should remove old version and install fresh one.
After installation, you can use all features programmatically without UI
by import kawa_sripts
in Python Console or in .py
text assets.
You can contact me here:
- Discord:
kawashirov#8363
- VRChatRU Discord:
mxHxk3B
- Twitter: @kawashirov
- Github: kawashirov
- VRChat: kawashirov
Please follow and support me on ko-fi too ❤
Features
TODO ¯_(ツ)_/¯
How to use. Example of VRChat world: Russian Apartament: Хрущевка
My world "Russian Apartament: Хрущевка" for VRChat uses this addon for baking large hierarchy of objects and 400+ materials into few combined objects and single 4K x 4K PBR atlas!
And every time I change something in my project I don't need to set up anything: just
running building script bake2.py
,
waiting a few minutes, and my .fbx
+ .png
atlases are ready to be put into Unity project.
You can use this building script as reference. Most of the features in kawa_scripts
I implemented for my projects, especially this one.
There is some utility functions in bake2.py
, but main are make_working_hierarchy
and make_atlas
.
First one, make_working_hierarchy
Does the following:
- Duplicates entire hierarchy of raw Objects into separate scene.
- Applies proper objects naming to duplicated hierarchy.
- Instantiates all collections (with proper objects naming).
- Makes single-user objects
- Converts non-mesh (Curves) objects into mesh-objects
- Instantiates all material slots (Object-overrides)
- Applies all modifiers of Objects.
- Applies all transform scales
- Combines some parts of hierarchy with a lots of small objects into few large objects.
All these complex operations made using BaseInstantiator
and BaseMeshCombiner
.
For example this complex hierarchy:
flattens to this:
Second one, make_atlas
Packs most of the materials into large texture atlas:
(Image scaled down to 2k because of hosting limits.)
There is almost full support of PBR layers such as Normals, Metallic, Smoothness, Emission. Atlas is baked using Blender's bake features, so you can build own complex PBR materials using Cycles shader nodes and bake them together with other materials into same texture atlas.
Expand source code
# Kawashirov's Scripts (c) 2019 by Sergey V. Kawashirov
#
# Kawashirov's Scripts is licensed under a
# Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License.
#
# You should have received a copy of the license along with this
# work. If not, see <http://creativecommons.org/licenses/by-nc-sa/3.0/>.
#
#
"""
`kawa_scripts` is an addon and package of useful methods for **Blender 2.8x+**
made by Kawashirov.
It's designed to use mostly form Python interactive console or from Python scripts.
Basically this addon provides powerful tool for making fully-automated script
for preparing, finalizing and baking lots of raw parts (Objects, Meshes, Modifiers, Materials)
into few export-ready assets.
Besides internal API for building, there is a few useful operators,
especially for editing Shape Keys (see `shapekeys`) and applying Modifiers (see `modifiers`).
**Documentation is not yet finished, sorry.**
**My English is not very good, also sorry.**
.. include:: ./documentation.md
"""
from collections import OrderedDict as _OrderedDict
import typing as _typing
if _typing.TYPE_CHECKING:
from types import ModuleType
from typing import Dict
# Эти итак заимпортированы через __import__ но PyCharm их не видит
from . import shapekeys, commons, modifiers, vertex_groups
bl_info = {
"name": "Kawashirov's Scripts",
"author": "Sergey V. Kawashirov",
"description": "Kawashirov's Scripts for Unity and VRChat content creation",
"location": "There is no UI. Use it from scripts or console by `import kawa_scripts` (or whatever)",
"wiki_url": "",
"version": (2021, 8, 14),
"blender": (2, 83, 0),
"category": "Object",
}
addon_name = __name__
if "bpy" in locals() and "_modules_loaded" in locals():
from importlib import reload
print("Reloading Kawashirov's Scripts...")
for key, mod in list(_modules_loaded.items()):
print("Reloading {0}...".format(repr(mod)))
_modules_loaded[key] = reload(mod)
del reload
print("Reloaded Kawashirov's Scripts!")
_modules = [
"_internals",
"atlas_baker",
"combiner",
"commons",
"instantiator",
"modifiers",
"reporter",
"shader_nodes",
"shapekeys",
"tex_size_finder",
"uv",
"vertex_groups",
]
import bpy
__import__(name=__name__, fromlist=_modules)
_namespace = globals()
_modules_loaded = _OrderedDict() # type: Dict[str, ModuleType]
for _mod_name in _modules:
_modules_loaded[_mod_name] = _namespace.get(_mod_name)
del _namespace
from ._internals import log
def _shape_key_edit_mode_context_menu(self, context):
self.layout.separator() # EDIT-mode select
self.layout.operator(shapekeys.OperatorSelectVerticesAffectedByShapeKey.bl_idname, icon='VERTEXSEL')
self.layout.separator() # EDIT-mode revert
self.layout.operator(shapekeys.OperatorRevertSelectedInActiveToBasis.bl_idname, icon='KEY_DEHLT')
self.layout.operator(shapekeys.OperatorRevertSelectedInAllToBasis.bl_idname, icon='KEY_DEHLT')
self.layout.separator() # EDIT-mode apply
self.layout.operator(shapekeys.OperatorApplySelectedInActiveToBasis.bl_idname, icon='KEYINGSET')
self.layout.operator(shapekeys.OperatorApplySelectedInActiveToAll.bl_idname, icon='KEYINGSET')
def _shape_key_object_mode_context_menu(self, context):
self.layout.separator() # OBJECT-mode apply
self.layout.operator(shapekeys.OperatorApplyActiveToBasis.bl_idname, icon='KEYINGSET')
self.layout.operator(shapekeys.OperatorApplyActiveToAll.bl_idname, icon='KEYINGSET')
self.layout.separator() # OBJECT-mode clean
self.layout.operator(shapekeys.OperatorCleanupActive.bl_idname, icon='KEY_DEHLT')
self.layout.operator(shapekeys.OperatorCleanupAll.bl_idname, icon='KEY_DEHLT')
self.layout.operator(shapekeys.OperatorRemoveEmpty.bl_idname, icon='KEY_DEHLT')
# # #
class _MESH_MT_shape_key_context_kawa_sub_menu(bpy.types.Menu):
bl_label = "Kawashirov"
bl_idname = "MESH_MT_shape_key_context_kawa_sub_menu"
def draw(self, context):
_shape_key_edit_mode_context_menu(self, context)
_shape_key_object_mode_context_menu(self, context)
def _MESH_MT_shape_key_context_menu(self, context):
self.layout.menu(_MESH_MT_shape_key_context_kawa_sub_menu.bl_idname)
# # #
def _MESH_MT_vertex_group_context_menu(self, context):
self.layout.separator()
self.layout.operator(vertex_groups.OperatorRemoveEmpty.bl_idname, icon='X')
# # #
class _VIEW3D_MT_object_kawa_sub_menu(bpy.types.Menu):
bl_label = "Kawashirov"
bl_idname = "VIEW3D_MT_object_kawa_sub_menu"
def draw(self, context):
self.layout.separator() # transforms
self.layout.operator(commons.KawaApplyParentInverseMatrices.bl_idname, icon='ORIENTATION_LOCAL')
self.layout.separator() # modifiers
self.layout.operator(modifiers.KawaApplyDeformModifierHighPrecision.bl_idname, icon='MODIFIER')
self.layout.operator(modifiers.KawaApplyAllModifiersHighPrecision.bl_idname, icon='MODIFIER')
self.layout.operator(modifiers.KawaApplyArmatureToMeshesHighPrecision.bl_idname, icon='ARMATURE_DATA')
_shape_key_object_mode_context_menu(self, context)
self.layout.separator() # vertex groups
self.layout.operator(vertex_groups.OperatorRemoveEmpty.bl_idname, icon='X')
def _VIEW3D_MT_object(self, context):
self.layout.menu(_VIEW3D_MT_object_kawa_sub_menu.bl_idname)
# # #
class _VIEW3D_MT_edit_mesh_kawa_sub_menu(bpy.types.Menu):
bl_label = "Kawashirov"
bl_idname = "VIEW3D_MT_edit_mesh_kawa_sub_menu"
def draw(self, context):
_shape_key_edit_mode_context_menu(self, context)
def _VIEW3D_MT_edit_mesh_vertices(self, context):
self.layout.menu(_VIEW3D_MT_edit_mesh_kawa_sub_menu.bl_idname)
def _VIEW3D_MT_edit_mesh_context_menu(self, context):
self.layout.menu(_VIEW3D_MT_edit_mesh_kawa_sub_menu.bl_idname)
# # #
def register():
print("Hello from {0}!".format(__name__))
import logging
from datetime import datetime
log.py_log.setLevel(logging.DEBUG)
if len(log.py_log.handlers) < 1:
import tempfile
print("Updating kawa_scripts log handler!")
log_file = tempfile.gettempdir() + '/' + datetime.now().strftime("%Y-%m-%d-%H-%M-%S") + '-kawa.log'
log_formatter = logging.Formatter(fmt='[%(asctime)s][%(levelname)s] %(message)s')
log_handler = logging.FileHandler(log_file, mode='w', encoding='utf-8', delay=False)
log_handler.setFormatter(log_formatter)
log.py_log.addHandler(log_handler)
log.info("Log handler updated!")
from bpy.utils import register_class
for mod in _modules_loaded.values():
if mod and hasattr(mod, 'classes'):
for cls in mod.classes:
register_class(cls)
bpy.utils.register_class(_MESH_MT_shape_key_context_kawa_sub_menu)
bpy.utils.register_class(_VIEW3D_MT_object_kawa_sub_menu)
bpy.utils.register_class(_VIEW3D_MT_edit_mesh_kawa_sub_menu)
bpy.types.VIEW3D_MT_object.append(_VIEW3D_MT_object)
bpy.types.VIEW3D_MT_object_context_menu.append(_VIEW3D_MT_object)
bpy.types.VIEW3D_MT_edit_mesh_context_menu.append(_VIEW3D_MT_edit_mesh_context_menu)
bpy.types.VIEW3D_MT_edit_mesh_vertices.append(_VIEW3D_MT_edit_mesh_vertices)
bpy.types.MESH_MT_shape_key_context_menu.append(_MESH_MT_shape_key_context_menu)
bpy.types.MESH_MT_vertex_group_context_menu.append(_MESH_MT_vertex_group_context_menu)
log.info("Hello from {0} once again!".format(__name__))
def unregister():
from bpy.utils import unregister_class
bpy.types.VIEW3D_MT_object.remove(_VIEW3D_MT_object)
bpy.types.VIEW3D_MT_object_context_menu.remove(_VIEW3D_MT_object)
bpy.types.VIEW3D_MT_edit_mesh_context_menu.remove(_VIEW3D_MT_edit_mesh_context_menu)
bpy.types.VIEW3D_MT_edit_mesh_vertices.remove(_VIEW3D_MT_edit_mesh_vertices)
bpy.types.MESH_MT_shape_key_context_menu.remove(_MESH_MT_shape_key_context_menu)
bpy.types.MESH_MT_vertex_group_context_menu.remove(_MESH_MT_vertex_group_context_menu)
bpy.utils.unregister_class(_MESH_MT_shape_key_context_kawa_sub_menu)
bpy.utils.unregister_class(_VIEW3D_MT_object_kawa_sub_menu)
bpy.utils.unregister_class(_VIEW3D_MT_edit_mesh_kawa_sub_menu)
for mod in reversed(_modules_loaded.values()):
if hasattr(mod, 'classes'):
for cls in reversed(mod.classes):
if cls.is_registered:
unregister_class(cls)
log.info("Goodbye from {0}...".format(__name__))
__pdoc__ = dict()
__pdoc__['register'] = False
__pdoc__['unregister'] = False
Sub-modules
kawa_scripts.atlas_baker
-
Tool for baking a lots of PBR materials on a lots of Objects into single texture atlas. See
BaseAtlasBaker
. kawa_scripts.combiner
-
Tool for combining few objects into single one. See
BaseMeshCombiner
. kawa_scripts.commons
kawa_scripts.instantiator
kawa_scripts.modifiers
kawa_scripts.reporter
kawa_scripts.shader_nodes
kawa_scripts.shapekeys
-
Useful tools for Shape Keys …
kawa_scripts.tex_size_finder
-
Tool for figuring out a texture size of material. See
TexSizeFinder
. kawa_scripts.uv
-
Useful tools for UV Layers
kawa_scripts.vertex_groups
-
Useful tools for Vertex Groups