@volter/blender-engine 0.1.148 → 0.1.149
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +16 -0
- package/README.md +4 -11
- package/browser/addons/vrm/LICENSE_(OPTION1)_MIT.txt +22 -0
- package/browser/addons/vrm/LICENSE_(OPTION2)_GPL-3_0.txt +674 -0
- package/browser/addons/vrm/LICENSE_MAIN.txt +1 -0
- package/browser/addons/vrm/README.txt +3 -0
- package/browser/addons/vrm/__init__.py +41 -0
- package/browser/addons/vrm/blender_manifest.toml +16 -0
- package/browser/addons/vrm/common/__init__.py +1 -0
- package/browser/addons/vrm/common/animation.py +58 -0
- package/browser/addons/vrm/common/blender_manifest.py +82 -0
- package/browser/addons/vrm/common/char.py +16 -0
- package/browser/addons/vrm/common/convert.py +287 -0
- package/browser/addons/vrm/common/convert_any.py +48 -0
- package/browser/addons/vrm/common/debug.py +40 -0
- package/browser/addons/vrm/common/deep.py +162 -0
- package/browser/addons/vrm/common/error_dialog.py +274 -0
- package/browser/addons/vrm/common/fs.py +71 -0
- package/browser/addons/vrm/common/gl.py +20 -0
- package/browser/addons/vrm/common/gltf.py +1149 -0
- package/browser/addons/vrm/common/human_bone_mapper/__init__.py +1 -0
- package/browser/addons/vrm/common/human_bone_mapper/biped_mapping.py +84 -0
- package/browser/addons/vrm/common/human_bone_mapper/cats_blender_plugin_fix_model_mapping.py +63 -0
- package/browser/addons/vrm/common/human_bone_mapper/human_bone_mapper.py +203 -0
- package/browser/addons/vrm/common/human_bone_mapper/microsoft_rocketbox_mapping.py +69 -0
- package/browser/addons/vrm/common/human_bone_mapper/mixamo_mapping.py +62 -0
- package/browser/addons/vrm/common/human_bone_mapper/mmd_mapping.py +115 -0
- package/browser/addons/vrm/common/human_bone_mapper/mpfb_mapping.py +120 -0
- package/browser/addons/vrm/common/human_bone_mapper/ready_player_me_mapping.py +65 -0
- package/browser/addons/vrm/common/human_bone_mapper/reallusion_mapping.py +94 -0
- package/browser/addons/vrm/common/human_bone_mapper/rigify_meta_rig_mapping.py +65 -0
- package/browser/addons/vrm/common/human_bone_mapper/structure_based_mapping.py +891 -0
- package/browser/addons/vrm/common/human_bone_mapper/unreal_mapping.py +62 -0
- package/browser/addons/vrm/common/human_bone_mapper/vrm_addon_mapping.py +112 -0
- package/browser/addons/vrm/common/human_bone_mapper/vroid_mapping.py +89 -0
- package/browser/addons/vrm/common/legacy_gltf.py +16 -0
- package/browser/addons/vrm/common/logger.py +84 -0
- package/browser/addons/vrm/common/mtoon0.blend +0 -0
- package/browser/addons/vrm/common/mtoon1.blend +0 -0
- package/browser/addons/vrm/common/mtoon1_outline.blend +0 -0
- package/browser/addons/vrm/common/mtoon_auto_setup.blend +0 -0
- package/browser/addons/vrm/common/mtoon_unversioned.py +62 -0
- package/browser/addons/vrm/common/ops/__init__.py +10 -0
- package/browser/addons/vrm/common/ops/export_scene.py +67 -0
- package/browser/addons/vrm/common/ops/icyp.py +53 -0
- package/browser/addons/vrm/common/ops/import_scene.py +57 -0
- package/browser/addons/vrm/common/ops/vrm.py +2380 -0
- package/browser/addons/vrm/common/ops/wm.py +167 -0
- package/browser/addons/vrm/common/preferences.py +362 -0
- package/browser/addons/vrm/common/progress.py +87 -0
- package/browser/addons/vrm/common/rotation.py +89 -0
- package/browser/addons/vrm/common/safe_removal.py +46 -0
- package/browser/addons/vrm/common/scene_watcher.py +230 -0
- package/browser/addons/vrm/common/shader.py +2243 -0
- package/browser/addons/vrm/common/shape_key_mapper/__init__.py +1 -0
- package/browser/addons/vrm/common/shape_key_mapper/arkit_mapping.py +168 -0
- package/browser/addons/vrm/common/shape_key_mapper/mmd_mapping.py +62 -0
- package/browser/addons/vrm/common/shape_key_mapper/ready_player_me_mapping.py +52 -0
- package/browser/addons/vrm/common/shape_key_mapper/vrchat_mapping.py +17 -0
- package/browser/addons/vrm/common/third_party_user_extension.py +214 -0
- package/browser/addons/vrm/common/transparent_z_write.blend +0 -0
- package/browser/addons/vrm/common/version.py +161 -0
- package/browser/addons/vrm/common/vrm0/__init__.py +1 -0
- package/browser/addons/vrm/common/vrm0/human_bone.py +662 -0
- package/browser/addons/vrm/common/vrm0/material_property.py +346 -0
- package/browser/addons/vrm/common/vrm1/__init__.py +1 -0
- package/browser/addons/vrm/common/vrm1/expression_preset.py +207 -0
- package/browser/addons/vrm/common/vrm1/human_bone.py +822 -0
- package/browser/addons/vrm/common/workspace.py +227 -0
- package/browser/addons/vrm/common/writable_context.py +77 -0
- package/browser/addons/vrm/documentation/en-us/animation/index.md +63 -0
- package/browser/addons/vrm/documentation/en-us/create-humanoid-vrm-from-scratch/index.md +131 -0
- package/browser/addons/vrm/documentation/en-us/create-simple-vrm-from-scratch/index.md +30 -0
- package/browser/addons/vrm/documentation/en-us/development/index.md +136 -0
- package/browser/addons/vrm/documentation/en-us/index.md +41 -0
- package/browser/addons/vrm/documentation/en-us/installation/index.md +152 -0
- package/browser/addons/vrm/documentation/en-us/material-mtoon/index.md +122 -0
- package/browser/addons/vrm/documentation/en-us/material-pbr/index.md +94 -0
- package/browser/addons/vrm/documentation/en-us/scripting-api/index.md +391 -0
- package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrm/index.md +57 -0
- package/browser/addons/vrm/documentation/en-us/ui/export_scene.vrma/index.md +17 -0
- package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrm/index.md +61 -0
- package/browser/addons/vrm/documentation/en-us/ui/import_scene.vrma/index.md +13 -0
- package/browser/addons/vrm/documentation/ja-jp/animation/index.md +57 -0
- package/browser/addons/vrm/documentation/ja-jp/create-humanoid-vrm-from-scratch/index.md +129 -0
- package/browser/addons/vrm/documentation/ja-jp/create-simple-vrm-from-scratch/index.md +29 -0
- package/browser/addons/vrm/documentation/ja-jp/development/index.md +137 -0
- package/browser/addons/vrm/documentation/ja-jp/index.md +37 -0
- package/browser/addons/vrm/documentation/ja-jp/installation/index.md +150 -0
- package/browser/addons/vrm/documentation/ja-jp/material-mtoon/index.md +113 -0
- package/browser/addons/vrm/documentation/ja-jp/material-pbr/index.md +90 -0
- package/browser/addons/vrm/documentation/ja-jp/scripting-api/index.md +389 -0
- package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrm/index.md +55 -0
- package/browser/addons/vrm/documentation/ja-jp/ui/export_scene.vrma/index.md +19 -0
- package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrm/index.md +56 -0
- package/browser/addons/vrm/documentation/ja-jp/ui/import_scene.vrma/index.md +14 -0
- package/browser/addons/vrm/editor/__init__.py +1 -0
- package/browser/addons/vrm/editor/extension.py +425 -0
- package/browser/addons/vrm/editor/extension_accessor.py +75 -0
- package/browser/addons/vrm/editor/handler.py +84 -0
- package/browser/addons/vrm/editor/khr_character/__init__.py +1 -0
- package/browser/addons/vrm/editor/khr_character/panel.py +69 -0
- package/browser/addons/vrm/editor/khr_character/property_group.py +27 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/__init__.py +1 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/ops.py +464 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/panel.py +136 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/property_group.py +83 -0
- package/browser/addons/vrm/editor/khr_xmp_json_ld/ui_list.py +198 -0
- package/browser/addons/vrm/editor/make_armature.py +709 -0
- package/browser/addons/vrm/editor/menu.py +147 -0
- package/browser/addons/vrm/editor/migration.py +297 -0
- package/browser/addons/vrm/editor/mtoon1/__init__.py +1 -0
- package/browser/addons/vrm/editor/mtoon1/handler.py +20 -0
- package/browser/addons/vrm/editor/mtoon1/migration.py +536 -0
- package/browser/addons/vrm/editor/mtoon1/ops.py +304 -0
- package/browser/addons/vrm/editor/mtoon1/panel.py +442 -0
- package/browser/addons/vrm/editor/mtoon1/property_group.py +4977 -0
- package/browser/addons/vrm/editor/mtoon1/scene_watcher.py +381 -0
- package/browser/addons/vrm/editor/node_constraint1/__init__.py +1 -0
- package/browser/addons/vrm/editor/node_constraint1/panel.py +317 -0
- package/browser/addons/vrm/editor/node_constraint1/property_group.py +25 -0
- package/browser/addons/vrm/editor/ops.py +471 -0
- package/browser/addons/vrm/editor/panel.py +315 -0
- package/browser/addons/vrm/editor/property_group.py +888 -0
- package/browser/addons/vrm/editor/search.py +682 -0
- package/browser/addons/vrm/editor/spring_bone1/__init__.py +1 -0
- package/browser/addons/vrm/editor/spring_bone1/handler.py +994 -0
- package/browser/addons/vrm/editor/spring_bone1/menu.py +246 -0
- package/browser/addons/vrm/editor/spring_bone1/migration.py +86 -0
- package/browser/addons/vrm/editor/spring_bone1/ops.py +1679 -0
- package/browser/addons/vrm/editor/spring_bone1/panel.py +605 -0
- package/browser/addons/vrm/editor/spring_bone1/property_group.py +1457 -0
- package/browser/addons/vrm/editor/spring_bone1/ui_list.py +408 -0
- package/browser/addons/vrm/editor/subscription.py +123 -0
- package/browser/addons/vrm/editor/t_pose.py +713 -0
- package/browser/addons/vrm/editor/validation.py +1271 -0
- package/browser/addons/vrm/editor/vrm0/__init__.py +1 -0
- package/browser/addons/vrm/editor/vrm0/gizmo_group.py +63 -0
- package/browser/addons/vrm/editor/vrm0/handler.py +23 -0
- package/browser/addons/vrm/editor/vrm0/menu.py +145 -0
- package/browser/addons/vrm/editor/vrm0/migration.py +761 -0
- package/browser/addons/vrm/editor/vrm0/ops.py +2145 -0
- package/browser/addons/vrm/editor/vrm0/panel.py +1333 -0
- package/browser/addons/vrm/editor/vrm0/property_group.py +1818 -0
- package/browser/addons/vrm/editor/vrm0/ui_list.py +688 -0
- package/browser/addons/vrm/editor/vrm1/__init__.py +1 -0
- package/browser/addons/vrm/editor/vrm1/handler.py +28 -0
- package/browser/addons/vrm/editor/vrm1/menu.py +76 -0
- package/browser/addons/vrm/editor/vrm1/migration.py +321 -0
- package/browser/addons/vrm/editor/vrm1/ops.py +2679 -0
- package/browser/addons/vrm/editor/vrm1/panel.py +1243 -0
- package/browser/addons/vrm/editor/vrm1/property_group.py +2087 -0
- package/browser/addons/vrm/editor/vrm1/scene_watcher.py +90 -0
- package/browser/addons/vrm/editor/vrm1/ui_list.py +533 -0
- package/browser/addons/vrm/exporter/__init__.py +1 -0
- package/browser/addons/vrm/exporter/abstract_base_vrm_exporter.py +628 -0
- package/browser/addons/vrm/exporter/export_scene.py +930 -0
- package/browser/addons/vrm/exporter/gltf2_export_user_extension.py +45 -0
- package/browser/addons/vrm/exporter/khr_character_exporter.py +34 -0
- package/browser/addons/vrm/exporter/vrm0_exporter.py +4020 -0
- package/browser/addons/vrm/exporter/vrm1_exporter.py +3682 -0
- package/browser/addons/vrm/exporter/vrm_animation_exporter.py +1035 -0
- package/browser/addons/vrm/external/__init__.py +1 -0
- package/browser/addons/vrm/external/auto_rig_pro_support.py +3 -0
- package/browser/addons/vrm/external/io_scene_gltf2_support.py +418 -0
- package/browser/addons/vrm/external/rigify_support.py +1 -0
- package/browser/addons/vrm/importer/__init__.py +1 -0
- package/browser/addons/vrm/importer/abstract_base_vrm_importer.py +1548 -0
- package/browser/addons/vrm/importer/file_handler.py +34 -0
- package/browser/addons/vrm/importer/gltf2_import_user_extension.py +268 -0
- package/browser/addons/vrm/importer/import_scene.py +646 -0
- package/browser/addons/vrm/importer/license_validation.py +198 -0
- package/browser/addons/vrm/importer/vrm0_importer.py +1723 -0
- package/browser/addons/vrm/importer/vrm1_importer.py +2014 -0
- package/browser/addons/vrm/importer/vrm_animation_importer.py +763 -0
- package/browser/addons/vrm/importer/vrm_diff.py +316 -0
- package/browser/addons/vrm/locale/__init__.py +1 -0
- package/browser/addons/vrm/locale/ja_jp.py +826 -0
- package/browser/addons/vrm/locale/ruff.toml +8 -0
- package/browser/addons/vrm/locale/translation_dictionary.py +10 -0
- package/browser/addons/vrm/locale/zh_hans.py +928 -0
- package/browser/addons/vrm/registration.py +670 -0
- package/browser/addons/vrm.json +18 -0
- package/browser/blender-emscripten-engine.mts +60 -128
- package/browser/blender-engine.mts +20 -186
- package/browser/blender-wali-engine.mts +35 -81
- package/browser/describe-thrown.mts +3 -6
- package/browser/document-chunks.mts +4 -16
- package/browser/gltf_export.py +3161 -0
- package/browser/heap-growth.mts +23 -0
- package/browser/index.ts +2 -0
- package/browser/protocol.ts +119 -35
- package/browser/pull-job.mts +2 -10
- package/browser/rna.ts +190 -73
- package/browser/runtime.ts +197 -82
- package/browser/session-addons.mts +33 -0
- package/browser/session-frame.mts +5 -24
- package/browser/session.py +1338 -1427
- package/browser/three/attach-presenter.ts +11 -39
- package/browser/three/blender-base64.ts +1 -36
- package/browser/three/blender-corner-normals.ts +1 -23
- package/browser/three/blender-display-shaders.json +1 -1
- package/browser/three/blender-display-shaders.lut +0 -0
- package/browser/three/blender-display-transform.ts +2 -1
- package/browser/three/blender-frame-columns.ts +5 -13
- package/browser/three/blender-graph-material.ts +18 -3
- package/browser/three/blender-node-graph.ts +10 -34
- package/browser/three/blender-physical-material.ts +2 -31
- package/browser/three/blender-runtime-armature.ts +7 -60
- package/browser/three/blender-runtime-frame.ts +9 -23
- package/browser/three/blender-runtime-geometry.ts +22 -26
- package/browser/three/blender-runtime-lighting.ts +48 -178
- package/browser/three/blender-runtime-shadows.ts +187 -1
- package/browser/three/blender-runtime-skeleton.ts +53 -1
- package/browser/three/blender-runtime-view.ts +505 -283
- package/browser/three/blender-runtime-weights.ts +9 -72
- package/browser/three/blender-sky.ts +13 -33
- package/browser/three/blender-triangulate.ts +7 -35
- package/browser/three/blender-viewport-sampling.ts +235 -0
- package/browser/three/blender-workbench-material.ts +25 -29
- package/browser/three/blender-workbench-outline.ts +199 -0
- package/browser/three/blender-world-volume.ts +62 -10
- package/browser/three/presenter.ts +10 -26
- package/browser/three/release.ts +5 -21
- package/browser/three/sky-precompute-worker.ts +1 -18
- package/browser/three/sky-worker.ts +5 -23
- package/browser/three/world-field-sampler.ts +12 -26
- package/browser/volter_three.py +9 -105
- package/browser/worker.ts +156 -151
- package/package.json +5 -2
- package/wasm/BUNDLE.json +17 -17
- package/wasm/DEPENDENCY-LICENSES.txt +14 -0
- package/wasm/blender_browser.data.br +0 -0
- package/wasm/blender_browser.js +1 -1
- package/wasm/blender_browser.wasm.br +0 -0
- package/browser/frame-transfer.mts +0 -19
- package/browser/three/agx-base-srgb.lut +0 -0
- package/browser/three/agx-look-medium-high-contrast.lut +0 -0
- package/browser/three/agx-look-punchy.lut +0 -0
- package/browser/three/blender-agx.ts +0 -235
- package/browser/three/blender-display-lut.ts +0 -145
- package/browser/three/blender-filmic.ts +0 -49
- package/browser/three/blender-standard.ts +0 -68
- package/browser/three/blender-world-visibility.ts +0 -278
- package/browser/three/filmic-srgb.lut +0 -0
|
@@ -0,0 +1,4977 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
|
|
2
|
+
import math
|
|
3
|
+
import re
|
|
4
|
+
import sys
|
|
5
|
+
from collections.abc import Callable, Mapping, Sequence
|
|
6
|
+
from dataclasses import dataclass
|
|
7
|
+
from sys import float_info
|
|
8
|
+
from typing import TYPE_CHECKING, Final, Optional, Protocol, Union
|
|
9
|
+
|
|
10
|
+
import bpy
|
|
11
|
+
from bpy.props import (
|
|
12
|
+
BoolProperty,
|
|
13
|
+
EnumProperty,
|
|
14
|
+
FloatProperty,
|
|
15
|
+
FloatVectorProperty,
|
|
16
|
+
IntProperty,
|
|
17
|
+
IntVectorProperty,
|
|
18
|
+
PointerProperty,
|
|
19
|
+
)
|
|
20
|
+
from bpy.types import (
|
|
21
|
+
Context,
|
|
22
|
+
Driver,
|
|
23
|
+
FCurve,
|
|
24
|
+
Image,
|
|
25
|
+
Material,
|
|
26
|
+
Mesh,
|
|
27
|
+
Node,
|
|
28
|
+
NodeReroute,
|
|
29
|
+
NodesModifier,
|
|
30
|
+
NodeSocketColor,
|
|
31
|
+
NodeSocketFloat,
|
|
32
|
+
NodeTree,
|
|
33
|
+
Object,
|
|
34
|
+
PropertyGroup,
|
|
35
|
+
ShaderNodeBsdfPrincipled,
|
|
36
|
+
ShaderNodeEmission,
|
|
37
|
+
ShaderNodeGroup,
|
|
38
|
+
ShaderNodeMapping,
|
|
39
|
+
ShaderNodeMath,
|
|
40
|
+
ShaderNodeNormalMap,
|
|
41
|
+
ShaderNodeOutputMaterial,
|
|
42
|
+
ShaderNodeTexImage,
|
|
43
|
+
)
|
|
44
|
+
from bpy_extras.node_shader_utils import PrincipledBSDFWrapper
|
|
45
|
+
from mathutils import Vector
|
|
46
|
+
|
|
47
|
+
from ...common import convert, shader
|
|
48
|
+
from ...common.gl import (
|
|
49
|
+
GL_CLAMP_TO_EDGE,
|
|
50
|
+
GL_LINEAR,
|
|
51
|
+
GL_LINEAR_MIPMAP_LINEAR,
|
|
52
|
+
GL_LINEAR_MIPMAP_NEAREST,
|
|
53
|
+
GL_MIRRORED_REPEAT,
|
|
54
|
+
GL_NEAREST,
|
|
55
|
+
GL_NEAREST_MIPMAP_LINEAR,
|
|
56
|
+
GL_NEAREST_MIPMAP_NEAREST,
|
|
57
|
+
GL_REPEAT,
|
|
58
|
+
)
|
|
59
|
+
from ...common.logger import get_logger
|
|
60
|
+
from ...common.preferences import VrmAddonPreferences, get_preferences
|
|
61
|
+
from ...common.shader import LegacyAddonMaterial, MmdMaterial
|
|
62
|
+
from ...common.version import get_addon_version
|
|
63
|
+
from ..extension_accessor import get_material_extension
|
|
64
|
+
from ..property_group import property_group_enum
|
|
65
|
+
|
|
66
|
+
_logger = get_logger(__name__)
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
MTOON1_OUTPUT_NODE_GROUP_NAME: Final = "Mtoon1Material.Mtoon1Output"
|
|
70
|
+
|
|
71
|
+
PRINCIPLED_BSDF_BASE_COLOR_INPUT_KEY: Final = "Base Color"
|
|
72
|
+
PRINCIPLED_BSDF_ALPHA_INPUT_KEY: Final = "Alpha"
|
|
73
|
+
PRINCIPLED_BSDF_EMISSION_INPUT_KEY: Final = (
|
|
74
|
+
"Emission Color" if bpy.app.version >= (4,) else "Emission"
|
|
75
|
+
)
|
|
76
|
+
PRINCIPLED_BSDF_EMISSION_STRENGTH_INPUT_KEY: Final = "Emission Strength"
|
|
77
|
+
PRINCIPLED_BSDF_NORMAL_INPUT_KEY: Final = "Normal"
|
|
78
|
+
NORMAL_MAP_COLOR_INPUT_KEY: Final = "Color"
|
|
79
|
+
EMISSION_COLOR_INPUT_KEY: Final = "Color"
|
|
80
|
+
EMISSION_STRENGTH_INPUT_KEY: Final = "Strength"
|
|
81
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: Final = "Color"
|
|
82
|
+
TEX_IMAGE_ALPHA_OUTPUT_KEY: Final = "Alpha"
|
|
83
|
+
|
|
84
|
+
IMAGE_INTERPOLATION_CLOSEST: Final = "Closest"
|
|
85
|
+
IMAGE_INTERPOLATION_LINEAR: Final = "Linear"
|
|
86
|
+
IMAGE_INTERPOLATION_CUBIC: Final = "Cubic"
|
|
87
|
+
IMAGE_INTERPOLATION_SMART: Final = "Smart"
|
|
88
|
+
GL_LINEAR_IMAGE_INTERPOLATIONS: Final = (
|
|
89
|
+
IMAGE_INTERPOLATION_LINEAR,
|
|
90
|
+
IMAGE_INTERPOLATION_CUBIC,
|
|
91
|
+
IMAGE_INTERPOLATION_SMART,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
ALPHA_CLIP_INPUT_NODE_NAME: Final = "Mtoon1Material.AlphaClip.Input"
|
|
95
|
+
ALPHA_CLIP_INPUT_NODE_SOCKET_NAME: Final = "Value"
|
|
96
|
+
ALPHA_CLIP_OUTPUT_NODE_NAME: Final = "Mtoon1Material.AlphaClip.Output"
|
|
97
|
+
ALPHA_CLIP_OUTPUT_NODE_SOCKET_NAME: Final = "Value"
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def _get_gltf_emissive_node(material: Material) -> Optional[ShaderNodeEmission]:
|
|
101
|
+
node_tree = material.node_tree
|
|
102
|
+
if not node_tree:
|
|
103
|
+
return None
|
|
104
|
+
return next(
|
|
105
|
+
(
|
|
106
|
+
node
|
|
107
|
+
for node in node_tree.nodes
|
|
108
|
+
if isinstance(node, ShaderNodeEmission)
|
|
109
|
+
and node.name == "Mtoon1Material.GltfEmissive"
|
|
110
|
+
),
|
|
111
|
+
None,
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
class NodeSocketTarget(Protocol):
|
|
116
|
+
def get_in_socket_name(self) -> str: ...
|
|
117
|
+
|
|
118
|
+
def create_node_selector(self, material: Material) -> Callable[[Node], bool]: ...
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class PrincipledBsdfNodeSocketTarget(NodeSocketTarget):
|
|
122
|
+
def __init__(self, *, in_socket_name: str) -> None:
|
|
123
|
+
self.in_socket_name = in_socket_name
|
|
124
|
+
|
|
125
|
+
def get_in_socket_name(self) -> str:
|
|
126
|
+
return self.in_socket_name
|
|
127
|
+
|
|
128
|
+
@staticmethod
|
|
129
|
+
def get_node_name(material: Material) -> Optional[str]:
|
|
130
|
+
# node has a short lifetime on the native side and is dangerous, so avoid
|
|
131
|
+
# exposing it outside the function
|
|
132
|
+
node = PrincipledBSDFWrapper(material).node_principled_bsdf
|
|
133
|
+
if node is None:
|
|
134
|
+
return None
|
|
135
|
+
# Use intern to avoid using str directly referenced from node that will be
|
|
136
|
+
# destroyed in the future
|
|
137
|
+
# Previously, using str referenced from destroyed Bone caused problems,
|
|
138
|
+
# so this is a precautionary measure, though it might be overly cautious
|
|
139
|
+
return sys.intern(node.name)
|
|
140
|
+
|
|
141
|
+
def create_node_selector(self, material: Material) -> Callable[[Node], bool]:
|
|
142
|
+
name = self.get_node_name(material)
|
|
143
|
+
if name is None:
|
|
144
|
+
return lambda _: False
|
|
145
|
+
return lambda node: (
|
|
146
|
+
isinstance(node, ShaderNodeBsdfPrincipled) and node.name == name
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class StaticNodeSocketTarget(NodeSocketTarget):
|
|
151
|
+
def __init__(
|
|
152
|
+
self, *, in_node_name: str, in_node_type: type[Node], in_socket_name: str
|
|
153
|
+
) -> None:
|
|
154
|
+
self.in_node_name = in_node_name
|
|
155
|
+
self.in_node_type = in_node_type
|
|
156
|
+
self.in_socket_name = in_socket_name
|
|
157
|
+
|
|
158
|
+
def get_in_socket_name(self) -> str:
|
|
159
|
+
return self.in_socket_name
|
|
160
|
+
|
|
161
|
+
def create_node_selector(self, material: Material) -> Callable[[Node], bool]:
|
|
162
|
+
_ = material
|
|
163
|
+
return lambda node: (
|
|
164
|
+
isinstance(node, self.in_node_type) and node.name == self.in_node_name
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class PrincipledBsdfNormalMapNodeSocketTarget(NodeSocketTarget):
|
|
169
|
+
def get_in_socket_name(self) -> str:
|
|
170
|
+
return NORMAL_MAP_COLOR_INPUT_KEY
|
|
171
|
+
|
|
172
|
+
@staticmethod
|
|
173
|
+
def get_node_name(material: Material) -> Optional[str]:
|
|
174
|
+
# node has a short lifetime on the native side and is dangerous, so avoid
|
|
175
|
+
# exposing it outside the function
|
|
176
|
+
node = PrincipledBSDFWrapper(material).node_normalmap
|
|
177
|
+
if node is None:
|
|
178
|
+
return None
|
|
179
|
+
# Use intern to avoid using str directly referenced from node that will be
|
|
180
|
+
# destroyed in the future
|
|
181
|
+
# Previously, using str referenced from destroyed Bone caused problems,
|
|
182
|
+
# so this is a precautionary measure, though it might be overly cautious
|
|
183
|
+
return sys.intern(node.name)
|
|
184
|
+
|
|
185
|
+
def create_node_selector(self, material: Material) -> Callable[[Node], bool]:
|
|
186
|
+
name = self.get_node_name(material)
|
|
187
|
+
if name is None:
|
|
188
|
+
return lambda _: False
|
|
189
|
+
return lambda node: isinstance(node, ShaderNodeNormalMap) and node.name == name
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
class GltfEmissionNodeSocketTarget(NodeSocketTarget):
|
|
193
|
+
def get_in_socket_name(self) -> str:
|
|
194
|
+
return EMISSION_COLOR_INPUT_KEY
|
|
195
|
+
|
|
196
|
+
def create_node_selector(self, material: Material) -> Callable[[Node], bool]:
|
|
197
|
+
_ = material
|
|
198
|
+
# https://github.com/KhronosGroup/glTF-Blender-IO/pull/740
|
|
199
|
+
return lambda node: isinstance(node, ShaderNodeEmission)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
class NodeGroupSocketTarget(NodeSocketTarget):
|
|
203
|
+
def __init__(self, *, node_group_node_tree_name: str, in_socket_name: str) -> None:
|
|
204
|
+
self.node_group_node_tree_name = node_group_node_tree_name
|
|
205
|
+
self.in_socket_name = in_socket_name
|
|
206
|
+
|
|
207
|
+
def get_in_socket_name(self) -> str:
|
|
208
|
+
return self.in_socket_name
|
|
209
|
+
|
|
210
|
+
def select_node(self, node: Node) -> bool:
|
|
211
|
+
if not isinstance(node, ShaderNodeGroup):
|
|
212
|
+
return False
|
|
213
|
+
node_tree = node.node_tree
|
|
214
|
+
if not node_tree:
|
|
215
|
+
return False
|
|
216
|
+
return node_tree.name == self.node_group_node_tree_name
|
|
217
|
+
|
|
218
|
+
def create_node_selector(self, material: Material) -> Callable[[Node], bool]:
|
|
219
|
+
_ = material
|
|
220
|
+
return self.select_node
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
class MaterialTraceablePropertyGroup(PropertyGroup):
|
|
224
|
+
def find_material(self) -> Material:
|
|
225
|
+
id_data = self.id_data
|
|
226
|
+
if isinstance(id_data, Material):
|
|
227
|
+
return id_data
|
|
228
|
+
|
|
229
|
+
message = (
|
|
230
|
+
f"{type(self)}/{self}.id_data is not a {Material}"
|
|
231
|
+
+ f" but {type(id_data)}/{id_data}"
|
|
232
|
+
)
|
|
233
|
+
raise AssertionError(message)
|
|
234
|
+
|
|
235
|
+
def find_outline_property_group(
|
|
236
|
+
self, material: Material
|
|
237
|
+
) -> Optional["MaterialTraceablePropertyGroup"]:
|
|
238
|
+
if get_material_extension(material).mtoon1.is_outline_material:
|
|
239
|
+
return None
|
|
240
|
+
outline_material = get_material_extension(material).mtoon1.outline_material
|
|
241
|
+
if not outline_material:
|
|
242
|
+
return None
|
|
243
|
+
if material.name == outline_material.name:
|
|
244
|
+
_logger.error(
|
|
245
|
+
"Base material and outline material are same. name=%s",
|
|
246
|
+
material.name,
|
|
247
|
+
)
|
|
248
|
+
return None
|
|
249
|
+
path_from_id = self.path_from_id()
|
|
250
|
+
property_group = outline_material.path_resolve(path_from_id, False)
|
|
251
|
+
if isinstance(property_group, MaterialTraceablePropertyGroup):
|
|
252
|
+
return property_group
|
|
253
|
+
message = f"No matching property group: {type(self)}/{self} {path_from_id}"
|
|
254
|
+
raise AssertionError(message)
|
|
255
|
+
|
|
256
|
+
def get_bool(
|
|
257
|
+
self,
|
|
258
|
+
node_group_name: str,
|
|
259
|
+
group_label: str,
|
|
260
|
+
*,
|
|
261
|
+
default_value: bool,
|
|
262
|
+
) -> bool:
|
|
263
|
+
value = self.get_value(
|
|
264
|
+
node_group_name, group_label, default_value=int(default_value)
|
|
265
|
+
)
|
|
266
|
+
if isinstance(value, float):
|
|
267
|
+
return math.fabs(value) > 0.000001
|
|
268
|
+
return bool(value)
|
|
269
|
+
|
|
270
|
+
def get_float(
|
|
271
|
+
self,
|
|
272
|
+
node_group_name: str,
|
|
273
|
+
group_label: str,
|
|
274
|
+
*,
|
|
275
|
+
default_value: float,
|
|
276
|
+
) -> float:
|
|
277
|
+
value = self.get_value(
|
|
278
|
+
node_group_name, group_label, default_value=default_value
|
|
279
|
+
)
|
|
280
|
+
return float(value)
|
|
281
|
+
|
|
282
|
+
def get_int(
|
|
283
|
+
self,
|
|
284
|
+
node_group_name: str,
|
|
285
|
+
group_label: str,
|
|
286
|
+
*,
|
|
287
|
+
default_value: int,
|
|
288
|
+
) -> int:
|
|
289
|
+
value = self.get_value(
|
|
290
|
+
node_group_name, group_label, default_value=default_value
|
|
291
|
+
)
|
|
292
|
+
if isinstance(value, bool):
|
|
293
|
+
return int(value)
|
|
294
|
+
if isinstance(value, int):
|
|
295
|
+
return value
|
|
296
|
+
return round(value)
|
|
297
|
+
|
|
298
|
+
def get_value(
|
|
299
|
+
self,
|
|
300
|
+
node_group_name: str,
|
|
301
|
+
group_label: str,
|
|
302
|
+
*,
|
|
303
|
+
default_value: float,
|
|
304
|
+
) -> Union[float, int, bool]:
|
|
305
|
+
material = self.find_material()
|
|
306
|
+
node_tree = material.node_tree
|
|
307
|
+
if not node_tree:
|
|
308
|
+
return default_value
|
|
309
|
+
|
|
310
|
+
node = next(
|
|
311
|
+
(
|
|
312
|
+
node
|
|
313
|
+
for node in node_tree.nodes
|
|
314
|
+
if isinstance(node, ShaderNodeGroup)
|
|
315
|
+
and node.node_tree
|
|
316
|
+
and node.node_tree.name == node_group_name
|
|
317
|
+
),
|
|
318
|
+
None,
|
|
319
|
+
)
|
|
320
|
+
if not node:
|
|
321
|
+
return default_value
|
|
322
|
+
|
|
323
|
+
socket = node.inputs.get(group_label)
|
|
324
|
+
if isinstance(
|
|
325
|
+
socket,
|
|
326
|
+
(
|
|
327
|
+
*shader.BOOL_SOCKET_CLASSES,
|
|
328
|
+
*shader.FLOAT_SOCKET_CLASSES,
|
|
329
|
+
*shader.INT_SOCKET_CLASSES,
|
|
330
|
+
),
|
|
331
|
+
):
|
|
332
|
+
return socket.default_value
|
|
333
|
+
|
|
334
|
+
return default_value
|
|
335
|
+
|
|
336
|
+
def get_rgb(
|
|
337
|
+
self,
|
|
338
|
+
node_group_name: str,
|
|
339
|
+
group_label: str,
|
|
340
|
+
*,
|
|
341
|
+
default_value: tuple[float, float, float],
|
|
342
|
+
) -> tuple[float, float, float]:
|
|
343
|
+
material = self.find_material()
|
|
344
|
+
node_tree = material.node_tree
|
|
345
|
+
if not node_tree:
|
|
346
|
+
return default_value
|
|
347
|
+
|
|
348
|
+
node = next(
|
|
349
|
+
(
|
|
350
|
+
node
|
|
351
|
+
for node in node_tree.nodes
|
|
352
|
+
if isinstance(node, ShaderNodeGroup)
|
|
353
|
+
and node.node_tree
|
|
354
|
+
and node.node_tree.name == node_group_name
|
|
355
|
+
),
|
|
356
|
+
None,
|
|
357
|
+
)
|
|
358
|
+
if not node:
|
|
359
|
+
return default_value
|
|
360
|
+
|
|
361
|
+
socket = node.inputs.get(group_label)
|
|
362
|
+
if isinstance(socket, shader.COLOR_SOCKET_CLASSES):
|
|
363
|
+
return (
|
|
364
|
+
socket.default_value[0],
|
|
365
|
+
socket.default_value[1],
|
|
366
|
+
socket.default_value[2],
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
return default_value
|
|
370
|
+
|
|
371
|
+
def set_value(
|
|
372
|
+
self,
|
|
373
|
+
node_group_name: str,
|
|
374
|
+
group_label: str,
|
|
375
|
+
value_obj: object,
|
|
376
|
+
) -> None:
|
|
377
|
+
if isinstance(value_obj, float):
|
|
378
|
+
value = convert.float_or_none(value_obj)
|
|
379
|
+
if value is None:
|
|
380
|
+
return
|
|
381
|
+
elif isinstance(value_obj, int):
|
|
382
|
+
value = value_obj
|
|
383
|
+
else:
|
|
384
|
+
return
|
|
385
|
+
|
|
386
|
+
material = self.find_material()
|
|
387
|
+
outline = self.find_outline_property_group(material)
|
|
388
|
+
if outline:
|
|
389
|
+
outline.set_value(node_group_name, group_label, value)
|
|
390
|
+
|
|
391
|
+
node_tree = material.node_tree
|
|
392
|
+
if not node_tree:
|
|
393
|
+
return
|
|
394
|
+
|
|
395
|
+
node = next(
|
|
396
|
+
(
|
|
397
|
+
node
|
|
398
|
+
for node in node_tree.nodes
|
|
399
|
+
if isinstance(node, ShaderNodeGroup)
|
|
400
|
+
and node.node_tree
|
|
401
|
+
and node.node_tree.name == node_group_name
|
|
402
|
+
),
|
|
403
|
+
None,
|
|
404
|
+
)
|
|
405
|
+
if not node:
|
|
406
|
+
_logger.warning('No group node "%s"', node_group_name)
|
|
407
|
+
return
|
|
408
|
+
|
|
409
|
+
socket = node.inputs.get(group_label)
|
|
410
|
+
if isinstance(socket, shader.BOOL_SOCKET_CLASSES):
|
|
411
|
+
socket.default_value = bool(value)
|
|
412
|
+
elif isinstance(socket, shader.FLOAT_SOCKET_CLASSES):
|
|
413
|
+
socket.default_value = float(value)
|
|
414
|
+
elif isinstance(socket, shader.INT_SOCKET_CLASSES):
|
|
415
|
+
socket.default_value = int(value)
|
|
416
|
+
else:
|
|
417
|
+
_logger.warning(
|
|
418
|
+
'No "%s" in shader node group "%s"', group_label, node_group_name
|
|
419
|
+
)
|
|
420
|
+
|
|
421
|
+
def set_bool(
|
|
422
|
+
self,
|
|
423
|
+
node_group_name: str,
|
|
424
|
+
group_label: str,
|
|
425
|
+
value: object,
|
|
426
|
+
) -> None:
|
|
427
|
+
self.set_value(node_group_name, group_label, 1 if value else 0)
|
|
428
|
+
|
|
429
|
+
def set_int(
|
|
430
|
+
self,
|
|
431
|
+
node_group_name: str,
|
|
432
|
+
group_label: str,
|
|
433
|
+
value: object,
|
|
434
|
+
) -> None:
|
|
435
|
+
self.set_value(node_group_name, group_label, value)
|
|
436
|
+
|
|
437
|
+
def set_rgba(
|
|
438
|
+
self,
|
|
439
|
+
node_group_name: str,
|
|
440
|
+
group_label: str,
|
|
441
|
+
value: object,
|
|
442
|
+
default_value: Optional[tuple[float, float, float, float]] = None,
|
|
443
|
+
) -> None:
|
|
444
|
+
material = self.find_material()
|
|
445
|
+
|
|
446
|
+
outline = self.find_outline_property_group(material)
|
|
447
|
+
if outline:
|
|
448
|
+
outline.set_rgba(node_group_name, group_label, value, default_value)
|
|
449
|
+
|
|
450
|
+
if not default_value:
|
|
451
|
+
default_value = (0.0, 0.0, 0.0, 0.0)
|
|
452
|
+
|
|
453
|
+
node_tree = material.node_tree
|
|
454
|
+
if not node_tree:
|
|
455
|
+
return
|
|
456
|
+
|
|
457
|
+
rgba = shader.rgba_or_none(value) or default_value
|
|
458
|
+
|
|
459
|
+
node = next(
|
|
460
|
+
(
|
|
461
|
+
node
|
|
462
|
+
for node in node_tree.nodes
|
|
463
|
+
if isinstance(node, ShaderNodeGroup)
|
|
464
|
+
and node.node_tree
|
|
465
|
+
and node.node_tree.name == node_group_name
|
|
466
|
+
),
|
|
467
|
+
None,
|
|
468
|
+
)
|
|
469
|
+
if not node:
|
|
470
|
+
_logger.warning('No group node "%s"', node_group_name)
|
|
471
|
+
return
|
|
472
|
+
|
|
473
|
+
socket = node.inputs.get(group_label)
|
|
474
|
+
if not isinstance(socket, shader.COLOR_SOCKET_CLASSES):
|
|
475
|
+
_logger.warning(
|
|
476
|
+
'No "%s" in shader node group "%s"', group_label, node_group_name
|
|
477
|
+
)
|
|
478
|
+
return
|
|
479
|
+
|
|
480
|
+
socket.default_value = rgba
|
|
481
|
+
|
|
482
|
+
def set_rgb(
|
|
483
|
+
self,
|
|
484
|
+
node_group_name: str,
|
|
485
|
+
group_label: str,
|
|
486
|
+
value: object,
|
|
487
|
+
default_value: Optional[tuple[float, float, float]] = None,
|
|
488
|
+
) -> None:
|
|
489
|
+
material = self.find_material()
|
|
490
|
+
|
|
491
|
+
outline = self.find_outline_property_group(material)
|
|
492
|
+
if outline:
|
|
493
|
+
outline.set_rgb(node_group_name, group_label, value, default_value)
|
|
494
|
+
|
|
495
|
+
if not default_value:
|
|
496
|
+
default_value = (0.0, 0.0, 0.0)
|
|
497
|
+
|
|
498
|
+
node_tree = material.node_tree
|
|
499
|
+
if not node_tree:
|
|
500
|
+
return
|
|
501
|
+
|
|
502
|
+
rgb = shader.rgb_or_none(value) or default_value
|
|
503
|
+
|
|
504
|
+
node = next(
|
|
505
|
+
(
|
|
506
|
+
node
|
|
507
|
+
for node in node_tree.nodes
|
|
508
|
+
if isinstance(node, ShaderNodeGroup)
|
|
509
|
+
and node.node_tree
|
|
510
|
+
and node.node_tree.name == node_group_name
|
|
511
|
+
),
|
|
512
|
+
None,
|
|
513
|
+
)
|
|
514
|
+
if not node:
|
|
515
|
+
_logger.warning('No group node "%s"', node_group_name)
|
|
516
|
+
return
|
|
517
|
+
|
|
518
|
+
socket = node.inputs.get(group_label)
|
|
519
|
+
if not isinstance(socket, shader.COLOR_SOCKET_CLASSES):
|
|
520
|
+
_logger.warning(
|
|
521
|
+
'No "%s" in shader node group "%s"', group_label, node_group_name
|
|
522
|
+
)
|
|
523
|
+
return
|
|
524
|
+
|
|
525
|
+
socket.default_value = (*rgb, 1.0)
|
|
526
|
+
|
|
527
|
+
def set_vector3(
|
|
528
|
+
self,
|
|
529
|
+
node_group_name: str,
|
|
530
|
+
group_label: str,
|
|
531
|
+
value: object,
|
|
532
|
+
default_value: Optional[tuple[float, float, float]] = None,
|
|
533
|
+
) -> None:
|
|
534
|
+
material = self.find_material()
|
|
535
|
+
|
|
536
|
+
outline = self.find_outline_property_group(material)
|
|
537
|
+
if outline:
|
|
538
|
+
outline.set_vector3(node_group_name, group_label, value, default_value)
|
|
539
|
+
|
|
540
|
+
if not default_value:
|
|
541
|
+
default_value = (0.0, 0.0, 0.0)
|
|
542
|
+
|
|
543
|
+
node_tree = material.node_tree
|
|
544
|
+
if not node_tree:
|
|
545
|
+
return
|
|
546
|
+
|
|
547
|
+
vector3 = convert.float3_or_none(value) or default_value
|
|
548
|
+
|
|
549
|
+
node = next(
|
|
550
|
+
(
|
|
551
|
+
node
|
|
552
|
+
for node in node_tree.nodes
|
|
553
|
+
if isinstance(node, ShaderNodeGroup)
|
|
554
|
+
and node.node_tree
|
|
555
|
+
and node.node_tree.name == node_group_name
|
|
556
|
+
),
|
|
557
|
+
None,
|
|
558
|
+
)
|
|
559
|
+
if not node:
|
|
560
|
+
_logger.warning('No group node "%s"', node_group_name)
|
|
561
|
+
return
|
|
562
|
+
|
|
563
|
+
socket = node.inputs.get(group_label)
|
|
564
|
+
if not isinstance(socket, shader.VECTOR_SOCKET_CLASSES):
|
|
565
|
+
_logger.warning(
|
|
566
|
+
'No "%s" in shader node group "%s"', group_label, node_group_name
|
|
567
|
+
)
|
|
568
|
+
return
|
|
569
|
+
|
|
570
|
+
socket.default_value = vector3
|
|
571
|
+
|
|
572
|
+
|
|
573
|
+
class TextureTraceablePropertyGroup(MaterialTraceablePropertyGroup):
|
|
574
|
+
def get_texture_info_property_group(self) -> "Mtoon1TextureInfoPropertyGroup":
|
|
575
|
+
chain = self.path_from_id().split(".")
|
|
576
|
+
if chain[-1:] == ["sampler"]:
|
|
577
|
+
chain = chain[:-1]
|
|
578
|
+
if chain[-1:] == ["index"]:
|
|
579
|
+
chain = chain[:-1]
|
|
580
|
+
if chain[-1:] == ["khr_texture_transform"]:
|
|
581
|
+
chain = chain[:-1]
|
|
582
|
+
if chain[-1:] == ["extensions"]:
|
|
583
|
+
chain = chain[:-1]
|
|
584
|
+
material = self.find_material()
|
|
585
|
+
property_group = material.path_resolve(".".join(chain), False)
|
|
586
|
+
if not isinstance(property_group, Mtoon1TextureInfoPropertyGroup):
|
|
587
|
+
message = f"{property_group} is not a Mtoon1TextureInfoPropertyGroup"
|
|
588
|
+
raise TypeError(message)
|
|
589
|
+
return property_group
|
|
590
|
+
|
|
591
|
+
def get_texture_node_name(self, extra: str) -> str:
|
|
592
|
+
texture_info = self.get_texture_info_property_group()
|
|
593
|
+
name = type(texture_info.index).__name__
|
|
594
|
+
return re.sub("PropertyGroup$", "", name) + "." + extra
|
|
595
|
+
|
|
596
|
+
def get_image_texture_node_name(self) -> str:
|
|
597
|
+
return self.get_texture_node_name("Image")
|
|
598
|
+
|
|
599
|
+
def get_image_texture_uv_node_name(self) -> str:
|
|
600
|
+
return self.get_texture_node_name("Uv")
|
|
601
|
+
|
|
602
|
+
@classmethod
|
|
603
|
+
def link_nodes(
|
|
604
|
+
cls,
|
|
605
|
+
material: Material,
|
|
606
|
+
out_node_name: str,
|
|
607
|
+
out_node_type: type[Node],
|
|
608
|
+
out_node_socket_name: str,
|
|
609
|
+
node_socket_target: NodeSocketTarget,
|
|
610
|
+
) -> None:
|
|
611
|
+
node_tree = material.node_tree
|
|
612
|
+
if not node_tree:
|
|
613
|
+
return
|
|
614
|
+
|
|
615
|
+
select_in_node = node_socket_target.create_node_selector(material)
|
|
616
|
+
in_socket_name = node_socket_target.get_in_socket_name()
|
|
617
|
+
|
|
618
|
+
# Check if already connected
|
|
619
|
+
connection_check_node = next(
|
|
620
|
+
(
|
|
621
|
+
link.from_node
|
|
622
|
+
for link in node_tree.links
|
|
623
|
+
if select_in_node(link.to_node)
|
|
624
|
+
and link.to_socket
|
|
625
|
+
and link.to_socket.name == in_socket_name
|
|
626
|
+
),
|
|
627
|
+
None,
|
|
628
|
+
)
|
|
629
|
+
while connection_check_node:
|
|
630
|
+
if (
|
|
631
|
+
isinstance(connection_check_node, out_node_type)
|
|
632
|
+
and connection_check_node.name == out_node_name
|
|
633
|
+
):
|
|
634
|
+
return
|
|
635
|
+
if isinstance(connection_check_node, NodeReroute):
|
|
636
|
+
connection_check_inputs = connection_check_node.inputs
|
|
637
|
+
if not connection_check_inputs:
|
|
638
|
+
break
|
|
639
|
+
connection_check_links = connection_check_inputs[0].links
|
|
640
|
+
if not connection_check_links:
|
|
641
|
+
break
|
|
642
|
+
connection_check_link = connection_check_links[0]
|
|
643
|
+
connection_check_node = connection_check_link.from_node
|
|
644
|
+
continue
|
|
645
|
+
break
|
|
646
|
+
|
|
647
|
+
# If connected to unrelated node, disconnect the link
|
|
648
|
+
cls.unlink_nodes(material, node_socket_target)
|
|
649
|
+
|
|
650
|
+
# Search for output node and socket
|
|
651
|
+
out_node = node_tree.nodes.get(out_node_name)
|
|
652
|
+
if not isinstance(out_node, out_node_type):
|
|
653
|
+
_logger.error("No output node: %s", out_node_name)
|
|
654
|
+
return
|
|
655
|
+
out_socket = out_node.outputs.get(out_node_socket_name)
|
|
656
|
+
if not out_socket:
|
|
657
|
+
_logger.error("No output node socket: %s", out_node_socket_name)
|
|
658
|
+
return
|
|
659
|
+
traversing_sockets = [out_socket]
|
|
660
|
+
while traversing_sockets:
|
|
661
|
+
traversing_socket = traversing_sockets.pop()
|
|
662
|
+
for connection_check_link in traversing_socket.links:
|
|
663
|
+
connection_check_node = connection_check_link.to_node
|
|
664
|
+
if not isinstance(connection_check_node, NodeReroute):
|
|
665
|
+
continue
|
|
666
|
+
if connection_check_node.label != in_socket_name:
|
|
667
|
+
traversing_sockets.extend(connection_check_node.outputs)
|
|
668
|
+
continue
|
|
669
|
+
traversing_outputs = connection_check_node.outputs
|
|
670
|
+
if not traversing_outputs:
|
|
671
|
+
continue
|
|
672
|
+
out_socket = traversing_outputs[0]
|
|
673
|
+
out_node = connection_check_node
|
|
674
|
+
break
|
|
675
|
+
|
|
676
|
+
# Search for input node and socket
|
|
677
|
+
in_node = next(
|
|
678
|
+
(n for n in node_tree.nodes if select_in_node(n)),
|
|
679
|
+
None,
|
|
680
|
+
)
|
|
681
|
+
if not in_node:
|
|
682
|
+
_logger.error("No input node")
|
|
683
|
+
return
|
|
684
|
+
|
|
685
|
+
in_socket = in_node.inputs.get(in_socket_name)
|
|
686
|
+
if not in_socket:
|
|
687
|
+
_logger.error("No input socket: %s", in_socket_name)
|
|
688
|
+
return
|
|
689
|
+
|
|
690
|
+
node_tree.links.new(in_socket, out_socket)
|
|
691
|
+
|
|
692
|
+
@classmethod
|
|
693
|
+
def unlink_nodes(
|
|
694
|
+
cls,
|
|
695
|
+
material: Material,
|
|
696
|
+
node_socket_target: NodeSocketTarget,
|
|
697
|
+
) -> None:
|
|
698
|
+
while True:
|
|
699
|
+
# Refresh in_node/out_node. These nodes may be invalidated.
|
|
700
|
+
node_tree = material.node_tree
|
|
701
|
+
if not node_tree:
|
|
702
|
+
return
|
|
703
|
+
|
|
704
|
+
select_in_node = node_socket_target.create_node_selector(material)
|
|
705
|
+
in_socket_name = node_socket_target.get_in_socket_name()
|
|
706
|
+
disconnecting_link = next(
|
|
707
|
+
(
|
|
708
|
+
link
|
|
709
|
+
for link in node_tree.links
|
|
710
|
+
if select_in_node(link.to_node)
|
|
711
|
+
and link.to_socket
|
|
712
|
+
and link.to_socket.name == in_socket_name
|
|
713
|
+
),
|
|
714
|
+
None,
|
|
715
|
+
)
|
|
716
|
+
if not disconnecting_link:
|
|
717
|
+
return
|
|
718
|
+
|
|
719
|
+
node_tree.links.remove(disconnecting_link)
|
|
720
|
+
|
|
721
|
+
@classmethod
|
|
722
|
+
def link_or_unlink_nodes(
|
|
723
|
+
cls,
|
|
724
|
+
material: Material,
|
|
725
|
+
out_node_name: str,
|
|
726
|
+
out_node_type: type[Node],
|
|
727
|
+
out_node_socket_name: str,
|
|
728
|
+
node_socket_target: NodeSocketTarget,
|
|
729
|
+
*,
|
|
730
|
+
link: bool,
|
|
731
|
+
) -> None:
|
|
732
|
+
if link:
|
|
733
|
+
cls.link_nodes(
|
|
734
|
+
material,
|
|
735
|
+
out_node_name,
|
|
736
|
+
out_node_type,
|
|
737
|
+
out_node_socket_name,
|
|
738
|
+
node_socket_target,
|
|
739
|
+
)
|
|
740
|
+
else:
|
|
741
|
+
cls.unlink_nodes(
|
|
742
|
+
material,
|
|
743
|
+
node_socket_target,
|
|
744
|
+
)
|
|
745
|
+
|
|
746
|
+
def update_image(self, image: Optional[Image]) -> None:
|
|
747
|
+
material = self.find_material()
|
|
748
|
+
|
|
749
|
+
outline = self.find_outline_property_group(material)
|
|
750
|
+
if outline and isinstance(outline, TextureTraceablePropertyGroup):
|
|
751
|
+
outline.update_image(image)
|
|
752
|
+
|
|
753
|
+
node_tree = material.node_tree
|
|
754
|
+
if not node_tree:
|
|
755
|
+
return
|
|
756
|
+
|
|
757
|
+
node_name = self.get_image_texture_node_name()
|
|
758
|
+
|
|
759
|
+
node = node_tree.nodes.get(node_name)
|
|
760
|
+
if not isinstance(node, ShaderNodeTexImage):
|
|
761
|
+
_logger.warning('No shader node tex image "%s"', node_name)
|
|
762
|
+
return
|
|
763
|
+
|
|
764
|
+
node.image = image
|
|
765
|
+
|
|
766
|
+
texture_info = self.get_texture_info_property_group()
|
|
767
|
+
|
|
768
|
+
for (
|
|
769
|
+
output_socket_name,
|
|
770
|
+
node_socket_targets,
|
|
771
|
+
) in texture_info.node_socket_targets.items():
|
|
772
|
+
for node_socket_target in node_socket_targets:
|
|
773
|
+
self.link_or_unlink_nodes(
|
|
774
|
+
material,
|
|
775
|
+
node_name,
|
|
776
|
+
ShaderNodeTexImage,
|
|
777
|
+
output_socket_name,
|
|
778
|
+
node_socket_target,
|
|
779
|
+
link=bool(image),
|
|
780
|
+
)
|
|
781
|
+
|
|
782
|
+
texture_info.setup_drivers(material)
|
|
783
|
+
|
|
784
|
+
def get_connected_node_image(self) -> Optional[Image]:
|
|
785
|
+
material = self.find_material()
|
|
786
|
+
if bpy.app.version < (5, 0, 0) and not material.use_nodes:
|
|
787
|
+
return None
|
|
788
|
+
|
|
789
|
+
node_tree = material.node_tree
|
|
790
|
+
if not node_tree:
|
|
791
|
+
return None
|
|
792
|
+
|
|
793
|
+
texture_info = self.get_texture_info_property_group()
|
|
794
|
+
node_socket_targets = next(
|
|
795
|
+
iter(texture_info.node_socket_targets.values()), None
|
|
796
|
+
)
|
|
797
|
+
if not node_socket_targets:
|
|
798
|
+
return None
|
|
799
|
+
|
|
800
|
+
node_socket_target = next(iter(node_socket_targets), None)
|
|
801
|
+
if not node_socket_target:
|
|
802
|
+
return None
|
|
803
|
+
|
|
804
|
+
node_selector = node_socket_target.create_node_selector(material)
|
|
805
|
+
node = next((node for node in node_tree.nodes if node_selector(node)), None)
|
|
806
|
+
if not node:
|
|
807
|
+
return None
|
|
808
|
+
|
|
809
|
+
traversing_input_socket = None
|
|
810
|
+
for input_socket in node.inputs:
|
|
811
|
+
if input_socket.name == node_socket_target.get_in_socket_name():
|
|
812
|
+
traversing_input_socket = input_socket
|
|
813
|
+
break
|
|
814
|
+
|
|
815
|
+
while True:
|
|
816
|
+
if not traversing_input_socket:
|
|
817
|
+
return None
|
|
818
|
+
|
|
819
|
+
links_to_input_socket = traversing_input_socket.links
|
|
820
|
+
traversing_input_socket = None
|
|
821
|
+
for link_to_input_socket in links_to_input_socket:
|
|
822
|
+
from_node = link_to_input_socket.from_node
|
|
823
|
+
if isinstance(from_node, ShaderNodeTexImage):
|
|
824
|
+
return from_node.image
|
|
825
|
+
if isinstance(from_node, NodeReroute):
|
|
826
|
+
traversing_input_socket = from_node.inputs[0]
|
|
827
|
+
break
|
|
828
|
+
|
|
829
|
+
def get_texture_uv_int(self, name: str, default_value: int) -> int:
|
|
830
|
+
node_name = self.get_image_texture_uv_node_name()
|
|
831
|
+
material = self.find_material()
|
|
832
|
+
if not material.node_tree:
|
|
833
|
+
return default_value
|
|
834
|
+
node_tree = material.node_tree
|
|
835
|
+
node = node_tree.nodes.get(node_name)
|
|
836
|
+
if not isinstance(node, ShaderNodeGroup):
|
|
837
|
+
return default_value
|
|
838
|
+
socket = node.inputs.get(name)
|
|
839
|
+
if not socket:
|
|
840
|
+
_logger.warning('No "%s" in shader node group "%s"', name, node_name)
|
|
841
|
+
return default_value
|
|
842
|
+
|
|
843
|
+
if isinstance(socket, shader.FLOAT_SOCKET_CLASSES):
|
|
844
|
+
return round(socket.default_value)
|
|
845
|
+
if isinstance(socket, shader.INT_SOCKET_CLASSES):
|
|
846
|
+
return socket.default_value
|
|
847
|
+
|
|
848
|
+
return default_value
|
|
849
|
+
|
|
850
|
+
def get_texture_uv_float(self, name: str, default_value: float) -> float:
|
|
851
|
+
node_name = self.get_image_texture_uv_node_name()
|
|
852
|
+
material = self.find_material()
|
|
853
|
+
if not material.node_tree:
|
|
854
|
+
return default_value
|
|
855
|
+
node_tree = material.node_tree
|
|
856
|
+
node = node_tree.nodes.get(node_name)
|
|
857
|
+
if not isinstance(node, ShaderNodeGroup):
|
|
858
|
+
return default_value
|
|
859
|
+
socket = node.inputs.get(name)
|
|
860
|
+
if not socket:
|
|
861
|
+
_logger.warning('No "%s" in shader node group "%s"', name, node_name)
|
|
862
|
+
return default_value
|
|
863
|
+
|
|
864
|
+
if isinstance(socket, shader.FLOAT_SOCKET_CLASSES):
|
|
865
|
+
return socket.default_value
|
|
866
|
+
if isinstance(socket, shader.INT_SOCKET_CLASSES):
|
|
867
|
+
return float(socket.default_value)
|
|
868
|
+
|
|
869
|
+
return default_value
|
|
870
|
+
|
|
871
|
+
def set_texture_uv(self, name: str, value: object) -> None:
|
|
872
|
+
node_name = self.get_image_texture_uv_node_name()
|
|
873
|
+
material = self.find_material()
|
|
874
|
+
if not material.node_tree:
|
|
875
|
+
return
|
|
876
|
+
node_tree = material.node_tree
|
|
877
|
+
node = node_tree.nodes.get(node_name)
|
|
878
|
+
if not isinstance(node, ShaderNodeGroup):
|
|
879
|
+
return
|
|
880
|
+
socket = node.inputs.get(name)
|
|
881
|
+
if not socket:
|
|
882
|
+
_logger.warning('No "%s" in shader node group "%s"', name, node_name)
|
|
883
|
+
return
|
|
884
|
+
|
|
885
|
+
if isinstance(value, (float, int)):
|
|
886
|
+
if isinstance(socket, shader.FLOAT_SOCKET_CLASSES):
|
|
887
|
+
socket.default_value = float(value)
|
|
888
|
+
if isinstance(socket, shader.INT_SOCKET_CLASSES):
|
|
889
|
+
socket.default_value = int(value)
|
|
890
|
+
elif (vector2 := convert.float2_or_none(value)) is not None and isinstance(
|
|
891
|
+
socket, shader.VECTOR_SOCKET_CLASSES
|
|
892
|
+
):
|
|
893
|
+
socket.default_value = (*vector2, 0.0)
|
|
894
|
+
|
|
895
|
+
outline = self.find_outline_property_group(material)
|
|
896
|
+
if not outline:
|
|
897
|
+
return
|
|
898
|
+
if not isinstance(outline, TextureTraceablePropertyGroup):
|
|
899
|
+
return
|
|
900
|
+
outline.set_texture_uv(name, value)
|
|
901
|
+
|
|
902
|
+
|
|
903
|
+
class Mtoon1KhrTextureTransformPropertyGroup(TextureTraceablePropertyGroup):
|
|
904
|
+
def is_default(self) -> bool:
|
|
905
|
+
offset_x, offset_y = self.offset
|
|
906
|
+
scale_x, scale_y = self.scale
|
|
907
|
+
return (
|
|
908
|
+
abs(offset_x - shader.UV_GROUP_UV_OFFSET_X_DEFAULT) < float_info.epsilon
|
|
909
|
+
and abs(offset_y - shader.UV_GROUP_UV_OFFSET_Y_DEFAULT) < float_info.epsilon
|
|
910
|
+
and abs(scale_x - shader.UV_GROUP_UV_SCALE_X_DEFAULT) < float_info.epsilon
|
|
911
|
+
and abs(scale_y - shader.UV_GROUP_UV_SCALE_Y_DEFAULT) < float_info.epsilon
|
|
912
|
+
)
|
|
913
|
+
|
|
914
|
+
def _call_overridden_get_texture_offset(self) -> tuple[float, float]:
|
|
915
|
+
return self._get_texture_offset()
|
|
916
|
+
|
|
917
|
+
def _get_texture_offset(self) -> tuple[float, float]:
|
|
918
|
+
return (0, 0)
|
|
919
|
+
|
|
920
|
+
def _call_overridden_set_texture_offset(self, value: object) -> None:
|
|
921
|
+
self._set_texture_offset(value)
|
|
922
|
+
|
|
923
|
+
def _set_texture_offset(self, value: object) -> None:
|
|
924
|
+
_ = value
|
|
925
|
+
|
|
926
|
+
def _call_overridden_get_texture_scale(self) -> tuple[float, float]:
|
|
927
|
+
return self._get_texture_scale()
|
|
928
|
+
|
|
929
|
+
def _get_texture_scale(self) -> tuple[float, float]:
|
|
930
|
+
return 1, 1
|
|
931
|
+
|
|
932
|
+
def _call_overridden_set_texture_scale(self, value: object) -> None:
|
|
933
|
+
self._set_texture_scale(value)
|
|
934
|
+
|
|
935
|
+
def _set_texture_scale(self, value: object) -> None:
|
|
936
|
+
_ = value
|
|
937
|
+
|
|
938
|
+
offset: FloatVectorProperty( # type: ignore[valid-type]
|
|
939
|
+
name="Offset",
|
|
940
|
+
size=2,
|
|
941
|
+
default=(
|
|
942
|
+
shader.UV_GROUP_UV_OFFSET_X_DEFAULT,
|
|
943
|
+
shader.UV_GROUP_UV_OFFSET_Y_DEFAULT,
|
|
944
|
+
),
|
|
945
|
+
get=_call_overridden_get_texture_offset,
|
|
946
|
+
set=_call_overridden_set_texture_offset,
|
|
947
|
+
)
|
|
948
|
+
|
|
949
|
+
scale: FloatVectorProperty( # type: ignore[valid-type]
|
|
950
|
+
name="Scale",
|
|
951
|
+
size=2,
|
|
952
|
+
default=(
|
|
953
|
+
shader.UV_GROUP_UV_SCALE_X_DEFAULT,
|
|
954
|
+
shader.UV_GROUP_UV_SCALE_Y_DEFAULT,
|
|
955
|
+
),
|
|
956
|
+
get=_call_overridden_get_texture_scale,
|
|
957
|
+
set=_call_overridden_set_texture_scale,
|
|
958
|
+
)
|
|
959
|
+
|
|
960
|
+
if TYPE_CHECKING:
|
|
961
|
+
# This code is auto generated.
|
|
962
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
963
|
+
offset: Sequence[float] # type: ignore[no-redef]
|
|
964
|
+
scale: Sequence[float] # type: ignore[no-redef]
|
|
965
|
+
|
|
966
|
+
|
|
967
|
+
class Mtoon1NonBaseColorKhrTextureTransformPropertyGroup(
|
|
968
|
+
Mtoon1KhrTextureTransformPropertyGroup
|
|
969
|
+
):
|
|
970
|
+
def _get_texture_offset(self) -> tuple[float, float]:
|
|
971
|
+
mtoon1 = get_material_extension(self.find_material()).mtoon1
|
|
972
|
+
if any(
|
|
973
|
+
texture_info.extensions.khr_texture_transform == self
|
|
974
|
+
for texture_info in mtoon1.non_uv_transformable_texture_info()
|
|
975
|
+
):
|
|
976
|
+
return (0.0, 0.0)
|
|
977
|
+
base_color_texture = mtoon1.pbr_metallic_roughness.base_color_texture
|
|
978
|
+
offset = base_color_texture.extensions.khr_texture_transform.offset
|
|
979
|
+
return (offset[0], offset[1])
|
|
980
|
+
|
|
981
|
+
def _set_texture_offset(self, value: object) -> None:
|
|
982
|
+
_ = value
|
|
983
|
+
# https://github.com/vrm-c/UniVRM/blob/v0.131.1/Packages/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials/BuiltInVrm10MToonMaterialExporter.cs#L166-L177
|
|
984
|
+
_logger.info(
|
|
985
|
+
"Setting texture offset is not supported for non-base color textures"
|
|
986
|
+
)
|
|
987
|
+
|
|
988
|
+
def _get_texture_scale(self) -> tuple[float, float]:
|
|
989
|
+
mtoon1 = get_material_extension(self.find_material()).mtoon1
|
|
990
|
+
if any(
|
|
991
|
+
texture_info.extensions.khr_texture_transform == self
|
|
992
|
+
for texture_info in mtoon1.non_uv_transformable_texture_info()
|
|
993
|
+
):
|
|
994
|
+
return (1.0, 1.0)
|
|
995
|
+
base_color_texture = mtoon1.pbr_metallic_roughness.base_color_texture
|
|
996
|
+
scale = base_color_texture.extensions.khr_texture_transform.scale
|
|
997
|
+
return (scale[0], scale[1])
|
|
998
|
+
|
|
999
|
+
def _set_texture_scale(self, value: object) -> None:
|
|
1000
|
+
_ = value
|
|
1001
|
+
# https://github.com/vrm-c/UniVRM/blob/v0.131.1/Packages/VRM10/Runtime/IO/Material/BuiltInRP/Export/Materials/BuiltInVrm10MToonMaterialExporter.cs#L166-L177
|
|
1002
|
+
_logger.info(
|
|
1003
|
+
"Setting texture scale is not supported for non-base color textures"
|
|
1004
|
+
)
|
|
1005
|
+
|
|
1006
|
+
|
|
1007
|
+
class Mtoon1BaseColorKhrTextureTransformPropertyGroup(
|
|
1008
|
+
Mtoon1KhrTextureTransformPropertyGroup
|
|
1009
|
+
):
|
|
1010
|
+
def _get_texture_offset(self) -> tuple[float, float]:
|
|
1011
|
+
x = self.get_texture_uv_float(
|
|
1012
|
+
shader.UV_GROUP_UV_OFFSET_X_LABEL,
|
|
1013
|
+
default_value=shader.UV_GROUP_UV_OFFSET_X_DEFAULT,
|
|
1014
|
+
)
|
|
1015
|
+
y = self.get_texture_uv_float(
|
|
1016
|
+
shader.UV_GROUP_UV_OFFSET_Y_LABEL,
|
|
1017
|
+
default_value=shader.UV_GROUP_UV_OFFSET_Y_DEFAULT,
|
|
1018
|
+
)
|
|
1019
|
+
return x, y
|
|
1020
|
+
|
|
1021
|
+
def _set_texture_offset(self, value: object) -> None:
|
|
1022
|
+
offset = convert.float2_or_none(value)
|
|
1023
|
+
if offset is None:
|
|
1024
|
+
return
|
|
1025
|
+
material = self.find_material()
|
|
1026
|
+
node_tree = material.node_tree
|
|
1027
|
+
if not node_tree:
|
|
1028
|
+
return
|
|
1029
|
+
|
|
1030
|
+
ext = get_material_extension(material)
|
|
1031
|
+
for texture_info, offset in [
|
|
1032
|
+
*[
|
|
1033
|
+
(texture_info, offset)
|
|
1034
|
+
for texture_info in ext.mtoon1.uv_transformable_texture_info()
|
|
1035
|
+
],
|
|
1036
|
+
*[
|
|
1037
|
+
(texture_info, (0, 0))
|
|
1038
|
+
for texture_info in ext.mtoon1.non_uv_transformable_texture_info()
|
|
1039
|
+
],
|
|
1040
|
+
]:
|
|
1041
|
+
khr_texture_transform = texture_info.extensions.khr_texture_transform
|
|
1042
|
+
|
|
1043
|
+
khr_texture_transform.set_texture_uv(
|
|
1044
|
+
shader.UV_GROUP_UV_OFFSET_X_LABEL, offset[0]
|
|
1045
|
+
)
|
|
1046
|
+
khr_texture_transform.set_texture_uv(
|
|
1047
|
+
shader.UV_GROUP_UV_OFFSET_Y_LABEL, offset[1]
|
|
1048
|
+
)
|
|
1049
|
+
|
|
1050
|
+
node_name = khr_texture_transform.get_image_texture_node_name()
|
|
1051
|
+
node = node_tree.nodes.get(node_name)
|
|
1052
|
+
if not isinstance(node, ShaderNodeTexImage):
|
|
1053
|
+
_logger.warning('No shader node tex image "%s"', node_name)
|
|
1054
|
+
continue
|
|
1055
|
+
node.texture_mapping.translation = Vector((0, 0, 0))
|
|
1056
|
+
|
|
1057
|
+
outline = khr_texture_transform.find_outline_property_group(material)
|
|
1058
|
+
if not outline:
|
|
1059
|
+
continue
|
|
1060
|
+
if not isinstance(outline, Mtoon1KhrTextureTransformPropertyGroup):
|
|
1061
|
+
continue
|
|
1062
|
+
outline.offset = offset
|
|
1063
|
+
|
|
1064
|
+
def _get_texture_scale(self) -> tuple[float, float]:
|
|
1065
|
+
x = self.get_texture_uv_float(
|
|
1066
|
+
shader.UV_GROUP_UV_SCALE_X_LABEL,
|
|
1067
|
+
default_value=shader.UV_GROUP_UV_SCALE_X_DEFAULT,
|
|
1068
|
+
)
|
|
1069
|
+
y = self.get_texture_uv_float(
|
|
1070
|
+
shader.UV_GROUP_UV_SCALE_Y_LABEL,
|
|
1071
|
+
default_value=shader.UV_GROUP_UV_SCALE_Y_DEFAULT,
|
|
1072
|
+
)
|
|
1073
|
+
return x, y
|
|
1074
|
+
|
|
1075
|
+
def _set_texture_scale(self, value: object) -> None:
|
|
1076
|
+
scale = convert.float2_or_none(value)
|
|
1077
|
+
if scale is None:
|
|
1078
|
+
return
|
|
1079
|
+
material = self.find_material()
|
|
1080
|
+
node_tree = material.node_tree
|
|
1081
|
+
if not node_tree:
|
|
1082
|
+
return
|
|
1083
|
+
|
|
1084
|
+
ext = get_material_extension(material)
|
|
1085
|
+
for texture_info, scale in [
|
|
1086
|
+
*[
|
|
1087
|
+
(texture_info, scale)
|
|
1088
|
+
for texture_info in ext.mtoon1.uv_transformable_texture_info()
|
|
1089
|
+
],
|
|
1090
|
+
*[
|
|
1091
|
+
(texture_info, (1, 1))
|
|
1092
|
+
for texture_info in ext.mtoon1.non_uv_transformable_texture_info()
|
|
1093
|
+
],
|
|
1094
|
+
]:
|
|
1095
|
+
khr_texture_transform = texture_info.extensions.khr_texture_transform
|
|
1096
|
+
|
|
1097
|
+
khr_texture_transform.set_texture_uv(
|
|
1098
|
+
shader.UV_GROUP_UV_SCALE_X_LABEL, scale[0]
|
|
1099
|
+
)
|
|
1100
|
+
khr_texture_transform.set_texture_uv(
|
|
1101
|
+
shader.UV_GROUP_UV_SCALE_Y_LABEL, scale[1]
|
|
1102
|
+
)
|
|
1103
|
+
|
|
1104
|
+
node_name = khr_texture_transform.get_image_texture_node_name()
|
|
1105
|
+
node = node_tree.nodes.get(node_name)
|
|
1106
|
+
if not isinstance(node, ShaderNodeTexImage):
|
|
1107
|
+
_logger.warning('No shader node tex image "%s"', node_name)
|
|
1108
|
+
continue
|
|
1109
|
+
node.texture_mapping.scale = Vector((1, 1, 1))
|
|
1110
|
+
|
|
1111
|
+
outline = khr_texture_transform.find_outline_property_group(material)
|
|
1112
|
+
if not outline:
|
|
1113
|
+
continue
|
|
1114
|
+
if not isinstance(outline, Mtoon1KhrTextureTransformPropertyGroup):
|
|
1115
|
+
continue
|
|
1116
|
+
outline.scale = scale
|
|
1117
|
+
|
|
1118
|
+
|
|
1119
|
+
class Mtoon1ShadeMultiplyKhrTextureTransformPropertyGroup(
|
|
1120
|
+
Mtoon1NonBaseColorKhrTextureTransformPropertyGroup
|
|
1121
|
+
):
|
|
1122
|
+
pass
|
|
1123
|
+
|
|
1124
|
+
|
|
1125
|
+
class Mtoon1NormalKhrTextureTransformPropertyGroup(
|
|
1126
|
+
Mtoon1NonBaseColorKhrTextureTransformPropertyGroup
|
|
1127
|
+
):
|
|
1128
|
+
pass
|
|
1129
|
+
|
|
1130
|
+
|
|
1131
|
+
class Mtoon1ShadingShiftKhrTextureTransformPropertyGroup(
|
|
1132
|
+
Mtoon1NonBaseColorKhrTextureTransformPropertyGroup
|
|
1133
|
+
):
|
|
1134
|
+
pass
|
|
1135
|
+
|
|
1136
|
+
|
|
1137
|
+
class Mtoon1EmissiveKhrTextureTransformPropertyGroup(
|
|
1138
|
+
Mtoon1NonBaseColorKhrTextureTransformPropertyGroup
|
|
1139
|
+
):
|
|
1140
|
+
pass
|
|
1141
|
+
|
|
1142
|
+
|
|
1143
|
+
class Mtoon1RimMultiplyKhrTextureTransformPropertyGroup(
|
|
1144
|
+
Mtoon1NonBaseColorKhrTextureTransformPropertyGroup
|
|
1145
|
+
):
|
|
1146
|
+
pass
|
|
1147
|
+
|
|
1148
|
+
|
|
1149
|
+
class Mtoon1MatcapKhrTextureTransformPropertyGroup(
|
|
1150
|
+
Mtoon1NonBaseColorKhrTextureTransformPropertyGroup
|
|
1151
|
+
):
|
|
1152
|
+
pass
|
|
1153
|
+
|
|
1154
|
+
|
|
1155
|
+
class Mtoon1OutlineWidthMultiplyKhrTextureTransformPropertyGroup(
|
|
1156
|
+
Mtoon1NonBaseColorKhrTextureTransformPropertyGroup
|
|
1157
|
+
):
|
|
1158
|
+
pass
|
|
1159
|
+
|
|
1160
|
+
|
|
1161
|
+
class Mtoon1UvAnimationMaskKhrTextureTransformPropertyGroup(
|
|
1162
|
+
Mtoon1NonBaseColorKhrTextureTransformPropertyGroup
|
|
1163
|
+
):
|
|
1164
|
+
pass
|
|
1165
|
+
|
|
1166
|
+
|
|
1167
|
+
class Mtoon1TextureInfoExtensionsPropertyGroup(PropertyGroup):
|
|
1168
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1169
|
+
type=Mtoon1KhrTextureTransformPropertyGroup
|
|
1170
|
+
)
|
|
1171
|
+
|
|
1172
|
+
if TYPE_CHECKING:
|
|
1173
|
+
# This code is auto generated.
|
|
1174
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1175
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1176
|
+
Mtoon1KhrTextureTransformPropertyGroup
|
|
1177
|
+
)
|
|
1178
|
+
|
|
1179
|
+
|
|
1180
|
+
class Mtoon1BaseColorTextureInfoExtensionsPropertyGroup(
|
|
1181
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1182
|
+
):
|
|
1183
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1184
|
+
type=Mtoon1BaseColorKhrTextureTransformPropertyGroup
|
|
1185
|
+
)
|
|
1186
|
+
|
|
1187
|
+
if TYPE_CHECKING:
|
|
1188
|
+
# This code is auto generated.
|
|
1189
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1190
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1191
|
+
Mtoon1BaseColorKhrTextureTransformPropertyGroup
|
|
1192
|
+
)
|
|
1193
|
+
|
|
1194
|
+
|
|
1195
|
+
class Mtoon1ShadeMultiplyTextureInfoExtensionsPropertyGroup(
|
|
1196
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1197
|
+
):
|
|
1198
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1199
|
+
type=Mtoon1ShadeMultiplyKhrTextureTransformPropertyGroup
|
|
1200
|
+
)
|
|
1201
|
+
|
|
1202
|
+
if TYPE_CHECKING:
|
|
1203
|
+
# This code is auto generated.
|
|
1204
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1205
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1206
|
+
Mtoon1ShadeMultiplyKhrTextureTransformPropertyGroup
|
|
1207
|
+
)
|
|
1208
|
+
|
|
1209
|
+
|
|
1210
|
+
class Mtoon1NormalTextureInfoExtensionsPropertyGroup(
|
|
1211
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1212
|
+
):
|
|
1213
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1214
|
+
type=Mtoon1NormalKhrTextureTransformPropertyGroup
|
|
1215
|
+
)
|
|
1216
|
+
|
|
1217
|
+
if TYPE_CHECKING:
|
|
1218
|
+
# This code is auto generated.
|
|
1219
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1220
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1221
|
+
Mtoon1NormalKhrTextureTransformPropertyGroup
|
|
1222
|
+
)
|
|
1223
|
+
|
|
1224
|
+
|
|
1225
|
+
class Mtoon1ShadingShiftTextureInfoExtensionsPropertyGroup(
|
|
1226
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1227
|
+
):
|
|
1228
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1229
|
+
type=Mtoon1ShadingShiftKhrTextureTransformPropertyGroup
|
|
1230
|
+
)
|
|
1231
|
+
|
|
1232
|
+
if TYPE_CHECKING:
|
|
1233
|
+
# This code is auto generated.
|
|
1234
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1235
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1236
|
+
Mtoon1ShadingShiftKhrTextureTransformPropertyGroup
|
|
1237
|
+
)
|
|
1238
|
+
|
|
1239
|
+
|
|
1240
|
+
class Mtoon1EmissiveTextureInfoExtensionsPropertyGroup(
|
|
1241
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1242
|
+
):
|
|
1243
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1244
|
+
type=Mtoon1EmissiveKhrTextureTransformPropertyGroup
|
|
1245
|
+
)
|
|
1246
|
+
|
|
1247
|
+
if TYPE_CHECKING:
|
|
1248
|
+
# This code is auto generated.
|
|
1249
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1250
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1251
|
+
Mtoon1EmissiveKhrTextureTransformPropertyGroup
|
|
1252
|
+
)
|
|
1253
|
+
|
|
1254
|
+
|
|
1255
|
+
class Mtoon1RimMultiplyTextureInfoExtensionsPropertyGroup(
|
|
1256
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1257
|
+
):
|
|
1258
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1259
|
+
type=Mtoon1RimMultiplyKhrTextureTransformPropertyGroup
|
|
1260
|
+
)
|
|
1261
|
+
|
|
1262
|
+
if TYPE_CHECKING:
|
|
1263
|
+
# This code is auto generated.
|
|
1264
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1265
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1266
|
+
Mtoon1RimMultiplyKhrTextureTransformPropertyGroup
|
|
1267
|
+
)
|
|
1268
|
+
|
|
1269
|
+
|
|
1270
|
+
class Mtoon1MatcapTextureInfoExtensionsPropertyGroup(
|
|
1271
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1272
|
+
):
|
|
1273
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1274
|
+
type=Mtoon1MatcapKhrTextureTransformPropertyGroup
|
|
1275
|
+
)
|
|
1276
|
+
|
|
1277
|
+
if TYPE_CHECKING:
|
|
1278
|
+
# This code is auto generated.
|
|
1279
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1280
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1281
|
+
Mtoon1MatcapKhrTextureTransformPropertyGroup
|
|
1282
|
+
)
|
|
1283
|
+
|
|
1284
|
+
|
|
1285
|
+
class Mtoon1OutlineWidthMultiplyTextureInfoExtensionsPropertyGroup(
|
|
1286
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1287
|
+
):
|
|
1288
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1289
|
+
type=Mtoon1OutlineWidthMultiplyKhrTextureTransformPropertyGroup
|
|
1290
|
+
)
|
|
1291
|
+
|
|
1292
|
+
if TYPE_CHECKING:
|
|
1293
|
+
# This code is auto generated.
|
|
1294
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1295
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1296
|
+
Mtoon1OutlineWidthMultiplyKhrTextureTransformPropertyGroup
|
|
1297
|
+
)
|
|
1298
|
+
|
|
1299
|
+
|
|
1300
|
+
class Mtoon1UvAnimationMaskTextureInfoExtensionsPropertyGroup(
|
|
1301
|
+
Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1302
|
+
):
|
|
1303
|
+
khr_texture_transform: PointerProperty( # type: ignore[valid-type]
|
|
1304
|
+
type=Mtoon1UvAnimationMaskKhrTextureTransformPropertyGroup
|
|
1305
|
+
)
|
|
1306
|
+
|
|
1307
|
+
if TYPE_CHECKING:
|
|
1308
|
+
# This code is auto generated.
|
|
1309
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1310
|
+
khr_texture_transform: ( # type: ignore[no-redef]
|
|
1311
|
+
Mtoon1UvAnimationMaskKhrTextureTransformPropertyGroup
|
|
1312
|
+
)
|
|
1313
|
+
|
|
1314
|
+
|
|
1315
|
+
class Mtoon1SamplerPropertyGroup(TextureTraceablePropertyGroup):
|
|
1316
|
+
(
|
|
1317
|
+
mag_filter_enum,
|
|
1318
|
+
(
|
|
1319
|
+
MAG_FILTER_NEAREST,
|
|
1320
|
+
MAG_FILTER_LINEAR,
|
|
1321
|
+
),
|
|
1322
|
+
) = property_group_enum(
|
|
1323
|
+
("NEAREST", "Nearest", "", "NONE", GL_NEAREST),
|
|
1324
|
+
("LINEAR", "Linear", "", "NONE", GL_LINEAR),
|
|
1325
|
+
)
|
|
1326
|
+
MAG_FILTER_DEFAULT = MAG_FILTER_LINEAR
|
|
1327
|
+
|
|
1328
|
+
def _get_mag_filter(self) -> int:
|
|
1329
|
+
default_value = self.MAG_FILTER_DEFAULT.value
|
|
1330
|
+
|
|
1331
|
+
material = self.find_material()
|
|
1332
|
+
node_name = self.get_image_texture_node_name()
|
|
1333
|
+
node_tree = material.node_tree
|
|
1334
|
+
if node_tree is None:
|
|
1335
|
+
return default_value
|
|
1336
|
+
|
|
1337
|
+
node = node_tree.nodes.get(node_name)
|
|
1338
|
+
if not isinstance(node, ShaderNodeTexImage):
|
|
1339
|
+
return default_value
|
|
1340
|
+
|
|
1341
|
+
if node.interpolation == IMAGE_INTERPOLATION_CLOSEST:
|
|
1342
|
+
return GL_NEAREST
|
|
1343
|
+
|
|
1344
|
+
if node.interpolation in GL_LINEAR_IMAGE_INTERPOLATIONS:
|
|
1345
|
+
return GL_LINEAR
|
|
1346
|
+
|
|
1347
|
+
value = self.get("mag_filter")
|
|
1348
|
+
if isinstance(value, int) and value in self.mag_filter_enum.values():
|
|
1349
|
+
return value
|
|
1350
|
+
|
|
1351
|
+
return default_value
|
|
1352
|
+
|
|
1353
|
+
def _set_mag_filter(self, value: int) -> None:
|
|
1354
|
+
# If input value conflicts with TexImage value, change TexImage value
|
|
1355
|
+
# If input value is GL_NEAREST and TexImage is Closest, delete internal value
|
|
1356
|
+
# If input value is GL_LINEAR and TexImage is Linear/Cubic/Smart,
|
|
1357
|
+
# delete internal value
|
|
1358
|
+
|
|
1359
|
+
if value not in self.mag_filter_enum.values():
|
|
1360
|
+
self.pop("mag_filter", None)
|
|
1361
|
+
return
|
|
1362
|
+
|
|
1363
|
+
material = self.find_material()
|
|
1364
|
+
node_name = self.get_image_texture_node_name()
|
|
1365
|
+
node_tree = material.node_tree
|
|
1366
|
+
if node_tree is not None:
|
|
1367
|
+
node = node_tree.nodes.get(node_name)
|
|
1368
|
+
if isinstance(node, ShaderNodeTexImage):
|
|
1369
|
+
if value == GL_NEAREST:
|
|
1370
|
+
if node.interpolation == IMAGE_INTERPOLATION_CLOSEST:
|
|
1371
|
+
self.pop("mag_filter", None)
|
|
1372
|
+
return
|
|
1373
|
+
node.interpolation = IMAGE_INTERPOLATION_CLOSEST
|
|
1374
|
+
if value == GL_LINEAR:
|
|
1375
|
+
if node.interpolation in GL_LINEAR_IMAGE_INTERPOLATIONS:
|
|
1376
|
+
self.pop("mag_filter", None)
|
|
1377
|
+
return
|
|
1378
|
+
node.interpolation = IMAGE_INTERPOLATION_LINEAR
|
|
1379
|
+
|
|
1380
|
+
self["mag_filter"] = value
|
|
1381
|
+
|
|
1382
|
+
def _get_min_filter(self) -> int:
|
|
1383
|
+
value = self.get("min_filter")
|
|
1384
|
+
if isinstance(value, int) and value in self.min_filter_enum.values():
|
|
1385
|
+
return value
|
|
1386
|
+
|
|
1387
|
+
default_value = self.MIN_FILTER_DEFAULT.value
|
|
1388
|
+
|
|
1389
|
+
material = self.find_material()
|
|
1390
|
+
node_name = self.get_image_texture_node_name()
|
|
1391
|
+
node_tree = material.node_tree
|
|
1392
|
+
if node_tree is None:
|
|
1393
|
+
return default_value
|
|
1394
|
+
|
|
1395
|
+
node = node_tree.nodes.get(node_name)
|
|
1396
|
+
if not isinstance(node, ShaderNodeTexImage):
|
|
1397
|
+
return default_value
|
|
1398
|
+
|
|
1399
|
+
if node.interpolation == IMAGE_INTERPOLATION_CLOSEST:
|
|
1400
|
+
return GL_NEAREST
|
|
1401
|
+
|
|
1402
|
+
if node.interpolation in GL_LINEAR_IMAGE_INTERPOLATIONS:
|
|
1403
|
+
return GL_LINEAR
|
|
1404
|
+
|
|
1405
|
+
return default_value
|
|
1406
|
+
|
|
1407
|
+
def _set_min_filter(self, value: int) -> None:
|
|
1408
|
+
# If input value is GL_NEAREST and TexImage is Closest, delete internal value
|
|
1409
|
+
# If input value is GL_LINEAR and TexImage is Linear/Cubic/Smart,
|
|
1410
|
+
# delete internal value
|
|
1411
|
+
|
|
1412
|
+
if value not in self.min_filter_enum.values():
|
|
1413
|
+
self.pop("min_filter", None)
|
|
1414
|
+
return
|
|
1415
|
+
|
|
1416
|
+
material = self.find_material()
|
|
1417
|
+
node_name = self.get_image_texture_node_name()
|
|
1418
|
+
node_tree = material.node_tree
|
|
1419
|
+
if node_tree is not None:
|
|
1420
|
+
node = node_tree.nodes.get(node_name)
|
|
1421
|
+
if isinstance(node, ShaderNodeTexImage):
|
|
1422
|
+
if (
|
|
1423
|
+
value == GL_NEAREST
|
|
1424
|
+
and node.interpolation == IMAGE_INTERPOLATION_CLOSEST
|
|
1425
|
+
):
|
|
1426
|
+
self.pop("min_filter", None)
|
|
1427
|
+
return
|
|
1428
|
+
if (
|
|
1429
|
+
value == GL_LINEAR
|
|
1430
|
+
and node.interpolation in GL_LINEAR_IMAGE_INTERPOLATIONS
|
|
1431
|
+
):
|
|
1432
|
+
self.pop("min_filter", None)
|
|
1433
|
+
return
|
|
1434
|
+
|
|
1435
|
+
self["min_filter"] = value
|
|
1436
|
+
|
|
1437
|
+
(
|
|
1438
|
+
min_filter_enum,
|
|
1439
|
+
(
|
|
1440
|
+
MIN_FILTER_NEAREST,
|
|
1441
|
+
MIN_FILTER_LINEAR,
|
|
1442
|
+
MIN_FILTER_NEAREST_MIPMAP_NEAREST,
|
|
1443
|
+
MIN_FILTER_LINEAR_MIPMAP_NEAREST,
|
|
1444
|
+
MIN_FILTER_NEAREST_MIPMAP_LINEAR,
|
|
1445
|
+
MIN_FILTER_LINEAR_MIPMAP_LINEAR,
|
|
1446
|
+
),
|
|
1447
|
+
) = property_group_enum(
|
|
1448
|
+
("NEAREST", "Nearest", "", "NONE", GL_NEAREST),
|
|
1449
|
+
("LINEAR", "Linear", "", "NONE", GL_LINEAR),
|
|
1450
|
+
(
|
|
1451
|
+
"NEAREST_MIPMAP_NEAREST",
|
|
1452
|
+
"Nearest Mipmap Nearest",
|
|
1453
|
+
"",
|
|
1454
|
+
"NONE",
|
|
1455
|
+
GL_NEAREST_MIPMAP_NEAREST,
|
|
1456
|
+
),
|
|
1457
|
+
(
|
|
1458
|
+
"LINEAR_MIPMAP_NEAREST",
|
|
1459
|
+
"Linear Mipmap Nearest",
|
|
1460
|
+
"",
|
|
1461
|
+
"NONE",
|
|
1462
|
+
GL_LINEAR_MIPMAP_NEAREST,
|
|
1463
|
+
),
|
|
1464
|
+
(
|
|
1465
|
+
"NEAREST_MIPMAP_LINEAR",
|
|
1466
|
+
"Nearest Mipmap Linear",
|
|
1467
|
+
"",
|
|
1468
|
+
"NONE",
|
|
1469
|
+
GL_NEAREST_MIPMAP_LINEAR,
|
|
1470
|
+
),
|
|
1471
|
+
(
|
|
1472
|
+
"LINEAR_MIPMAP_LINEAR",
|
|
1473
|
+
"Linear Mipmap Linear",
|
|
1474
|
+
"",
|
|
1475
|
+
"NONE",
|
|
1476
|
+
GL_LINEAR_MIPMAP_LINEAR,
|
|
1477
|
+
),
|
|
1478
|
+
)
|
|
1479
|
+
MIN_FILTER_DEFAULT = MIN_FILTER_LINEAR
|
|
1480
|
+
|
|
1481
|
+
# https://github.com/KhronosGroup/glTF/blob/2a9996a2ea66ab712590eaf62f39f1115996f5a3/specification/2.0/schema/sampler.schema.json#L67-L117
|
|
1482
|
+
(
|
|
1483
|
+
wrap_enum,
|
|
1484
|
+
(
|
|
1485
|
+
WRAP_CLAMP_TO_EDGE,
|
|
1486
|
+
WRAP_MIRRORED_REPEAT,
|
|
1487
|
+
WRAP_REPEAT,
|
|
1488
|
+
),
|
|
1489
|
+
) = property_group_enum(
|
|
1490
|
+
("CLAMP_TO_EDGE", "Clamp to Edge", "", "NONE", GL_CLAMP_TO_EDGE),
|
|
1491
|
+
("MIRRORED_REPEAT", "Mirrored Repeat", "", "NONE", GL_MIRRORED_REPEAT),
|
|
1492
|
+
("REPEAT", "Repeat", "", "NONE", GL_REPEAT),
|
|
1493
|
+
)
|
|
1494
|
+
|
|
1495
|
+
WRAP_DEFAULT = WRAP_REPEAT
|
|
1496
|
+
|
|
1497
|
+
def _get_wrap_s(self) -> int:
|
|
1498
|
+
wrap_s = self.get_texture_uv_int(
|
|
1499
|
+
shader.UV_GROUP_WRAP_S_LABEL, shader.UV_GROUP_WRAP_S_DEFAULT
|
|
1500
|
+
)
|
|
1501
|
+
if wrap_s in self.wrap_enum.values():
|
|
1502
|
+
return wrap_s
|
|
1503
|
+
return shader.UV_GROUP_WRAP_S_DEFAULT
|
|
1504
|
+
|
|
1505
|
+
def _set_wrap_s(self, value: object) -> None:
|
|
1506
|
+
self.set_texture_uv(shader.UV_GROUP_WRAP_S_LABEL, value)
|
|
1507
|
+
|
|
1508
|
+
def _get_wrap_t(self) -> int:
|
|
1509
|
+
wrap_t = self.get_texture_uv_int(
|
|
1510
|
+
shader.UV_GROUP_WRAP_T_LABEL, shader.UV_GROUP_WRAP_T_DEFAULT
|
|
1511
|
+
)
|
|
1512
|
+
if wrap_t in self.wrap_enum.values():
|
|
1513
|
+
return wrap_t
|
|
1514
|
+
return shader.UV_GROUP_WRAP_T_DEFAULT
|
|
1515
|
+
|
|
1516
|
+
def _set_wrap_t(self, value: object) -> None:
|
|
1517
|
+
self.set_texture_uv(shader.UV_GROUP_WRAP_T_LABEL, value)
|
|
1518
|
+
|
|
1519
|
+
mag_filter: EnumProperty( # type: ignore[valid-type]
|
|
1520
|
+
items=mag_filter_enum.items(),
|
|
1521
|
+
get=_get_mag_filter,
|
|
1522
|
+
set=_set_mag_filter,
|
|
1523
|
+
name="Mag Filter",
|
|
1524
|
+
)
|
|
1525
|
+
|
|
1526
|
+
min_filter: EnumProperty( # type: ignore[valid-type]
|
|
1527
|
+
items=min_filter_enum.items(),
|
|
1528
|
+
get=_get_min_filter,
|
|
1529
|
+
set=_set_min_filter,
|
|
1530
|
+
name="Min Filter",
|
|
1531
|
+
)
|
|
1532
|
+
|
|
1533
|
+
wrap_s: EnumProperty( # type: ignore[valid-type]
|
|
1534
|
+
items=wrap_enum.items(),
|
|
1535
|
+
name="Wrap S",
|
|
1536
|
+
default=WRAP_DEFAULT.value,
|
|
1537
|
+
get=_get_wrap_s,
|
|
1538
|
+
set=_set_wrap_s,
|
|
1539
|
+
)
|
|
1540
|
+
|
|
1541
|
+
wrap_t: EnumProperty( # type: ignore[valid-type]
|
|
1542
|
+
items=wrap_enum.items(),
|
|
1543
|
+
name="Wrap T",
|
|
1544
|
+
default=WRAP_DEFAULT.value,
|
|
1545
|
+
get=_get_wrap_t,
|
|
1546
|
+
set=_set_wrap_t,
|
|
1547
|
+
)
|
|
1548
|
+
|
|
1549
|
+
if TYPE_CHECKING:
|
|
1550
|
+
# This code is auto generated.
|
|
1551
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1552
|
+
mag_filter: str # type: ignore[no-redef]
|
|
1553
|
+
min_filter: str # type: ignore[no-redef]
|
|
1554
|
+
wrap_s: str # type: ignore[no-redef]
|
|
1555
|
+
wrap_t: str # type: ignore[no-redef]
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
class Mtoon1BaseColorSamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1559
|
+
pass
|
|
1560
|
+
|
|
1561
|
+
|
|
1562
|
+
class Mtoon1ShadeMultiplySamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1563
|
+
pass
|
|
1564
|
+
|
|
1565
|
+
|
|
1566
|
+
class Mtoon1NormalSamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1567
|
+
pass
|
|
1568
|
+
|
|
1569
|
+
|
|
1570
|
+
class Mtoon1ShadingShiftSamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1571
|
+
pass
|
|
1572
|
+
|
|
1573
|
+
|
|
1574
|
+
class Mtoon1EmissiveSamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1575
|
+
pass
|
|
1576
|
+
|
|
1577
|
+
|
|
1578
|
+
class Mtoon1RimMultiplySamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1579
|
+
pass
|
|
1580
|
+
|
|
1581
|
+
|
|
1582
|
+
class Mtoon1MatcapSamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1583
|
+
pass
|
|
1584
|
+
|
|
1585
|
+
|
|
1586
|
+
class Mtoon1OutlineWidthMultiplySamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1587
|
+
pass
|
|
1588
|
+
|
|
1589
|
+
|
|
1590
|
+
class Mtoon1UvAnimationMaskSamplerPropertyGroup(Mtoon1SamplerPropertyGroup):
|
|
1591
|
+
pass
|
|
1592
|
+
|
|
1593
|
+
|
|
1594
|
+
class Mtoon1TexturePropertyGroup(TextureTraceablePropertyGroup):
|
|
1595
|
+
label = ""
|
|
1596
|
+
panel_label = label
|
|
1597
|
+
colorspace = "sRGB"
|
|
1598
|
+
|
|
1599
|
+
def _update_source(self, context: Context) -> None:
|
|
1600
|
+
_ = context
|
|
1601
|
+
self.update_image(self.source)
|
|
1602
|
+
|
|
1603
|
+
source: PointerProperty( # type: ignore[valid-type]
|
|
1604
|
+
type=Image,
|
|
1605
|
+
update=_update_source,
|
|
1606
|
+
)
|
|
1607
|
+
|
|
1608
|
+
def _update_source_for_desynced_node_tree(self, context: Context) -> None:
|
|
1609
|
+
"""Update PointerProperty() passed to prop() when not synced with NodeTree.
|
|
1610
|
+
|
|
1611
|
+
When not synced with NodeTree, want to display the correct Image name on
|
|
1612
|
+
the Placeholder side of prop().
|
|
1613
|
+
Therefore, it operates as follows:
|
|
1614
|
+
- Always display Placeholder, so the value always returns None
|
|
1615
|
+
- When a value is input from outside, reset the value to None and
|
|
1616
|
+
transfer to self.source
|
|
1617
|
+
"""
|
|
1618
|
+
original_syncing_source_name: Optional[str] = None
|
|
1619
|
+
if self.source_for_desynced_node_tree:
|
|
1620
|
+
original_syncing_source_name = self.source_for_desynced_node_tree.name
|
|
1621
|
+
|
|
1622
|
+
if self.source_for_desynced_node_tree is not None:
|
|
1623
|
+
self.source_for_desynced_node_tree = None # trigger recursive assignment
|
|
1624
|
+
|
|
1625
|
+
if original_syncing_source_name is not None:
|
|
1626
|
+
image = context.blend_data.images.get(original_syncing_source_name)
|
|
1627
|
+
if image:
|
|
1628
|
+
self.source = image
|
|
1629
|
+
else:
|
|
1630
|
+
self.source = None
|
|
1631
|
+
|
|
1632
|
+
source_for_desynced_node_tree: PointerProperty( # type: ignore[valid-type]
|
|
1633
|
+
type=Image,
|
|
1634
|
+
update=_update_source_for_desynced_node_tree,
|
|
1635
|
+
)
|
|
1636
|
+
|
|
1637
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1638
|
+
type=Mtoon1SamplerPropertyGroup
|
|
1639
|
+
)
|
|
1640
|
+
|
|
1641
|
+
if TYPE_CHECKING:
|
|
1642
|
+
# This code is auto generated.
|
|
1643
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1644
|
+
source: Optional[Image] # type: ignore[no-redef]
|
|
1645
|
+
source_for_desynced_node_tree: Optional[Image] # type: ignore[no-redef]
|
|
1646
|
+
sampler: Mtoon1SamplerPropertyGroup # type: ignore[no-redef]
|
|
1647
|
+
|
|
1648
|
+
|
|
1649
|
+
class Mtoon1BaseColorTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1650
|
+
label = "Lit Color, Alpha"
|
|
1651
|
+
panel_label = label
|
|
1652
|
+
colorspace = "sRGB"
|
|
1653
|
+
|
|
1654
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1655
|
+
type=Mtoon1BaseColorSamplerPropertyGroup
|
|
1656
|
+
)
|
|
1657
|
+
|
|
1658
|
+
def update_image(self, image: Optional[Image]) -> None:
|
|
1659
|
+
super().update_image(image)
|
|
1660
|
+
material = self.find_material()
|
|
1661
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
1662
|
+
alpha_mode_value = mtoon1.alpha_mode_enum.identifier_to_value(
|
|
1663
|
+
mtoon1.alpha_mode, mtoon1.ALPHA_MODE_OPAQUE.value
|
|
1664
|
+
)
|
|
1665
|
+
mtoon1.update_alpha_nodes(
|
|
1666
|
+
material,
|
|
1667
|
+
alpha_mode_value,
|
|
1668
|
+
)
|
|
1669
|
+
|
|
1670
|
+
if TYPE_CHECKING:
|
|
1671
|
+
# This code is auto generated.
|
|
1672
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1673
|
+
sampler: Mtoon1BaseColorSamplerPropertyGroup # type: ignore[no-redef]
|
|
1674
|
+
|
|
1675
|
+
|
|
1676
|
+
class Mtoon1ShadeMultiplyTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1677
|
+
label = "Shade Color"
|
|
1678
|
+
panel_label = label
|
|
1679
|
+
colorspace = "sRGB"
|
|
1680
|
+
|
|
1681
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1682
|
+
type=Mtoon1ShadeMultiplySamplerPropertyGroup
|
|
1683
|
+
)
|
|
1684
|
+
|
|
1685
|
+
if TYPE_CHECKING:
|
|
1686
|
+
# This code is auto generated.
|
|
1687
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1688
|
+
sampler: Mtoon1ShadeMultiplySamplerPropertyGroup # type: ignore[no-redef]
|
|
1689
|
+
|
|
1690
|
+
|
|
1691
|
+
class Mtoon1NormalTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1692
|
+
label = "Normal Map"
|
|
1693
|
+
panel_label = label
|
|
1694
|
+
colorspace = "Non-Color"
|
|
1695
|
+
|
|
1696
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1697
|
+
type=Mtoon1NormalSamplerPropertyGroup
|
|
1698
|
+
)
|
|
1699
|
+
|
|
1700
|
+
if TYPE_CHECKING:
|
|
1701
|
+
# This code is auto generated.
|
|
1702
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1703
|
+
sampler: Mtoon1NormalSamplerPropertyGroup # type: ignore[no-redef]
|
|
1704
|
+
|
|
1705
|
+
|
|
1706
|
+
class Mtoon1ShadingShiftTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1707
|
+
label = "Additive Shading Shift"
|
|
1708
|
+
panel_label = label
|
|
1709
|
+
colorspace = "Non-Color"
|
|
1710
|
+
|
|
1711
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1712
|
+
type=Mtoon1ShadingShiftSamplerPropertyGroup
|
|
1713
|
+
)
|
|
1714
|
+
|
|
1715
|
+
if TYPE_CHECKING:
|
|
1716
|
+
# This code is auto generated.
|
|
1717
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1718
|
+
sampler: Mtoon1ShadingShiftSamplerPropertyGroup # type: ignore[no-redef]
|
|
1719
|
+
|
|
1720
|
+
|
|
1721
|
+
class Mtoon1EmissiveTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1722
|
+
label = "Emission"
|
|
1723
|
+
panel_label = label
|
|
1724
|
+
colorspace = "sRGB"
|
|
1725
|
+
|
|
1726
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1727
|
+
type=Mtoon1EmissiveSamplerPropertyGroup
|
|
1728
|
+
)
|
|
1729
|
+
|
|
1730
|
+
if TYPE_CHECKING:
|
|
1731
|
+
# This code is auto generated.
|
|
1732
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1733
|
+
sampler: Mtoon1EmissiveSamplerPropertyGroup # type: ignore[no-redef]
|
|
1734
|
+
|
|
1735
|
+
|
|
1736
|
+
class Mtoon1RimMultiplyTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1737
|
+
label = "Rim Color"
|
|
1738
|
+
panel_label = label
|
|
1739
|
+
colorspace = "sRGB"
|
|
1740
|
+
|
|
1741
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1742
|
+
type=Mtoon1RimMultiplySamplerPropertyGroup
|
|
1743
|
+
)
|
|
1744
|
+
|
|
1745
|
+
if TYPE_CHECKING:
|
|
1746
|
+
# This code is auto generated.
|
|
1747
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1748
|
+
sampler: Mtoon1RimMultiplySamplerPropertyGroup # type: ignore[no-redef]
|
|
1749
|
+
|
|
1750
|
+
|
|
1751
|
+
class Mtoon1MatcapTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1752
|
+
label = "Matcap Rim"
|
|
1753
|
+
panel_label = label
|
|
1754
|
+
colorspace = "sRGB"
|
|
1755
|
+
|
|
1756
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1757
|
+
type=Mtoon1MatcapSamplerPropertyGroup
|
|
1758
|
+
)
|
|
1759
|
+
|
|
1760
|
+
if TYPE_CHECKING:
|
|
1761
|
+
# This code is auto generated.
|
|
1762
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1763
|
+
sampler: Mtoon1MatcapSamplerPropertyGroup # type: ignore[no-redef]
|
|
1764
|
+
|
|
1765
|
+
|
|
1766
|
+
class Mtoon1OutlineWidthMultiplyTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1767
|
+
label = "Outline Width"
|
|
1768
|
+
panel_label = label
|
|
1769
|
+
colorspace = "Non-Color"
|
|
1770
|
+
|
|
1771
|
+
def _update_source(self, context: Context) -> None:
|
|
1772
|
+
mtoon1 = get_material_extension(self.find_material()).mtoon1
|
|
1773
|
+
mtoon1.extensions.vrmc_materials_mtoon.update_outline_geometry()
|
|
1774
|
+
super()._update_source(context)
|
|
1775
|
+
|
|
1776
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1777
|
+
type=Mtoon1OutlineWidthMultiplySamplerPropertyGroup
|
|
1778
|
+
)
|
|
1779
|
+
|
|
1780
|
+
if TYPE_CHECKING:
|
|
1781
|
+
# This code is auto generated.
|
|
1782
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1783
|
+
sampler: ( # type: ignore[no-redef]
|
|
1784
|
+
Mtoon1OutlineWidthMultiplySamplerPropertyGroup
|
|
1785
|
+
)
|
|
1786
|
+
|
|
1787
|
+
|
|
1788
|
+
class Mtoon1UvAnimationMaskTexturePropertyGroup(Mtoon1TexturePropertyGroup):
|
|
1789
|
+
label = "UV Animation Mask"
|
|
1790
|
+
panel_label = "Mask"
|
|
1791
|
+
colorspace = "Non-Color"
|
|
1792
|
+
|
|
1793
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
1794
|
+
type=Mtoon1UvAnimationMaskSamplerPropertyGroup
|
|
1795
|
+
)
|
|
1796
|
+
|
|
1797
|
+
if TYPE_CHECKING:
|
|
1798
|
+
# This code is auto generated.
|
|
1799
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1800
|
+
sampler: Mtoon1UvAnimationMaskSamplerPropertyGroup # type: ignore[no-redef]
|
|
1801
|
+
|
|
1802
|
+
|
|
1803
|
+
class Mtoon1TextureInfoPropertyGroup(MaterialTraceablePropertyGroup):
|
|
1804
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {}
|
|
1805
|
+
|
|
1806
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
1807
|
+
type=Mtoon1TexturePropertyGroup
|
|
1808
|
+
)
|
|
1809
|
+
|
|
1810
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
1811
|
+
type=Mtoon1TextureInfoExtensionsPropertyGroup
|
|
1812
|
+
)
|
|
1813
|
+
|
|
1814
|
+
@dataclass(frozen=True)
|
|
1815
|
+
class TextureInfoBackup:
|
|
1816
|
+
source: Optional[Image]
|
|
1817
|
+
mag_filter: Optional[str]
|
|
1818
|
+
min_filter: Optional[str]
|
|
1819
|
+
wrap_s: str
|
|
1820
|
+
wrap_t: str
|
|
1821
|
+
offset: tuple[float, float]
|
|
1822
|
+
scale: tuple[float, float]
|
|
1823
|
+
|
|
1824
|
+
def backup(self) -> TextureInfoBackup:
|
|
1825
|
+
return Mtoon1TextureInfoPropertyGroup.TextureInfoBackup(
|
|
1826
|
+
source=self.index.get_connected_node_image(),
|
|
1827
|
+
mag_filter=self.index.sampler.mag_filter,
|
|
1828
|
+
min_filter=self.index.sampler.min_filter,
|
|
1829
|
+
wrap_s=self.index.sampler.wrap_s,
|
|
1830
|
+
wrap_t=self.index.sampler.wrap_t,
|
|
1831
|
+
offset=(
|
|
1832
|
+
self.extensions.khr_texture_transform.offset[0],
|
|
1833
|
+
self.extensions.khr_texture_transform.offset[1],
|
|
1834
|
+
),
|
|
1835
|
+
scale=(
|
|
1836
|
+
self.extensions.khr_texture_transform.scale[0],
|
|
1837
|
+
self.extensions.khr_texture_transform.scale[1],
|
|
1838
|
+
),
|
|
1839
|
+
)
|
|
1840
|
+
|
|
1841
|
+
def restore(self, backup: TextureInfoBackup) -> None:
|
|
1842
|
+
self.index.source = backup.source
|
|
1843
|
+
|
|
1844
|
+
if (
|
|
1845
|
+
backup.mag_filter
|
|
1846
|
+
in Mtoon1SamplerPropertyGroup.mag_filter_enum.identifiers()
|
|
1847
|
+
):
|
|
1848
|
+
self.index.sampler.mag_filter = backup.mag_filter
|
|
1849
|
+
elif backup.mag_filter is not None:
|
|
1850
|
+
_logger.warning("invalid mag filter: %s", backup.mag_filter)
|
|
1851
|
+
self.index.sampler.mag_filter = (
|
|
1852
|
+
Mtoon1SamplerPropertyGroup.MAG_FILTER_DEFAULT.identifier
|
|
1853
|
+
)
|
|
1854
|
+
|
|
1855
|
+
if (
|
|
1856
|
+
backup.min_filter
|
|
1857
|
+
in Mtoon1SamplerPropertyGroup.min_filter_enum.identifiers()
|
|
1858
|
+
):
|
|
1859
|
+
self.index.sampler.min_filter = backup.min_filter
|
|
1860
|
+
elif backup.min_filter is not None:
|
|
1861
|
+
_logger.warning("invalid min filter: %s", backup.min_filter)
|
|
1862
|
+
self.index.sampler.min_filter = (
|
|
1863
|
+
Mtoon1SamplerPropertyGroup.MIN_FILTER_DEFAULT.identifier
|
|
1864
|
+
)
|
|
1865
|
+
|
|
1866
|
+
if backup.wrap_s in Mtoon1SamplerPropertyGroup.wrap_enum.identifiers():
|
|
1867
|
+
self.index.sampler.wrap_s = backup.wrap_s
|
|
1868
|
+
else:
|
|
1869
|
+
_logger.warning("invalid wrap s: %s", backup.wrap_s)
|
|
1870
|
+
self.index.sampler.wrap_s = (
|
|
1871
|
+
Mtoon1SamplerPropertyGroup.WRAP_DEFAULT.identifier
|
|
1872
|
+
)
|
|
1873
|
+
|
|
1874
|
+
if backup.wrap_t in Mtoon1SamplerPropertyGroup.wrap_enum.identifiers():
|
|
1875
|
+
self.index.sampler.wrap_t = backup.wrap_t
|
|
1876
|
+
else:
|
|
1877
|
+
_logger.warning("invalid wrap t: %s", backup.wrap_t)
|
|
1878
|
+
self.index.sampler.wrap_t = (
|
|
1879
|
+
Mtoon1SamplerPropertyGroup.WRAP_DEFAULT.identifier
|
|
1880
|
+
)
|
|
1881
|
+
|
|
1882
|
+
self.extensions.khr_texture_transform.offset = backup.offset
|
|
1883
|
+
self.extensions.khr_texture_transform.scale = backup.scale
|
|
1884
|
+
|
|
1885
|
+
show_expanded: BoolProperty() # type: ignore[valid-type]
|
|
1886
|
+
|
|
1887
|
+
def setup_drivers(self, material: Material) -> None:
|
|
1888
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
1889
|
+
if not mtoon1.enabled:
|
|
1890
|
+
return
|
|
1891
|
+
node_tree = material.node_tree
|
|
1892
|
+
if not node_tree:
|
|
1893
|
+
return
|
|
1894
|
+
animation_data = node_tree.animation_data
|
|
1895
|
+
if not animation_data:
|
|
1896
|
+
animation_data = node_tree.animation_data_create()
|
|
1897
|
+
if not animation_data:
|
|
1898
|
+
_logger.error(
|
|
1899
|
+
'Failed to create anomation data for node tree "%s"', node_tree.name
|
|
1900
|
+
)
|
|
1901
|
+
return
|
|
1902
|
+
uv_node_name = self.index.get_image_texture_uv_node_name()
|
|
1903
|
+
uv_node = node_tree.nodes.get(uv_node_name)
|
|
1904
|
+
if not uv_node or not isinstance(uv_node, ShaderNodeGroup):
|
|
1905
|
+
_logger.error('Failed to get uv node "%s"', uv_node_name)
|
|
1906
|
+
return
|
|
1907
|
+
image_node_name = self.index.get_image_texture_node_name()
|
|
1908
|
+
image_node = node_tree.nodes.get(image_node_name)
|
|
1909
|
+
image_exists = isinstance(image_node, ShaderNodeTexImage) and isinstance(
|
|
1910
|
+
image_node.image, Image
|
|
1911
|
+
)
|
|
1912
|
+
for size_index, uv_input_label in (
|
|
1913
|
+
(0, shader.UV_GROUP_IMAGE_WIDTH_LABEL),
|
|
1914
|
+
(1, shader.UV_GROUP_IMAGE_HEIGHT_LABEL),
|
|
1915
|
+
):
|
|
1916
|
+
uv_input_index = next(
|
|
1917
|
+
iter(
|
|
1918
|
+
index
|
|
1919
|
+
for index, socket in enumerate(uv_node.inputs)
|
|
1920
|
+
if socket.name == uv_input_label
|
|
1921
|
+
),
|
|
1922
|
+
None,
|
|
1923
|
+
)
|
|
1924
|
+
if uv_input_index is None:
|
|
1925
|
+
_logger.error('Failed to get uv input index for "%s"', uv_input_label)
|
|
1926
|
+
continue
|
|
1927
|
+
data_path = (
|
|
1928
|
+
f'nodes["{uv_node_name}"]'
|
|
1929
|
+
+ f".inputs[{uv_input_index}]"
|
|
1930
|
+
+ ".default_value"
|
|
1931
|
+
)
|
|
1932
|
+
fcurve: Optional[Union[FCurve, list[FCurve]]] = next(
|
|
1933
|
+
iter(
|
|
1934
|
+
fcurve
|
|
1935
|
+
for fcurve in animation_data.drivers
|
|
1936
|
+
if fcurve.data_path == data_path
|
|
1937
|
+
),
|
|
1938
|
+
None,
|
|
1939
|
+
)
|
|
1940
|
+
if fcurve is None:
|
|
1941
|
+
try:
|
|
1942
|
+
fcurve = node_tree.driver_add(data_path)
|
|
1943
|
+
except TypeError:
|
|
1944
|
+
continue
|
|
1945
|
+
if not isinstance(fcurve, FCurve):
|
|
1946
|
+
_logger.error(
|
|
1947
|
+
'Failed to get fcurve "%s" for node tree "%s"',
|
|
1948
|
+
data_path,
|
|
1949
|
+
node_tree.name,
|
|
1950
|
+
)
|
|
1951
|
+
continue
|
|
1952
|
+
if fcurve.array_index != 0:
|
|
1953
|
+
fcurve.array_index = 0
|
|
1954
|
+
driver = fcurve.driver
|
|
1955
|
+
if not isinstance(driver, Driver):
|
|
1956
|
+
_logger.error('Failed to get driver for fcurve "%s"', data_path)
|
|
1957
|
+
continue
|
|
1958
|
+
if driver.type != "SUM":
|
|
1959
|
+
driver.type = "SUM"
|
|
1960
|
+
if not driver.variables:
|
|
1961
|
+
driver.variables.new()
|
|
1962
|
+
while len(driver.variables) > 1:
|
|
1963
|
+
driver.variables.remove(driver.variables[-1])
|
|
1964
|
+
variable = driver.variables[0]
|
|
1965
|
+
if variable.type != "SINGLE_PROP":
|
|
1966
|
+
variable.type = "SINGLE_PROP"
|
|
1967
|
+
if not variable.targets:
|
|
1968
|
+
_logger.error(
|
|
1969
|
+
'No targets in variable for fcurve "%s" in node_tree "%s"',
|
|
1970
|
+
data_path,
|
|
1971
|
+
node_tree.name,
|
|
1972
|
+
)
|
|
1973
|
+
continue
|
|
1974
|
+
target = variable.targets[0]
|
|
1975
|
+
if target.id_type != "MATERIAL":
|
|
1976
|
+
target.id_type = "MATERIAL"
|
|
1977
|
+
if target.id != material:
|
|
1978
|
+
target.id = material
|
|
1979
|
+
target_data_path = (
|
|
1980
|
+
"node_tree"
|
|
1981
|
+
+ f'.nodes["{image_node_name}"]'
|
|
1982
|
+
+ ".image"
|
|
1983
|
+
+ f".size[{size_index}]"
|
|
1984
|
+
)
|
|
1985
|
+
if target.data_path != target_data_path or (
|
|
1986
|
+
# Blender 2.93 sets is_valid to False once image is deleted.
|
|
1987
|
+
# This is resolved by resetting data_path.
|
|
1988
|
+
image_exists and (not fcurve.is_valid or not driver.is_valid)
|
|
1989
|
+
):
|
|
1990
|
+
target.data_path = target_data_path
|
|
1991
|
+
|
|
1992
|
+
if TYPE_CHECKING:
|
|
1993
|
+
# This code is auto generated.
|
|
1994
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
1995
|
+
index: Mtoon1TexturePropertyGroup # type: ignore[no-redef]
|
|
1996
|
+
extensions: Mtoon1TextureInfoExtensionsPropertyGroup # type: ignore[no-redef]
|
|
1997
|
+
show_expanded: bool # type: ignore[no-redef]
|
|
1998
|
+
|
|
1999
|
+
|
|
2000
|
+
# https://github.com/KhronosGroup/glTF/blob/1ab49ec412e638f2e5af0289e9fbb60c7271e457/specification/2.0/schema/textureInfo.schema.json
|
|
2001
|
+
class Mtoon1BaseColorTextureInfoPropertyGroup(Mtoon1TextureInfoPropertyGroup):
|
|
2002
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2003
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2004
|
+
NodeGroupSocketTarget(
|
|
2005
|
+
node_group_node_tree_name=shader.OUTPUT_GROUP_NAME,
|
|
2006
|
+
in_socket_name="Lit Color Texture Color",
|
|
2007
|
+
),
|
|
2008
|
+
PrincipledBsdfNodeSocketTarget(
|
|
2009
|
+
in_socket_name=PRINCIPLED_BSDF_BASE_COLOR_INPUT_KEY
|
|
2010
|
+
),
|
|
2011
|
+
],
|
|
2012
|
+
TEX_IMAGE_ALPHA_OUTPUT_KEY: [
|
|
2013
|
+
NodeGroupSocketTarget(
|
|
2014
|
+
node_group_node_tree_name=shader.OUTPUT_GROUP_NAME,
|
|
2015
|
+
in_socket_name="Lit Color Texture Alpha",
|
|
2016
|
+
),
|
|
2017
|
+
],
|
|
2018
|
+
}
|
|
2019
|
+
|
|
2020
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2021
|
+
type=Mtoon1BaseColorTexturePropertyGroup
|
|
2022
|
+
)
|
|
2023
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2024
|
+
type=Mtoon1BaseColorTextureInfoExtensionsPropertyGroup
|
|
2025
|
+
)
|
|
2026
|
+
|
|
2027
|
+
if TYPE_CHECKING:
|
|
2028
|
+
# This code is auto generated.
|
|
2029
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2030
|
+
index: Mtoon1BaseColorTexturePropertyGroup # type: ignore[no-redef]
|
|
2031
|
+
extensions: ( # type: ignore[no-redef]
|
|
2032
|
+
Mtoon1BaseColorTextureInfoExtensionsPropertyGroup
|
|
2033
|
+
)
|
|
2034
|
+
|
|
2035
|
+
|
|
2036
|
+
class Mtoon1ShadeMultiplyTextureInfoPropertyGroup(Mtoon1TextureInfoPropertyGroup):
|
|
2037
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2038
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2039
|
+
NodeGroupSocketTarget(
|
|
2040
|
+
node_group_node_tree_name=shader.OUTPUT_GROUP_NAME,
|
|
2041
|
+
in_socket_name="Shade Color Texture",
|
|
2042
|
+
),
|
|
2043
|
+
],
|
|
2044
|
+
}
|
|
2045
|
+
|
|
2046
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2047
|
+
type=Mtoon1ShadeMultiplyTexturePropertyGroup
|
|
2048
|
+
)
|
|
2049
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2050
|
+
type=Mtoon1ShadeMultiplyTextureInfoExtensionsPropertyGroup
|
|
2051
|
+
)
|
|
2052
|
+
|
|
2053
|
+
if TYPE_CHECKING:
|
|
2054
|
+
# This code is auto generated.
|
|
2055
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2056
|
+
index: Mtoon1ShadeMultiplyTexturePropertyGroup # type: ignore[no-redef]
|
|
2057
|
+
extensions: ( # type: ignore[no-redef]
|
|
2058
|
+
Mtoon1ShadeMultiplyTextureInfoExtensionsPropertyGroup
|
|
2059
|
+
)
|
|
2060
|
+
|
|
2061
|
+
|
|
2062
|
+
# https://github.com/KhronosGroup/glTF/blob/1ab49ec412e638f2e5af0289e9fbb60c7271e457/specification/2.0/schema/material.normalTextureInfo.schema.json
|
|
2063
|
+
class Mtoon1NormalTextureInfoPropertyGroup(Mtoon1TextureInfoPropertyGroup):
|
|
2064
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2065
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2066
|
+
NodeGroupSocketTarget(
|
|
2067
|
+
node_group_node_tree_name=shader.NORMAL_GROUP_NAME,
|
|
2068
|
+
in_socket_name="Normal Map Texture",
|
|
2069
|
+
),
|
|
2070
|
+
PrincipledBsdfNormalMapNodeSocketTarget(),
|
|
2071
|
+
],
|
|
2072
|
+
}
|
|
2073
|
+
|
|
2074
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2075
|
+
type=Mtoon1NormalTexturePropertyGroup
|
|
2076
|
+
)
|
|
2077
|
+
|
|
2078
|
+
def _get_scale(self) -> float:
|
|
2079
|
+
return self.get_float(
|
|
2080
|
+
shader.NORMAL_GROUP_NAME,
|
|
2081
|
+
shader.NORMAL_GROUP_SCALE_LABEL,
|
|
2082
|
+
default_value=shader.NORMAL_GROUP_SCALE_DEFAULT,
|
|
2083
|
+
)
|
|
2084
|
+
|
|
2085
|
+
def _set_scale(self, value: object) -> None:
|
|
2086
|
+
self.set_value(
|
|
2087
|
+
shader.NORMAL_GROUP_NAME,
|
|
2088
|
+
shader.NORMAL_GROUP_SCALE_LABEL,
|
|
2089
|
+
value,
|
|
2090
|
+
)
|
|
2091
|
+
material = self.find_material()
|
|
2092
|
+
principled_bsdf = PrincipledBSDFWrapper(material, is_readonly=False)
|
|
2093
|
+
principled_bsdf.normalmap_strength = self.scale
|
|
2094
|
+
|
|
2095
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
2096
|
+
if mtoon1.is_outline_material:
|
|
2097
|
+
return
|
|
2098
|
+
outline_material = mtoon1.outline_material
|
|
2099
|
+
if not outline_material:
|
|
2100
|
+
return
|
|
2101
|
+
outline_principled_bsdf = PrincipledBSDFWrapper(
|
|
2102
|
+
outline_material, is_readonly=False
|
|
2103
|
+
)
|
|
2104
|
+
outline_principled_bsdf.normalmap_strength = self.scale
|
|
2105
|
+
|
|
2106
|
+
scale: FloatProperty( # type: ignore[valid-type]
|
|
2107
|
+
name="Scale",
|
|
2108
|
+
default=shader.NORMAL_GROUP_SCALE_DEFAULT,
|
|
2109
|
+
get=_get_scale,
|
|
2110
|
+
set=_set_scale,
|
|
2111
|
+
)
|
|
2112
|
+
|
|
2113
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2114
|
+
type=Mtoon1NormalTextureInfoExtensionsPropertyGroup
|
|
2115
|
+
)
|
|
2116
|
+
|
|
2117
|
+
if TYPE_CHECKING:
|
|
2118
|
+
# This code is auto generated.
|
|
2119
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2120
|
+
index: Mtoon1NormalTexturePropertyGroup # type: ignore[no-redef]
|
|
2121
|
+
scale: float # type: ignore[no-redef]
|
|
2122
|
+
extensions: ( # type: ignore[no-redef]
|
|
2123
|
+
Mtoon1NormalTextureInfoExtensionsPropertyGroup
|
|
2124
|
+
)
|
|
2125
|
+
|
|
2126
|
+
|
|
2127
|
+
# https://github.com/vrm-c/vrm-specification/blob/c5d1afdc4d59c292cb4fd6d54cad1dc0c4d19c60/specification/VRMC_materials_mtoon-1.0/schema/mtoon.shadingShiftTexture.schema.json
|
|
2128
|
+
class Mtoon1ShadingShiftTextureInfoPropertyGroup(Mtoon1TextureInfoPropertyGroup):
|
|
2129
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2130
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2131
|
+
NodeGroupSocketTarget(
|
|
2132
|
+
node_group_node_tree_name=shader.OUTPUT_GROUP_NAME,
|
|
2133
|
+
in_socket_name="Shading Shift Texture",
|
|
2134
|
+
),
|
|
2135
|
+
],
|
|
2136
|
+
}
|
|
2137
|
+
|
|
2138
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2139
|
+
type=Mtoon1ShadingShiftTexturePropertyGroup
|
|
2140
|
+
)
|
|
2141
|
+
|
|
2142
|
+
def _get_scale(self) -> float:
|
|
2143
|
+
return self.get_float(
|
|
2144
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2145
|
+
shader.OUTPUT_GROUP_SHADING_SHIFT_TEXTURE_SCALE_LABEL,
|
|
2146
|
+
default_value=shader.OUTPUT_GROUP_SHADING_SHIFT_TEXTURE_SCALE_DEFAULT,
|
|
2147
|
+
)
|
|
2148
|
+
|
|
2149
|
+
def _set_scale(self, value: object) -> None:
|
|
2150
|
+
self.set_value(
|
|
2151
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2152
|
+
shader.OUTPUT_GROUP_SHADING_SHIFT_TEXTURE_SCALE_LABEL,
|
|
2153
|
+
value,
|
|
2154
|
+
)
|
|
2155
|
+
|
|
2156
|
+
scale: FloatProperty( # type: ignore[valid-type]
|
|
2157
|
+
name="Scale",
|
|
2158
|
+
default=shader.OUTPUT_GROUP_SHADING_SHIFT_TEXTURE_SCALE_DEFAULT,
|
|
2159
|
+
set=_set_scale,
|
|
2160
|
+
get=_get_scale,
|
|
2161
|
+
)
|
|
2162
|
+
|
|
2163
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2164
|
+
type=Mtoon1ShadingShiftTextureInfoExtensionsPropertyGroup
|
|
2165
|
+
)
|
|
2166
|
+
|
|
2167
|
+
if TYPE_CHECKING:
|
|
2168
|
+
# This code is auto generated.
|
|
2169
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2170
|
+
index: Mtoon1ShadingShiftTexturePropertyGroup # type: ignore[no-redef]
|
|
2171
|
+
scale: float # type: ignore[no-redef]
|
|
2172
|
+
extensions: ( # type: ignore[no-redef]
|
|
2173
|
+
Mtoon1ShadingShiftTextureInfoExtensionsPropertyGroup
|
|
2174
|
+
)
|
|
2175
|
+
|
|
2176
|
+
|
|
2177
|
+
# https://github.com/KhronosGroup/glTF/blob/1ab49ec412e638f2e5af0289e9fbb60c7271e457/specification/2.0/schema/textureInfo.schema.json
|
|
2178
|
+
class Mtoon1EmissiveTextureInfoPropertyGroup(Mtoon1TextureInfoPropertyGroup):
|
|
2179
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2180
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2181
|
+
NodeGroupSocketTarget(
|
|
2182
|
+
node_group_node_tree_name=shader.OUTPUT_GROUP_NAME,
|
|
2183
|
+
in_socket_name="Emissive Texture",
|
|
2184
|
+
),
|
|
2185
|
+
PrincipledBsdfNodeSocketTarget(
|
|
2186
|
+
in_socket_name=PRINCIPLED_BSDF_EMISSION_INPUT_KEY,
|
|
2187
|
+
),
|
|
2188
|
+
GltfEmissionNodeSocketTarget(),
|
|
2189
|
+
],
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2193
|
+
type=Mtoon1EmissiveTexturePropertyGroup
|
|
2194
|
+
)
|
|
2195
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2196
|
+
type=Mtoon1EmissiveTextureInfoExtensionsPropertyGroup
|
|
2197
|
+
)
|
|
2198
|
+
|
|
2199
|
+
if TYPE_CHECKING:
|
|
2200
|
+
# This code is auto generated.
|
|
2201
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2202
|
+
index: Mtoon1EmissiveTexturePropertyGroup # type: ignore[no-redef]
|
|
2203
|
+
extensions: ( # type: ignore[no-redef]
|
|
2204
|
+
Mtoon1EmissiveTextureInfoExtensionsPropertyGroup
|
|
2205
|
+
)
|
|
2206
|
+
|
|
2207
|
+
|
|
2208
|
+
class Mtoon1RimMultiplyTextureInfoPropertyGroup(Mtoon1TextureInfoPropertyGroup):
|
|
2209
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2210
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2211
|
+
NodeGroupSocketTarget(
|
|
2212
|
+
node_group_node_tree_name=shader.OUTPUT_GROUP_NAME,
|
|
2213
|
+
in_socket_name="Rim Color Texture",
|
|
2214
|
+
),
|
|
2215
|
+
],
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2219
|
+
type=Mtoon1RimMultiplyTexturePropertyGroup
|
|
2220
|
+
)
|
|
2221
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2222
|
+
type=Mtoon1RimMultiplyTextureInfoExtensionsPropertyGroup
|
|
2223
|
+
)
|
|
2224
|
+
|
|
2225
|
+
if TYPE_CHECKING:
|
|
2226
|
+
# This code is auto generated.
|
|
2227
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2228
|
+
index: Mtoon1RimMultiplyTexturePropertyGroup # type: ignore[no-redef]
|
|
2229
|
+
extensions: ( # type: ignore[no-redef]
|
|
2230
|
+
Mtoon1RimMultiplyTextureInfoExtensionsPropertyGroup
|
|
2231
|
+
)
|
|
2232
|
+
|
|
2233
|
+
|
|
2234
|
+
class Mtoon1MatcapTextureInfoPropertyGroup(Mtoon1TextureInfoPropertyGroup):
|
|
2235
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2236
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2237
|
+
NodeGroupSocketTarget(
|
|
2238
|
+
node_group_node_tree_name=shader.OUTPUT_GROUP_NAME,
|
|
2239
|
+
in_socket_name="MatCap Texture",
|
|
2240
|
+
),
|
|
2241
|
+
],
|
|
2242
|
+
}
|
|
2243
|
+
|
|
2244
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2245
|
+
type=Mtoon1MatcapTexturePropertyGroup
|
|
2246
|
+
)
|
|
2247
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2248
|
+
type=Mtoon1MatcapTextureInfoExtensionsPropertyGroup
|
|
2249
|
+
)
|
|
2250
|
+
|
|
2251
|
+
if TYPE_CHECKING:
|
|
2252
|
+
# This code is auto generated.
|
|
2253
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2254
|
+
index: Mtoon1MatcapTexturePropertyGroup # type: ignore[no-redef]
|
|
2255
|
+
extensions: ( # type: ignore[no-redef]
|
|
2256
|
+
Mtoon1MatcapTextureInfoExtensionsPropertyGroup
|
|
2257
|
+
)
|
|
2258
|
+
|
|
2259
|
+
|
|
2260
|
+
class Mtoon1OutlineWidthMultiplyTextureInfoPropertyGroup(
|
|
2261
|
+
Mtoon1TextureInfoPropertyGroup
|
|
2262
|
+
):
|
|
2263
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2264
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2265
|
+
NodeGroupSocketTarget(
|
|
2266
|
+
node_group_node_tree_name=shader.OUTPUT_GROUP_NAME,
|
|
2267
|
+
in_socket_name="Outline Width Texture",
|
|
2268
|
+
),
|
|
2269
|
+
],
|
|
2270
|
+
}
|
|
2271
|
+
|
|
2272
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2273
|
+
type=Mtoon1OutlineWidthMultiplyTexturePropertyGroup
|
|
2274
|
+
)
|
|
2275
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2276
|
+
type=Mtoon1OutlineWidthMultiplyTextureInfoExtensionsPropertyGroup
|
|
2277
|
+
)
|
|
2278
|
+
|
|
2279
|
+
if TYPE_CHECKING:
|
|
2280
|
+
# This code is auto generated.
|
|
2281
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2282
|
+
index: Mtoon1OutlineWidthMultiplyTexturePropertyGroup # type: ignore[no-redef]
|
|
2283
|
+
extensions: ( # type: ignore[no-redef]
|
|
2284
|
+
Mtoon1OutlineWidthMultiplyTextureInfoExtensionsPropertyGroup
|
|
2285
|
+
)
|
|
2286
|
+
|
|
2287
|
+
|
|
2288
|
+
class Mtoon1UvAnimationMaskTextureInfoPropertyGroup(Mtoon1TextureInfoPropertyGroup):
|
|
2289
|
+
node_socket_targets: Mapping[str, Sequence[NodeSocketTarget]] = {
|
|
2290
|
+
TEX_IMAGE_COLOR_OUTPUT_KEY: [
|
|
2291
|
+
NodeGroupSocketTarget(
|
|
2292
|
+
node_group_node_tree_name=shader.UV_ANIMATION_GROUP_NAME,
|
|
2293
|
+
in_socket_name="Mask Texture",
|
|
2294
|
+
),
|
|
2295
|
+
],
|
|
2296
|
+
}
|
|
2297
|
+
|
|
2298
|
+
index: PointerProperty( # type: ignore[valid-type]
|
|
2299
|
+
type=Mtoon1UvAnimationMaskTexturePropertyGroup
|
|
2300
|
+
)
|
|
2301
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
2302
|
+
type=Mtoon1UvAnimationMaskTextureInfoExtensionsPropertyGroup
|
|
2303
|
+
)
|
|
2304
|
+
|
|
2305
|
+
if TYPE_CHECKING:
|
|
2306
|
+
# This code is auto generated.
|
|
2307
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2308
|
+
index: Mtoon1UvAnimationMaskTexturePropertyGroup # type: ignore[no-redef]
|
|
2309
|
+
extensions: ( # type: ignore[no-redef]
|
|
2310
|
+
Mtoon1UvAnimationMaskTextureInfoExtensionsPropertyGroup
|
|
2311
|
+
)
|
|
2312
|
+
|
|
2313
|
+
|
|
2314
|
+
class Mtoon0SamplerPropertyGroup(PropertyGroup):
|
|
2315
|
+
mag_filter: EnumProperty( # type: ignore[valid-type]
|
|
2316
|
+
items=Mtoon1SamplerPropertyGroup.mag_filter_enum.items(),
|
|
2317
|
+
name="Mag Filter",
|
|
2318
|
+
)
|
|
2319
|
+
|
|
2320
|
+
min_filter: EnumProperty( # type: ignore[valid-type]
|
|
2321
|
+
items=Mtoon1SamplerPropertyGroup.min_filter_enum.items(),
|
|
2322
|
+
name="Min Filter",
|
|
2323
|
+
)
|
|
2324
|
+
|
|
2325
|
+
wrap_s: EnumProperty( # type: ignore[valid-type]
|
|
2326
|
+
items=Mtoon1SamplerPropertyGroup.wrap_enum.items(),
|
|
2327
|
+
name="Wrap S",
|
|
2328
|
+
default=Mtoon1SamplerPropertyGroup.WRAP_DEFAULT.value,
|
|
2329
|
+
)
|
|
2330
|
+
|
|
2331
|
+
wrap_t: EnumProperty( # type: ignore[valid-type]
|
|
2332
|
+
items=Mtoon1SamplerPropertyGroup.wrap_enum.items(),
|
|
2333
|
+
name="Wrap T",
|
|
2334
|
+
default=Mtoon1SamplerPropertyGroup.WRAP_DEFAULT.value,
|
|
2335
|
+
)
|
|
2336
|
+
|
|
2337
|
+
if TYPE_CHECKING:
|
|
2338
|
+
# This code is auto generated.
|
|
2339
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2340
|
+
mag_filter: str # type: ignore[no-redef]
|
|
2341
|
+
min_filter: str # type: ignore[no-redef]
|
|
2342
|
+
wrap_s: str # type: ignore[no-redef]
|
|
2343
|
+
wrap_t: str # type: ignore[no-redef]
|
|
2344
|
+
|
|
2345
|
+
|
|
2346
|
+
class Mtoon0TexturePropertyGroup(PropertyGroup):
|
|
2347
|
+
label = ""
|
|
2348
|
+
panel_label = ""
|
|
2349
|
+
colorspace = "sRGB"
|
|
2350
|
+
|
|
2351
|
+
def get_connected_node_image(self) -> Optional[Image]:
|
|
2352
|
+
return self.source if isinstance(self.source, Image) else None
|
|
2353
|
+
|
|
2354
|
+
source: PointerProperty( # type: ignore[valid-type]
|
|
2355
|
+
type=Image,
|
|
2356
|
+
)
|
|
2357
|
+
|
|
2358
|
+
sampler: PointerProperty( # type: ignore[valid-type]
|
|
2359
|
+
type=Mtoon0SamplerPropertyGroup,
|
|
2360
|
+
)
|
|
2361
|
+
|
|
2362
|
+
show_expanded: BoolProperty() # type: ignore[valid-type]
|
|
2363
|
+
|
|
2364
|
+
if TYPE_CHECKING:
|
|
2365
|
+
# This code is auto generated.
|
|
2366
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2367
|
+
source: Optional[Image] # type: ignore[no-redef]
|
|
2368
|
+
sampler: Mtoon0SamplerPropertyGroup # type: ignore[no-redef]
|
|
2369
|
+
show_expanded: bool # type: ignore[no-redef]
|
|
2370
|
+
|
|
2371
|
+
|
|
2372
|
+
class Mtoon0ReceiveShadowTexturePropertyGroup(Mtoon0TexturePropertyGroup):
|
|
2373
|
+
label = "Shadow Receive Multiplier"
|
|
2374
|
+
panel_label = label
|
|
2375
|
+
colorspace = "Non-Color"
|
|
2376
|
+
|
|
2377
|
+
|
|
2378
|
+
class Mtoon0ShadingGradeTexturePropertyGroup(Mtoon0TexturePropertyGroup):
|
|
2379
|
+
label = "Lit & Shade Mixing Multiplier"
|
|
2380
|
+
panel_label = label
|
|
2381
|
+
colorspace = "Non-Color"
|
|
2382
|
+
|
|
2383
|
+
|
|
2384
|
+
# https://github.com/KhronosGroup/glTF/blob/1ab49ec412e638f2e5af0289e9fbb60c7271e457/specification/2.0/schema/material.pbrMetallicRoughness.schema.json#L9-L26
|
|
2385
|
+
class Mtoon1PbrMetallicRoughnessPropertyGroup(MaterialTraceablePropertyGroup):
|
|
2386
|
+
def _get_base_color_factor(self) -> tuple[float, float, float, float]:
|
|
2387
|
+
r, g, b = self.get_rgb(
|
|
2388
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2389
|
+
shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_COLOR_LABEL,
|
|
2390
|
+
default_value=shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_COLOR_DEFAULT,
|
|
2391
|
+
)
|
|
2392
|
+
a = self.get_value(
|
|
2393
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2394
|
+
shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_ALPHA_LABEL,
|
|
2395
|
+
default_value=shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_ALPHA_DEFAULT,
|
|
2396
|
+
)
|
|
2397
|
+
return (r, g, b, a)
|
|
2398
|
+
|
|
2399
|
+
def _set_base_color_factor(self, value: object) -> None:
|
|
2400
|
+
color = convert.float4_or_none(value)
|
|
2401
|
+
if color is None:
|
|
2402
|
+
return
|
|
2403
|
+
self.set_rgba(
|
|
2404
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2405
|
+
shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_COLOR_LABEL,
|
|
2406
|
+
color,
|
|
2407
|
+
)
|
|
2408
|
+
self.set_value(
|
|
2409
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2410
|
+
shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_ALPHA_LABEL,
|
|
2411
|
+
color[3],
|
|
2412
|
+
)
|
|
2413
|
+
material = self.find_material()
|
|
2414
|
+
principled_bsdf = PrincipledBSDFWrapper(material, is_readonly=False)
|
|
2415
|
+
principled_bsdf.base_color = (
|
|
2416
|
+
color[0],
|
|
2417
|
+
color[1],
|
|
2418
|
+
color[2],
|
|
2419
|
+
)
|
|
2420
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
2421
|
+
alpha_mode_value = mtoon1.alpha_mode_enum.identifier_to_value(
|
|
2422
|
+
mtoon1.alpha_mode, mtoon1.ALPHA_MODE_OPAQUE.value
|
|
2423
|
+
)
|
|
2424
|
+
mtoon1.update_alpha_nodes(material, alpha_mode_value)
|
|
2425
|
+
|
|
2426
|
+
if mtoon1.is_outline_material:
|
|
2427
|
+
return
|
|
2428
|
+
outline_material = mtoon1.outline_material
|
|
2429
|
+
if not outline_material:
|
|
2430
|
+
return
|
|
2431
|
+
outline_mtoon1 = get_material_extension(outline_material).mtoon1
|
|
2432
|
+
outline_mtoon1.update_alpha_nodes(outline_material, alpha_mode_value)
|
|
2433
|
+
|
|
2434
|
+
base_color_factor: FloatVectorProperty( # type: ignore[valid-type]
|
|
2435
|
+
size=4,
|
|
2436
|
+
subtype="COLOR",
|
|
2437
|
+
default=(
|
|
2438
|
+
*shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_COLOR_DEFAULT,
|
|
2439
|
+
shader.OUTPUT_GROUP_BASE_COLOR_FACTOR_ALPHA_DEFAULT,
|
|
2440
|
+
),
|
|
2441
|
+
min=0,
|
|
2442
|
+
max=1,
|
|
2443
|
+
get=_get_base_color_factor,
|
|
2444
|
+
set=_set_base_color_factor,
|
|
2445
|
+
)
|
|
2446
|
+
|
|
2447
|
+
base_color_texture: PointerProperty( # type: ignore[valid-type]
|
|
2448
|
+
type=Mtoon1BaseColorTextureInfoPropertyGroup
|
|
2449
|
+
)
|
|
2450
|
+
|
|
2451
|
+
if TYPE_CHECKING:
|
|
2452
|
+
# This code is auto generated.
|
|
2453
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2454
|
+
base_color_factor: Sequence[float] # type: ignore[no-redef]
|
|
2455
|
+
base_color_texture: ( # type: ignore[no-redef]
|
|
2456
|
+
Mtoon1BaseColorTextureInfoPropertyGroup
|
|
2457
|
+
)
|
|
2458
|
+
|
|
2459
|
+
|
|
2460
|
+
class Mtoon1VrmcMaterialsMtoonPropertyGroup(MaterialTraceablePropertyGroup):
|
|
2461
|
+
def _get_transparent_with_z_write(self) -> bool:
|
|
2462
|
+
return self.get_bool(
|
|
2463
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2464
|
+
shader.OUTPUT_GROUP_TRANSPARENT_WITH_Z_WRITE_LABEL,
|
|
2465
|
+
default_value=shader.OUTPUT_GROUP_TRANSPARENT_WITH_Z_WRITE_DEFAULT,
|
|
2466
|
+
)
|
|
2467
|
+
|
|
2468
|
+
def _set_transparent_with_z_write(self, value: object) -> None:
|
|
2469
|
+
self.set_bool(
|
|
2470
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2471
|
+
shader.OUTPUT_GROUP_TRANSPARENT_WITH_Z_WRITE_LABEL,
|
|
2472
|
+
value,
|
|
2473
|
+
)
|
|
2474
|
+
|
|
2475
|
+
mtoon1 = get_material_extension(self.find_material()).mtoon1
|
|
2476
|
+
mtoon1.mtoon0_render_queue_and_clamp = mtoon1.mtoon0_render_queue
|
|
2477
|
+
|
|
2478
|
+
transparent_with_z_write: BoolProperty( # type: ignore[valid-type]
|
|
2479
|
+
name="Transparent With ZWrite Mode",
|
|
2480
|
+
default=shader.OUTPUT_GROUP_TRANSPARENT_WITH_Z_WRITE_DEFAULT,
|
|
2481
|
+
get=_get_transparent_with_z_write,
|
|
2482
|
+
set=_set_transparent_with_z_write,
|
|
2483
|
+
)
|
|
2484
|
+
|
|
2485
|
+
def _get_render_queue_offset_number(self) -> int:
|
|
2486
|
+
return self.get_int(
|
|
2487
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2488
|
+
shader.OUTPUT_GROUP_RENDER_QUEUE_OFFSET_NUMBER_LABEL,
|
|
2489
|
+
default_value=shader.OUTPUT_GROUP_RENDER_QUEUE_OFFSET_NUMBER_DEFAULT,
|
|
2490
|
+
)
|
|
2491
|
+
|
|
2492
|
+
def _set_render_queue_offset_number(self, value: int) -> None:
|
|
2493
|
+
self.set_int(
|
|
2494
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2495
|
+
shader.OUTPUT_GROUP_RENDER_QUEUE_OFFSET_NUMBER_LABEL,
|
|
2496
|
+
value,
|
|
2497
|
+
)
|
|
2498
|
+
|
|
2499
|
+
render_queue_offset_number: IntProperty( # type: ignore[valid-type]
|
|
2500
|
+
name="RenderQueue Offset",
|
|
2501
|
+
min=shader.OUTPUT_GROUP_RENDER_QUEUE_OFFSET_NUMBER_MIN,
|
|
2502
|
+
default=shader.OUTPUT_GROUP_RENDER_QUEUE_OFFSET_NUMBER_DEFAULT,
|
|
2503
|
+
max=shader.OUTPUT_GROUP_RENDER_QUEUE_OFFSET_NUMBER_MAX,
|
|
2504
|
+
get=_get_render_queue_offset_number,
|
|
2505
|
+
set=_set_render_queue_offset_number,
|
|
2506
|
+
)
|
|
2507
|
+
|
|
2508
|
+
shade_multiply_texture: PointerProperty( # type: ignore[valid-type]
|
|
2509
|
+
type=Mtoon1ShadeMultiplyTextureInfoPropertyGroup
|
|
2510
|
+
)
|
|
2511
|
+
|
|
2512
|
+
def _get_shade_color_factor(self) -> tuple[float, float, float]:
|
|
2513
|
+
return self.get_rgb(
|
|
2514
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2515
|
+
shader.OUTPUT_GROUP_SHADE_COLOR_FACTOR_LABEL,
|
|
2516
|
+
default_value=shader.OUTPUT_GROUP_SHADE_COLOR_FACTOR_DEFAULT,
|
|
2517
|
+
)
|
|
2518
|
+
|
|
2519
|
+
def _set_shade_color_factor(self, value: object) -> None:
|
|
2520
|
+
self.set_rgb(
|
|
2521
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2522
|
+
shader.OUTPUT_GROUP_SHADE_COLOR_FACTOR_LABEL,
|
|
2523
|
+
value,
|
|
2524
|
+
)
|
|
2525
|
+
|
|
2526
|
+
shade_color_factor: FloatVectorProperty( # type: ignore[valid-type]
|
|
2527
|
+
size=3,
|
|
2528
|
+
subtype="COLOR",
|
|
2529
|
+
default=shader.OUTPUT_GROUP_SHADE_COLOR_FACTOR_DEFAULT,
|
|
2530
|
+
min=0.0,
|
|
2531
|
+
max=1.0,
|
|
2532
|
+
get=_get_shade_color_factor,
|
|
2533
|
+
set=_set_shade_color_factor,
|
|
2534
|
+
)
|
|
2535
|
+
|
|
2536
|
+
shading_shift_texture: PointerProperty( # type: ignore[valid-type]
|
|
2537
|
+
type=Mtoon1ShadingShiftTextureInfoPropertyGroup
|
|
2538
|
+
)
|
|
2539
|
+
|
|
2540
|
+
def _get_shading_shift_factor(self) -> float:
|
|
2541
|
+
return self.get_float(
|
|
2542
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2543
|
+
shader.OUTPUT_GROUP_SHADING_SHIFT_FACTOR_LABEL,
|
|
2544
|
+
default_value=shader.OUTPUT_GROUP_SHADING_SHIFT_FACTOR_DEFAULT,
|
|
2545
|
+
)
|
|
2546
|
+
|
|
2547
|
+
def _set_shading_shift_factor(self, value: object) -> None:
|
|
2548
|
+
self.set_value(
|
|
2549
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2550
|
+
shader.OUTPUT_GROUP_SHADING_SHIFT_FACTOR_LABEL,
|
|
2551
|
+
value,
|
|
2552
|
+
)
|
|
2553
|
+
|
|
2554
|
+
shading_shift_factor: FloatProperty( # type: ignore[valid-type]
|
|
2555
|
+
name=shader.OUTPUT_GROUP_SHADING_SHIFT_FACTOR_LABEL,
|
|
2556
|
+
soft_min=-1.0,
|
|
2557
|
+
default=shader.OUTPUT_GROUP_SHADING_SHIFT_FACTOR_DEFAULT,
|
|
2558
|
+
soft_max=1.0,
|
|
2559
|
+
get=_get_shading_shift_factor,
|
|
2560
|
+
set=_set_shading_shift_factor,
|
|
2561
|
+
)
|
|
2562
|
+
|
|
2563
|
+
def _get_shading_toony_factor(self) -> float:
|
|
2564
|
+
return self.get_float(
|
|
2565
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2566
|
+
shader.OUTPUT_GROUP_SHADING_TOONY_FACTOR_LABEL,
|
|
2567
|
+
default_value=shader.OUTPUT_GROUP_SHADING_TOONY_FACTOR_DEFAULT,
|
|
2568
|
+
)
|
|
2569
|
+
|
|
2570
|
+
def _set_shading_toony_factor(self, value: object) -> None:
|
|
2571
|
+
self.set_value(
|
|
2572
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2573
|
+
shader.OUTPUT_GROUP_SHADING_TOONY_FACTOR_LABEL,
|
|
2574
|
+
value,
|
|
2575
|
+
)
|
|
2576
|
+
|
|
2577
|
+
shading_toony_factor: FloatProperty( # type: ignore[valid-type]
|
|
2578
|
+
name=shader.OUTPUT_GROUP_SHADING_TOONY_FACTOR_LABEL,
|
|
2579
|
+
min=0.0,
|
|
2580
|
+
default=shader.OUTPUT_GROUP_SHADING_TOONY_FACTOR_DEFAULT,
|
|
2581
|
+
max=1.0,
|
|
2582
|
+
get=_get_shading_toony_factor,
|
|
2583
|
+
set=_set_shading_toony_factor,
|
|
2584
|
+
)
|
|
2585
|
+
|
|
2586
|
+
def _get_gi_equalization_factor(self) -> float:
|
|
2587
|
+
return self.get_float(
|
|
2588
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2589
|
+
shader.OUTPUT_GROUP_GI_EQUALIZATION_FACTOR_LABEL,
|
|
2590
|
+
default_value=shader.OUTPUT_GROUP_GI_EQUALIZATION_FACTOR_DEFAULT,
|
|
2591
|
+
)
|
|
2592
|
+
|
|
2593
|
+
def _set_gi_equalization_factor(self, value: object) -> None:
|
|
2594
|
+
self.set_value(
|
|
2595
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2596
|
+
shader.OUTPUT_GROUP_GI_EQUALIZATION_FACTOR_LABEL,
|
|
2597
|
+
value,
|
|
2598
|
+
)
|
|
2599
|
+
|
|
2600
|
+
gi_equalization_factor: FloatProperty( # type: ignore[valid-type]
|
|
2601
|
+
name="GI Equalization",
|
|
2602
|
+
min=0.0,
|
|
2603
|
+
default=shader.OUTPUT_GROUP_GI_EQUALIZATION_FACTOR_DEFAULT,
|
|
2604
|
+
max=1.0,
|
|
2605
|
+
get=_get_gi_equalization_factor,
|
|
2606
|
+
set=_set_gi_equalization_factor,
|
|
2607
|
+
)
|
|
2608
|
+
|
|
2609
|
+
def _get_matcap_factor(self) -> tuple[float, float, float]:
|
|
2610
|
+
return self.get_rgb(
|
|
2611
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2612
|
+
shader.OUTPUT_GROUP_MATCAP_FACTOR_LABEL,
|
|
2613
|
+
default_value=shader.OUTPUT_GROUP_MATCAP_FACTOR_DEFAULT,
|
|
2614
|
+
)
|
|
2615
|
+
|
|
2616
|
+
def _set_matcap_factor(self, value: object) -> None:
|
|
2617
|
+
self.set_rgb(
|
|
2618
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2619
|
+
shader.OUTPUT_GROUP_MATCAP_FACTOR_LABEL,
|
|
2620
|
+
value,
|
|
2621
|
+
)
|
|
2622
|
+
|
|
2623
|
+
matcap_factor: FloatVectorProperty( # type: ignore[valid-type]
|
|
2624
|
+
size=3,
|
|
2625
|
+
subtype="COLOR",
|
|
2626
|
+
default=shader.OUTPUT_GROUP_MATCAP_FACTOR_DEFAULT,
|
|
2627
|
+
min=0,
|
|
2628
|
+
max=1,
|
|
2629
|
+
get=_get_matcap_factor,
|
|
2630
|
+
set=_set_matcap_factor,
|
|
2631
|
+
)
|
|
2632
|
+
|
|
2633
|
+
matcap_texture: PointerProperty( # type: ignore[valid-type]
|
|
2634
|
+
type=Mtoon1MatcapTextureInfoPropertyGroup
|
|
2635
|
+
)
|
|
2636
|
+
|
|
2637
|
+
def _get_parametric_rim_color_factor(self) -> tuple[float, float, float]:
|
|
2638
|
+
return self.get_rgb(
|
|
2639
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2640
|
+
shader.OUTPUT_GROUP_PARAMETRIC_RIM_COLOR_FACTOR_LABEL,
|
|
2641
|
+
default_value=shader.OUTPUT_GROUP_PARAMETRIC_RIM_COLOR_FACTOR_DEFAULT,
|
|
2642
|
+
)
|
|
2643
|
+
|
|
2644
|
+
def _set_parametric_rim_color_factor(self, value: object) -> None:
|
|
2645
|
+
self.set_rgb(
|
|
2646
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2647
|
+
shader.OUTPUT_GROUP_PARAMETRIC_RIM_COLOR_FACTOR_LABEL,
|
|
2648
|
+
value,
|
|
2649
|
+
)
|
|
2650
|
+
|
|
2651
|
+
parametric_rim_color_factor: FloatVectorProperty( # type: ignore[valid-type]
|
|
2652
|
+
name=shader.OUTPUT_GROUP_PARAMETRIC_RIM_COLOR_FACTOR_LABEL,
|
|
2653
|
+
size=3,
|
|
2654
|
+
subtype="COLOR",
|
|
2655
|
+
default=shader.OUTPUT_GROUP_PARAMETRIC_RIM_COLOR_FACTOR_DEFAULT,
|
|
2656
|
+
min=0,
|
|
2657
|
+
max=1,
|
|
2658
|
+
get=_get_parametric_rim_color_factor,
|
|
2659
|
+
set=_set_parametric_rim_color_factor,
|
|
2660
|
+
)
|
|
2661
|
+
|
|
2662
|
+
rim_multiply_texture: PointerProperty( # type: ignore[valid-type]
|
|
2663
|
+
type=Mtoon1RimMultiplyTextureInfoPropertyGroup
|
|
2664
|
+
)
|
|
2665
|
+
|
|
2666
|
+
def _get_rim_lighting_mix_factor(self) -> float:
|
|
2667
|
+
return self.get_value(
|
|
2668
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2669
|
+
shader.OUTPUT_GROUP_RIM_LIGHTING_MIX_FACTOR_LABEL,
|
|
2670
|
+
default_value=shader.OUTPUT_GROUP_RIM_LIGHTING_MIX_FACTOR_DEFAULT,
|
|
2671
|
+
)
|
|
2672
|
+
|
|
2673
|
+
def _set_rim_lighting_mix_factor(self, value: object) -> None:
|
|
2674
|
+
self.set_value(
|
|
2675
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2676
|
+
shader.OUTPUT_GROUP_RIM_LIGHTING_MIX_FACTOR_LABEL,
|
|
2677
|
+
value,
|
|
2678
|
+
)
|
|
2679
|
+
|
|
2680
|
+
rim_lighting_mix_factor: FloatProperty( # type: ignore[valid-type]
|
|
2681
|
+
name=shader.OUTPUT_GROUP_RIM_LIGHTING_MIX_FACTOR_LABEL,
|
|
2682
|
+
default=shader.OUTPUT_GROUP_RIM_LIGHTING_MIX_FACTOR_DEFAULT,
|
|
2683
|
+
soft_min=0,
|
|
2684
|
+
soft_max=1,
|
|
2685
|
+
get=_get_rim_lighting_mix_factor,
|
|
2686
|
+
set=_set_rim_lighting_mix_factor,
|
|
2687
|
+
)
|
|
2688
|
+
|
|
2689
|
+
def _get_parametric_rim_fresnel_power_factor(self) -> float:
|
|
2690
|
+
return self.get_float(
|
|
2691
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2692
|
+
shader.OUTPUT_GROUP_PARAMETRIC_RIM_FRESNEL_POWER_LABEL,
|
|
2693
|
+
default_value=shader.OUTPUT_GROUP_PARAMETRIC_RIM_FRESNEL_POWER_DEFAULT,
|
|
2694
|
+
)
|
|
2695
|
+
|
|
2696
|
+
def _set_parametric_rim_fresnel_power_factor(self, value: object) -> None:
|
|
2697
|
+
self.set_value(
|
|
2698
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2699
|
+
shader.OUTPUT_GROUP_PARAMETRIC_RIM_FRESNEL_POWER_LABEL,
|
|
2700
|
+
value,
|
|
2701
|
+
)
|
|
2702
|
+
|
|
2703
|
+
parametric_rim_fresnel_power_factor: FloatProperty( # type: ignore[valid-type]
|
|
2704
|
+
name=shader.OUTPUT_GROUP_PARAMETRIC_RIM_FRESNEL_POWER_LABEL,
|
|
2705
|
+
min=0.0,
|
|
2706
|
+
default=shader.OUTPUT_GROUP_PARAMETRIC_RIM_FRESNEL_POWER_DEFAULT,
|
|
2707
|
+
soft_max=100.0,
|
|
2708
|
+
get=_get_parametric_rim_fresnel_power_factor,
|
|
2709
|
+
set=_set_parametric_rim_fresnel_power_factor,
|
|
2710
|
+
)
|
|
2711
|
+
|
|
2712
|
+
def _get_parametric_rim_lift_factor(self) -> float:
|
|
2713
|
+
return self.get_float(
|
|
2714
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2715
|
+
shader.OUTPUT_GROUP_PARAMETRIC_RIM_LIFT_FACTOR_LABEL,
|
|
2716
|
+
default_value=shader.OUTPUT_GROUP_PARAMETRIC_RIM_LIFT_FACTOR_DEFAULT,
|
|
2717
|
+
)
|
|
2718
|
+
|
|
2719
|
+
def _set_parametric_rim_lift_factor(self, value: object) -> None:
|
|
2720
|
+
self.set_value(
|
|
2721
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2722
|
+
shader.OUTPUT_GROUP_PARAMETRIC_RIM_LIFT_FACTOR_LABEL,
|
|
2723
|
+
value,
|
|
2724
|
+
)
|
|
2725
|
+
|
|
2726
|
+
parametric_rim_lift_factor: FloatProperty( # type: ignore[valid-type]
|
|
2727
|
+
name=shader.OUTPUT_GROUP_PARAMETRIC_RIM_LIFT_FACTOR_LABEL,
|
|
2728
|
+
soft_min=0.0,
|
|
2729
|
+
default=shader.OUTPUT_GROUP_PARAMETRIC_RIM_LIFT_FACTOR_DEFAULT,
|
|
2730
|
+
soft_max=1.0,
|
|
2731
|
+
get=_get_parametric_rim_lift_factor,
|
|
2732
|
+
set=_set_parametric_rim_lift_factor,
|
|
2733
|
+
)
|
|
2734
|
+
|
|
2735
|
+
(
|
|
2736
|
+
outline_width_mode_enum,
|
|
2737
|
+
(
|
|
2738
|
+
OUTLINE_WIDTH_MODE_NONE,
|
|
2739
|
+
OUTLINE_WIDTH_MODE_WORLD_COORDINATES,
|
|
2740
|
+
OUTLINE_WIDTH_MODE_SCREEN_COORDINATES,
|
|
2741
|
+
),
|
|
2742
|
+
) = property_group_enum(
|
|
2743
|
+
(
|
|
2744
|
+
"none",
|
|
2745
|
+
"None",
|
|
2746
|
+
"",
|
|
2747
|
+
"NONE",
|
|
2748
|
+
shader.OUTPUT_GROUP_OUTLINE_WIDTH_MODE_MIN,
|
|
2749
|
+
),
|
|
2750
|
+
("worldCoordinates", "World Coordinates", "", "NONE", 1),
|
|
2751
|
+
(
|
|
2752
|
+
"screenCoordinates",
|
|
2753
|
+
"Screen Coordinates",
|
|
2754
|
+
"",
|
|
2755
|
+
"NONE",
|
|
2756
|
+
shader.OUTPUT_GROUP_OUTLINE_WIDTH_MODE_MAX,
|
|
2757
|
+
),
|
|
2758
|
+
)
|
|
2759
|
+
|
|
2760
|
+
def _get_outline_width_mode(self) -> int:
|
|
2761
|
+
return self.get_int(
|
|
2762
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2763
|
+
shader.OUTPUT_GROUP_OUTLINE_WIDTH_MODE_LABEL,
|
|
2764
|
+
default_value=shader.OUTPUT_GROUP_OUTLINE_WIDTH_MODE_DEFAULT,
|
|
2765
|
+
)
|
|
2766
|
+
|
|
2767
|
+
def _set_outline_width_mode(self, value: object) -> None:
|
|
2768
|
+
self.set_int(
|
|
2769
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2770
|
+
shader.OUTPUT_GROUP_OUTLINE_WIDTH_MODE_LABEL,
|
|
2771
|
+
value,
|
|
2772
|
+
)
|
|
2773
|
+
self.update_outline_geometry()
|
|
2774
|
+
|
|
2775
|
+
def update_outline_geometry(self) -> None:
|
|
2776
|
+
material = self.find_material()
|
|
2777
|
+
if get_material_extension(material).mtoon1.is_outline_material:
|
|
2778
|
+
return
|
|
2779
|
+
refresh_mtoon1_outline(material_name=material.name, create_modifier=True)
|
|
2780
|
+
|
|
2781
|
+
outline_width_mode: EnumProperty( # type: ignore[valid-type]
|
|
2782
|
+
items=outline_width_mode_enum.items(),
|
|
2783
|
+
name=shader.OUTPUT_GROUP_OUTLINE_WIDTH_MODE_LABEL,
|
|
2784
|
+
get=_get_outline_width_mode,
|
|
2785
|
+
set=_set_outline_width_mode,
|
|
2786
|
+
)
|
|
2787
|
+
|
|
2788
|
+
def _get_outline_width_factor(self) -> float:
|
|
2789
|
+
return self.get_value(
|
|
2790
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2791
|
+
shader.OUTPUT_GROUP_OUTLINE_WIDTH_FACTOR_LABEL,
|
|
2792
|
+
default_value=shader.OUTPUT_GROUP_OUTLINE_WIDTH_FACTOR_DEFAULT,
|
|
2793
|
+
)
|
|
2794
|
+
|
|
2795
|
+
def _set_outline_width_factor(self, value: object) -> None:
|
|
2796
|
+
self.set_value(
|
|
2797
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2798
|
+
shader.OUTPUT_GROUP_OUTLINE_WIDTH_FACTOR_LABEL,
|
|
2799
|
+
value,
|
|
2800
|
+
)
|
|
2801
|
+
self.update_outline_geometry()
|
|
2802
|
+
|
|
2803
|
+
outline_width_factor: FloatProperty( # type: ignore[valid-type]
|
|
2804
|
+
name=shader.OUTPUT_GROUP_OUTLINE_WIDTH_FACTOR_LABEL,
|
|
2805
|
+
default=shader.OUTPUT_GROUP_OUTLINE_WIDTH_FACTOR_DEFAULT,
|
|
2806
|
+
min=0.0,
|
|
2807
|
+
soft_max=0.05,
|
|
2808
|
+
get=_get_outline_width_factor,
|
|
2809
|
+
set=_set_outline_width_factor,
|
|
2810
|
+
)
|
|
2811
|
+
|
|
2812
|
+
outline_width_multiply_texture: PointerProperty( # type: ignore[valid-type]
|
|
2813
|
+
type=Mtoon1OutlineWidthMultiplyTextureInfoPropertyGroup
|
|
2814
|
+
)
|
|
2815
|
+
|
|
2816
|
+
def _get_outline_color_factor(self) -> tuple[float, float, float]:
|
|
2817
|
+
return self.get_rgb(
|
|
2818
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2819
|
+
shader.OUTPUT_GROUP_OUTLINE_COLOR_FACTOR_LABEL,
|
|
2820
|
+
default_value=shader.OUTPUT_GROUP_OUTLINE_COLOR_FACTOR_DEFAULT,
|
|
2821
|
+
)
|
|
2822
|
+
|
|
2823
|
+
def _set_outline_color_factor(self, value: object) -> None:
|
|
2824
|
+
self.set_rgb(
|
|
2825
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2826
|
+
shader.OUTPUT_GROUP_OUTLINE_COLOR_FACTOR_LABEL,
|
|
2827
|
+
value,
|
|
2828
|
+
shader.OUTPUT_GROUP_OUTLINE_COLOR_FACTOR_DEFAULT,
|
|
2829
|
+
)
|
|
2830
|
+
self.update_outline_geometry()
|
|
2831
|
+
|
|
2832
|
+
material = self.find_material()
|
|
2833
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
2834
|
+
if mtoon1.is_outline_material:
|
|
2835
|
+
return
|
|
2836
|
+
outline_material = mtoon1.outline_material
|
|
2837
|
+
if not outline_material:
|
|
2838
|
+
return
|
|
2839
|
+
outline_principled_bsdf = PrincipledBSDFWrapper(
|
|
2840
|
+
outline_material, is_readonly=False
|
|
2841
|
+
)
|
|
2842
|
+
|
|
2843
|
+
outline_diffuse_alpha = outline_material.diffuse_color[3]
|
|
2844
|
+
outline_principled_bsdf.base_color = (
|
|
2845
|
+
self.outline_color_factor[0],
|
|
2846
|
+
self.outline_color_factor[1],
|
|
2847
|
+
self.outline_color_factor[2],
|
|
2848
|
+
)
|
|
2849
|
+
outline_material.diffuse_color[3] = outline_diffuse_alpha
|
|
2850
|
+
|
|
2851
|
+
outline_color_factor: FloatVectorProperty( # type: ignore[valid-type]
|
|
2852
|
+
name=shader.OUTPUT_GROUP_OUTLINE_COLOR_FACTOR_LABEL,
|
|
2853
|
+
size=3,
|
|
2854
|
+
subtype="COLOR",
|
|
2855
|
+
default=shader.OUTPUT_GROUP_OUTLINE_COLOR_FACTOR_DEFAULT,
|
|
2856
|
+
min=0,
|
|
2857
|
+
max=1,
|
|
2858
|
+
get=_get_outline_color_factor,
|
|
2859
|
+
set=_set_outline_color_factor,
|
|
2860
|
+
)
|
|
2861
|
+
|
|
2862
|
+
def _get_outline_lighting_mix_factor(self) -> float:
|
|
2863
|
+
return self.get_value(
|
|
2864
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2865
|
+
shader.OUTPUT_GROUP_OUTLINE_LIGHTING_MIX_FACTOR_LABEL,
|
|
2866
|
+
default_value=shader.OUTPUT_GROUP_OUTLINE_LIGHTING_MIX_FACTOR_DEFAULT,
|
|
2867
|
+
)
|
|
2868
|
+
|
|
2869
|
+
def _set_outline_lighting_mix_factor(self, value: object) -> None:
|
|
2870
|
+
self.set_value(
|
|
2871
|
+
shader.OUTPUT_GROUP_NAME,
|
|
2872
|
+
shader.OUTPUT_GROUP_OUTLINE_LIGHTING_MIX_FACTOR_LABEL,
|
|
2873
|
+
value,
|
|
2874
|
+
)
|
|
2875
|
+
self.update_outline_geometry()
|
|
2876
|
+
|
|
2877
|
+
outline_lighting_mix_factor: FloatProperty( # type: ignore[valid-type]
|
|
2878
|
+
name=shader.OUTPUT_GROUP_OUTLINE_LIGHTING_MIX_FACTOR_LABEL,
|
|
2879
|
+
min=0.0,
|
|
2880
|
+
default=shader.OUTPUT_GROUP_OUTLINE_LIGHTING_MIX_FACTOR_DEFAULT,
|
|
2881
|
+
max=1.0,
|
|
2882
|
+
get=_get_outline_lighting_mix_factor,
|
|
2883
|
+
set=_set_outline_lighting_mix_factor,
|
|
2884
|
+
)
|
|
2885
|
+
|
|
2886
|
+
def _update_enable_outline_preview(self, context: Context) -> None:
|
|
2887
|
+
material_name = self.find_material().name
|
|
2888
|
+
refresh_mtoon1_outline(
|
|
2889
|
+
context, material_name=material_name, create_modifier=True
|
|
2890
|
+
)
|
|
2891
|
+
for material in context.blend_data.materials:
|
|
2892
|
+
if material.name == material_name:
|
|
2893
|
+
continue
|
|
2894
|
+
ext = get_material_extension(material).mtoon1
|
|
2895
|
+
if not ext.enabled:
|
|
2896
|
+
continue
|
|
2897
|
+
mtoon = ext.extensions.vrmc_materials_mtoon
|
|
2898
|
+
if mtoon.enable_outline_preview != self.enable_outline_preview:
|
|
2899
|
+
mtoon.enable_outline_preview = self.enable_outline_preview
|
|
2900
|
+
|
|
2901
|
+
enable_outline_preview: BoolProperty( # type: ignore[valid-type]
|
|
2902
|
+
default=True,
|
|
2903
|
+
update=_update_enable_outline_preview,
|
|
2904
|
+
)
|
|
2905
|
+
|
|
2906
|
+
uv_animation_mask_texture: PointerProperty( # type: ignore[valid-type]
|
|
2907
|
+
type=Mtoon1UvAnimationMaskTextureInfoPropertyGroup
|
|
2908
|
+
)
|
|
2909
|
+
|
|
2910
|
+
def _get_uv_animation_scroll_x_speed_factor(self) -> float:
|
|
2911
|
+
return self.get_value(
|
|
2912
|
+
shader.UV_ANIMATION_GROUP_NAME,
|
|
2913
|
+
shader.UV_ANIMATION_GROUP_TRANSLATE_X_LABEL,
|
|
2914
|
+
default_value=shader.UV_ANIMATION_GROUP_TRANSLATE_X_DEFAULT,
|
|
2915
|
+
)
|
|
2916
|
+
|
|
2917
|
+
def _set_uv_animation_scroll_x_speed_factor(self, value: object) -> None:
|
|
2918
|
+
self.set_value(
|
|
2919
|
+
shader.UV_ANIMATION_GROUP_NAME,
|
|
2920
|
+
shader.UV_ANIMATION_GROUP_TRANSLATE_X_LABEL,
|
|
2921
|
+
value,
|
|
2922
|
+
)
|
|
2923
|
+
|
|
2924
|
+
uv_animation_scroll_x_speed_factor: FloatProperty( # type: ignore[valid-type]
|
|
2925
|
+
name=shader.UV_ANIMATION_GROUP_TRANSLATE_X_LABEL,
|
|
2926
|
+
default=shader.UV_ANIMATION_GROUP_TRANSLATE_X_DEFAULT,
|
|
2927
|
+
get=_get_uv_animation_scroll_x_speed_factor,
|
|
2928
|
+
set=_set_uv_animation_scroll_x_speed_factor,
|
|
2929
|
+
)
|
|
2930
|
+
|
|
2931
|
+
def _get_uv_animation_scroll_y_speed_factor(self) -> float:
|
|
2932
|
+
return self.get_value(
|
|
2933
|
+
shader.UV_ANIMATION_GROUP_NAME,
|
|
2934
|
+
shader.UV_ANIMATION_GROUP_TRANSLATE_Y_LABEL,
|
|
2935
|
+
default_value=shader.UV_ANIMATION_GROUP_TRANSLATE_Y_DEFAULT,
|
|
2936
|
+
)
|
|
2937
|
+
|
|
2938
|
+
def _set_uv_animation_scroll_y_speed_factor(self, value: object) -> None:
|
|
2939
|
+
self.set_value(
|
|
2940
|
+
shader.UV_ANIMATION_GROUP_NAME,
|
|
2941
|
+
shader.UV_ANIMATION_GROUP_TRANSLATE_Y_LABEL,
|
|
2942
|
+
value,
|
|
2943
|
+
)
|
|
2944
|
+
|
|
2945
|
+
uv_animation_scroll_y_speed_factor: FloatProperty( # type: ignore[valid-type]
|
|
2946
|
+
name=shader.UV_ANIMATION_GROUP_TRANSLATE_Y_LABEL,
|
|
2947
|
+
default=shader.UV_ANIMATION_GROUP_TRANSLATE_Y_DEFAULT,
|
|
2948
|
+
get=_get_uv_animation_scroll_y_speed_factor,
|
|
2949
|
+
set=_set_uv_animation_scroll_y_speed_factor,
|
|
2950
|
+
)
|
|
2951
|
+
|
|
2952
|
+
def _get_uv_animation_rotation_speed_factor(self) -> float:
|
|
2953
|
+
return self.get_value(
|
|
2954
|
+
shader.UV_ANIMATION_GROUP_NAME,
|
|
2955
|
+
shader.UV_ANIMATION_GROUP_ROTATION_LABEL,
|
|
2956
|
+
default_value=shader.UV_ANIMATION_GROUP_ROTATION_DEFAULT,
|
|
2957
|
+
)
|
|
2958
|
+
|
|
2959
|
+
def _set_uv_animation_rotation_speed_factor(self, value: object) -> None:
|
|
2960
|
+
self.set_value(
|
|
2961
|
+
shader.UV_ANIMATION_GROUP_NAME,
|
|
2962
|
+
shader.UV_ANIMATION_GROUP_ROTATION_LABEL,
|
|
2963
|
+
value,
|
|
2964
|
+
)
|
|
2965
|
+
|
|
2966
|
+
uv_animation_rotation_speed_factor: FloatProperty( # type: ignore[valid-type]
|
|
2967
|
+
name=shader.UV_ANIMATION_GROUP_ROTATION_LABEL,
|
|
2968
|
+
get=_get_uv_animation_rotation_speed_factor,
|
|
2969
|
+
set=_set_uv_animation_rotation_speed_factor,
|
|
2970
|
+
)
|
|
2971
|
+
|
|
2972
|
+
if TYPE_CHECKING:
|
|
2973
|
+
# This code is auto generated.
|
|
2974
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
2975
|
+
transparent_with_z_write: bool # type: ignore[no-redef]
|
|
2976
|
+
render_queue_offset_number: int # type: ignore[no-redef]
|
|
2977
|
+
shade_multiply_texture: ( # type: ignore[no-redef]
|
|
2978
|
+
Mtoon1ShadeMultiplyTextureInfoPropertyGroup
|
|
2979
|
+
)
|
|
2980
|
+
shade_color_factor: Sequence[float] # type: ignore[no-redef]
|
|
2981
|
+
shading_shift_texture: ( # type: ignore[no-redef]
|
|
2982
|
+
Mtoon1ShadingShiftTextureInfoPropertyGroup
|
|
2983
|
+
)
|
|
2984
|
+
shading_shift_factor: float # type: ignore[no-redef]
|
|
2985
|
+
shading_toony_factor: float # type: ignore[no-redef]
|
|
2986
|
+
gi_equalization_factor: float # type: ignore[no-redef]
|
|
2987
|
+
matcap_factor: Sequence[float] # type: ignore[no-redef]
|
|
2988
|
+
matcap_texture: Mtoon1MatcapTextureInfoPropertyGroup # type: ignore[no-redef]
|
|
2989
|
+
parametric_rim_color_factor: Sequence[float] # type: ignore[no-redef]
|
|
2990
|
+
rim_multiply_texture: ( # type: ignore[no-redef]
|
|
2991
|
+
Mtoon1RimMultiplyTextureInfoPropertyGroup
|
|
2992
|
+
)
|
|
2993
|
+
rim_lighting_mix_factor: float # type: ignore[no-redef]
|
|
2994
|
+
parametric_rim_fresnel_power_factor: float # type: ignore[no-redef]
|
|
2995
|
+
parametric_rim_lift_factor: float # type: ignore[no-redef]
|
|
2996
|
+
outline_width_mode: str # type: ignore[no-redef]
|
|
2997
|
+
outline_width_factor: float # type: ignore[no-redef]
|
|
2998
|
+
outline_width_multiply_texture: ( # type: ignore[no-redef]
|
|
2999
|
+
Mtoon1OutlineWidthMultiplyTextureInfoPropertyGroup
|
|
3000
|
+
)
|
|
3001
|
+
outline_color_factor: Sequence[float] # type: ignore[no-redef]
|
|
3002
|
+
outline_lighting_mix_factor: float # type: ignore[no-redef]
|
|
3003
|
+
enable_outline_preview: bool # type: ignore[no-redef]
|
|
3004
|
+
uv_animation_mask_texture: ( # type: ignore[no-redef]
|
|
3005
|
+
Mtoon1UvAnimationMaskTextureInfoPropertyGroup
|
|
3006
|
+
)
|
|
3007
|
+
uv_animation_scroll_x_speed_factor: float # type: ignore[no-redef]
|
|
3008
|
+
uv_animation_scroll_y_speed_factor: float # type: ignore[no-redef]
|
|
3009
|
+
uv_animation_rotation_speed_factor: float # type: ignore[no-redef]
|
|
3010
|
+
|
|
3011
|
+
|
|
3012
|
+
# https://github.com/KhronosGroup/glTF/blob/d997b7dc7e426bc791f5613475f5b4490da0b099/extensions/2.0/Khronos/KHR_materials_emissive_strength/schema/glTF.KHR_materials_emissive_strength.schema.json
|
|
3013
|
+
class Mtoon1KhrMaterialsEmissiveStrengthPropertyGroup(MaterialTraceablePropertyGroup):
|
|
3014
|
+
def _get_emissive_strength(self) -> float:
|
|
3015
|
+
return self.get_float(
|
|
3016
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3017
|
+
shader.OUTPUT_GROUP_EMISSIVE_STRENGTH_LABEL,
|
|
3018
|
+
default_value=shader.OUTPUT_GROUP_EMISSIVE_STRENGTH_DEFAULT,
|
|
3019
|
+
)
|
|
3020
|
+
|
|
3021
|
+
def _set_emissive_strength(self, value: object) -> None:
|
|
3022
|
+
self.set_value(
|
|
3023
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3024
|
+
shader.OUTPUT_GROUP_EMISSIVE_STRENGTH_LABEL,
|
|
3025
|
+
value,
|
|
3026
|
+
)
|
|
3027
|
+
|
|
3028
|
+
material = self.find_material()
|
|
3029
|
+
principled_bsdf = PrincipledBSDFWrapper(material, is_readonly=False)
|
|
3030
|
+
principled_bsdf.emission_strength = self.emissive_strength
|
|
3031
|
+
|
|
3032
|
+
emissive_node = _get_gltf_emissive_node(material)
|
|
3033
|
+
if emissive_node is not None:
|
|
3034
|
+
socket = emissive_node.inputs.get(EMISSION_STRENGTH_INPUT_KEY)
|
|
3035
|
+
if isinstance(socket, NodeSocketFloat):
|
|
3036
|
+
socket.default_value = self.emissive_strength
|
|
3037
|
+
|
|
3038
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
3039
|
+
if mtoon1.is_outline_material:
|
|
3040
|
+
return
|
|
3041
|
+
outline_material = mtoon1.outline_material
|
|
3042
|
+
if not outline_material:
|
|
3043
|
+
return
|
|
3044
|
+
outline_principled_bsdf = PrincipledBSDFWrapper(
|
|
3045
|
+
outline_material, is_readonly=False
|
|
3046
|
+
)
|
|
3047
|
+
outline_principled_bsdf.emission_strength = self.emissive_strength
|
|
3048
|
+
|
|
3049
|
+
outline_emissive_node = _get_gltf_emissive_node(outline_material)
|
|
3050
|
+
if outline_emissive_node is not None:
|
|
3051
|
+
outline_socket = outline_emissive_node.inputs.get(
|
|
3052
|
+
EMISSION_STRENGTH_INPUT_KEY
|
|
3053
|
+
)
|
|
3054
|
+
if isinstance(outline_socket, NodeSocketFloat):
|
|
3055
|
+
outline_socket.default_value = self.emissive_strength
|
|
3056
|
+
|
|
3057
|
+
emissive_strength: FloatProperty( # type: ignore[valid-type]
|
|
3058
|
+
name="Strength",
|
|
3059
|
+
min=0.0,
|
|
3060
|
+
default=shader.OUTPUT_GROUP_EMISSIVE_STRENGTH_DEFAULT,
|
|
3061
|
+
get=_get_emissive_strength,
|
|
3062
|
+
set=_set_emissive_strength,
|
|
3063
|
+
)
|
|
3064
|
+
|
|
3065
|
+
if TYPE_CHECKING:
|
|
3066
|
+
# This code is auto generated.
|
|
3067
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
3068
|
+
emissive_strength: float # type: ignore[no-redef]
|
|
3069
|
+
|
|
3070
|
+
|
|
3071
|
+
class Mtoon1MaterialExtensionsPropertyGroup(PropertyGroup):
|
|
3072
|
+
vrmc_materials_mtoon: PointerProperty( # type: ignore[valid-type]
|
|
3073
|
+
type=Mtoon1VrmcMaterialsMtoonPropertyGroup
|
|
3074
|
+
)
|
|
3075
|
+
khr_materials_emissive_strength: PointerProperty( # type: ignore[valid-type]
|
|
3076
|
+
type=Mtoon1KhrMaterialsEmissiveStrengthPropertyGroup
|
|
3077
|
+
)
|
|
3078
|
+
|
|
3079
|
+
if TYPE_CHECKING:
|
|
3080
|
+
# This code is auto generated.
|
|
3081
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
3082
|
+
vrmc_materials_mtoon: ( # type: ignore[no-redef]
|
|
3083
|
+
Mtoon1VrmcMaterialsMtoonPropertyGroup
|
|
3084
|
+
)
|
|
3085
|
+
khr_materials_emissive_strength: ( # type: ignore[no-redef]
|
|
3086
|
+
Mtoon1KhrMaterialsEmissiveStrengthPropertyGroup
|
|
3087
|
+
)
|
|
3088
|
+
|
|
3089
|
+
|
|
3090
|
+
# https://github.com/vrm-c/vrm-specification/blob/8dc51ec7241be27ee95f159cefc0190a0e41967b/specification/VRMC_materials_mtoon-1.0-beta/schema/VRMC_materials_mtoon.schema.json
|
|
3091
|
+
class Mtoon1MaterialPropertyGroup(MaterialTraceablePropertyGroup):
|
|
3092
|
+
UNMANAGED_ADDON_VERSION = VrmAddonPreferences.UNMANAGED_ADDON_VERSION
|
|
3093
|
+
|
|
3094
|
+
addon_version: IntVectorProperty( # type: ignore[valid-type]
|
|
3095
|
+
size=3,
|
|
3096
|
+
default=UNMANAGED_ADDON_VERSION,
|
|
3097
|
+
)
|
|
3098
|
+
|
|
3099
|
+
pbr_metallic_roughness: PointerProperty( # type: ignore[valid-type]
|
|
3100
|
+
type=Mtoon1PbrMetallicRoughnessPropertyGroup
|
|
3101
|
+
)
|
|
3102
|
+
|
|
3103
|
+
(
|
|
3104
|
+
alpha_mode_enum,
|
|
3105
|
+
(
|
|
3106
|
+
ALPHA_MODE_OPAQUE,
|
|
3107
|
+
ALPHA_MODE_MASK,
|
|
3108
|
+
ALPHA_MODE_BLEND,
|
|
3109
|
+
),
|
|
3110
|
+
) = property_group_enum(
|
|
3111
|
+
("OPAQUE", "Opaque", "", "NONE", 0),
|
|
3112
|
+
("MASK", "Cutout", "", "NONE", 1),
|
|
3113
|
+
("BLEND", "Transparent", "", "NONE", 2),
|
|
3114
|
+
)
|
|
3115
|
+
|
|
3116
|
+
alpha_mode_blend_method_hashed: BoolProperty() # type: ignore[valid-type]
|
|
3117
|
+
|
|
3118
|
+
def _get_alpha_mode(self) -> int:
|
|
3119
|
+
alpha_mode_value = self.get_int(
|
|
3120
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3121
|
+
shader.OUTPUT_GROUP_ALPHA_MODE_LABEL,
|
|
3122
|
+
default_value=self.ALPHA_MODE_OPAQUE.value,
|
|
3123
|
+
)
|
|
3124
|
+
if alpha_mode_value in self.alpha_mode_enum.values():
|
|
3125
|
+
return alpha_mode_value
|
|
3126
|
+
return self.ALPHA_MODE_OPAQUE.value
|
|
3127
|
+
|
|
3128
|
+
@staticmethod
|
|
3129
|
+
def update_alpha_nodes(material: Material, alpha_mode_value: int) -> None:
|
|
3130
|
+
node_tree = material.node_tree
|
|
3131
|
+
if not node_tree:
|
|
3132
|
+
return
|
|
3133
|
+
|
|
3134
|
+
# Align with glTF nodes
|
|
3135
|
+
# https://docs.blender.org/manual/en/4.2/addons/import_export/scene_gltf2.html#alpha-modes
|
|
3136
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
3137
|
+
texture = mtoon1.pbr_metallic_roughness.base_color_texture.index
|
|
3138
|
+
tex_image_node_name = texture.get_image_texture_node_name()
|
|
3139
|
+
|
|
3140
|
+
if alpha_mode_value != mtoon1.ALPHA_MODE_MASK.value:
|
|
3141
|
+
TextureTraceablePropertyGroup.unlink_nodes(
|
|
3142
|
+
material,
|
|
3143
|
+
StaticNodeSocketTarget(
|
|
3144
|
+
in_node_name=ALPHA_CLIP_INPUT_NODE_NAME,
|
|
3145
|
+
in_node_type=ShaderNodeMath,
|
|
3146
|
+
in_socket_name=ALPHA_CLIP_INPUT_NODE_SOCKET_NAME,
|
|
3147
|
+
),
|
|
3148
|
+
)
|
|
3149
|
+
TextureTraceablePropertyGroup.unlink_nodes(
|
|
3150
|
+
material,
|
|
3151
|
+
PrincipledBsdfNodeSocketTarget(
|
|
3152
|
+
in_socket_name=PRINCIPLED_BSDF_ALPHA_INPUT_KEY
|
|
3153
|
+
),
|
|
3154
|
+
)
|
|
3155
|
+
if alpha_mode_value != mtoon1.ALPHA_MODE_BLEND.value or bpy.app.version < (
|
|
3156
|
+
4,
|
|
3157
|
+
2,
|
|
3158
|
+
):
|
|
3159
|
+
TextureTraceablePropertyGroup.unlink_nodes(
|
|
3160
|
+
material,
|
|
3161
|
+
PrincipledBsdfNodeSocketTarget(
|
|
3162
|
+
in_socket_name=PRINCIPLED_BSDF_ALPHA_INPUT_KEY
|
|
3163
|
+
),
|
|
3164
|
+
)
|
|
3165
|
+
|
|
3166
|
+
principled_bsdf = PrincipledBSDFWrapper(material, is_readonly=False)
|
|
3167
|
+
if bpy.app.version < (4, 2):
|
|
3168
|
+
principled_bsdf.alpha = mtoon1.pbr_metallic_roughness.base_color_factor[3]
|
|
3169
|
+
tex_image_node = node_tree.nodes.get(tex_image_node_name)
|
|
3170
|
+
if isinstance(tex_image_node, ShaderNodeTexImage):
|
|
3171
|
+
TextureTraceablePropertyGroup.link_or_unlink_nodes(
|
|
3172
|
+
material,
|
|
3173
|
+
tex_image_node_name,
|
|
3174
|
+
ShaderNodeTexImage,
|
|
3175
|
+
TEX_IMAGE_ALPHA_OUTPUT_KEY,
|
|
3176
|
+
PrincipledBsdfNodeSocketTarget(
|
|
3177
|
+
in_socket_name=PRINCIPLED_BSDF_ALPHA_INPUT_KEY
|
|
3178
|
+
),
|
|
3179
|
+
link=bool(tex_image_node.image),
|
|
3180
|
+
)
|
|
3181
|
+
elif alpha_mode_value == mtoon1.ALPHA_MODE_OPAQUE.value:
|
|
3182
|
+
principled_bsdf.alpha = 1.0
|
|
3183
|
+
elif alpha_mode_value == mtoon1.ALPHA_MODE_MASK.value:
|
|
3184
|
+
tex_image_node = node_tree.nodes.get(tex_image_node_name)
|
|
3185
|
+
image_exists = False
|
|
3186
|
+
if isinstance(tex_image_node, ShaderNodeTexImage):
|
|
3187
|
+
image_exists = bool(tex_image_node.image)
|
|
3188
|
+
TextureTraceablePropertyGroup.link_or_unlink_nodes(
|
|
3189
|
+
material,
|
|
3190
|
+
tex_image_node_name,
|
|
3191
|
+
ShaderNodeTexImage,
|
|
3192
|
+
TEX_IMAGE_ALPHA_OUTPUT_KEY,
|
|
3193
|
+
StaticNodeSocketTarget(
|
|
3194
|
+
in_node_name=ALPHA_CLIP_INPUT_NODE_NAME,
|
|
3195
|
+
in_node_type=ShaderNodeMath,
|
|
3196
|
+
in_socket_name=ALPHA_CLIP_INPUT_NODE_SOCKET_NAME,
|
|
3197
|
+
),
|
|
3198
|
+
link=image_exists,
|
|
3199
|
+
)
|
|
3200
|
+
TextureTraceablePropertyGroup.link_or_unlink_nodes(
|
|
3201
|
+
material,
|
|
3202
|
+
ALPHA_CLIP_OUTPUT_NODE_NAME,
|
|
3203
|
+
ShaderNodeMath,
|
|
3204
|
+
ALPHA_CLIP_OUTPUT_NODE_SOCKET_NAME,
|
|
3205
|
+
PrincipledBsdfNodeSocketTarget(
|
|
3206
|
+
in_socket_name=PRINCIPLED_BSDF_ALPHA_INPUT_KEY
|
|
3207
|
+
),
|
|
3208
|
+
link=image_exists,
|
|
3209
|
+
)
|
|
3210
|
+
if not image_exists:
|
|
3211
|
+
alpha = mtoon1.pbr_metallic_roughness.base_color_factor[3]
|
|
3212
|
+
if alpha >= mtoon1.alpha_cutoff:
|
|
3213
|
+
principled_bsdf.alpha = 1.0
|
|
3214
|
+
else:
|
|
3215
|
+
principled_bsdf.alpha = 0.0
|
|
3216
|
+
elif alpha_mode_value == mtoon1.ALPHA_MODE_BLEND.value:
|
|
3217
|
+
principled_bsdf.alpha = mtoon1.pbr_metallic_roughness.base_color_factor[3]
|
|
3218
|
+
tex_image_node = node_tree.nodes.get(tex_image_node_name)
|
|
3219
|
+
if isinstance(tex_image_node, ShaderNodeTexImage):
|
|
3220
|
+
TextureTraceablePropertyGroup.link_or_unlink_nodes(
|
|
3221
|
+
material,
|
|
3222
|
+
tex_image_node_name,
|
|
3223
|
+
ShaderNodeTexImage,
|
|
3224
|
+
TEX_IMAGE_ALPHA_OUTPUT_KEY,
|
|
3225
|
+
PrincipledBsdfNodeSocketTarget(
|
|
3226
|
+
in_socket_name=PRINCIPLED_BSDF_ALPHA_INPUT_KEY
|
|
3227
|
+
),
|
|
3228
|
+
link=bool(tex_image_node.image),
|
|
3229
|
+
)
|
|
3230
|
+
|
|
3231
|
+
alpha_clip_input_node = node_tree.nodes.get(ALPHA_CLIP_INPUT_NODE_NAME)
|
|
3232
|
+
if (
|
|
3233
|
+
isinstance(alpha_clip_input_node, ShaderNodeMath)
|
|
3234
|
+
and alpha_clip_input_node.operation == "LESS_THAN"
|
|
3235
|
+
):
|
|
3236
|
+
inputs = alpha_clip_input_node.inputs
|
|
3237
|
+
if len(inputs) >= 2:
|
|
3238
|
+
alpha_input = inputs[0]
|
|
3239
|
+
if isinstance(alpha_input, shader.FLOAT_SOCKET_CLASSES):
|
|
3240
|
+
alpha_input.default_value = (
|
|
3241
|
+
mtoon1.pbr_metallic_roughness.base_color_factor[3]
|
|
3242
|
+
)
|
|
3243
|
+
else:
|
|
3244
|
+
_logger.error(
|
|
3245
|
+
"Unexpected alpha input node input type: %s", type(alpha_input)
|
|
3246
|
+
)
|
|
3247
|
+
|
|
3248
|
+
alpha_cutoff_input = inputs[1]
|
|
3249
|
+
if isinstance(alpha_cutoff_input, shader.FLOAT_SOCKET_CLASSES):
|
|
3250
|
+
alpha_cutoff_input.default_value = mtoon1.alpha_cutoff
|
|
3251
|
+
else:
|
|
3252
|
+
_logger.error(
|
|
3253
|
+
"Unexpected alpha clip input node input type: %s",
|
|
3254
|
+
type(alpha_cutoff_input),
|
|
3255
|
+
)
|
|
3256
|
+
else:
|
|
3257
|
+
_logger.error(
|
|
3258
|
+
"Unexpected alpha clip input node input length: %s", len(inputs)
|
|
3259
|
+
)
|
|
3260
|
+
else:
|
|
3261
|
+
_logger.error(
|
|
3262
|
+
"Unexpected alpha clip input node type: %s",
|
|
3263
|
+
type(alpha_clip_input_node),
|
|
3264
|
+
)
|
|
3265
|
+
|
|
3266
|
+
def _set_alpha_mode(self, value: int) -> None:
|
|
3267
|
+
changed = self._get_alpha_mode() != value
|
|
3268
|
+
|
|
3269
|
+
material = self.find_material()
|
|
3270
|
+
|
|
3271
|
+
shadow_method = None
|
|
3272
|
+
if bpy.app.version < (4, 2):
|
|
3273
|
+
if material.blend_method == "HASHED":
|
|
3274
|
+
self.alpha_mode_blend_method_hashed = True
|
|
3275
|
+
if material.blend_method == "BLEND":
|
|
3276
|
+
self.alpha_mode_blend_method_hashed = False
|
|
3277
|
+
|
|
3278
|
+
if value == self.ALPHA_MODE_OPAQUE.value:
|
|
3279
|
+
material.blend_method = "OPAQUE"
|
|
3280
|
+
shadow_method = "OPAQUE"
|
|
3281
|
+
elif value == self.ALPHA_MODE_MASK.value:
|
|
3282
|
+
material.blend_method = "CLIP"
|
|
3283
|
+
shadow_method = "CLIP"
|
|
3284
|
+
elif value == self.ALPHA_MODE_BLEND.value:
|
|
3285
|
+
material.blend_method = "HASHED"
|
|
3286
|
+
shadow_method = "HASHED"
|
|
3287
|
+
else:
|
|
3288
|
+
_logger.error("Unexpected alpha mode: %s", value)
|
|
3289
|
+
material.blend_method = "OPAQUE"
|
|
3290
|
+
shadow_method = "OPAQUE"
|
|
3291
|
+
|
|
3292
|
+
self.set_value(
|
|
3293
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3294
|
+
shader.OUTPUT_GROUP_ALPHA_MODE_LABEL,
|
|
3295
|
+
value,
|
|
3296
|
+
)
|
|
3297
|
+
|
|
3298
|
+
if changed:
|
|
3299
|
+
self._set_mtoon0_render_queue_and_clamp(self.mtoon0_render_queue)
|
|
3300
|
+
|
|
3301
|
+
self.update_alpha_nodes(material, value)
|
|
3302
|
+
|
|
3303
|
+
if self.is_outline_material:
|
|
3304
|
+
if bpy.app.version < (4, 2):
|
|
3305
|
+
material.shadow_method = "NONE"
|
|
3306
|
+
return
|
|
3307
|
+
|
|
3308
|
+
if bpy.app.version < (4, 3) and shadow_method is not None:
|
|
3309
|
+
material.shadow_method = shadow_method
|
|
3310
|
+
|
|
3311
|
+
outline_material = self.outline_material
|
|
3312
|
+
if not outline_material:
|
|
3313
|
+
return
|
|
3314
|
+
alpha_mode = self.alpha_mode_enum.value_to_identifier(
|
|
3315
|
+
value, self.ALPHA_MODE_OPAQUE.identifier
|
|
3316
|
+
)
|
|
3317
|
+
get_material_extension(outline_material).mtoon1.alpha_mode = alpha_mode
|
|
3318
|
+
|
|
3319
|
+
alpha_mode: EnumProperty( # type: ignore[valid-type]
|
|
3320
|
+
items=alpha_mode_enum.items(),
|
|
3321
|
+
name="Alpha Mode",
|
|
3322
|
+
get=_get_alpha_mode,
|
|
3323
|
+
set=_set_alpha_mode,
|
|
3324
|
+
)
|
|
3325
|
+
|
|
3326
|
+
def _get_double_sided(self) -> bool:
|
|
3327
|
+
return not self.find_material().use_backface_culling
|
|
3328
|
+
|
|
3329
|
+
def _set_double_sided(self, value: object) -> None:
|
|
3330
|
+
material = self.find_material()
|
|
3331
|
+
material.use_backface_culling = not value
|
|
3332
|
+
self.set_bool(
|
|
3333
|
+
shader.OUTPUT_GROUP_NAME, shader.OUTPUT_GROUP_DOUBLE_SIDED_LABEL, value
|
|
3334
|
+
)
|
|
3335
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
3336
|
+
if mtoon1.is_outline_material:
|
|
3337
|
+
return
|
|
3338
|
+
outline_material = mtoon1.outline_material
|
|
3339
|
+
if not outline_material:
|
|
3340
|
+
return
|
|
3341
|
+
get_material_extension(outline_material).mtoon1.double_sided = False
|
|
3342
|
+
|
|
3343
|
+
double_sided: BoolProperty( # type: ignore[valid-type]
|
|
3344
|
+
name=shader.OUTPUT_GROUP_DOUBLE_SIDED_LABEL,
|
|
3345
|
+
get=_get_double_sided,
|
|
3346
|
+
set=_set_double_sided,
|
|
3347
|
+
)
|
|
3348
|
+
|
|
3349
|
+
def _get_alpha_cutoff(self) -> float:
|
|
3350
|
+
return self.get_float(
|
|
3351
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3352
|
+
shader.OUTPUT_GROUP_ALPHA_CUTOFF_LABEL,
|
|
3353
|
+
default_value=shader.OUTPUT_GROUP_ALPHA_CUTOFF_DEFAULT,
|
|
3354
|
+
)
|
|
3355
|
+
|
|
3356
|
+
def _set_alpha_cutoff(self, value: float) -> None:
|
|
3357
|
+
material = self.find_material()
|
|
3358
|
+
if bpy.app.version < (4, 2):
|
|
3359
|
+
# glTF alphaCutoff: >= is opaque
|
|
3360
|
+
# Blender <4.2 alpha_threshold: > is opaque
|
|
3361
|
+
# Subtract 0.00001 to absorb this difference.
|
|
3362
|
+
material.alpha_threshold = max(0, min(1.0, value - 0.00001))
|
|
3363
|
+
self.set_value(
|
|
3364
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3365
|
+
shader.OUTPUT_GROUP_ALPHA_CUTOFF_LABEL,
|
|
3366
|
+
max(0.0, value),
|
|
3367
|
+
)
|
|
3368
|
+
|
|
3369
|
+
alpha_mode_value = self.alpha_mode_enum.identifier_to_value(
|
|
3370
|
+
self.alpha_mode, self.ALPHA_MODE_OPAQUE.value
|
|
3371
|
+
)
|
|
3372
|
+
self.update_alpha_nodes(material, alpha_mode_value)
|
|
3373
|
+
|
|
3374
|
+
if self.is_outline_material:
|
|
3375
|
+
return
|
|
3376
|
+
outline_material = self.outline_material
|
|
3377
|
+
if not outline_material:
|
|
3378
|
+
return
|
|
3379
|
+
get_material_extension(outline_material).mtoon1.alpha_cutoff = value
|
|
3380
|
+
|
|
3381
|
+
alpha_cutoff: FloatProperty( # type: ignore[valid-type]
|
|
3382
|
+
name="Cutoff",
|
|
3383
|
+
min=0,
|
|
3384
|
+
soft_max=1,
|
|
3385
|
+
get=_get_alpha_cutoff,
|
|
3386
|
+
set=_set_alpha_cutoff,
|
|
3387
|
+
)
|
|
3388
|
+
|
|
3389
|
+
normal_texture: PointerProperty( # type: ignore[valid-type]
|
|
3390
|
+
type=Mtoon1NormalTextureInfoPropertyGroup
|
|
3391
|
+
)
|
|
3392
|
+
|
|
3393
|
+
emissive_texture: PointerProperty( # type: ignore[valid-type]
|
|
3394
|
+
type=Mtoon1EmissiveTextureInfoPropertyGroup
|
|
3395
|
+
)
|
|
3396
|
+
|
|
3397
|
+
def _get_emissive_factor(self) -> tuple[float, float, float]:
|
|
3398
|
+
return self.get_rgb(
|
|
3399
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3400
|
+
shader.OUTPUT_GROUP_EMISSIVE_FACTOR_LABEL,
|
|
3401
|
+
default_value=shader.OUTPUT_GROUP_EMISSIVE_FACTOR_DEFAULT,
|
|
3402
|
+
)
|
|
3403
|
+
|
|
3404
|
+
def _set_emissive_factor(self, value: object) -> None:
|
|
3405
|
+
self.set_rgb(
|
|
3406
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3407
|
+
shader.OUTPUT_GROUP_EMISSIVE_FACTOR_LABEL,
|
|
3408
|
+
value,
|
|
3409
|
+
shader.OUTPUT_GROUP_EMISSIVE_FACTOR_DEFAULT,
|
|
3410
|
+
)
|
|
3411
|
+
|
|
3412
|
+
material = self.find_material()
|
|
3413
|
+
principled_bsdf = PrincipledBSDFWrapper(material, is_readonly=False)
|
|
3414
|
+
principled_bsdf.emission_color = (
|
|
3415
|
+
self.emissive_factor[0],
|
|
3416
|
+
self.emissive_factor[1],
|
|
3417
|
+
self.emissive_factor[2],
|
|
3418
|
+
)
|
|
3419
|
+
|
|
3420
|
+
emissive_node = _get_gltf_emissive_node(material)
|
|
3421
|
+
if emissive_node is not None:
|
|
3422
|
+
socket = emissive_node.inputs.get(EMISSION_COLOR_INPUT_KEY)
|
|
3423
|
+
if isinstance(socket, NodeSocketColor):
|
|
3424
|
+
socket.default_value = (
|
|
3425
|
+
self.emissive_factor[0],
|
|
3426
|
+
self.emissive_factor[1],
|
|
3427
|
+
self.emissive_factor[2],
|
|
3428
|
+
1,
|
|
3429
|
+
)
|
|
3430
|
+
|
|
3431
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
3432
|
+
if mtoon1.is_outline_material:
|
|
3433
|
+
return
|
|
3434
|
+
outline_material = mtoon1.outline_material
|
|
3435
|
+
if not outline_material:
|
|
3436
|
+
return
|
|
3437
|
+
outline_principled_bsdf = PrincipledBSDFWrapper(
|
|
3438
|
+
outline_material, is_readonly=False
|
|
3439
|
+
)
|
|
3440
|
+
outline_principled_bsdf.emission_color = (
|
|
3441
|
+
self.emissive_factor[0],
|
|
3442
|
+
self.emissive_factor[1],
|
|
3443
|
+
self.emissive_factor[2],
|
|
3444
|
+
)
|
|
3445
|
+
|
|
3446
|
+
outline_emissive_node = _get_gltf_emissive_node(material)
|
|
3447
|
+
if outline_emissive_node is not None:
|
|
3448
|
+
outline_socket = outline_emissive_node.inputs.get(EMISSION_COLOR_INPUT_KEY)
|
|
3449
|
+
if isinstance(outline_socket, NodeSocketColor):
|
|
3450
|
+
outline_socket.default_value = (
|
|
3451
|
+
self.emissive_factor[0],
|
|
3452
|
+
self.emissive_factor[1],
|
|
3453
|
+
self.emissive_factor[2],
|
|
3454
|
+
1,
|
|
3455
|
+
)
|
|
3456
|
+
|
|
3457
|
+
emissive_factor: FloatVectorProperty( # type: ignore[valid-type]
|
|
3458
|
+
size=3,
|
|
3459
|
+
subtype="COLOR",
|
|
3460
|
+
default=shader.OUTPUT_GROUP_EMISSIVE_FACTOR_DEFAULT,
|
|
3461
|
+
min=0,
|
|
3462
|
+
max=1,
|
|
3463
|
+
get=_get_emissive_factor,
|
|
3464
|
+
set=_set_emissive_factor,
|
|
3465
|
+
)
|
|
3466
|
+
|
|
3467
|
+
extensions: PointerProperty( # type: ignore[valid-type]
|
|
3468
|
+
type=Mtoon1MaterialExtensionsPropertyGroup
|
|
3469
|
+
)
|
|
3470
|
+
|
|
3471
|
+
def _get_enabled(self) -> bool:
|
|
3472
|
+
if self.is_outline_material:
|
|
3473
|
+
return False
|
|
3474
|
+
|
|
3475
|
+
material = self.find_material()
|
|
3476
|
+
if bpy.app.version < (5, 0, 0) and not material.use_nodes:
|
|
3477
|
+
return False
|
|
3478
|
+
|
|
3479
|
+
node_tree = material.node_tree
|
|
3480
|
+
if not node_tree:
|
|
3481
|
+
return False
|
|
3482
|
+
|
|
3483
|
+
group_node = node_tree.nodes.get("Mtoon1Material.Mtoon1Output")
|
|
3484
|
+
if not isinstance(group_node, ShaderNodeGroup):
|
|
3485
|
+
return False
|
|
3486
|
+
|
|
3487
|
+
group_node_tree = group_node.node_tree
|
|
3488
|
+
if not group_node_tree:
|
|
3489
|
+
return False
|
|
3490
|
+
|
|
3491
|
+
if group_node_tree.name != shader.OUTPUT_GROUP_NAME:
|
|
3492
|
+
return False
|
|
3493
|
+
|
|
3494
|
+
return bool(self.get("enabled"))
|
|
3495
|
+
|
|
3496
|
+
def _set_enabled(self, value: object) -> None:
|
|
3497
|
+
material = self.find_material()
|
|
3498
|
+
|
|
3499
|
+
if not value:
|
|
3500
|
+
if self.get("enabled") and (
|
|
3501
|
+
bpy.app.version >= (5, 0, 0) or material.use_nodes
|
|
3502
|
+
):
|
|
3503
|
+
convert_mtoon1_to_bsdf_principled(material)
|
|
3504
|
+
self["enabled"] = False
|
|
3505
|
+
return
|
|
3506
|
+
|
|
3507
|
+
if bpy.app.version < (5, 0, 0) and not material.use_nodes:
|
|
3508
|
+
material.use_nodes = True
|
|
3509
|
+
if self.enabled:
|
|
3510
|
+
return
|
|
3511
|
+
|
|
3512
|
+
convert_material_to_mtoon1(material)
|
|
3513
|
+
self["enabled"] = True
|
|
3514
|
+
self.setup_drivers()
|
|
3515
|
+
|
|
3516
|
+
enabled: BoolProperty( # type: ignore[valid-type]
|
|
3517
|
+
name="Enable VRM MToon Material",
|
|
3518
|
+
get=_get_enabled,
|
|
3519
|
+
set=_set_enabled,
|
|
3520
|
+
)
|
|
3521
|
+
|
|
3522
|
+
export_shape_key_normals: BoolProperty( # type: ignore[valid-type]
|
|
3523
|
+
name="Export Shape Key Normals",
|
|
3524
|
+
)
|
|
3525
|
+
|
|
3526
|
+
def _update_is_outline_material(self, _context: Context) -> None:
|
|
3527
|
+
self.set_bool(
|
|
3528
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3529
|
+
shader.OUTPUT_GROUP_IS_OUTLINE_LABEL,
|
|
3530
|
+
self.is_outline_material,
|
|
3531
|
+
)
|
|
3532
|
+
self.set_bool(
|
|
3533
|
+
shader.NORMAL_GROUP_NAME,
|
|
3534
|
+
shader.NORMAL_GROUP_IS_OUTLINE_LABEL,
|
|
3535
|
+
self.is_outline_material,
|
|
3536
|
+
)
|
|
3537
|
+
self.set_bool(
|
|
3538
|
+
shader.OUTPUT_GROUP_NAME,
|
|
3539
|
+
shader.OUTPUT_GROUP_DOUBLE_SIDED_LABEL,
|
|
3540
|
+
False if self.is_outline_material else self.double_sided,
|
|
3541
|
+
)
|
|
3542
|
+
|
|
3543
|
+
is_outline_material: BoolProperty( # type: ignore[valid-type]
|
|
3544
|
+
update=_update_is_outline_material,
|
|
3545
|
+
)
|
|
3546
|
+
|
|
3547
|
+
outline_material: PointerProperty( # type: ignore[valid-type]
|
|
3548
|
+
type=Material,
|
|
3549
|
+
)
|
|
3550
|
+
|
|
3551
|
+
def uv_transformable_texture_info(self) -> list[Mtoon1TextureInfoPropertyGroup]:
|
|
3552
|
+
return [
|
|
3553
|
+
self.pbr_metallic_roughness.base_color_texture,
|
|
3554
|
+
self.normal_texture,
|
|
3555
|
+
self.emissive_texture,
|
|
3556
|
+
self.extensions.vrmc_materials_mtoon.shade_multiply_texture,
|
|
3557
|
+
self.extensions.vrmc_materials_mtoon.shading_shift_texture,
|
|
3558
|
+
self.extensions.vrmc_materials_mtoon.rim_multiply_texture,
|
|
3559
|
+
self.extensions.vrmc_materials_mtoon.uv_animation_mask_texture,
|
|
3560
|
+
]
|
|
3561
|
+
|
|
3562
|
+
def non_uv_transformable_texture_info(self) -> list[Mtoon1TextureInfoPropertyGroup]:
|
|
3563
|
+
return [
|
|
3564
|
+
self.extensions.vrmc_materials_mtoon.matcap_texture,
|
|
3565
|
+
self.extensions.vrmc_materials_mtoon.outline_width_multiply_texture,
|
|
3566
|
+
]
|
|
3567
|
+
|
|
3568
|
+
def all_texture_info(self) -> list[Mtoon1TextureInfoPropertyGroup]:
|
|
3569
|
+
return (
|
|
3570
|
+
self.uv_transformable_texture_info()
|
|
3571
|
+
+ self.non_uv_transformable_texture_info()
|
|
3572
|
+
)
|
|
3573
|
+
|
|
3574
|
+
def all_textures(
|
|
3575
|
+
self, *, downgrade_to_mtoon0: bool
|
|
3576
|
+
) -> list[Union[Mtoon0TexturePropertyGroup, Mtoon1TexturePropertyGroup]]:
|
|
3577
|
+
result: list[Union[Mtoon0TexturePropertyGroup, Mtoon1TexturePropertyGroup]] = []
|
|
3578
|
+
result.extend(
|
|
3579
|
+
[
|
|
3580
|
+
self.pbr_metallic_roughness.base_color_texture.index,
|
|
3581
|
+
self.extensions.vrmc_materials_mtoon.shade_multiply_texture.index,
|
|
3582
|
+
self.normal_texture.index,
|
|
3583
|
+
]
|
|
3584
|
+
)
|
|
3585
|
+
if downgrade_to_mtoon0:
|
|
3586
|
+
result.extend(
|
|
3587
|
+
[
|
|
3588
|
+
self.mtoon0_receive_shadow_texture,
|
|
3589
|
+
self.mtoon0_shading_grade_texture,
|
|
3590
|
+
]
|
|
3591
|
+
)
|
|
3592
|
+
result.append(self.emissive_texture.index)
|
|
3593
|
+
if not downgrade_to_mtoon0:
|
|
3594
|
+
result.append(
|
|
3595
|
+
self.extensions.vrmc_materials_mtoon.shading_shift_texture.index
|
|
3596
|
+
)
|
|
3597
|
+
result.extend(
|
|
3598
|
+
[
|
|
3599
|
+
self.extensions.vrmc_materials_mtoon.matcap_texture.index,
|
|
3600
|
+
self.extensions.vrmc_materials_mtoon.rim_multiply_texture.index,
|
|
3601
|
+
self.extensions.vrmc_materials_mtoon.outline_width_multiply_texture.index,
|
|
3602
|
+
self.extensions.vrmc_materials_mtoon.uv_animation_mask_texture.index,
|
|
3603
|
+
]
|
|
3604
|
+
)
|
|
3605
|
+
return result
|
|
3606
|
+
|
|
3607
|
+
show_expanded_mtoon0: BoolProperty( # type: ignore[valid-type]
|
|
3608
|
+
name="Show MToon 0.0 Options",
|
|
3609
|
+
)
|
|
3610
|
+
|
|
3611
|
+
mtoon0_front_cull_mode: BoolProperty( # type: ignore[valid-type]
|
|
3612
|
+
name="Front Face Culling",
|
|
3613
|
+
)
|
|
3614
|
+
|
|
3615
|
+
mtoon0_outline_scaled_max_distance: FloatProperty( # type: ignore[valid-type]
|
|
3616
|
+
name="Outline Width Scaled Max Distance",
|
|
3617
|
+
min=1,
|
|
3618
|
+
default=1,
|
|
3619
|
+
max=10,
|
|
3620
|
+
)
|
|
3621
|
+
|
|
3622
|
+
mtoon0_light_color_attenuation: FloatProperty( # type: ignore[valid-type]
|
|
3623
|
+
name="LightColor Attenuation",
|
|
3624
|
+
min=0,
|
|
3625
|
+
default=0,
|
|
3626
|
+
max=1,
|
|
3627
|
+
)
|
|
3628
|
+
|
|
3629
|
+
mtoon0_receive_shadow_texture: PointerProperty( # type: ignore[valid-type]
|
|
3630
|
+
type=Mtoon0ReceiveShadowTexturePropertyGroup
|
|
3631
|
+
)
|
|
3632
|
+
|
|
3633
|
+
mtoon0_receive_shadow_rate: FloatProperty( # type: ignore[valid-type]
|
|
3634
|
+
min=0,
|
|
3635
|
+
default=1,
|
|
3636
|
+
max=1,
|
|
3637
|
+
)
|
|
3638
|
+
|
|
3639
|
+
mtoon0_shading_grade_texture: PointerProperty( # type: ignore[valid-type]
|
|
3640
|
+
type=Mtoon0ShadingGradeTexturePropertyGroup
|
|
3641
|
+
)
|
|
3642
|
+
|
|
3643
|
+
mtoon0_shading_grade_rate: FloatProperty( # type: ignore[valid-type]
|
|
3644
|
+
min=0,
|
|
3645
|
+
default=1,
|
|
3646
|
+
max=1,
|
|
3647
|
+
)
|
|
3648
|
+
|
|
3649
|
+
mtoon0_rim_lighting_mix: FloatProperty( # type: ignore[valid-type]
|
|
3650
|
+
name="Rim LightingMix (MToon 0.0)",
|
|
3651
|
+
min=0,
|
|
3652
|
+
default=0,
|
|
3653
|
+
max=1,
|
|
3654
|
+
)
|
|
3655
|
+
|
|
3656
|
+
def _get_mtoon0_render_queue_and_clamp(self) -> int:
|
|
3657
|
+
return int(self.mtoon0_render_queue)
|
|
3658
|
+
|
|
3659
|
+
def _set_mtoon0_render_queue_and_clamp(self, value: int) -> None:
|
|
3660
|
+
# https://github.com/Santarh/MToon/blob/42b03163459ac8e6b7aee08070d0f4f912035069/MToon/Scripts/Utils.cs#L74-L113
|
|
3661
|
+
if self.alpha_mode == self.ALPHA_MODE_OPAQUE.identifier:
|
|
3662
|
+
mtoon0_render_queue = 2000
|
|
3663
|
+
elif self.alpha_mode == self.ALPHA_MODE_MASK.identifier:
|
|
3664
|
+
mtoon0_render_queue = 2450
|
|
3665
|
+
elif not self.extensions.vrmc_materials_mtoon.transparent_with_z_write:
|
|
3666
|
+
mtoon0_render_queue = max(2951, min(3000, value))
|
|
3667
|
+
else:
|
|
3668
|
+
mtoon0_render_queue = max(2501, min(2550, value))
|
|
3669
|
+
|
|
3670
|
+
if self.mtoon0_render_queue != mtoon0_render_queue:
|
|
3671
|
+
self.mtoon0_render_queue = mtoon0_render_queue
|
|
3672
|
+
|
|
3673
|
+
# Set the Render Queue value for MToon0. Performs clamping when assigning values.
|
|
3674
|
+
# UniVRM performs clamping when setting values from UI or when changing
|
|
3675
|
+
# Alpha Mode etc., so use this to match that behavior.
|
|
3676
|
+
mtoon0_render_queue_and_clamp: IntProperty( # type: ignore[valid-type]
|
|
3677
|
+
name="Render Queue",
|
|
3678
|
+
get=_get_mtoon0_render_queue_and_clamp,
|
|
3679
|
+
set=_set_mtoon0_render_queue_and_clamp,
|
|
3680
|
+
)
|
|
3681
|
+
|
|
3682
|
+
# Set the Render Queue value for MToon0. Does not perform clamping when
|
|
3683
|
+
# assigning values.
|
|
3684
|
+
# UniVRM does not perform clamping during VRM0 import or export,
|
|
3685
|
+
# so use this during import or export to match that behavior.
|
|
3686
|
+
mtoon0_render_queue: IntProperty( # type: ignore[valid-type]
|
|
3687
|
+
name="Render Queue",
|
|
3688
|
+
default=2000,
|
|
3689
|
+
)
|
|
3690
|
+
|
|
3691
|
+
def setup_drivers(self) -> None:
|
|
3692
|
+
material = self.find_material()
|
|
3693
|
+
for texture_info in self.all_texture_info():
|
|
3694
|
+
texture_info.setup_drivers(material)
|
|
3695
|
+
|
|
3696
|
+
if TYPE_CHECKING:
|
|
3697
|
+
# This code is auto generated.
|
|
3698
|
+
# To regenerate, run the `uv run tools/property_typing.py` command.
|
|
3699
|
+
addon_version: Sequence[int] # type: ignore[no-redef]
|
|
3700
|
+
pbr_metallic_roughness: ( # type: ignore[no-redef]
|
|
3701
|
+
Mtoon1PbrMetallicRoughnessPropertyGroup
|
|
3702
|
+
)
|
|
3703
|
+
alpha_mode_blend_method_hashed: bool # type: ignore[no-redef]
|
|
3704
|
+
alpha_mode: str # type: ignore[no-redef]
|
|
3705
|
+
double_sided: bool # type: ignore[no-redef]
|
|
3706
|
+
alpha_cutoff: float # type: ignore[no-redef]
|
|
3707
|
+
normal_texture: Mtoon1NormalTextureInfoPropertyGroup # type: ignore[no-redef]
|
|
3708
|
+
emissive_texture: ( # type: ignore[no-redef]
|
|
3709
|
+
Mtoon1EmissiveTextureInfoPropertyGroup
|
|
3710
|
+
)
|
|
3711
|
+
emissive_factor: Sequence[float] # type: ignore[no-redef]
|
|
3712
|
+
extensions: Mtoon1MaterialExtensionsPropertyGroup # type: ignore[no-redef]
|
|
3713
|
+
enabled: bool # type: ignore[no-redef]
|
|
3714
|
+
export_shape_key_normals: bool # type: ignore[no-redef]
|
|
3715
|
+
is_outline_material: bool # type: ignore[no-redef]
|
|
3716
|
+
outline_material: Optional[Material] # type: ignore[no-redef]
|
|
3717
|
+
show_expanded_mtoon0: bool # type: ignore[no-redef]
|
|
3718
|
+
mtoon0_front_cull_mode: bool # type: ignore[no-redef]
|
|
3719
|
+
mtoon0_outline_scaled_max_distance: float # type: ignore[no-redef]
|
|
3720
|
+
mtoon0_light_color_attenuation: float # type: ignore[no-redef]
|
|
3721
|
+
mtoon0_receive_shadow_texture: ( # type: ignore[no-redef]
|
|
3722
|
+
Mtoon0ReceiveShadowTexturePropertyGroup
|
|
3723
|
+
)
|
|
3724
|
+
mtoon0_receive_shadow_rate: float # type: ignore[no-redef]
|
|
3725
|
+
mtoon0_shading_grade_texture: ( # type: ignore[no-redef]
|
|
3726
|
+
Mtoon0ShadingGradeTexturePropertyGroup
|
|
3727
|
+
)
|
|
3728
|
+
mtoon0_shading_grade_rate: float # type: ignore[no-redef]
|
|
3729
|
+
mtoon0_rim_lighting_mix: float # type: ignore[no-redef]
|
|
3730
|
+
mtoon0_render_queue_and_clamp: int # type: ignore[no-redef]
|
|
3731
|
+
mtoon0_render_queue: int # type: ignore[no-redef]
|
|
3732
|
+
|
|
3733
|
+
|
|
3734
|
+
def reset_shader_node_group(
|
|
3735
|
+
context: Context,
|
|
3736
|
+
material: Material,
|
|
3737
|
+
*,
|
|
3738
|
+
reset_material_node_tree: bool,
|
|
3739
|
+
reset_node_groups: bool,
|
|
3740
|
+
) -> None:
|
|
3741
|
+
gltf = get_material_extension(material).mtoon1
|
|
3742
|
+
mtoon = gltf.extensions.vrmc_materials_mtoon
|
|
3743
|
+
|
|
3744
|
+
base_color_factor = list(gltf.pbr_metallic_roughness.base_color_factor)
|
|
3745
|
+
base_color_texture = gltf.pbr_metallic_roughness.base_color_texture.backup()
|
|
3746
|
+
alpha_mode_blend_method_hashed = gltf.alpha_mode_blend_method_hashed
|
|
3747
|
+
alpha_mode = gltf.alpha_mode
|
|
3748
|
+
double_sided = gltf.double_sided
|
|
3749
|
+
alpha_cutoff = gltf.alpha_cutoff
|
|
3750
|
+
normal_texture = gltf.normal_texture.backup()
|
|
3751
|
+
normal_texture_scale = gltf.normal_texture.scale
|
|
3752
|
+
emissive_texture = gltf.emissive_texture.backup()
|
|
3753
|
+
emissive_factor = list(gltf.emissive_factor)
|
|
3754
|
+
export_shape_key_normals = gltf.export_shape_key_normals
|
|
3755
|
+
emissive_strength = (
|
|
3756
|
+
gltf.extensions.khr_materials_emissive_strength.emissive_strength
|
|
3757
|
+
)
|
|
3758
|
+
|
|
3759
|
+
transparent_with_z_write = mtoon.transparent_with_z_write
|
|
3760
|
+
render_queue_offset_number = mtoon.render_queue_offset_number
|
|
3761
|
+
shade_multiply_texture = mtoon.shade_multiply_texture.backup()
|
|
3762
|
+
shade_color_factor = list(mtoon.shade_color_factor)
|
|
3763
|
+
shading_shift_texture = mtoon.shading_shift_texture.backup()
|
|
3764
|
+
shading_shift_texture_scale = mtoon.shading_shift_texture.scale
|
|
3765
|
+
shading_shift_factor = mtoon.shading_shift_factor
|
|
3766
|
+
shading_toony_factor = mtoon.shading_toony_factor
|
|
3767
|
+
gi_equalization_factor = mtoon.gi_equalization_factor
|
|
3768
|
+
matcap_factor = list(mtoon.matcap_factor)
|
|
3769
|
+
matcap_texture = mtoon.matcap_texture.backup()
|
|
3770
|
+
parametric_rim_color_factor = list(mtoon.parametric_rim_color_factor)
|
|
3771
|
+
rim_multiply_texture = mtoon.rim_multiply_texture.backup()
|
|
3772
|
+
rim_lighting_mix_factor = mtoon.rim_lighting_mix_factor
|
|
3773
|
+
parametric_rim_fresnel_power_factor = mtoon.parametric_rim_fresnel_power_factor
|
|
3774
|
+
parametric_rim_lift_factor = mtoon.parametric_rim_lift_factor
|
|
3775
|
+
enable_outline_preview = mtoon.enable_outline_preview
|
|
3776
|
+
outline_width_mode = mtoon.outline_width_mode
|
|
3777
|
+
outline_width_factor = mtoon.outline_width_factor
|
|
3778
|
+
outline_width_multiply_texture = mtoon.outline_width_multiply_texture.backup()
|
|
3779
|
+
outline_color_factor = list(mtoon.outline_color_factor)
|
|
3780
|
+
outline_lighting_mix_factor = mtoon.outline_lighting_mix_factor
|
|
3781
|
+
uv_animation_mask_texture = mtoon.uv_animation_mask_texture.backup()
|
|
3782
|
+
uv_animation_scroll_x_speed_factor = mtoon.uv_animation_scroll_x_speed_factor
|
|
3783
|
+
uv_animation_scroll_y_speed_factor = mtoon.uv_animation_scroll_y_speed_factor
|
|
3784
|
+
uv_animation_rotation_speed_factor = mtoon.uv_animation_rotation_speed_factor
|
|
3785
|
+
|
|
3786
|
+
if reset_material_node_tree:
|
|
3787
|
+
shader.load_mtoon1_shader(
|
|
3788
|
+
context,
|
|
3789
|
+
material,
|
|
3790
|
+
reset_node_groups=reset_node_groups,
|
|
3791
|
+
)
|
|
3792
|
+
outline_material = gltf.outline_material
|
|
3793
|
+
if outline_material:
|
|
3794
|
+
shader.load_mtoon1_shader(
|
|
3795
|
+
context,
|
|
3796
|
+
outline_material,
|
|
3797
|
+
reset_node_groups=reset_node_groups,
|
|
3798
|
+
)
|
|
3799
|
+
|
|
3800
|
+
gltf.is_outline_material = False
|
|
3801
|
+
outline_material = gltf.outline_material
|
|
3802
|
+
if outline_material:
|
|
3803
|
+
get_material_extension(outline_material).mtoon1.is_outline_material = True
|
|
3804
|
+
|
|
3805
|
+
gltf.pbr_metallic_roughness.base_color_factor = base_color_factor
|
|
3806
|
+
gltf.pbr_metallic_roughness.base_color_texture.restore(base_color_texture)
|
|
3807
|
+
gltf.alpha_mode_blend_method_hashed = alpha_mode_blend_method_hashed
|
|
3808
|
+
gltf.alpha_mode = alpha_mode
|
|
3809
|
+
gltf.double_sided = double_sided
|
|
3810
|
+
gltf.alpha_cutoff = alpha_cutoff
|
|
3811
|
+
gltf.normal_texture.restore(normal_texture)
|
|
3812
|
+
gltf.normal_texture.scale = normal_texture_scale
|
|
3813
|
+
gltf.emissive_texture.restore(emissive_texture)
|
|
3814
|
+
gltf.emissive_factor = emissive_factor
|
|
3815
|
+
gltf.export_shape_key_normals = export_shape_key_normals
|
|
3816
|
+
gltf.extensions.khr_materials_emissive_strength.emissive_strength = (
|
|
3817
|
+
emissive_strength
|
|
3818
|
+
)
|
|
3819
|
+
|
|
3820
|
+
mtoon.transparent_with_z_write = transparent_with_z_write
|
|
3821
|
+
mtoon.render_queue_offset_number = render_queue_offset_number
|
|
3822
|
+
mtoon.shade_multiply_texture.restore(shade_multiply_texture)
|
|
3823
|
+
mtoon.shade_color_factor = shade_color_factor
|
|
3824
|
+
mtoon.shading_shift_texture.restore(shading_shift_texture)
|
|
3825
|
+
mtoon.shading_shift_texture.scale = shading_shift_texture_scale
|
|
3826
|
+
mtoon.shading_shift_factor = shading_shift_factor
|
|
3827
|
+
mtoon.shading_toony_factor = shading_toony_factor
|
|
3828
|
+
mtoon.gi_equalization_factor = gi_equalization_factor
|
|
3829
|
+
mtoon.matcap_factor = matcap_factor
|
|
3830
|
+
mtoon.matcap_texture.restore(matcap_texture)
|
|
3831
|
+
mtoon.parametric_rim_color_factor = parametric_rim_color_factor
|
|
3832
|
+
mtoon.rim_multiply_texture.restore(rim_multiply_texture)
|
|
3833
|
+
mtoon.rim_lighting_mix_factor = rim_lighting_mix_factor
|
|
3834
|
+
mtoon.parametric_rim_fresnel_power_factor = parametric_rim_fresnel_power_factor
|
|
3835
|
+
mtoon.parametric_rim_lift_factor = parametric_rim_lift_factor
|
|
3836
|
+
mtoon.enable_outline_preview = enable_outline_preview
|
|
3837
|
+
mtoon.outline_width_mode = outline_width_mode
|
|
3838
|
+
mtoon.outline_width_factor = outline_width_factor
|
|
3839
|
+
mtoon.outline_width_multiply_texture.restore(outline_width_multiply_texture)
|
|
3840
|
+
mtoon.outline_color_factor = outline_color_factor
|
|
3841
|
+
mtoon.outline_lighting_mix_factor = outline_lighting_mix_factor
|
|
3842
|
+
mtoon.uv_animation_mask_texture.restore(uv_animation_mask_texture)
|
|
3843
|
+
mtoon.uv_animation_scroll_x_speed_factor = uv_animation_scroll_x_speed_factor
|
|
3844
|
+
mtoon.uv_animation_scroll_y_speed_factor = uv_animation_scroll_y_speed_factor
|
|
3845
|
+
mtoon.uv_animation_rotation_speed_factor = uv_animation_rotation_speed_factor
|
|
3846
|
+
|
|
3847
|
+
gltf.setup_drivers()
|
|
3848
|
+
gltf.addon_version = get_addon_version()
|
|
3849
|
+
|
|
3850
|
+
|
|
3851
|
+
@dataclass(frozen=True)
|
|
3852
|
+
class NodesModifierInputKey:
|
|
3853
|
+
material_key: str
|
|
3854
|
+
outline_material_key: str
|
|
3855
|
+
outline_width_mode_key: str
|
|
3856
|
+
outline_width_factor_key: str
|
|
3857
|
+
outline_width_multiply_texture_key: str
|
|
3858
|
+
outline_width_multiply_texture_exists_key: str
|
|
3859
|
+
outline_width_multiply_texture_uv_key: str
|
|
3860
|
+
outline_width_multiply_texture_uv_offset_x_key: str
|
|
3861
|
+
outline_width_multiply_texture_uv_offset_y_key: str
|
|
3862
|
+
outline_width_multiply_texture_uv_scale_x_key: str
|
|
3863
|
+
outline_width_multiply_texture_uv_scale_y_key: str
|
|
3864
|
+
extrude_mesh_individual_key: str
|
|
3865
|
+
object_key: str
|
|
3866
|
+
enabled_key: str
|
|
3867
|
+
|
|
3868
|
+
@property
|
|
3869
|
+
def outline_width_multiply_texture_uv_use_attribute_key(self) -> str:
|
|
3870
|
+
return self.outline_width_multiply_texture_uv_key + "_use_attribute"
|
|
3871
|
+
|
|
3872
|
+
@property
|
|
3873
|
+
def outline_width_multiply_texture_uv_attribute_name_key(self) -> str:
|
|
3874
|
+
return self.outline_width_multiply_texture_uv_key + "_attribute_name"
|
|
3875
|
+
|
|
3876
|
+
|
|
3877
|
+
def _get_nodes_modifier_input_key(
|
|
3878
|
+
node_group: NodeTree,
|
|
3879
|
+
) -> Optional[NodesModifierInputKey]:
|
|
3880
|
+
if bpy.app.version < (4, 0):
|
|
3881
|
+
keys = [i.identifier for i in node_group.inputs]
|
|
3882
|
+
else:
|
|
3883
|
+
from bpy.types import NodeTreeInterfaceSocket
|
|
3884
|
+
|
|
3885
|
+
keys = [
|
|
3886
|
+
item.identifier
|
|
3887
|
+
for item in node_group.interface.items_tree
|
|
3888
|
+
if item.item_type == "SOCKET"
|
|
3889
|
+
and isinstance(item, NodeTreeInterfaceSocket)
|
|
3890
|
+
and item.in_out == "INPUT"
|
|
3891
|
+
]
|
|
3892
|
+
|
|
3893
|
+
if len(keys) < 15:
|
|
3894
|
+
return None
|
|
3895
|
+
return NodesModifierInputKey(
|
|
3896
|
+
material_key=keys[1],
|
|
3897
|
+
outline_material_key=keys[2],
|
|
3898
|
+
outline_width_mode_key=keys[3],
|
|
3899
|
+
outline_width_factor_key=keys[4],
|
|
3900
|
+
outline_width_multiply_texture_key=keys[5],
|
|
3901
|
+
outline_width_multiply_texture_exists_key=keys[6],
|
|
3902
|
+
outline_width_multiply_texture_uv_key=keys[7],
|
|
3903
|
+
outline_width_multiply_texture_uv_offset_x_key=keys[8],
|
|
3904
|
+
outline_width_multiply_texture_uv_offset_y_key=keys[9],
|
|
3905
|
+
outline_width_multiply_texture_uv_scale_x_key=keys[10],
|
|
3906
|
+
outline_width_multiply_texture_uv_scale_y_key=keys[11],
|
|
3907
|
+
extrude_mesh_individual_key=keys[12],
|
|
3908
|
+
object_key=keys[13],
|
|
3909
|
+
enabled_key=keys[14],
|
|
3910
|
+
)
|
|
3911
|
+
|
|
3912
|
+
|
|
3913
|
+
class NodesModifierCustomProperties:
|
|
3914
|
+
def __init__(
|
|
3915
|
+
self, modifier: NodesModifier, input_key: NodesModifierInputKey
|
|
3916
|
+
) -> None:
|
|
3917
|
+
self.modifier = modifier
|
|
3918
|
+
self.input_key = input_key
|
|
3919
|
+
|
|
3920
|
+
def _set(self, key: str, value: object) -> bool:
|
|
3921
|
+
if self.modifier.get(key) == value:
|
|
3922
|
+
return False
|
|
3923
|
+
self.modifier[key] = value
|
|
3924
|
+
return True
|
|
3925
|
+
|
|
3926
|
+
def get_material(self) -> Optional[Material]:
|
|
3927
|
+
material = self.modifier.get(self.input_key.material_key)
|
|
3928
|
+
if material is None:
|
|
3929
|
+
return None
|
|
3930
|
+
if not isinstance(material, Material):
|
|
3931
|
+
_logger.error(
|
|
3932
|
+
"Expected Material for key: %s, modifier: %s, got: %s",
|
|
3933
|
+
self.input_key.material_key,
|
|
3934
|
+
self.modifier.name,
|
|
3935
|
+
type(material),
|
|
3936
|
+
)
|
|
3937
|
+
return None
|
|
3938
|
+
return material
|
|
3939
|
+
|
|
3940
|
+
def set_material(self, value: Material) -> bool:
|
|
3941
|
+
return self._set(self.input_key.material_key, value)
|
|
3942
|
+
|
|
3943
|
+
def set_outline_material(self, value: Material) -> bool:
|
|
3944
|
+
return self._set(self.input_key.outline_material_key, value)
|
|
3945
|
+
|
|
3946
|
+
def set_outline_width_mode(self, value: int) -> bool:
|
|
3947
|
+
return self._set(self.input_key.outline_width_mode_key, value)
|
|
3948
|
+
|
|
3949
|
+
def set_outline_width_factor(self, value: float) -> bool:
|
|
3950
|
+
return self._set(self.input_key.outline_width_factor_key, value)
|
|
3951
|
+
|
|
3952
|
+
def set_outline_width_multiply_texture(self, value: Optional[Image]) -> bool:
|
|
3953
|
+
return self._set(self.input_key.outline_width_multiply_texture_key, value)
|
|
3954
|
+
|
|
3955
|
+
def set_outline_width_multiply_texture_exists(self, *, value: bool) -> bool:
|
|
3956
|
+
return self._set(
|
|
3957
|
+
self.input_key.outline_width_multiply_texture_exists_key, value
|
|
3958
|
+
)
|
|
3959
|
+
|
|
3960
|
+
def set_outline_width_multiply_texture_uv_use_attribute(
|
|
3961
|
+
self, *, value: Union[bool, int]
|
|
3962
|
+
) -> bool:
|
|
3963
|
+
return self._set(
|
|
3964
|
+
self.input_key.outline_width_multiply_texture_uv_use_attribute_key, value
|
|
3965
|
+
)
|
|
3966
|
+
|
|
3967
|
+
def set_outline_width_multiply_texture_uv_attribute_name(self, value: str) -> bool:
|
|
3968
|
+
return self._set(
|
|
3969
|
+
self.input_key.outline_width_multiply_texture_uv_attribute_name_key, value
|
|
3970
|
+
)
|
|
3971
|
+
|
|
3972
|
+
def set_outline_width_multiply_texture_uv_offset_x(self, value: float) -> bool:
|
|
3973
|
+
return self._set(
|
|
3974
|
+
self.input_key.outline_width_multiply_texture_uv_offset_x_key, value
|
|
3975
|
+
)
|
|
3976
|
+
|
|
3977
|
+
def set_outline_width_multiply_texture_uv_offset_y(self, value: float) -> bool:
|
|
3978
|
+
return self._set(
|
|
3979
|
+
self.input_key.outline_width_multiply_texture_uv_offset_y_key, value
|
|
3980
|
+
)
|
|
3981
|
+
|
|
3982
|
+
def set_outline_width_multiply_texture_uv_scale_x(self, value: float) -> bool:
|
|
3983
|
+
return self._set(
|
|
3984
|
+
self.input_key.outline_width_multiply_texture_uv_scale_x_key, value
|
|
3985
|
+
)
|
|
3986
|
+
|
|
3987
|
+
def set_outline_width_multiply_texture_uv_scale_y(self, value: float) -> bool:
|
|
3988
|
+
return self._set(
|
|
3989
|
+
self.input_key.outline_width_multiply_texture_uv_scale_y_key, value
|
|
3990
|
+
)
|
|
3991
|
+
|
|
3992
|
+
def set_extrude_mesh_individual(self, *, value: bool) -> bool:
|
|
3993
|
+
return self._set(self.input_key.extrude_mesh_individual_key, value)
|
|
3994
|
+
|
|
3995
|
+
def set_object(self, value: Object) -> bool:
|
|
3996
|
+
return self._set(self.input_key.object_key, value)
|
|
3997
|
+
|
|
3998
|
+
def set_enabled(self, *, value: bool) -> bool:
|
|
3999
|
+
return self._set(self.input_key.enabled_key, value)
|
|
4000
|
+
|
|
4001
|
+
|
|
4002
|
+
class NodesModifierProperties:
|
|
4003
|
+
def __init__(
|
|
4004
|
+
self, modifier: NodesModifier, input_key: NodesModifierInputKey
|
|
4005
|
+
) -> None:
|
|
4006
|
+
self.modifier = modifier
|
|
4007
|
+
self.input_key = input_key
|
|
4008
|
+
|
|
4009
|
+
def _get(self, key: str, attr: str = "value") -> Optional[object]:
|
|
4010
|
+
socket = getattr(getattr(self.modifier.properties, "inputs", None), key, None)
|
|
4011
|
+
if not socket:
|
|
4012
|
+
_logger.error(
|
|
4013
|
+
"Socket not found for key: %s, modifier: %s", key, self.modifier.name
|
|
4014
|
+
)
|
|
4015
|
+
return None
|
|
4016
|
+
return getattr(socket, attr)
|
|
4017
|
+
|
|
4018
|
+
def _set(self, key: str, attr: str, value: object) -> bool:
|
|
4019
|
+
socket = getattr(getattr(self.modifier.properties, "inputs", None), key, None)
|
|
4020
|
+
if not socket:
|
|
4021
|
+
_logger.error(
|
|
4022
|
+
"Socket not found for key: %s, modifier: %s", key, self.modifier.name
|
|
4023
|
+
)
|
|
4024
|
+
return False
|
|
4025
|
+
if getattr(socket, attr) == value:
|
|
4026
|
+
return False
|
|
4027
|
+
setattr(socket, attr, value)
|
|
4028
|
+
return True
|
|
4029
|
+
|
|
4030
|
+
def _set_value(self, key: str, value: object) -> bool:
|
|
4031
|
+
changed = False
|
|
4032
|
+
changed |= self._set(key, "type", "VALUE")
|
|
4033
|
+
changed |= self._set(key, "value", value)
|
|
4034
|
+
return changed
|
|
4035
|
+
|
|
4036
|
+
def get_material(self) -> Optional[Material]:
|
|
4037
|
+
material = self._get(self.input_key.material_key)
|
|
4038
|
+
if material is None:
|
|
4039
|
+
return None
|
|
4040
|
+
if not isinstance(material, Material):
|
|
4041
|
+
_logger.error(
|
|
4042
|
+
"Expected Material for key: %s, modifier: %s, got: %s",
|
|
4043
|
+
self.input_key.material_key,
|
|
4044
|
+
self.modifier.name,
|
|
4045
|
+
type(material),
|
|
4046
|
+
)
|
|
4047
|
+
return None
|
|
4048
|
+
return material
|
|
4049
|
+
|
|
4050
|
+
def set_material(self, value: Material) -> bool:
|
|
4051
|
+
return self._set_value(self.input_key.material_key, value)
|
|
4052
|
+
|
|
4053
|
+
def set_outline_material(self, value: Material) -> bool:
|
|
4054
|
+
return self._set_value(self.input_key.outline_material_key, value)
|
|
4055
|
+
|
|
4056
|
+
def set_outline_width_mode(self, value: int) -> bool:
|
|
4057
|
+
return self._set_value(self.input_key.outline_width_mode_key, value)
|
|
4058
|
+
|
|
4059
|
+
def set_outline_width_factor(self, value: float) -> bool:
|
|
4060
|
+
return self._set_value(self.input_key.outline_width_factor_key, value)
|
|
4061
|
+
|
|
4062
|
+
def set_outline_width_multiply_texture(self, value: Optional[Image]) -> bool:
|
|
4063
|
+
return self._set_value(self.input_key.outline_width_multiply_texture_key, value)
|
|
4064
|
+
|
|
4065
|
+
def set_outline_width_multiply_texture_exists(self, *, value: bool) -> bool:
|
|
4066
|
+
return self._set_value(
|
|
4067
|
+
self.input_key.outline_width_multiply_texture_exists_key, value
|
|
4068
|
+
)
|
|
4069
|
+
|
|
4070
|
+
def set_outline_width_multiply_texture_uv_use_attribute(
|
|
4071
|
+
self, *, value: Union[bool, int]
|
|
4072
|
+
) -> bool:
|
|
4073
|
+
return self._set(
|
|
4074
|
+
self.input_key.outline_width_multiply_texture_uv_key,
|
|
4075
|
+
"type",
|
|
4076
|
+
"ATTRIBUTE" if value else "VALUE",
|
|
4077
|
+
)
|
|
4078
|
+
|
|
4079
|
+
def set_outline_width_multiply_texture_uv_attribute_name(self, value: str) -> bool:
|
|
4080
|
+
return self._set(
|
|
4081
|
+
self.input_key.outline_width_multiply_texture_uv_key,
|
|
4082
|
+
"attribute_name",
|
|
4083
|
+
value,
|
|
4084
|
+
)
|
|
4085
|
+
|
|
4086
|
+
def set_outline_width_multiply_texture_uv_offset_x(self, value: float) -> bool:
|
|
4087
|
+
return self._set_value(
|
|
4088
|
+
self.input_key.outline_width_multiply_texture_uv_offset_x_key, value
|
|
4089
|
+
)
|
|
4090
|
+
|
|
4091
|
+
def set_outline_width_multiply_texture_uv_offset_y(self, value: float) -> bool:
|
|
4092
|
+
return self._set_value(
|
|
4093
|
+
self.input_key.outline_width_multiply_texture_uv_offset_y_key, value
|
|
4094
|
+
)
|
|
4095
|
+
|
|
4096
|
+
def set_outline_width_multiply_texture_uv_scale_x(self, value: float) -> bool:
|
|
4097
|
+
return self._set_value(
|
|
4098
|
+
self.input_key.outline_width_multiply_texture_uv_scale_x_key, value
|
|
4099
|
+
)
|
|
4100
|
+
|
|
4101
|
+
def set_outline_width_multiply_texture_uv_scale_y(self, value: float) -> bool:
|
|
4102
|
+
return self._set_value(
|
|
4103
|
+
self.input_key.outline_width_multiply_texture_uv_scale_y_key, value
|
|
4104
|
+
)
|
|
4105
|
+
|
|
4106
|
+
def set_extrude_mesh_individual(self, *, value: bool) -> bool:
|
|
4107
|
+
return self._set_value(self.input_key.extrude_mesh_individual_key, value)
|
|
4108
|
+
|
|
4109
|
+
def set_object(self, value: Object) -> bool:
|
|
4110
|
+
return self._set_value(self.input_key.object_key, value)
|
|
4111
|
+
|
|
4112
|
+
def set_enabled(self, *, value: bool) -> bool:
|
|
4113
|
+
return self._set_value(self.input_key.enabled_key, value)
|
|
4114
|
+
|
|
4115
|
+
|
|
4116
|
+
class NodesModifierPropertiesProtocol(Protocol):
|
|
4117
|
+
def get_material(self) -> Optional[Material]: ...
|
|
4118
|
+
def set_material(self, value: Material) -> bool: ...
|
|
4119
|
+
def set_outline_material(self, value: Material) -> bool: ...
|
|
4120
|
+
def set_outline_width_mode(self, value: int) -> bool: ...
|
|
4121
|
+
def set_outline_width_factor(self, value: float) -> bool: ...
|
|
4122
|
+
def set_outline_width_multiply_texture(self, value: Optional[Image]) -> bool: ...
|
|
4123
|
+
def set_outline_width_multiply_texture_exists(self, *, value: bool) -> bool: ...
|
|
4124
|
+
def set_outline_width_multiply_texture_uv_use_attribute(
|
|
4125
|
+
self, *, value: Union[bool, int]
|
|
4126
|
+
) -> bool: ...
|
|
4127
|
+
def set_outline_width_multiply_texture_uv_attribute_name(
|
|
4128
|
+
self, value: str
|
|
4129
|
+
) -> bool: ...
|
|
4130
|
+
def set_outline_width_multiply_texture_uv_offset_x(self, value: float) -> bool: ...
|
|
4131
|
+
def set_outline_width_multiply_texture_uv_offset_y(self, value: float) -> bool: ...
|
|
4132
|
+
def set_outline_width_multiply_texture_uv_scale_x(self, value: float) -> bool: ...
|
|
4133
|
+
def set_outline_width_multiply_texture_uv_scale_y(self, value: float) -> bool: ...
|
|
4134
|
+
def set_extrude_mesh_individual(self, *, value: bool) -> bool: ...
|
|
4135
|
+
def set_object(self, value: Object) -> bool: ...
|
|
4136
|
+
def set_enabled(self, *, value: bool) -> bool: ...
|
|
4137
|
+
|
|
4138
|
+
|
|
4139
|
+
def _get_nodes_modifier_input_properties(
|
|
4140
|
+
modifier: NodesModifier,
|
|
4141
|
+
) -> Optional[NodesModifierPropertiesProtocol]:
|
|
4142
|
+
node_group = modifier.node_group
|
|
4143
|
+
if not node_group:
|
|
4144
|
+
return None
|
|
4145
|
+
|
|
4146
|
+
input_key = _get_nodes_modifier_input_key(node_group)
|
|
4147
|
+
if not input_key:
|
|
4148
|
+
return None
|
|
4149
|
+
|
|
4150
|
+
if bpy.app.version < (5, 2):
|
|
4151
|
+
return NodesModifierCustomProperties(modifier, input_key)
|
|
4152
|
+
|
|
4153
|
+
return NodesModifierProperties(modifier, input_key)
|
|
4154
|
+
|
|
4155
|
+
|
|
4156
|
+
def generate_mtoon1_outline_material_name(material: Material) -> str:
|
|
4157
|
+
return f"MToon Outline ({material.name})"
|
|
4158
|
+
|
|
4159
|
+
|
|
4160
|
+
def _assign_mtoon_unversioned_image(
|
|
4161
|
+
context: Context,
|
|
4162
|
+
texture_info: Mtoon1TextureInfoPropertyGroup,
|
|
4163
|
+
image_name_and_sampler_type: Optional[tuple[str, int, int]],
|
|
4164
|
+
uv_offset: tuple[float, float],
|
|
4165
|
+
uv_scale: tuple[float, float],
|
|
4166
|
+
) -> None:
|
|
4167
|
+
texture_info.extensions.khr_texture_transform.offset = uv_offset
|
|
4168
|
+
texture_info.extensions.khr_texture_transform.scale = uv_scale
|
|
4169
|
+
|
|
4170
|
+
if image_name_and_sampler_type is None:
|
|
4171
|
+
return
|
|
4172
|
+
|
|
4173
|
+
image_name, wrap_number, filter_number = image_name_and_sampler_type
|
|
4174
|
+
image = context.blend_data.images.get(image_name)
|
|
4175
|
+
if not image:
|
|
4176
|
+
return
|
|
4177
|
+
|
|
4178
|
+
texture_info.index.source = image
|
|
4179
|
+
|
|
4180
|
+
texture_info.index.sampler.mag_filter = (
|
|
4181
|
+
Mtoon1SamplerPropertyGroup.mag_filter_enum.value_to_identifier(
|
|
4182
|
+
filter_number, Mtoon1SamplerPropertyGroup.MAG_FILTER_DEFAULT.identifier
|
|
4183
|
+
)
|
|
4184
|
+
)
|
|
4185
|
+
texture_info.index.sampler.min_filter = (
|
|
4186
|
+
Mtoon1SamplerPropertyGroup.min_filter_enum.value_to_identifier(
|
|
4187
|
+
filter_number, Mtoon1SamplerPropertyGroup.MIN_FILTER_DEFAULT.identifier
|
|
4188
|
+
)
|
|
4189
|
+
)
|
|
4190
|
+
|
|
4191
|
+
wrap = Mtoon1SamplerPropertyGroup.wrap_enum.value_to_identifier(
|
|
4192
|
+
wrap_number, Mtoon1SamplerPropertyGroup.WRAP_DEFAULT.identifier
|
|
4193
|
+
)
|
|
4194
|
+
texture_info.index.sampler.wrap_s = wrap
|
|
4195
|
+
texture_info.index.sampler.wrap_t = wrap
|
|
4196
|
+
|
|
4197
|
+
|
|
4198
|
+
def _convert_mtoon_unversioned_to_mtoon1(
|
|
4199
|
+
context: Context,
|
|
4200
|
+
material: Material,
|
|
4201
|
+
node: ShaderNodeGroup,
|
|
4202
|
+
) -> None:
|
|
4203
|
+
transparent_with_z_write = False
|
|
4204
|
+
alpha_cutoff: Optional[float] = 0.5
|
|
4205
|
+
if material.blend_method == "OPAQUE":
|
|
4206
|
+
alpha_mode = Mtoon1MaterialPropertyGroup.ALPHA_MODE_OPAQUE.identifier
|
|
4207
|
+
elif material.blend_method == "CLIP":
|
|
4208
|
+
alpha_cutoff = shader.get_float_value(node, "CutoffRate", 0, sys.float_info.max)
|
|
4209
|
+
if alpha_cutoff is None:
|
|
4210
|
+
alpha_cutoff = 0.5
|
|
4211
|
+
alpha_mode = Mtoon1MaterialPropertyGroup.ALPHA_MODE_MASK.identifier
|
|
4212
|
+
else:
|
|
4213
|
+
alpha_mode = Mtoon1MaterialPropertyGroup.ALPHA_MODE_BLEND.identifier
|
|
4214
|
+
transparent_with_z_write_float = shader.get_float_value(
|
|
4215
|
+
node, "TransparentWithZWrite"
|
|
4216
|
+
)
|
|
4217
|
+
transparent_with_z_write = (
|
|
4218
|
+
transparent_with_z_write_float is not None
|
|
4219
|
+
and math.fabs(transparent_with_z_write_float) >= sys.float_info.epsilon
|
|
4220
|
+
)
|
|
4221
|
+
|
|
4222
|
+
base_color_factor = shader.get_rgba_value(node, "DiffuseColor", 0.0, 1.0) or (
|
|
4223
|
+
0,
|
|
4224
|
+
0,
|
|
4225
|
+
0,
|
|
4226
|
+
1,
|
|
4227
|
+
)
|
|
4228
|
+
base_color_texture = shader.get_image_name_and_sampler_type(node, "MainTexture")
|
|
4229
|
+
|
|
4230
|
+
uv_offset = (0.0, 0.0)
|
|
4231
|
+
uv_scale = (1.0, 1.0)
|
|
4232
|
+
|
|
4233
|
+
main_texture_input_socket = node.inputs.get("MainTexture")
|
|
4234
|
+
if (
|
|
4235
|
+
main_texture_input_socket
|
|
4236
|
+
and (
|
|
4237
|
+
tex_image_node := shader.search_input_node(
|
|
4238
|
+
main_texture_input_socket, ShaderNodeTexImage
|
|
4239
|
+
)
|
|
4240
|
+
)
|
|
4241
|
+
and (vector_input_socket := tex_image_node.inputs.get("Vector"))
|
|
4242
|
+
and (
|
|
4243
|
+
mapping_node := shader.search_input_node(
|
|
4244
|
+
vector_input_socket, ShaderNodeMapping
|
|
4245
|
+
)
|
|
4246
|
+
)
|
|
4247
|
+
):
|
|
4248
|
+
location_socket = mapping_node.inputs.get("Location")
|
|
4249
|
+
if location_socket and isinstance(
|
|
4250
|
+
location_socket, shader.VECTOR_SOCKET_CLASSES
|
|
4251
|
+
):
|
|
4252
|
+
uv_offset = (
|
|
4253
|
+
float(location_socket.default_value[0]),
|
|
4254
|
+
float(location_socket.default_value[1]),
|
|
4255
|
+
)
|
|
4256
|
+
|
|
4257
|
+
scale_socket = mapping_node.inputs.get("Scale")
|
|
4258
|
+
if scale_socket and isinstance(scale_socket, shader.VECTOR_SOCKET_CLASSES):
|
|
4259
|
+
uv_scale = (
|
|
4260
|
+
float(scale_socket.default_value[0]),
|
|
4261
|
+
float(scale_socket.default_value[1]),
|
|
4262
|
+
)
|
|
4263
|
+
|
|
4264
|
+
shade_color_factor = shader.get_rgb_value(node, "ShadeColor", 0.0, 1.0) or (
|
|
4265
|
+
0,
|
|
4266
|
+
0,
|
|
4267
|
+
0,
|
|
4268
|
+
)
|
|
4269
|
+
shade_multiply_texture = shader.get_image_name_and_sampler_type(
|
|
4270
|
+
node, "ShadeTexture"
|
|
4271
|
+
)
|
|
4272
|
+
normal_texture = shader.get_image_name_and_sampler_type(node, "NormalmapTexture")
|
|
4273
|
+
if not normal_texture:
|
|
4274
|
+
normal_texture = shader.get_image_name_and_sampler_type(node, "NomalmapTexture")
|
|
4275
|
+
normal_texture_scale = shader.get_float_value(node, "BumpScale")
|
|
4276
|
+
|
|
4277
|
+
shading_shift_0x = shader.get_float_value(node, "ShadeShift")
|
|
4278
|
+
if shading_shift_0x is None:
|
|
4279
|
+
shading_shift_0x = 0.0
|
|
4280
|
+
|
|
4281
|
+
shading_toony_0x = shader.get_float_value(node, "ShadeToony")
|
|
4282
|
+
if shading_toony_0x is None:
|
|
4283
|
+
shading_toony_0x = 0.0
|
|
4284
|
+
|
|
4285
|
+
shading_shift_factor = convert.mtoon_shading_shift_0_to_1(
|
|
4286
|
+
shading_toony_0x, shading_shift_0x
|
|
4287
|
+
)
|
|
4288
|
+
shading_toony_factor = convert.mtoon_shading_toony_0_to_1(
|
|
4289
|
+
shading_toony_0x, shading_shift_0x
|
|
4290
|
+
)
|
|
4291
|
+
|
|
4292
|
+
gi_equalization_0x = shader.get_float_value(node, "IndirectLightIntensity")
|
|
4293
|
+
gi_equalization_factor = None
|
|
4294
|
+
if gi_equalization_0x is not None:
|
|
4295
|
+
gi_equalization_factor = convert.mtoon_intensity_to_gi_equalization(
|
|
4296
|
+
gi_equalization_0x
|
|
4297
|
+
)
|
|
4298
|
+
|
|
4299
|
+
emissive_factor = shader.get_rgb_value(node, "EmissionColor", 0.0, 1.0) or (
|
|
4300
|
+
0,
|
|
4301
|
+
0,
|
|
4302
|
+
0,
|
|
4303
|
+
)
|
|
4304
|
+
emissive_texture = shader.get_image_name_and_sampler_type(node, "Emission_Texture")
|
|
4305
|
+
matcap_texture = shader.get_image_name_and_sampler_type(node, "SphereAddTexture")
|
|
4306
|
+
|
|
4307
|
+
parametric_rim_color_factor = shader.get_rgb_value(node, "RimColor", 0.0, 1.0)
|
|
4308
|
+
parametric_rim_fresnel_power_factor = shader.get_float_value(
|
|
4309
|
+
node, "RimFresnelPower", 0.0, sys.float_info.max
|
|
4310
|
+
)
|
|
4311
|
+
parametric_rim_lift_factor = shader.get_float_value(node, "RimLift")
|
|
4312
|
+
|
|
4313
|
+
rim_multiply_texture = shader.get_image_name_and_sampler_type(node, "RimTexture")
|
|
4314
|
+
|
|
4315
|
+
outline_width_mode_float = shader.get_float_value(node, "OutlineWidthMode")
|
|
4316
|
+
outline_width = shader.get_float_value(node, "OutlineWidth")
|
|
4317
|
+
if outline_width is None:
|
|
4318
|
+
outline_width = 0.0
|
|
4319
|
+
outline_width_multiply_texture = shader.get_image_name_and_sampler_type(
|
|
4320
|
+
node, "OutlineWidthTexture"
|
|
4321
|
+
)
|
|
4322
|
+
|
|
4323
|
+
outline_color_factor = shader.get_rgb_value(node, "OutlineColor", 0.0, 1.0) or (
|
|
4324
|
+
0,
|
|
4325
|
+
0,
|
|
4326
|
+
0,
|
|
4327
|
+
)
|
|
4328
|
+
|
|
4329
|
+
outline_color_mode = shader.get_float_value(node, "OutlineColorMode")
|
|
4330
|
+
if outline_color_mode is not None:
|
|
4331
|
+
outline_color_mode = round(outline_color_mode)
|
|
4332
|
+
else:
|
|
4333
|
+
outline_color_mode = 0
|
|
4334
|
+
|
|
4335
|
+
outline_lighting_mix_factor = 0.0
|
|
4336
|
+
if outline_color_mode == 1:
|
|
4337
|
+
outline_lighting_mix_factor = (
|
|
4338
|
+
shader.get_float_value(node, "OutlineLightingMix") or 1.0
|
|
4339
|
+
)
|
|
4340
|
+
|
|
4341
|
+
uv_animation_mask_texture = shader.get_image_name_and_sampler_type(
|
|
4342
|
+
node, "UV_Animation_Mask_Texture"
|
|
4343
|
+
)
|
|
4344
|
+
uv_animation_rotation_speed_factor = shader.get_float_value(
|
|
4345
|
+
node, "UV_Scroll_Rotation"
|
|
4346
|
+
)
|
|
4347
|
+
uv_animation_scroll_x_speed_factor = shader.get_float_value(node, "UV_Scroll_X")
|
|
4348
|
+
uv_animation_scroll_y_speed_factor = shader.get_float_value(node, "UV_Scroll_Y")
|
|
4349
|
+
if uv_animation_scroll_y_speed_factor is not None:
|
|
4350
|
+
uv_animation_scroll_y_speed_factor *= -1
|
|
4351
|
+
|
|
4352
|
+
shader.load_mtoon1_shader(context, material, reset_node_groups=True)
|
|
4353
|
+
|
|
4354
|
+
gltf = get_material_extension(material).mtoon1
|
|
4355
|
+
mtoon = gltf.extensions.vrmc_materials_mtoon
|
|
4356
|
+
|
|
4357
|
+
gltf.alpha_mode = alpha_mode
|
|
4358
|
+
gltf.alpha_cutoff = alpha_cutoff
|
|
4359
|
+
mtoon.transparent_with_z_write = transparent_with_z_write
|
|
4360
|
+
gltf.pbr_metallic_roughness.base_color_factor = base_color_factor
|
|
4361
|
+
_assign_mtoon_unversioned_image(
|
|
4362
|
+
context,
|
|
4363
|
+
gltf.pbr_metallic_roughness.base_color_texture,
|
|
4364
|
+
base_color_texture,
|
|
4365
|
+
uv_offset,
|
|
4366
|
+
uv_scale,
|
|
4367
|
+
)
|
|
4368
|
+
mtoon.shade_color_factor = shade_color_factor
|
|
4369
|
+
_assign_mtoon_unversioned_image(
|
|
4370
|
+
context,
|
|
4371
|
+
mtoon.shade_multiply_texture,
|
|
4372
|
+
shade_multiply_texture,
|
|
4373
|
+
uv_offset,
|
|
4374
|
+
uv_scale,
|
|
4375
|
+
)
|
|
4376
|
+
_assign_mtoon_unversioned_image(
|
|
4377
|
+
context, gltf.normal_texture, normal_texture, uv_offset, uv_scale
|
|
4378
|
+
)
|
|
4379
|
+
if normal_texture_scale is not None:
|
|
4380
|
+
gltf.normal_texture.scale = normal_texture_scale
|
|
4381
|
+
|
|
4382
|
+
mtoon.shading_shift_factor = shading_shift_factor
|
|
4383
|
+
mtoon.shading_toony_factor = shading_toony_factor
|
|
4384
|
+
|
|
4385
|
+
if gi_equalization_factor is not None:
|
|
4386
|
+
mtoon.gi_equalization_factor = gi_equalization_factor
|
|
4387
|
+
|
|
4388
|
+
gltf.emissive_factor = emissive_factor
|
|
4389
|
+
_assign_mtoon_unversioned_image(
|
|
4390
|
+
context, gltf.emissive_texture, emissive_texture, uv_offset, uv_scale
|
|
4391
|
+
)
|
|
4392
|
+
_assign_mtoon_unversioned_image(
|
|
4393
|
+
context, mtoon.matcap_texture, matcap_texture, (0, 0), (1, 1)
|
|
4394
|
+
)
|
|
4395
|
+
|
|
4396
|
+
if parametric_rim_color_factor is not None:
|
|
4397
|
+
mtoon.parametric_rim_color_factor = parametric_rim_color_factor
|
|
4398
|
+
if parametric_rim_fresnel_power_factor is not None:
|
|
4399
|
+
mtoon.parametric_rim_fresnel_power_factor = parametric_rim_fresnel_power_factor
|
|
4400
|
+
if parametric_rim_lift_factor is not None:
|
|
4401
|
+
mtoon.parametric_rim_lift_factor = parametric_rim_lift_factor
|
|
4402
|
+
|
|
4403
|
+
_assign_mtoon_unversioned_image(
|
|
4404
|
+
context, mtoon.rim_multiply_texture, rim_multiply_texture, uv_offset, uv_scale
|
|
4405
|
+
)
|
|
4406
|
+
|
|
4407
|
+
mtoon.rim_lighting_mix_factor = 1.0
|
|
4408
|
+
mtoon.enable_outline_preview = get_preferences(context).enable_mtoon_outline_preview
|
|
4409
|
+
|
|
4410
|
+
if outline_width_mode_float is not None:
|
|
4411
|
+
outline_width_mode = round(outline_width_mode_float)
|
|
4412
|
+
else:
|
|
4413
|
+
outline_width_mode = 0
|
|
4414
|
+
|
|
4415
|
+
if outline_width_mode == 1:
|
|
4416
|
+
mtoon.outline_width_mode = mtoon.OUTLINE_WIDTH_MODE_WORLD_COORDINATES.identifier
|
|
4417
|
+
mtoon.outline_width_factor = max(0.0, outline_width * 0.01)
|
|
4418
|
+
elif outline_width_mode == 2:
|
|
4419
|
+
mtoon.outline_width_mode = (
|
|
4420
|
+
mtoon.OUTLINE_WIDTH_MODE_SCREEN_COORDINATES.identifier
|
|
4421
|
+
)
|
|
4422
|
+
mtoon.outline_width_factor = max(0.0, outline_width * 0.01 * 0.5)
|
|
4423
|
+
else:
|
|
4424
|
+
mtoon.outline_width_mode = mtoon.OUTLINE_WIDTH_MODE_NONE.identifier
|
|
4425
|
+
|
|
4426
|
+
_assign_mtoon_unversioned_image(
|
|
4427
|
+
context,
|
|
4428
|
+
mtoon.outline_width_multiply_texture,
|
|
4429
|
+
outline_width_multiply_texture,
|
|
4430
|
+
uv_offset,
|
|
4431
|
+
uv_scale,
|
|
4432
|
+
)
|
|
4433
|
+
|
|
4434
|
+
mtoon.outline_color_factor = outline_color_factor
|
|
4435
|
+
mtoon.outline_lighting_mix_factor = 0.0
|
|
4436
|
+
if outline_color_mode == 1:
|
|
4437
|
+
mtoon.outline_lighting_mix_factor = outline_lighting_mix_factor
|
|
4438
|
+
|
|
4439
|
+
_assign_mtoon_unversioned_image(
|
|
4440
|
+
context,
|
|
4441
|
+
mtoon.uv_animation_mask_texture,
|
|
4442
|
+
uv_animation_mask_texture,
|
|
4443
|
+
uv_offset,
|
|
4444
|
+
uv_scale,
|
|
4445
|
+
)
|
|
4446
|
+
|
|
4447
|
+
if uv_animation_rotation_speed_factor is not None:
|
|
4448
|
+
mtoon.uv_animation_rotation_speed_factor = uv_animation_rotation_speed_factor
|
|
4449
|
+
if uv_animation_scroll_x_speed_factor is not None:
|
|
4450
|
+
mtoon.uv_animation_scroll_x_speed_factor = uv_animation_scroll_x_speed_factor
|
|
4451
|
+
if uv_animation_scroll_y_speed_factor is not None:
|
|
4452
|
+
mtoon.uv_animation_scroll_y_speed_factor = uv_animation_scroll_y_speed_factor
|
|
4453
|
+
|
|
4454
|
+
|
|
4455
|
+
def convert_material_to_mtoon1(
|
|
4456
|
+
material: Material, context: Optional[Context] = None
|
|
4457
|
+
) -> None:
|
|
4458
|
+
resolved_context = context or bpy.context
|
|
4459
|
+
|
|
4460
|
+
if (
|
|
4461
|
+
legacy_addon_material := LegacyAddonMaterial.try_parse(material)
|
|
4462
|
+
) and legacy_addon_material.shader_name == "MToon_unversioned":
|
|
4463
|
+
_convert_mtoon_unversioned_to_mtoon1(
|
|
4464
|
+
resolved_context, material, legacy_addon_material.shader_node_group
|
|
4465
|
+
)
|
|
4466
|
+
return
|
|
4467
|
+
|
|
4468
|
+
mmd_material = MmdMaterial.try_parse(material)
|
|
4469
|
+
if mmd_material:
|
|
4470
|
+
reset_shader_node_group(
|
|
4471
|
+
resolved_context,
|
|
4472
|
+
material,
|
|
4473
|
+
reset_material_node_tree=True,
|
|
4474
|
+
reset_node_groups=False,
|
|
4475
|
+
)
|
|
4476
|
+
|
|
4477
|
+
gltf = get_material_extension(material).mtoon1
|
|
4478
|
+
mtoon = gltf.extensions.vrmc_materials_mtoon
|
|
4479
|
+
if texture := mmd_material.texture:
|
|
4480
|
+
gltf.pbr_metallic_roughness.base_color_texture.index.source = texture
|
|
4481
|
+
mtoon.shade_multiply_texture.index.source = texture
|
|
4482
|
+
gltf.pbr_metallic_roughness.base_color_factor = (
|
|
4483
|
+
0,
|
|
4484
|
+
0,
|
|
4485
|
+
0,
|
|
4486
|
+
mmd_material.alpha,
|
|
4487
|
+
)
|
|
4488
|
+
else:
|
|
4489
|
+
gltf.pbr_metallic_roughness.base_color_factor = (
|
|
4490
|
+
mmd_material.diffuse_color[0],
|
|
4491
|
+
mmd_material.diffuse_color[1],
|
|
4492
|
+
mmd_material.diffuse_color[2],
|
|
4493
|
+
mmd_material.alpha,
|
|
4494
|
+
)
|
|
4495
|
+
gltf.double_sided = mmd_material.double_sided
|
|
4496
|
+
if mmd_material.alpha < 1.0:
|
|
4497
|
+
gltf.alpha_mode = Mtoon1MaterialPropertyGroup.ALPHA_MODE_BLEND.identifier
|
|
4498
|
+
return
|
|
4499
|
+
|
|
4500
|
+
principled_bsdf = PrincipledBSDFWrapper(material)
|
|
4501
|
+
if not principled_bsdf.node_principled_bsdf:
|
|
4502
|
+
reset_shader_node_group(
|
|
4503
|
+
resolved_context,
|
|
4504
|
+
material,
|
|
4505
|
+
reset_material_node_tree=True,
|
|
4506
|
+
reset_node_groups=False,
|
|
4507
|
+
)
|
|
4508
|
+
return
|
|
4509
|
+
|
|
4510
|
+
base_color_factor = (
|
|
4511
|
+
principled_bsdf.base_color[0],
|
|
4512
|
+
principled_bsdf.base_color[1],
|
|
4513
|
+
principled_bsdf.base_color[2],
|
|
4514
|
+
principled_bsdf.alpha,
|
|
4515
|
+
)
|
|
4516
|
+
base_color_texture_node = principled_bsdf.base_color_texture
|
|
4517
|
+
base_color_texture_image = (
|
|
4518
|
+
base_color_texture_node.image if base_color_texture_node else None
|
|
4519
|
+
)
|
|
4520
|
+
|
|
4521
|
+
emissive_factor = principled_bsdf.emission_color
|
|
4522
|
+
emission_color_texture_node = principled_bsdf.emission_color_texture
|
|
4523
|
+
emissive_texture_image = (
|
|
4524
|
+
emission_color_texture_node.image if emission_color_texture_node else None
|
|
4525
|
+
)
|
|
4526
|
+
emissive_strength = principled_bsdf.emission_strength
|
|
4527
|
+
|
|
4528
|
+
normalmap_texture_node = principled_bsdf.normalmap_texture
|
|
4529
|
+
if normalmap_texture_node:
|
|
4530
|
+
normal_texture_image = normalmap_texture_node.image
|
|
4531
|
+
normal_texture_scale = principled_bsdf.normalmap_strength
|
|
4532
|
+
else:
|
|
4533
|
+
normal_texture_image = None
|
|
4534
|
+
normal_texture_scale = None
|
|
4535
|
+
|
|
4536
|
+
reset_shader_node_group(
|
|
4537
|
+
resolved_context,
|
|
4538
|
+
material,
|
|
4539
|
+
reset_material_node_tree=True,
|
|
4540
|
+
reset_node_groups=False,
|
|
4541
|
+
)
|
|
4542
|
+
|
|
4543
|
+
gltf = get_material_extension(material).mtoon1
|
|
4544
|
+
gltf.pbr_metallic_roughness.base_color_factor = base_color_factor
|
|
4545
|
+
if base_color_texture_image:
|
|
4546
|
+
gltf.pbr_metallic_roughness.base_color_texture.index.source = (
|
|
4547
|
+
base_color_texture_image
|
|
4548
|
+
)
|
|
4549
|
+
|
|
4550
|
+
gltf.emissive_factor = emissive_factor
|
|
4551
|
+
gltf.extensions.khr_materials_emissive_strength.emissive_strength = (
|
|
4552
|
+
emissive_strength
|
|
4553
|
+
)
|
|
4554
|
+
if emissive_texture_image:
|
|
4555
|
+
gltf.emissive_texture.index.source = emissive_texture_image
|
|
4556
|
+
|
|
4557
|
+
if normal_texture_image:
|
|
4558
|
+
gltf.normal_texture.index.source = normal_texture_image
|
|
4559
|
+
if normal_texture_scale is not None:
|
|
4560
|
+
gltf.normal_texture.scale = normal_texture_scale
|
|
4561
|
+
|
|
4562
|
+
|
|
4563
|
+
def convert_mtoon1_to_bsdf_principled(material: Material) -> None:
|
|
4564
|
+
if bpy.app.version < (5, 0, 0) and not material.use_nodes:
|
|
4565
|
+
material.use_nodes = True
|
|
4566
|
+
shader.clear_node_tree(material.node_tree, clear_inputs_outputs=True)
|
|
4567
|
+
if not material.node_tree:
|
|
4568
|
+
_logger.error("%s's node tree is None", material.name)
|
|
4569
|
+
return
|
|
4570
|
+
|
|
4571
|
+
principled_bsdf = PrincipledBSDFWrapper(material, is_readonly=False)
|
|
4572
|
+
gltf = get_material_extension(material).mtoon1
|
|
4573
|
+
|
|
4574
|
+
principled_bsdf.base_color = gltf.pbr_metallic_roughness.base_color_factor[:3]
|
|
4575
|
+
base_color_texture_image = (
|
|
4576
|
+
gltf.pbr_metallic_roughness.base_color_texture.index.source
|
|
4577
|
+
)
|
|
4578
|
+
if base_color_texture_image:
|
|
4579
|
+
base_color_texture_node = principled_bsdf.base_color_texture
|
|
4580
|
+
if base_color_texture_node:
|
|
4581
|
+
base_color_texture_node.image = base_color_texture_image
|
|
4582
|
+
|
|
4583
|
+
principled_bsdf.alpha = gltf.pbr_metallic_roughness.base_color_factor[3]
|
|
4584
|
+
principled_bsdf.emission_color = list(gltf.emissive_factor)
|
|
4585
|
+
principled_bsdf.emission_strength = (
|
|
4586
|
+
gltf.extensions.khr_materials_emissive_strength.emissive_strength
|
|
4587
|
+
)
|
|
4588
|
+
emissive_texture_image = gltf.emissive_texture.index.source
|
|
4589
|
+
if emissive_texture_image:
|
|
4590
|
+
emission_color_texture_node = principled_bsdf.emission_color_texture
|
|
4591
|
+
if emission_color_texture_node:
|
|
4592
|
+
emission_color_texture_node.image = emissive_texture_image
|
|
4593
|
+
|
|
4594
|
+
normal_texture_image = gltf.normal_texture.index.source
|
|
4595
|
+
if normal_texture_image:
|
|
4596
|
+
normalmap_texture_node = principled_bsdf.normalmap_texture
|
|
4597
|
+
if normalmap_texture_node:
|
|
4598
|
+
normalmap_texture_node.image = normal_texture_image
|
|
4599
|
+
normal_scale = gltf.normal_texture.scale
|
|
4600
|
+
if abs(normal_scale - 1) >= sys.float_info.epsilon:
|
|
4601
|
+
principled_bsdf.normalmap_strength = gltf.normal_texture.scale
|
|
4602
|
+
|
|
4603
|
+
|
|
4604
|
+
def _assign_mtoon1_outline(
|
|
4605
|
+
context: Context,
|
|
4606
|
+
material: Material,
|
|
4607
|
+
obj: Object,
|
|
4608
|
+
*,
|
|
4609
|
+
create_modifier: bool,
|
|
4610
|
+
) -> None:
|
|
4611
|
+
shader.load_mtoon1_outline_geometry_node_group(context, reset_node_groups=False)
|
|
4612
|
+
node_group = context.blend_data.node_groups.get(shader.OUTLINE_GEOMETRY_GROUP_NAME)
|
|
4613
|
+
if not node_group:
|
|
4614
|
+
return
|
|
4615
|
+
if not _get_nodes_modifier_input_key(node_group):
|
|
4616
|
+
return
|
|
4617
|
+
mtoon = get_material_extension(material).mtoon1.extensions.vrmc_materials_mtoon
|
|
4618
|
+
outline_width_mode_value = mtoon.outline_width_mode_enum.identifier_to_value(
|
|
4619
|
+
mtoon.outline_width_mode,
|
|
4620
|
+
mtoon.OUTLINE_WIDTH_MODE_NONE.value,
|
|
4621
|
+
)
|
|
4622
|
+
no_outline = (
|
|
4623
|
+
not mtoon.enable_outline_preview
|
|
4624
|
+
or outline_width_mode_value == mtoon.OUTLINE_WIDTH_MODE_NONE.value
|
|
4625
|
+
or mtoon.outline_width_factor < sys.float_info.epsilon
|
|
4626
|
+
)
|
|
4627
|
+
cleanup = no_outline
|
|
4628
|
+
modifier = None
|
|
4629
|
+
|
|
4630
|
+
for search_modifier_name in list(obj.modifiers.keys()):
|
|
4631
|
+
search_modifier = obj.modifiers.get(search_modifier_name)
|
|
4632
|
+
if not search_modifier:
|
|
4633
|
+
continue
|
|
4634
|
+
if search_modifier.type != "NODES":
|
|
4635
|
+
continue
|
|
4636
|
+
if not isinstance(search_modifier, NodesModifier):
|
|
4637
|
+
continue
|
|
4638
|
+
if not search_modifier.node_group:
|
|
4639
|
+
continue
|
|
4640
|
+
if search_modifier.node_group.name != shader.OUTLINE_GEOMETRY_GROUP_NAME:
|
|
4641
|
+
continue
|
|
4642
|
+
input_properties = _get_nodes_modifier_input_properties(search_modifier)
|
|
4643
|
+
if input_properties is None:
|
|
4644
|
+
continue
|
|
4645
|
+
search_material = input_properties.get_material()
|
|
4646
|
+
if search_material is None:
|
|
4647
|
+
continue
|
|
4648
|
+
if search_material.name != material.name:
|
|
4649
|
+
continue
|
|
4650
|
+
if cleanup:
|
|
4651
|
+
obj.modifiers.remove(search_modifier)
|
|
4652
|
+
continue
|
|
4653
|
+
modifier = search_modifier
|
|
4654
|
+
cleanup = True
|
|
4655
|
+
|
|
4656
|
+
if no_outline:
|
|
4657
|
+
return
|
|
4658
|
+
|
|
4659
|
+
if not modifier and not create_modifier:
|
|
4660
|
+
mtoon.outline_width_mode = mtoon.OUTLINE_WIDTH_MODE_NONE.identifier
|
|
4661
|
+
return
|
|
4662
|
+
|
|
4663
|
+
outline_material_name = generate_mtoon1_outline_material_name(material)
|
|
4664
|
+
modifier_name = f"MToon Outline ({material.name})"
|
|
4665
|
+
|
|
4666
|
+
outline_material = get_material_extension(material).mtoon1.outline_material
|
|
4667
|
+
reset_outline_material = False
|
|
4668
|
+
if not outline_material:
|
|
4669
|
+
reset_outline_material = True
|
|
4670
|
+
outline_material = context.blend_data.materials.new(name=outline_material_name)
|
|
4671
|
+
if bpy.app.version < (5, 0, 0) and not outline_material.use_nodes:
|
|
4672
|
+
outline_material.use_nodes = True
|
|
4673
|
+
if outline_material.diffuse_color[3] != 0.25:
|
|
4674
|
+
outline_material.diffuse_color[3] = 0.25
|
|
4675
|
+
if outline_material.roughness != 0:
|
|
4676
|
+
outline_material.roughness = 0
|
|
4677
|
+
shader.load_mtoon1_shader(context, outline_material, reset_node_groups=False)
|
|
4678
|
+
get_material_extension(outline_material).mtoon1.is_outline_material = True
|
|
4679
|
+
get_material_extension(material).mtoon1.outline_material = outline_material
|
|
4680
|
+
if outline_material.name != outline_material_name:
|
|
4681
|
+
outline_material.name = outline_material_name
|
|
4682
|
+
if bpy.app.version < (5, 0, 0) and not outline_material.use_nodes:
|
|
4683
|
+
outline_material.use_nodes = True
|
|
4684
|
+
if not get_material_extension(outline_material).mtoon1.is_outline_material:
|
|
4685
|
+
get_material_extension(outline_material).mtoon1.is_outline_material = True
|
|
4686
|
+
if (
|
|
4687
|
+
get_material_extension(outline_material).mtoon1.alpha_cutoff
|
|
4688
|
+
!= get_material_extension(material).mtoon1.alpha_cutoff
|
|
4689
|
+
):
|
|
4690
|
+
get_material_extension(
|
|
4691
|
+
outline_material
|
|
4692
|
+
).mtoon1.alpha_cutoff = get_material_extension(material).mtoon1.alpha_cutoff
|
|
4693
|
+
if (
|
|
4694
|
+
get_material_extension(outline_material).mtoon1.alpha_mode
|
|
4695
|
+
!= get_material_extension(material).mtoon1.alpha_mode
|
|
4696
|
+
):
|
|
4697
|
+
get_material_extension(
|
|
4698
|
+
outline_material
|
|
4699
|
+
).mtoon1.alpha_mode = get_material_extension(material).mtoon1.alpha_mode
|
|
4700
|
+
if bpy.app.version < (4, 3) and outline_material.shadow_method != "NONE":
|
|
4701
|
+
outline_material.shadow_method = "NONE"
|
|
4702
|
+
if not outline_material.use_backface_culling:
|
|
4703
|
+
outline_material.use_backface_culling = True
|
|
4704
|
+
if outline_material.show_transparent_back:
|
|
4705
|
+
outline_material.show_transparent_back = False
|
|
4706
|
+
|
|
4707
|
+
if not modifier:
|
|
4708
|
+
new_modifier = obj.modifiers.new(modifier_name, "NODES")
|
|
4709
|
+
if not isinstance(new_modifier, NodesModifier):
|
|
4710
|
+
message = f"{type(new_modifier)} is not a NodesModifier"
|
|
4711
|
+
raise AssertionError(message)
|
|
4712
|
+
modifier = new_modifier
|
|
4713
|
+
modifier.show_expanded = False
|
|
4714
|
+
modifier.show_in_editmode = False
|
|
4715
|
+
if bpy.app.version >= (4, 0):
|
|
4716
|
+
modifier.show_group_selector = False
|
|
4717
|
+
if bpy.app.version >= (4, 2):
|
|
4718
|
+
modifier.use_pin_to_last = True
|
|
4719
|
+
if bpy.app.version >= (5, 0):
|
|
4720
|
+
modifier.show_manage_panel = False
|
|
4721
|
+
|
|
4722
|
+
if modifier.name != modifier_name:
|
|
4723
|
+
modifier.name = modifier_name
|
|
4724
|
+
if modifier.node_group != node_group:
|
|
4725
|
+
modifier.node_group = node_group
|
|
4726
|
+
|
|
4727
|
+
input_properties = _get_nodes_modifier_input_properties(modifier)
|
|
4728
|
+
if input_properties is None:
|
|
4729
|
+
return
|
|
4730
|
+
|
|
4731
|
+
(
|
|
4732
|
+
outline_width_multiply_texture_uv_offset_x,
|
|
4733
|
+
outline_width_multiply_texture_uv_offset_y,
|
|
4734
|
+
) = mtoon.outline_width_multiply_texture.extensions.khr_texture_transform.offset
|
|
4735
|
+
(
|
|
4736
|
+
outline_width_multiply_texture_uv_scale_x,
|
|
4737
|
+
outline_width_multiply_texture_uv_scale_y,
|
|
4738
|
+
) = mtoon.outline_width_multiply_texture.extensions.khr_texture_transform.scale
|
|
4739
|
+
|
|
4740
|
+
uv_layer_name = None
|
|
4741
|
+
if isinstance((mesh_data := obj.data), Mesh):
|
|
4742
|
+
uv_layer_name = next(
|
|
4743
|
+
(
|
|
4744
|
+
uv_layer.name
|
|
4745
|
+
for uv_layer in mesh_data.uv_layers
|
|
4746
|
+
if uv_layer and uv_layer.active_render
|
|
4747
|
+
),
|
|
4748
|
+
None,
|
|
4749
|
+
)
|
|
4750
|
+
if uv_layer_name is None:
|
|
4751
|
+
uv_layer_name = "UVMap"
|
|
4752
|
+
|
|
4753
|
+
has_auto_smooth = tuple(bpy.app.version) < (4, 1)
|
|
4754
|
+
outline_width_multiply_texture_uv_use_attribute = (
|
|
4755
|
+
True if tuple(bpy.app.version) >= (4, 2) else 1
|
|
4756
|
+
)
|
|
4757
|
+
|
|
4758
|
+
modifier_input_changed = False
|
|
4759
|
+
modifier_input_changed |= input_properties.set_material(material)
|
|
4760
|
+
modifier_input_changed |= input_properties.set_outline_material(outline_material)
|
|
4761
|
+
modifier_input_changed |= input_properties.set_outline_width_mode(
|
|
4762
|
+
outline_width_mode_value
|
|
4763
|
+
)
|
|
4764
|
+
modifier_input_changed |= input_properties.set_outline_width_factor(
|
|
4765
|
+
mtoon.outline_width_factor
|
|
4766
|
+
)
|
|
4767
|
+
modifier_input_changed |= input_properties.set_outline_width_multiply_texture(
|
|
4768
|
+
mtoon.outline_width_multiply_texture.index.source
|
|
4769
|
+
)
|
|
4770
|
+
modifier_input_changed |= (
|
|
4771
|
+
input_properties.set_outline_width_multiply_texture_exists(
|
|
4772
|
+
value=bool(mtoon.outline_width_multiply_texture.index.source)
|
|
4773
|
+
)
|
|
4774
|
+
)
|
|
4775
|
+
modifier_input_changed |= (
|
|
4776
|
+
input_properties.set_outline_width_multiply_texture_uv_use_attribute(
|
|
4777
|
+
value=outline_width_multiply_texture_uv_use_attribute
|
|
4778
|
+
)
|
|
4779
|
+
)
|
|
4780
|
+
modifier_input_changed |= (
|
|
4781
|
+
input_properties.set_outline_width_multiply_texture_uv_attribute_name(
|
|
4782
|
+
uv_layer_name
|
|
4783
|
+
)
|
|
4784
|
+
)
|
|
4785
|
+
modifier_input_changed |= (
|
|
4786
|
+
input_properties.set_outline_width_multiply_texture_uv_offset_x(
|
|
4787
|
+
outline_width_multiply_texture_uv_offset_x
|
|
4788
|
+
)
|
|
4789
|
+
)
|
|
4790
|
+
modifier_input_changed |= (
|
|
4791
|
+
input_properties.set_outline_width_multiply_texture_uv_offset_y(
|
|
4792
|
+
outline_width_multiply_texture_uv_offset_y
|
|
4793
|
+
)
|
|
4794
|
+
)
|
|
4795
|
+
modifier_input_changed |= (
|
|
4796
|
+
input_properties.set_outline_width_multiply_texture_uv_scale_x(
|
|
4797
|
+
outline_width_multiply_texture_uv_scale_x
|
|
4798
|
+
)
|
|
4799
|
+
)
|
|
4800
|
+
modifier_input_changed |= (
|
|
4801
|
+
input_properties.set_outline_width_multiply_texture_uv_scale_y(
|
|
4802
|
+
outline_width_multiply_texture_uv_scale_y
|
|
4803
|
+
)
|
|
4804
|
+
)
|
|
4805
|
+
modifier_input_changed |= input_properties.set_extrude_mesh_individual(
|
|
4806
|
+
value=obj.type == "MESH"
|
|
4807
|
+
and isinstance(mesh_data := obj.data, Mesh)
|
|
4808
|
+
and not (has_auto_smooth and mesh_data.use_auto_smooth)
|
|
4809
|
+
and not any(polygon.use_smooth for polygon in mesh_data.polygons)
|
|
4810
|
+
)
|
|
4811
|
+
modifier_input_changed |= input_properties.set_object(obj)
|
|
4812
|
+
modifier_input_changed |= input_properties.set_enabled(
|
|
4813
|
+
value=obj.mode
|
|
4814
|
+
not in {"VERTEX_PAINT", "TEXTURE_PAINT", "WEIGHT_PAINT", "SCULPT"}
|
|
4815
|
+
)
|
|
4816
|
+
|
|
4817
|
+
if modifier_input_changed:
|
|
4818
|
+
modifier.show_viewport = not modifier.show_viewport
|
|
4819
|
+
modifier.show_viewport = not modifier.show_viewport
|
|
4820
|
+
|
|
4821
|
+
if reset_outline_material:
|
|
4822
|
+
reset_shader_node_group(
|
|
4823
|
+
context,
|
|
4824
|
+
material,
|
|
4825
|
+
reset_material_node_tree=False,
|
|
4826
|
+
reset_node_groups=False,
|
|
4827
|
+
)
|
|
4828
|
+
|
|
4829
|
+
|
|
4830
|
+
def refresh_mtoon1_outline_object(context: Context, obj: Object) -> None:
|
|
4831
|
+
if bpy.app.version < (3, 3):
|
|
4832
|
+
return
|
|
4833
|
+
for material_slot in obj.material_slots:
|
|
4834
|
+
material_ref = material_slot.material
|
|
4835
|
+
if not material_ref:
|
|
4836
|
+
continue
|
|
4837
|
+
|
|
4838
|
+
material = context.blend_data.materials.get(material_ref.name)
|
|
4839
|
+
if not material:
|
|
4840
|
+
continue
|
|
4841
|
+
|
|
4842
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
4843
|
+
if not mtoon1.enabled or mtoon1.is_outline_material:
|
|
4844
|
+
continue
|
|
4845
|
+
|
|
4846
|
+
_assign_mtoon1_outline(context, material, obj, create_modifier=False)
|
|
4847
|
+
|
|
4848
|
+
|
|
4849
|
+
def refresh_mtoon1_outline(
|
|
4850
|
+
context: Optional[Context] = None,
|
|
4851
|
+
material_name: Optional[str] = None,
|
|
4852
|
+
*,
|
|
4853
|
+
create_modifier: bool,
|
|
4854
|
+
) -> None:
|
|
4855
|
+
resolved_context = context or bpy.context
|
|
4856
|
+
if bpy.app.version < (3, 3):
|
|
4857
|
+
return
|
|
4858
|
+
for obj in resolved_context.blend_data.objects:
|
|
4859
|
+
if obj.type != "MESH":
|
|
4860
|
+
continue
|
|
4861
|
+
outline_material_names: list[str] = []
|
|
4862
|
+
for material_slot in obj.material_slots:
|
|
4863
|
+
material_ref = material_slot.material
|
|
4864
|
+
if not material_ref:
|
|
4865
|
+
continue
|
|
4866
|
+
|
|
4867
|
+
if material_name is not None and material_name != material_ref.name:
|
|
4868
|
+
continue
|
|
4869
|
+
|
|
4870
|
+
material = resolved_context.blend_data.materials.get(material_ref.name)
|
|
4871
|
+
if not material:
|
|
4872
|
+
continue
|
|
4873
|
+
|
|
4874
|
+
mtoon1 = get_material_extension(material).mtoon1
|
|
4875
|
+
if not mtoon1.enabled or mtoon1.is_outline_material:
|
|
4876
|
+
continue
|
|
4877
|
+
|
|
4878
|
+
_assign_mtoon1_outline(
|
|
4879
|
+
resolved_context,
|
|
4880
|
+
material,
|
|
4881
|
+
obj,
|
|
4882
|
+
create_modifier=create_modifier,
|
|
4883
|
+
)
|
|
4884
|
+
outline_material_names.append(material.name)
|
|
4885
|
+
if material_name is not None:
|
|
4886
|
+
continue
|
|
4887
|
+
|
|
4888
|
+
for search_modifier_name in list(obj.modifiers.keys()):
|
|
4889
|
+
search_modifier = obj.modifiers.get(search_modifier_name)
|
|
4890
|
+
if not search_modifier:
|
|
4891
|
+
continue
|
|
4892
|
+
if search_modifier.type != "NODES":
|
|
4893
|
+
continue
|
|
4894
|
+
if not isinstance(search_modifier, NodesModifier):
|
|
4895
|
+
continue
|
|
4896
|
+
node_group = search_modifier.node_group
|
|
4897
|
+
if not node_group:
|
|
4898
|
+
continue
|
|
4899
|
+
if node_group.name != shader.OUTLINE_GEOMETRY_GROUP_NAME:
|
|
4900
|
+
continue
|
|
4901
|
+
input_properties = _get_nodes_modifier_input_properties(search_modifier)
|
|
4902
|
+
if input_properties is None:
|
|
4903
|
+
continue
|
|
4904
|
+
search_material = input_properties.get_material()
|
|
4905
|
+
if (
|
|
4906
|
+
search_material is not None
|
|
4907
|
+
and search_material.name in outline_material_names
|
|
4908
|
+
):
|
|
4909
|
+
continue
|
|
4910
|
+
obj.modifiers.remove(search_modifier)
|
|
4911
|
+
|
|
4912
|
+
|
|
4913
|
+
def setup_drivers(context: Context) -> None:
|
|
4914
|
+
for material in context.blend_data.materials:
|
|
4915
|
+
get_material_extension(material).mtoon1.setup_drivers()
|
|
4916
|
+
shader.setup_frame_count_driver(context)
|
|
4917
|
+
|
|
4918
|
+
|
|
4919
|
+
def link_or_unlink_gltf_material_nodes(
|
|
4920
|
+
context: Context, material: Material, *, link: bool
|
|
4921
|
+
) -> None:
|
|
4922
|
+
TextureTraceablePropertyGroup.link_or_unlink_nodes(
|
|
4923
|
+
material,
|
|
4924
|
+
"Mtoon1Material.CompatibleShader",
|
|
4925
|
+
ShaderNodeBsdfPrincipled,
|
|
4926
|
+
"BSDF",
|
|
4927
|
+
StaticNodeSocketTarget(
|
|
4928
|
+
in_node_name="Mtoon1Material.CompatibleMaterialOutput",
|
|
4929
|
+
in_node_type=ShaderNodeOutputMaterial,
|
|
4930
|
+
in_socket_name="Surface",
|
|
4931
|
+
),
|
|
4932
|
+
link=link,
|
|
4933
|
+
)
|
|
4934
|
+
|
|
4935
|
+
output_group = context.blend_data.node_groups.get(shader.OUTPUT_GROUP_NAME)
|
|
4936
|
+
if output_group is None:
|
|
4937
|
+
return
|
|
4938
|
+
|
|
4939
|
+
for from_node_name, to_node_name in (
|
|
4940
|
+
(
|
|
4941
|
+
"EeveeMaterialOutputSwitch",
|
|
4942
|
+
"EeveeMaterialOutput",
|
|
4943
|
+
),
|
|
4944
|
+
(
|
|
4945
|
+
"CyclesMaterialOutputSwitch",
|
|
4946
|
+
"CyclesMaterialOutput",
|
|
4947
|
+
),
|
|
4948
|
+
):
|
|
4949
|
+
from_node = output_group.nodes.get(from_node_name)
|
|
4950
|
+
if not from_node or not isinstance(from_node, NodeReroute):
|
|
4951
|
+
continue
|
|
4952
|
+
from_socket = from_node.outputs[0]
|
|
4953
|
+
|
|
4954
|
+
to_node = output_group.nodes.get(to_node_name)
|
|
4955
|
+
if not to_node or not isinstance(to_node, ShaderNodeOutputMaterial):
|
|
4956
|
+
continue
|
|
4957
|
+
to_socket = to_node.inputs["Surface"]
|
|
4958
|
+
|
|
4959
|
+
existing_link = next(
|
|
4960
|
+
(
|
|
4961
|
+
link
|
|
4962
|
+
for link in output_group.links
|
|
4963
|
+
if link.from_node == from_node
|
|
4964
|
+
and link.from_socket == from_socket
|
|
4965
|
+
and link.to_node == to_node
|
|
4966
|
+
and link.to_socket == to_socket
|
|
4967
|
+
),
|
|
4968
|
+
None,
|
|
4969
|
+
)
|
|
4970
|
+
if existing_link:
|
|
4971
|
+
if not link:
|
|
4972
|
+
output_group.links.remove(existing_link)
|
|
4973
|
+
elif link:
|
|
4974
|
+
output_group.links.new(
|
|
4975
|
+
from_socket,
|
|
4976
|
+
to_socket,
|
|
4977
|
+
)
|