Skip to content

Commit

Permalink
Update to 0.16.0
Browse files Browse the repository at this point in the history
Update to 0.16.0
  • Loading branch information
Darkblader24 authored Nov 23, 2019
2 parents bb382b1 + 47839df commit 5306d62
Show file tree
Hide file tree
Showing 31 changed files with 688 additions and 352 deletions.
95 changes: 36 additions & 59 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Cats Blender Plugin (0.15.0)
# Cats Blender Plugin (0.16.0)

A tool designed to shorten steps needed to import and optimize models into VRChat.
Compatible models are: MMD, XNALara, Mixamo, Source Engine, Unreal Engine, DAZ/Poser, Blender Rigify, Sims 2, Motion Builder, 3DS Max and potentially more
Expand Down Expand Up @@ -35,7 +35,7 @@ Join our Discord to report errors, suggestions and make comments!
**Discord: https://discord.gg/f8yZGnv**

## Requirements
- Blender **2.79** or **2.80** (run as administrator is recommended)
- Blender **2.79** or **2.80** or **2.81** (run as administrator is recommended)
- mmd_tools is **no longer required**! Cats comes pre-installed with it!
- If you have custom Python installed which Blender might use, you need to have Numpy installed

Expand Down Expand Up @@ -280,50 +280,6 @@ This works by checking all bones and trying to figure out if they can be grouped
- Starts the merge process


## Copy Protection

