mirror of
https://gitlab.com/ProcyonLotor/vrchat-template.git
synced 2026-08-25 18:53:53 +05:00
Compare commits
20 Commits
308c7bd793
...
project-st
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
36a4cd76b1 | ||
|
|
01f42bcce5 | ||
|
|
47a346551c | ||
|
|
0fcc132eac | ||
|
|
acc87b4b09 | ||
|
|
89d3c504e6 | ||
|
|
fb5a718243 | ||
|
|
8f6a83b86f | ||
|
|
0f37a5a02c | ||
|
|
27c93c3e29 | ||
|
|
6c7f9e5493 | ||
|
|
5a270289f0 | ||
|
|
a01ccf03ce | ||
|
|
c2e20e8aa7 | ||
|
|
9bc6821b6d | ||
|
|
821a60251c | ||
|
|
b1690c7a57 | ||
|
|
3fd6371608 | ||
|
|
957768b38a | ||
|
|
255858a478 |
1
Assets/avatar-example/3rdparty/Mochie/MochieStandard.shader
vendored
Normal file
1
Assets/avatar-example/3rdparty/Mochie/MochieStandard.shader
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/3rdparty/Poiyomi/PoiyomiToon.shader
vendored
Normal file
1
Assets/avatar-example/3rdparty/Poiyomi/PoiyomiToon.shader
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/action/backflip.anim
Normal file
1
Assets/avatar-example/animations/action/backflip.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/action/conga.anim
Normal file
1
Assets/avatar-example/animations/action/conga.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/action/dance.anim
Normal file
1
Assets/avatar-example/animations/action/dance.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/action/high-five.anim
Normal file
1
Assets/avatar-example/animations/action/high-five.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/expressions/happy.anim
Normal file
1
Assets/avatar-example/animations/expressions/happy.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/expressions/mad.anim
Normal file
1
Assets/avatar-example/animations/expressions/mad.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/toggles/pants-off.anim
Normal file
1
Assets/avatar-example/animations/toggles/pants-off.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/toggles/pants-on.anim
Normal file
1
Assets/avatar-example/animations/toggles/pants-on.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/toggles/shirt-off.anim
Normal file
1
Assets/avatar-example/animations/toggles/shirt-off.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/toggles/shirt-on.anim
Normal file
1
Assets/avatar-example/animations/toggles/shirt-on.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/toggles/shoes-off.anim
Normal file
1
Assets/avatar-example/animations/toggles/shoes-off.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/animations/toggles/shoes-on.anim
Normal file
1
Assets/avatar-example/animations/toggles/shoes-on.anim
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/materials/body.mat
Normal file
1
Assets/avatar-example/materials/body.mat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/materials/body.mat.meta
Normal file
1
Assets/avatar-example/materials/body.mat.meta
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/materials/outfit1.mat
Normal file
1
Assets/avatar-example/materials/outfit1.mat
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/materials/outfit1.mat.meta
Normal file
1
Assets/avatar-example/materials/outfit1.mat.meta
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
72
Assets/avatar-example/mesh/blend~/add_setup_triplanar.py
Normal file
72
Assets/avatar-example/mesh/blend~/add_setup_triplanar.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
from math import pi
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
from bpy.types import Context, Operator
|
||||||
|
|
||||||
|
|
||||||
|
def create_triplanar_setup(context: Context) -> None:
|
||||||
|
"""
|
||||||
|
Creates triplanar setup - a mesh cube with UVProject modifier and 6 UV projectors
|
||||||
|
|
||||||
|
:param context: Current context
|
||||||
|
:type context: bpy.types.Context
|
||||||
|
"""
|
||||||
|
bpy.ops.object.empty_add(type='CUBE', radius=1.6, location=(1.6, 1.6, 1.6), rotation=(0, 0, 0))
|
||||||
|
anchor_empty = context.active_object
|
||||||
|
anchor_empty.name = "UV_anchor"
|
||||||
|
|
||||||
|
bpy.ops.mesh.primitive_cube_add(radius=1, calc_uvs=True)
|
||||||
|
cube_obj = context.active_object
|
||||||
|
|
||||||
|
bpy.ops.object.modifier_add(type='UV_PROJECT')
|
||||||
|
uv_mod = cube_obj.modifiers["UVProject"]
|
||||||
|
|
||||||
|
rotations_list = [
|
||||||
|
("top", (0, 0, 0)),
|
||||||
|
("front", (pi/2, 0, 0)),
|
||||||
|
("back", (pi/2, 0, pi)),
|
||||||
|
("left", (pi/2, 0, pi/2)),
|
||||||
|
("right", (pi/2, 0, -pi/2)),
|
||||||
|
("bottom", (pi, 0, 0)),
|
||||||
|
]
|
||||||
|
|
||||||
|
uv_mod.projector_count = len(rotations_list)
|
||||||
|
|
||||||
|
for i, (name, rotation) in enumerate(rotations_list):
|
||||||
|
bpy.ops.object.empty_add(type='SINGLE_ARROW', radius=1.6, location=(0, 0, 0), rotation=rotation)
|
||||||
|
uv_projector = context.active_object
|
||||||
|
uv_projector.name = "UV_%s" % name
|
||||||
|
uv_projector.parent = anchor_empty
|
||||||
|
uv_mod.projectors[i].object = uv_projector
|
||||||
|
|
||||||
|
|
||||||
|
class MESH_OT_AddTriplanarSetup(Operator):
|
||||||
|
bl_idname = "mesh.setup_triplanar_add"
|
||||||
|
bl_label = "Triplanar UV Setup"
|
||||||
|
bl_options = {'REGISTER', 'UNDO'}
|
||||||
|
|
||||||
|
def execute(self, context: Context):
|
||||||
|
try:
|
||||||
|
create_triplanar_setup(context)
|
||||||
|
except Exception as e:
|
||||||
|
self.report({'ERROR'}, str(e))
|
||||||
|
return {'CANCELLED'}
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
def draw_triplanar_setup(self, context):
|
||||||
|
self.layout.operator(MESH_OT_AddTriplanarSetup.bl_idname, icon='MOD_UVPROJECT')
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
bpy.utils.register_class(MESH_OT_AddTriplanarSetup)
|
||||||
|
if draw_triplanar_setup.__name__ not in [f.__name__ for f in bpy.types.INFO_MT_mesh_add._dyn_ui_initialize()]:
|
||||||
|
bpy.types.INFO_MT_mesh_add.append(draw_triplanar_setup)
|
||||||
|
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.types.INFO_MT_mesh_add.remove(draw_triplanar_setup)
|
||||||
|
bpy.utils.unregister_class(MESH_OT_AddTriplanarSetup)
|
||||||
|
|
||||||
|
|
||||||
|
register()
|
||||||
BIN
Assets/avatar-example/mesh/blend~/blender-setup-example.blend
LFS
Normal file
BIN
Assets/avatar-example/mesh/blend~/blender-setup-example.blend
LFS
Normal file
Binary file not shown.
288
Assets/avatar-example/mesh/blend~/fbx_export.py
Normal file
288
Assets/avatar-example/mesh/blend~/fbx_export.py
Normal file
@@ -0,0 +1,288 @@
|
|||||||
|
import os
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
_FUTURE = bpy.app.version >= (2, 80, 0)
|
||||||
|
from bpy.props import BoolProperty, EnumProperty, IntProperty, StringProperty
|
||||||
|
from bpy.types import Context, Operator, Panel, Scene, UIList
|
||||||
|
if _FUTURE:
|
||||||
|
from bpy.types import Collection as Group
|
||||||
|
else:
|
||||||
|
from bpy.types import Group as Group
|
||||||
|
|
||||||
|
|
||||||
|
def message_box(message: str, title: str = "Message", icon: str = 'INFO') -> None:
|
||||||
|
"""Shows modal window with a message
|
||||||
|
|
||||||
|
:param message: Message text
|
||||||
|
:param title: Window title
|
||||||
|
:param icon: Window icon
|
||||||
|
"""
|
||||||
|
def draw(self, context):
|
||||||
|
col = self.layout.column(align=True)
|
||||||
|
for line in message.strip().split("\n"):
|
||||||
|
col.label(text=line)
|
||||||
|
bpy.context.window_manager.popup_menu(draw, title=title, icon=icon)
|
||||||
|
|
||||||
|
|
||||||
|
def name_as_path(name: str) -> str:
|
||||||
|
"""Converts and sanitizes an arbitrary string to a canonical path with OS-specific separator
|
||||||
|
|
||||||
|
:param name: Some name
|
||||||
|
:returns: Canonical path
|
||||||
|
"""
|
||||||
|
return os.path.join(*[bpy.path.clean_name(n) for n in name.replace("\\", "/").split("/") if n]) + ".fbx"
|
||||||
|
|
||||||
|
|
||||||
|
def fbx_export(context: Context) -> None:
|
||||||
|
"""
|
||||||
|
Export all objects Groups to ASCII FBX
|
||||||
|
"""
|
||||||
|
print("[%s] Batch FBX export begin" % datetime.now())
|
||||||
|
|
||||||
|
settings_ascii = dict(
|
||||||
|
# Common
|
||||||
|
version='ASCII6100',
|
||||||
|
axis_forward='-Z',
|
||||||
|
axis_up='Y',
|
||||||
|
global_scale=1.0,
|
||||||
|
object_types=context.scene.fbx_object_types,
|
||||||
|
use_selection=True,
|
||||||
|
# Mesh
|
||||||
|
mesh_smooth_type='FACE',
|
||||||
|
use_mesh_edges=False,
|
||||||
|
use_mesh_modifiers=context.scene.fbx_use_modifiers,
|
||||||
|
use_tspace=False,
|
||||||
|
# Armature
|
||||||
|
add_leaf_bones=False,
|
||||||
|
armature_nodetype='NULL',
|
||||||
|
primary_bone_axis='Y',
|
||||||
|
secondary_bone_axis='X',
|
||||||
|
use_armature_deform_only=True,
|
||||||
|
# Animation
|
||||||
|
use_anim=context.scene.fbx_use_anim,
|
||||||
|
use_default_take=False,
|
||||||
|
# File
|
||||||
|
batch_mode='OFF',
|
||||||
|
path_mode='RELATIVE',
|
||||||
|
)
|
||||||
|
|
||||||
|
settings_binary = dict(
|
||||||
|
# Common
|
||||||
|
version='BIN7400',
|
||||||
|
axis_forward='-Z',
|
||||||
|
axis_up='Y',
|
||||||
|
apply_scale_options='FBX_SCALE_ALL',
|
||||||
|
apply_unit_scale=True,
|
||||||
|
bake_space_transform=True,
|
||||||
|
global_scale=1.0,
|
||||||
|
object_types=context.scene.fbx_object_types,
|
||||||
|
use_custom_props=True,
|
||||||
|
use_selection=True,
|
||||||
|
# Mesh
|
||||||
|
mesh_smooth_type='FACE',
|
||||||
|
use_mesh_edges=False,
|
||||||
|
use_mesh_modifiers=context.scene.fbx_use_modifiers,
|
||||||
|
use_mesh_modifiers_render=True,
|
||||||
|
use_tspace=False,
|
||||||
|
# Armature
|
||||||
|
add_leaf_bones=False,
|
||||||
|
armature_nodetype='NULL',
|
||||||
|
primary_bone_axis='Y',
|
||||||
|
secondary_bone_axis='X',
|
||||||
|
use_armature_deform_only=True,
|
||||||
|
# Animation
|
||||||
|
bake_anim=context.scene.fbx_use_anim,
|
||||||
|
bake_anim_force_startend_keying=True,
|
||||||
|
bake_anim_simplify_factor=1.0,
|
||||||
|
bake_anim_step=1.0,
|
||||||
|
bake_anim_use_all_actions=True,
|
||||||
|
bake_anim_use_all_bones=True,
|
||||||
|
bake_anim_use_nla_strips=True,
|
||||||
|
# File
|
||||||
|
batch_mode='OFF',
|
||||||
|
embed_textures=False,
|
||||||
|
path_mode='RELATIVE',
|
||||||
|
)
|
||||||
|
|
||||||
|
settings = settings_binary if _FUTURE or context.scene.fbx_force_binary else settings_ascii
|
||||||
|
if _FUTURE:
|
||||||
|
settings.pop('version')
|
||||||
|
rootpath = os.path.normpath(bpy.path.abspath(context.scene.fbx_export_dir))
|
||||||
|
groups = bpy.data.collections if _FUTURE else bpy.data.groups
|
||||||
|
override = context.copy()
|
||||||
|
|
||||||
|
for group in [g for g in groups if g.fbx_exportable]:
|
||||||
|
filepath = os.path.join(rootpath, name_as_path(group.name))
|
||||||
|
basepath = os.path.dirname(filepath)
|
||||||
|
|
||||||
|
if not os.path.exists(basepath):
|
||||||
|
os.makedirs(basepath)
|
||||||
|
|
||||||
|
override.update(
|
||||||
|
{
|
||||||
|
"selected_objects": group.objects
|
||||||
|
}
|
||||||
|
)
|
||||||
|
settings.update(
|
||||||
|
{
|
||||||
|
"filepath": filepath
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if bpy.app.version >= (4, 0, 0):
|
||||||
|
with context.temp_override(**override):
|
||||||
|
bpy.ops.export_scene.fbx(**settings)
|
||||||
|
else:
|
||||||
|
bpy.ops.export_scene.fbx(override, **settings)
|
||||||
|
|
||||||
|
print("\n[%s] Batch FBX export end." % datetime.now())
|
||||||
|
|
||||||
|
|
||||||
|
class FBX_OT_ManualExport(Operator):
|
||||||
|
bl_idname = "fbx.manual_export"
|
||||||
|
bl_label = "Manual Export"
|
||||||
|
bl_description = "Export FBX manualy"
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
try:
|
||||||
|
fbx_export(context)
|
||||||
|
except Exception as e:
|
||||||
|
self.report({'ERROR'}, str(e))
|
||||||
|
return {'CANCELLED'}
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class FBX_UL_ExportItems(UIList):
|
||||||
|
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
|
||||||
|
row = layout.row(align=True)
|
||||||
|
row.prop(item, "fbx_exportable", icon='CHECKBOX_HLT' if item.fbx_exportable else 'CHECKBOX_DEHLT', text="", emboss=False)
|
||||||
|
row.prop(item, "name", text="", emboss=False, icon='GROUP')
|
||||||
|
|
||||||
|
|
||||||
|
class SCENE_PT_fbx_autoexport(Panel):
|
||||||
|
"""Creates a Panel in the scene context of the properties editor"""
|
||||||
|
bl_label = "FBX Auto-Export"
|
||||||
|
bl_idname = "SCENE_PT_fbx_autoexport"
|
||||||
|
bl_space_type = 'PROPERTIES'
|
||||||
|
bl_region_type = 'WINDOW'
|
||||||
|
bl_context = "scene"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
scene = context.scene
|
||||||
|
|
||||||
|
col = layout.column()
|
||||||
|
|
||||||
|
split = col.split()
|
||||||
|
sub = split.column()
|
||||||
|
sub.label(text="Filter groups:")
|
||||||
|
sub.template_list("FBX_UL_ExportItems", "", bpy.data, "collections" if _FUTURE else "groups", scene, "fbx_group_index", rows=5)
|
||||||
|
sub = split.column()
|
||||||
|
sub.label(text="Filter object types:")
|
||||||
|
sub.prop(scene, "fbx_object_types")
|
||||||
|
|
||||||
|
col.separator()
|
||||||
|
|
||||||
|
if _FUTURE:
|
||||||
|
col.use_property_split = True
|
||||||
|
col.use_property_decorate = False
|
||||||
|
col.prop(scene, "fbx_on_save")
|
||||||
|
col.prop(scene, "fbx_use_anim")
|
||||||
|
col.prop(scene, "fbx_use_modifiers")
|
||||||
|
if not _FUTURE:
|
||||||
|
col.prop(scene, "fbx_force_binary")
|
||||||
|
|
||||||
|
col.separator()
|
||||||
|
|
||||||
|
col.prop(scene, "fbx_export_dir")
|
||||||
|
col.operator(FBX_OT_ManualExport.bl_idname)
|
||||||
|
|
||||||
|
|
||||||
|
def on_save(*args, **kwargs) -> None:
|
||||||
|
"""
|
||||||
|
Runs when Blender file is being saved
|
||||||
|
"""
|
||||||
|
if not bpy.context.scene.fbx_on_save:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
fbx_export(bpy.context)
|
||||||
|
except Exception as e:
|
||||||
|
message_box(str(e), "Export error", 'ERROR')
|
||||||
|
|
||||||
|
|
||||||
|
classes = [
|
||||||
|
FBX_OT_ManualExport,
|
||||||
|
FBX_UL_ExportItems,
|
||||||
|
SCENE_PT_fbx_autoexport,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def register() -> None:
|
||||||
|
for cls in classes:
|
||||||
|
bpy.utils.register_class(cls)
|
||||||
|
Scene.fbx_export_dir = StringProperty(
|
||||||
|
name="FBX Export Dir",
|
||||||
|
description="FBX Export Directory",
|
||||||
|
subtype="DIR_PATH",
|
||||||
|
default="//../fbx/",
|
||||||
|
)
|
||||||
|
Scene.fbx_on_save = BoolProperty(
|
||||||
|
name="Export on save",
|
||||||
|
description="Export FBX on Blender file save",
|
||||||
|
default=False
|
||||||
|
)
|
||||||
|
Scene.fbx_object_types = EnumProperty(
|
||||||
|
name="Object Types",
|
||||||
|
options={'ENUM_FLAG'},
|
||||||
|
items=(
|
||||||
|
('EMPTY', "Empty", ""),
|
||||||
|
('CAMERA', "Camera", ""),
|
||||||
|
('LAMP', "Lamp", ""),
|
||||||
|
('ARMATURE', "Armature", "WARNING: not supported in dupli/group instances"),
|
||||||
|
('MESH', "Mesh", ""),
|
||||||
|
('OTHER', "Other", "Other geometry types, like curve, metaball, etc. (converted to meshes)"),
|
||||||
|
),
|
||||||
|
description="Which kind of object to export",
|
||||||
|
default={'ARMATURE', 'EMPTY', 'MESH', 'OTHER'},
|
||||||
|
)
|
||||||
|
Scene.fbx_group_index = IntProperty(default=0)
|
||||||
|
Scene.fbx_force_binary = BoolProperty(
|
||||||
|
name="Binary Format",
|
||||||
|
description="Force export FBX file as binary",
|
||||||
|
default=False
|
||||||
|
)
|
||||||
|
Scene.fbx_use_anim = BoolProperty(
|
||||||
|
name="Include Animation",
|
||||||
|
description="Export baked keyframe animation",
|
||||||
|
default=False
|
||||||
|
)
|
||||||
|
Scene.fbx_use_modifiers = BoolProperty(
|
||||||
|
name="Apply Modifiers",
|
||||||
|
description="Apply modifiers to mesh objects.\n** WARNING: Breaks exporting shape keys",
|
||||||
|
default=False,
|
||||||
|
)
|
||||||
|
Group.fbx_exportable = BoolProperty(
|
||||||
|
name="Export Group",
|
||||||
|
description="Mark group as FBX exportable",
|
||||||
|
default=False
|
||||||
|
)
|
||||||
|
bpy.app.handlers.save_pre.append(on_save)
|
||||||
|
|
||||||
|
|
||||||
|
def unregister() -> None:
|
||||||
|
bpy.app.handlers.save_pre.remove(on_save)
|
||||||
|
del Group.fbx_exportable
|
||||||
|
del Scene.fbx_use_modifiers
|
||||||
|
del Scene.fbx_use_anim
|
||||||
|
del Scene.fbx_force_binary
|
||||||
|
del Scene.fbx_group_index
|
||||||
|
del Scene.fbx_object_types
|
||||||
|
del Scene.fbx_on_save
|
||||||
|
del Scene.fbx_export_dir
|
||||||
|
for cls in reversed(classes):
|
||||||
|
bpy.utils.unregister_class(cls)
|
||||||
|
|
||||||
|
|
||||||
|
register()
|
||||||
91
Assets/avatar-example/mesh/blend~/ui_bone_size.py
Normal file
91
Assets/avatar-example/mesh/blend~/ui_bone_size.py
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
import bpy
|
||||||
|
from bpy.props import FloatProperty
|
||||||
|
from bpy.types import Context, Operator, Panel
|
||||||
|
|
||||||
|
|
||||||
|
class ArmEditOperator:
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context: Context):
|
||||||
|
return (
|
||||||
|
context.active_object
|
||||||
|
and context.active_object.type == 'ARMATURE'
|
||||||
|
and context.active_bone
|
||||||
|
and context.mode == 'EDIT_ARMATURE'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class ARMATURE_OT_ReadBoneLength(ArmEditOperator, Operator):
|
||||||
|
"""Make length property equal to actual bone length"""
|
||||||
|
bl_idname = "armature.read_bone_length"
|
||||||
|
bl_label = "Read Bone Length"
|
||||||
|
bl_options = {'UNDO'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
context.active_bone.bbone_y = context.active_bone.length
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class ARMATURE_OT_MakeBoneSquare(ArmEditOperator, Operator):
|
||||||
|
"""Make bone's width and depth equal to it's length"""
|
||||||
|
bl_idname = "armature.make_bone_square"
|
||||||
|
bl_label = "Make Bone Square"
|
||||||
|
bl_options = {'UNDO'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
context.active_bone.bbone_x = context.active_bone.bbone_z = context.active_bone.length * 0.5
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class VIEW3D_PT_bone_size(Panel):
|
||||||
|
bl_space_type = 'VIEW_3D'
|
||||||
|
bl_region_type = 'UI'
|
||||||
|
bl_label = "Bone Size"
|
||||||
|
bl_options = {'DEFAULT_CLOSED'}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def poll(cls, context: Context):
|
||||||
|
scene = context.space_data
|
||||||
|
ob = context.active_object
|
||||||
|
return scene and ob and ob.type == 'ARMATURE' and ob.mode == 'EDIT'
|
||||||
|
|
||||||
|
def draw(self, context: Context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
col = layout.column()
|
||||||
|
col.prop(context.active_bone, "bbone_x", text="Bone Width")
|
||||||
|
col.prop(context.active_bone, "bbone_z", text="Bone Depth")
|
||||||
|
sub = col.row(align=True)
|
||||||
|
sub.operator(ARMATURE_OT_ReadBoneLength.bl_idname, icon="COPYDOWN", text="")
|
||||||
|
sub.prop(context.active_bone, "bbone_y", text="Bone Length")
|
||||||
|
col.operator(ARMATURE_OT_MakeBoneSquare.bl_idname, icon="MESH_PLANE")
|
||||||
|
|
||||||
|
|
||||||
|
def update_length(self, context) -> None:
|
||||||
|
context.active_bone.length = self.bbone_y
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
bpy.types.EditBone.bbone_y = FloatProperty(
|
||||||
|
name="B-Bone Display Y Length",
|
||||||
|
description="B-Bone Y size",
|
||||||
|
default=1.0,
|
||||||
|
min=0.0,
|
||||||
|
soft_min=0.001,
|
||||||
|
step=10,
|
||||||
|
precision=3,
|
||||||
|
options={'HIDDEN'},
|
||||||
|
update=update_length,
|
||||||
|
)
|
||||||
|
bpy.utils.register_class(ARMATURE_OT_ReadBoneLength)
|
||||||
|
bpy.utils.register_class(ARMATURE_OT_MakeBoneSquare)
|
||||||
|
bpy.utils.register_class(VIEW3D_PT_bone_size)
|
||||||
|
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.utils.unregister_class(VIEW3D_PT_bone_size)
|
||||||
|
bpy.utils.unregister_class(ARMATURE_OT_MakeBoneSquare)
|
||||||
|
bpy.utils.unregister_class(ARMATURE_OT_ReadBoneLength)
|
||||||
|
del bpy.types.EditBone.bbone_y
|
||||||
|
|
||||||
|
|
||||||
|
register()
|
||||||
113
Assets/avatar-example/mesh/blend~/ui_grid.py
Normal file
113
Assets/avatar-example/mesh/blend~/ui_grid.py
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
import math
|
||||||
|
|
||||||
|
import bpy
|
||||||
|
from bpy.props import EnumProperty, IntProperty
|
||||||
|
|
||||||
|
HU_TO_METERS_RATIO = 0.025 # 1hu = 2.5cm
|
||||||
|
GRID_SUBDIVISIONS = 8
|
||||||
|
|
||||||
|
|
||||||
|
class VIEW3D_OT_ResetGrid(bpy.types.Operator):
|
||||||
|
"""Reset grid settings to defaults"""
|
||||||
|
bl_idname = "screen.reset_grid"
|
||||||
|
bl_label = "Reset Grid"
|
||||||
|
bl_options = {'UNDO'}
|
||||||
|
|
||||||
|
def execute(self, context):
|
||||||
|
context.space_data.grid_lines = 16
|
||||||
|
context.space_data.grid_scale = 1.0
|
||||||
|
context.space_data.grid_subdivisions = 10
|
||||||
|
return {'FINISHED'}
|
||||||
|
|
||||||
|
|
||||||
|
class VIEW3D_PT_grid_level(bpy.types.Panel):
|
||||||
|
bl_space_type = 'VIEW_3D'
|
||||||
|
bl_region_type = 'UI'
|
||||||
|
bl_label = "Grid Level"
|
||||||
|
|
||||||
|
def draw(self, context):
|
||||||
|
layout = self.layout
|
||||||
|
|
||||||
|
row = layout.row()
|
||||||
|
row.prop(context.scene, "grid_type", expand=True)
|
||||||
|
|
||||||
|
col = layout.column()
|
||||||
|
if context.scene.grid_type == 'HAMMER':
|
||||||
|
col.prop(context.scene, "grid_hu")
|
||||||
|
|
||||||
|
grid_size = pow(2, context.scene.grid_hu)
|
||||||
|
|
||||||
|
split = col.split(align=True)
|
||||||
|
col_l = split.column()
|
||||||
|
col_l.alignment = 'RIGHT'
|
||||||
|
col_l.label("Hammer Units:")
|
||||||
|
col_l.label("Meters:")
|
||||||
|
col_r = split.column()
|
||||||
|
col_r.label("%i hu" % grid_size)
|
||||||
|
col_r.label("%.3f m" % (grid_size * HU_TO_METERS_RATIO))
|
||||||
|
|
||||||
|
elif context.scene.grid_type == 'POWEROF2':
|
||||||
|
col.prop(context.scene, "grid_po2")
|
||||||
|
|
||||||
|
layout.operator(VIEW3D_OT_ResetGrid.bl_idname)
|
||||||
|
|
||||||
|
|
||||||
|
def update_grid_hu(self, context) -> None:
|
||||||
|
grid_size = pow(2, self.grid_hu)
|
||||||
|
context.space_data.grid_lines = max(3, math.ceil(1024 / grid_size))
|
||||||
|
context.space_data.grid_scale = grid_size * HU_TO_METERS_RATIO
|
||||||
|
context.space_data.grid_subdivisions = GRID_SUBDIVISIONS
|
||||||
|
|
||||||
|
|
||||||
|
def update_grid_po2(self, context) -> None:
|
||||||
|
context.space_data.grid_lines = max(3, pow(2, self.grid_po2 + 5))
|
||||||
|
context.space_data.grid_scale = 1 / pow(2, self.grid_po2)
|
||||||
|
context.space_data.grid_subdivisions = GRID_SUBDIVISIONS
|
||||||
|
|
||||||
|
|
||||||
|
def update_type(self, context) -> None:
|
||||||
|
if self.grid_type == 'HAMMER':
|
||||||
|
update_grid_hu(self, context)
|
||||||
|
elif self.grid_type == 'POWEROF2':
|
||||||
|
update_grid_po2(self, context)
|
||||||
|
|
||||||
|
|
||||||
|
def register():
|
||||||
|
bpy.types.Scene.grid_type = EnumProperty(
|
||||||
|
items=(
|
||||||
|
('HAMMER', "Hammer Units", "Main basic settings"),
|
||||||
|
('POWEROF2', "Power Of 2", "Armature-related settings"),
|
||||||
|
),
|
||||||
|
name="Grid type",
|
||||||
|
description="",
|
||||||
|
update=update_type,
|
||||||
|
)
|
||||||
|
bpy.types.Scene.grid_hu = IntProperty(
|
||||||
|
name="Grid level",
|
||||||
|
description="Hammer Units grid level",
|
||||||
|
min=0,
|
||||||
|
max=9,
|
||||||
|
default=6,
|
||||||
|
update=update_grid_hu,
|
||||||
|
)
|
||||||
|
bpy.types.Scene.grid_po2 = IntProperty(
|
||||||
|
name="Grid divisions",
|
||||||
|
description="Grid divisions in power of 2",
|
||||||
|
min=-4,
|
||||||
|
max=4,
|
||||||
|
default=0,
|
||||||
|
update=update_grid_po2,
|
||||||
|
)
|
||||||
|
bpy.utils.register_class(VIEW3D_OT_ResetGrid)
|
||||||
|
bpy.utils.register_class(VIEW3D_PT_grid_level)
|
||||||
|
|
||||||
|
|
||||||
|
def unregister():
|
||||||
|
bpy.utils.unregister_class(VIEW3D_PT_grid_level)
|
||||||
|
bpy.utils.register_class(VIEW3D_OT_ResetGrid)
|
||||||
|
del bpy.types.Scene.grid_po2
|
||||||
|
del bpy.types.Scene.grid_hu
|
||||||
|
del bpy.types.Scene.grid_type
|
||||||
|
|
||||||
|
|
||||||
|
register()
|
||||||
BIN
Assets/avatar-example/mesh/fbx/avatar-example.fbx
LFS
Normal file
BIN
Assets/avatar-example/mesh/fbx/avatar-example.fbx
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/mesh/fbx/scene/room.fbx
LFS
Normal file
BIN
Assets/avatar-example/mesh/fbx/scene/room.fbx
LFS
Normal file
Binary file not shown.
1
Assets/avatar-example/mesh/unity/avatar-example.unity
Normal file
1
Assets/avatar-example/mesh/unity/avatar-example.unity
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/prefabs/player-follower.prefab
Normal file
1
Assets/avatar-example/prefabs/player-follower.prefab
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/prefabs/player-weapon.prefab
Normal file
1
Assets/avatar-example/prefabs/player-weapon.prefab
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/scripts/avatar-main-menu.asset
Normal file
1
Assets/avatar-example/scripts/avatar-main-menu.asset
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/scripts/avatar-parameters.asset
Normal file
1
Assets/avatar-example/scripts/avatar-parameters.asset
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/scripts/vrc-tracking-control.cs
Normal file
1
Assets/avatar-example/scripts/vrc-tracking-control.cs
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
1
Assets/avatar-example/shaders/standard-two-sided.shader
Normal file
1
Assets/avatar-example/shaders/standard-two-sided.shader
Normal file
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
BIN
Assets/avatar-example/sounds/cool-cats.ogg
LFS
Normal file
BIN
Assets/avatar-example/sounds/cool-cats.ogg
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/sounds/high5.ogg
LFS
Normal file
BIN
Assets/avatar-example/sounds/high5.ogg
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/sounds/purr.ogg
LFS
Normal file
BIN
Assets/avatar-example/sounds/purr.ogg
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/sounds/slap.ogg
LFS
Normal file
BIN
Assets/avatar-example/sounds/slap.ogg
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/textures/body/body_albedo.png
LFS
Normal file
BIN
Assets/avatar-example/textures/body/body_albedo.png
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/textures/body/body_metallic.png
LFS
Normal file
BIN
Assets/avatar-example/textures/body/body_metallic.png
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/textures/body/body_normal.png
LFS
Normal file
BIN
Assets/avatar-example/textures/body/body_normal.png
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/textures/outfit/outfit1_albedo.png
LFS
Normal file
BIN
Assets/avatar-example/textures/outfit/outfit1_albedo.png
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/textures/outfit/outfit1_metallic.png
LFS
Normal file
BIN
Assets/avatar-example/textures/outfit/outfit1_metallic.png
LFS
Normal file
Binary file not shown.
BIN
Assets/avatar-example/textures/outfit/outfit1_normal.png
LFS
Normal file
BIN
Assets/avatar-example/textures/outfit/outfit1_normal.png
LFS
Normal file
Binary file not shown.
Reference in New Issue
Block a user