![](https://i.imgur.com/5qP5bCT.png)

**Can protect your avatars from being ripped from the game cache.**
Game cache rips in most common cases do not include blendshapes and shaders.
This method will make it much harder for people that try to steal your avatar through ripping from cache.

**This is NOT a 100% protection**, but it's the best what you as a creator can currently do. If you want to be 100% safe, stay in private worlds with people you trust.

#### How to setup:

1. Do all the modifications to your model in Blender before you follow the next steps!
This option should be the last one you do in Blender before exporting!
2. You won't be able to see the mesh of your model inside the Unity bone mapping screen (it will be garbled mess, but only in there).
Because of that, if you need to actually see your models mesh (e.g. for straightening the fingers for VR), follow the extra steps below.
If you don't need to see the mesh (e.g. for unassigning the jaw bone) skip to step 2.
- Export your model from Blender without enabling the protection
- Load it up in Unity and configure it in the bone mapping screen and press "Done"
- In Blender: Click the "Enable Protection" button and export your model
- Then, except for just dragging the fbx into Unity, you need to go into the folder where this Unity project is located
and then replace the unprotected fbx with the protected one.
That way your configurations will be kept.
- Skip to step 5
3. In Blender: Click the "Enable Protection" button
4. Export it to Unity by either using the "Export" button within Cats or set the fbx export option by yourself:
Geometries > Smoothing > Set to "Face"
5. In Unity: Set the value of the blendshape 'Basis Original' to 100 like so:
https://i.imgur.com/RlrGTvV.gif
6. To fix any lighting issues select your .fbx and then select "Import" as the Tangents option here:

![](https://i.imgur.com/SqynQzw.png)
7. Because (for some odd reason) the protection increases your bounding box it could be too big to upload your model.
If the VRCSDK complains about your model being too large, edit your bounding box back to normal here:
(this option is below the blendshape list from above)

![](https://i.imgur.com/4NrfVOr.png)
8. Your avatar now behaves just like a normal one.

People that try to steal your avatar will then only see a box of mangled waifu trash instead of your original character.

**special thanks to @zarniwoop#6081**


## Shape Key

![](https://i.imgur.com/LgFK4KO.png)
Expand All @@ -342,6 +298,39 @@ It checks for a new version automatically once every day.

## Changelog

#### 0.16.0
- **Cats is now fully compatible with Blender 2.81!**
- **Importer**:
- Added support for ZIP files
- It will only extract the zip if importable models are found
- If multiple models are found in the zip, you can select the one you want in a popup window
- Japanese zip files will be extracted with the correct encoding
- Models can now be imported with Cats via the Windows command shell
- **Fix Model**:
- Hips bone will now be larger than before, to comply with the VRChat recommendations
- Read through them here: https://docs.vrchat.com/docs/full-body-tracking
- FFXIV models are now compatible
- Added "Fix Materials" option in Blender 2.80 and higher
- This will apply some VRChat related fixes to materials
- This has always been done in Fix Model but now you can turn it off
- **Model Options**:
- Remove Doubles no longer effects meshes with no shapekeys
- **Custom Model Creation**:
- Added "Join Meshes" option
- Merge Armatures and Attach Mesh no longer require a mesh on the armature
- Fixed bones from the merge armature sometimes getting unintentionally deleted
- **Optimization**:
- Added manual download button if Material Combiner is outdated
- **Copy Protection**:
- Removed Copy Protection panel
- It is no longer a good method for protecting against cache ripping
and it can cause performance and lighting issues
- **General**:
- Armatures will no longer be forced into rest position after any action
- Fixed armatures sometimes not getting detected
- Small bug fixes
- Updated mmd_tools

#### 0.15.0
- **Importer**:
- FBX no longer imports animations and poses by default
Expand All @@ -350,7 +339,7 @@ It checks for a new version automatically once every day.
- Added "Keep Upper Chest" option
- Warning: Currently having an Upper Chest breaks Eye Tracking, so don't use this if you want Eye Tracking
- Removed "Fix Full Body Tracking" option
- It is no longer needed for VrChat
- It is no longer needed for VRChat
- The button to add/remove the fix is still available in Model Options
- Improved Hips placement as recommended by VRChat
- Legs are now getting bend forward very slightly if they are completely straight
Expand Down Expand Up @@ -399,18 +388,6 @@ It checks for a new version automatically once every day.
- Fixed a bug while loading settings during startup
- Fixed a bug while loading the initial state after an operation

#### 0.13.3
- **Importer**:
- Fixed imported armatures being in edit mode
- **Custom Model Creation**:
- Merge Armatures now properly merges bones when the vertex group of one of the merging bones is missing
- Attach Mesh no longer removes zero weight bones and constraints
- **Model Options**:
- Fixed error when switching to object mode during pose mode
- **General**:
- Updated mmd_tools
- The Blender 2.80 API is stable now, so Cats should no longer break in 2.80

Read the full changelog [here](https://github.com/michaeldegroot/cats-blender-plugin/releases).


Expand Down
8 changes: 4 additions & 4 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
'author': 'GiveMeAllYourCats & Hotox',
'location': 'View 3D > Tool Shelf > CATS',
'description': 'A tool designed to shorten steps needed to import and optimize models into VRChat',
'version': (0, 15, 0), # Has to be (x, x, x) not [x, x, x]!! # Only change this version and the dev branch var right before publishing the new update!
'version': (0, 16, 0), # Has to be (x, x, x) not [x, x, x]!! # Only change this version and the dev branch var right before publishing the new update!
'blender': (2, 80, 0),
'wiki_url': 'https://github.com/michaeldegroot/cats-blender-plugin',
'tracker_url': 'https://github.com/michaeldegroot/cats-blender-plugin/issues',
Expand Down Expand Up @@ -206,11 +206,11 @@ def remove_corrupted_files():


def check_unsupported_blender_versions():
# Don't allow Blender versions older than 2.75
if bpy.app.version < (2, 75):
# Don't allow Blender versions older than 2.79
if bpy.app.version < (2, 79):
unregister()
sys.tracebacklimit = 0
raise ImportError('\n\nBlender versions older than 2.75 are not supported by Cats. '
raise ImportError('\n\nBlender versions older than 2.79 are not supported by Cats. '
'\nPlease use Blender 2.79 or later.'
'\n')

Expand Down
20 changes: 20 additions & 0 deletions extentions.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .tools import eyetracking as Eyetracking
from .tools import rootbone as Rootbone
from .tools import settings as Settings
from .tools import importer as Importer

from bpy.types import Scene, Material
from bpy.props import BoolProperty, EnumProperty, FloatProperty, IntProperty, CollectionProperty
Expand All @@ -16,6 +17,12 @@ def register():
update=Common.update_material_list
)

Scene.zip_content = EnumProperty(
name='Zip Content',
description='Select the model you want to import',
items=Importer.get_zip_content
)

Scene.keep_upper_chest = BoolProperty(
name='Keep Upper Chest',
description="VrChat now partially supports the Upper Chest bone, so deleting it is no longer necessary."
Expand Down Expand Up @@ -68,6 +75,12 @@ def register():
default=True
)

Scene.fix_materials = BoolProperty(
name='Fix Materials',
description="This will apply some VRChat related fixes to materials",
default=True
)

Scene.use_google_only = BoolProperty(
name='Use Old Translations (not recommended)',
description="Ignores the internal dictionary and only uses the Google Translator for shape key translations."
Expand Down Expand Up @@ -136,6 +149,13 @@ def register():
default=False
)

Scene.merge_armatures_join_meshes = BoolProperty(
name='Join Meshes',
description='This will join all meshes.'
'\nNot checking this will always apply transforms',
default=True
)

# Decimation
Scene.decimation_mode = EnumProperty(
name="Decimation Mode",
Expand Down
2 changes: 2 additions & 0 deletions extern_tools/mmd_tools_local/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,10 +124,12 @@ def register():
bpy.types.INFO_MT_file_import.append(menu_func_import)
bpy.types.INFO_MT_file_export.append(menu_func_export)
bpy.types.INFO_MT_armature_add.append(menu_func_armature)
#bpy.context.user_preferences.system.use_scripts_auto_execute = True
else:
bpy.types.TOPBAR_MT_file_import.append(menu_func_import)
bpy.types.TOPBAR_MT_file_export.append(menu_func_export)
bpy.types.VIEW3D_MT_armature_add.append(menu_func_armature)
#bpy.context.preferences.filepaths.use_scripts_auto_execute = True

def unregister():
if bpy.app.version < (2, 80, 0):
Expand Down
9 changes: 5 additions & 4 deletions extern_tools/mmd_tools_local/core/bone.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,10 +228,11 @@ def has_auto_local_axis(cls, name_j):
return False

@staticmethod
def patch_rna_idprop(pose_bones): # workaround for Rigify conflicts
from rna_prop_ui import rna_idprop_ui_get
for b in pose_bones:
rna_idprop_ui_get(b, create=True)
def patch_rna_idprop(pose_bones):
if bpy.app.version < (2, 81, 0): # workaround for Rigify conflicts (fixed in Blender 2.81)
from rna_prop_ui import rna_idprop_ui_get
for b in pose_bones:
rna_idprop_ui_get(b, create=True)

@classmethod
def clean_additional_transformation(cls, armature):
Expand Down
1 change: 0 additions & 1 deletion extern_tools/mmd_tools_local/core/camera.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,6 @@ def __add_ortho_driver(id_data, data_path, expression, index=-1):
target.data_path = 'data.type'
expression = expression.replace('$type', var.name)
d.driver.expression = expression
#bpy.context.user_preferences.system.use_scripts_auto_execute = True
__add_ortho_driver(cameraObj.data, 'ortho_scale', '25*(-$dis if $dis<0 else $dis)/45')
__add_ortho_driver(cameraObj, 'rotation_euler', 'pi if $type == 1 and $dis > 1e-5 else 0', index=1)

Expand Down
93 changes: 79 additions & 14 deletions extern_tools/mmd_tools_local/core/material.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,15 @@ def from_material_id(cls, material_id):
return cls(material)
return None

@classmethod
def clean_materials(cls, obj, can_remove):
materials = obj.data.materials
materials_pop = (lambda index: materials.pop(index=index, update_data=True)) if bpy.app.version < (2, 81, 0) else materials.pop
for i in sorted((x for x, m in enumerate(materials) if can_remove(m)), reverse=True):
m = materials_pop(index=i)
if m.users < 1:
bpy.data.materials.remove(m)

@classmethod
def swap_materials(cls, meshObj, mat1_ref, mat2_ref, reverse=False,
swap_slots=False):
Expand Down Expand Up @@ -369,6 +378,25 @@ def update_edge_color(self):
def update_edge_weight(self):
pass

@staticmethod
def convert_to_mmd_material(material):
m, mmd_material = material, material.mmd_material

map_diffuse = next((s.blend_type for s in m.texture_slots if s and s.use_map_color_diffuse), None)
use_diffuse = map_diffuse in {None, 'MULTIPLY'}
diffuse = m.diffuse_color*min(1.0, m.diffuse_intensity/0.8) if use_diffuse else (1.0, 1.0, 1.0)
mmd_material.diffuse_color = diffuse

map_alpha = next((s.blend_type for s in m.texture_slots if s and s.use_map_alpha), None)
if m.use_transparency and map_alpha in {None, 'MULTIPLY'}:
mmd_material.alpha = m.alpha

mmd_material.specular_color = m.specular_color*min(1.0, m.specular_intensity/0.8)
mmd_material.shininess = m.specular_hardness
mmd_material.is_double_sided = m.game_settings.use_backface_culling
mmd_material.enabled_self_shadow_map = m.use_cast_buffer_shadows and m.alpha > 1e-3
mmd_material.enabled_self_shadow = m.use_shadows


class _DummyTexture:
def __init__(self, image):
Expand Down Expand Up @@ -525,7 +553,7 @@ def update_shininess(self):
mmd_mat = mat.mmd_material
mat.roughness = 1/pow(max(mmd_mat.shininess, 1), 0.37)
if hasattr(mat, 'metallic'):
mat.metallic = 1 - mat.roughness
mat.metallic = pow(1 - mat.roughness, 2.7)
if hasattr(mat, 'specular_hardness'):
mat.specular_hardness = mmd_mat.shininess
self.__update_shader_input('Reflect', mmd_mat.shininess)
Expand All @@ -551,6 +579,36 @@ def update_self_shadow(self):
mmd_mat = mat.mmd_material
self.__update_shader_input('Self Shadow', mmd_mat.enabled_self_shadow)

@staticmethod
def convert_to_mmd_material(material):
m, mmd_material = material, material.mmd_material

if m.use_nodes and next((n for n in m.node_tree.nodes if n.name.startswith('mmd_')), None) is None:
tex_node = next((n for n in m.node_tree.nodes if n.bl_idname == 'ShaderNodeTexImage'), None)
if tex_node:
tex_node.name = 'mmd_base_tex'

mmd_material.diffuse_color = m.diffuse_color[:3]
if hasattr(m, 'alpha'):
mmd_material.alpha = m.alpha
elif len(m.diffuse_color) > 3:
mmd_material.alpha = m.diffuse_color[3]

mmd_material.specular_color = m.specular_color
if hasattr(m, 'specular_hardness'):
mmd_material.shininess = m.specular_hardness
else:
mmd_material.shininess = pow(1/max(m.roughness, 0.099), 1/.37)

if hasattr(m, 'game_settings'):
mmd_material.is_double_sided = not m.game_settings.use_backface_culling
elif hasattr(m, 'use_backface_culling'):
mmd_material.is_double_sided = not m.use_backface_culling

if hasattr(m, 'shadow_method'):
mmd_material.enabled_self_shadow_map = (m.shadow_method != 'NONE') and mmd_material.alpha > 1e-3
mmd_material.enabled_self_shadow = (m.shadow_method != 'NONE')


def __update_shader_input(self, name, val):
mat = self.material
Expand All @@ -570,6 +628,7 @@ def __update_shader_nodes(self):
from mathutils import Vector
nodes, links = mat.node_tree.nodes, mat.node_tree.links

class _Dummy: default_value, is_linked = None, True
node_shader = nodes.get('mmd_shader', None)
if node_shader is None:
node_shader = nodes.new('ShaderNodeGroup')
Expand All @@ -579,12 +638,13 @@ def __update_shader_nodes(self):
node_shader.node_tree = self.__get_shader()

mmd_mat = mat.mmd_material
node_shader.inputs['Ambient Color'].default_value = mmd_mat.ambient_color[:] + (1,)
node_shader.inputs['Diffuse Color'].default_value = mmd_mat.diffuse_color[:] + (1,)
node_shader.inputs['Specular Color'].default_value = mmd_mat.specular_color[:] + (1,)
node_shader.inputs['Alpha'].default_value = mmd_mat.alpha
node_shader.inputs['Reflect'].default_value = mmd_mat.shininess
node_shader.inputs['Double Sided'].default_value = mmd_mat.is_double_sided
node_shader.inputs.get('Ambient Color', _Dummy).default_value = mmd_mat.ambient_color[:] + (1,)
node_shader.inputs.get('Diffuse Color', _Dummy).default_value = mmd_mat.diffuse_color[:] + (1,)
node_shader.inputs.get('Specular Color', _Dummy).default_value = mmd_mat.specular_color[:] + (1,)
node_shader.inputs.get('Reflect', _Dummy).default_value = mmd_mat.shininess
node_shader.inputs.get('Alpha', _Dummy).default_value = mmd_mat.alpha
node_shader.inputs.get('Double Sided', _Dummy).default_value = mmd_mat.is_double_sided
node_shader.inputs.get('Self Shadow', _Dummy).default_value = mmd_mat.enabled_self_shadow

node_uv = nodes.get('mmd_tex_uv', None)
if node_uv is None:
Expand All @@ -604,12 +664,13 @@ def __update_shader_nodes(self):
for name_id in ('Base', 'Toon', 'Sphere'):
texture = self.__get_texture_node('mmd_%s_tex'%name_id.lower())
if texture:
if not texture.outputs['Color'].is_linked:
links.new(texture.outputs['Color'], node_shader.inputs[name_id+' Tex'])
if not texture.outputs['Alpha'].is_linked:
links.new(texture.outputs['Alpha'], node_shader.inputs[name_id+' Alpha'])
name_tex_in, name_alpha_in, name_uv_out = (name_id+x for x in (' Tex', ' Alpha', ' UV'))
if not node_shader.inputs.get(name_tex_in, _Dummy).is_linked:
links.new(texture.outputs['Color'], node_shader.inputs[name_tex_in])
if not node_shader.inputs.get(name_alpha_in, _Dummy).is_linked:
links.new(texture.outputs['Alpha'], node_shader.inputs[name_alpha_in])
if not texture.inputs['Vector'].is_linked:
links.new(node_uv.outputs[name_id+' UV'], texture.inputs['Vector'])
links.new(node_uv.outputs[name_uv_out], texture.inputs['Vector'])

def __get_shader_uv(self):
group_name = 'MMDTexUV'
Expand Down Expand Up @@ -647,8 +708,12 @@ def __new_io(shader_io, io_sockets, io_name, socket):

node_vector = __new_node('ShaderNodeMapping', (2, -1))
node_vector.vector_type = 'POINT'
node_vector.translation = (0.5, 0.5, 0.0)
node_vector.scale = (0.5, 0.5, 1.0)
if bpy.app.version < (2, 81, 0):
node_vector.translation = (0.5, 0.5, 0.0)
node_vector.scale = (0.5, 0.5, 1.0)
else:
node_vector.inputs['Location'].default_value = (0.5, 0.5, 0.0)
node_vector.inputs['Scale'].default_value = (0.5, 0.5, 1.0)

links.new(tex_coord.outputs['Normal'], vec_trans.inputs['Vector'])
links.new(vec_trans.outputs['Vector'], node_vector.inputs['Vector'])
Expand Down
Loading

0 comments on commit 5306d62

Please sign in to comment.