-
Notifications
You must be signed in to change notification settings - Fork 141
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: material.blend_method migration for EEVEE-Next
- Loading branch information
1 parent
11830c4
commit 41dca77
Showing
4 changed files
with
122 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
import ctypes | ||
import sysconfig | ||
from collections.abc import Mapping | ||
from platform import python_implementation | ||
from typing import Optional | ||
|
||
import bpy | ||
from bpy.types import Material | ||
|
||
from .logging import get_logger | ||
|
||
logger = get_logger(__name__) | ||
|
||
|
||
def read_blend_method_from_memory_address(material: Material) -> Optional[str]: | ||
"""material.blend_methodの値を直接メモリから読み取る. | ||
Blender 4.2からmaterial.blend_methodの値が廃止されて読めなくなった。 | ||
しかし、マテリアルのマイグレーションのためにはどうしてもその値を知る必要がある。 | ||
仕方がないので既知のプラットフォームに限定してメモリから直接値を読む。 | ||
ログは多めに出す。 | ||
""" | ||
if bpy.app.version < (4, 2): | ||
return material.blend_method | ||
|
||
if bpy.app.build_type != b"Release": | ||
logger.warning( | ||
f"Does not read the Blend Mode of {material.name}. " | ||
+ f'"{bpy.app.build_type!r}" builds are not supported.' | ||
) | ||
return None | ||
|
||
if python_implementation() != "CPython": | ||
logger.warning( | ||
f"Does not read the Blend Mode of {material.name}. " | ||
+ f"{python_implementation()} is not supported." | ||
) | ||
return None | ||
|
||
native_struct_offsets_by_major_minor: Mapping[ | ||
tuple[int, int], | ||
Mapping[str, int], | ||
] = { | ||
(4, 2): { | ||
"win-amd64": 324, | ||
"macosx-11.00-arm64": 324, | ||
}, | ||
} | ||
|
||
major_minor = ( # Use [x] to make type checkers happy | ||
bpy.app.version[0], | ||
bpy.app.version[1], | ||
) | ||
native_struct_offsets = native_struct_offsets_by_major_minor.get(major_minor) | ||
if native_struct_offsets is None: | ||
logger.warning( | ||
f"Does not read the Blend Mode of {material.name}. " | ||
+ f"Blender {major_minor[0]}.{major_minor[1]} is not supported." | ||
) | ||
return None | ||
|
||
platform = sysconfig.get_platform() | ||
native_struct_offset = native_struct_offsets.get(platform) | ||
if native_struct_offset is None: | ||
logger.warning( | ||
f"Does not read the Blend Mode of {material.name}. " | ||
+ f"{platform} is not supported." | ||
) | ||
return None | ||
|
||
logger.warning( | ||
f"Starts reading the Blend Mode of {material.name} from its memory address." | ||
) | ||
native_char = ctypes.c_char.from_address( | ||
material.as_pointer() + native_struct_offset | ||
) | ||
logger.warning( | ||
f"Finished reading the Blend Mode of {material.name} from its memory address." | ||
) | ||
|
||
if native_char.value == bytes([0]): | ||
return "OPAQUE" | ||
if native_char.value == bytes([3]): | ||
return "CLIP" | ||
if native_char.value == bytes([4]): | ||
return "HASHED" | ||
if native_char.value == bytes([5]): | ||
return "BLEND" | ||
|
||
return None |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
27 changes: 27 additions & 0 deletions
27
tests/blender_test_read_blend_method_from_memory_address.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
from pathlib import Path | ||
|
||
import bpy | ||
from bpy.types import Context | ||
|
||
from io_scene_vrm.common.native import read_blend_method_from_memory_address | ||
|
||
|
||
def test(context: Context) -> None: | ||
bpy.ops.wm.open_mainfile(filepath=str(Path(__file__).parent / "blend_mode.blend")) | ||
|
||
for material_name, expected_blend_method in { | ||
"Opaque": "OPAQUE", | ||
"AlphaClip": "CLIP", | ||
"AlphaHashed": "HASHED", | ||
"AlphaBlend": "BLEND", | ||
}.items(): | ||
material = context.blend_data.materials[material_name] | ||
actual_blend_method = read_blend_method_from_memory_address(material) | ||
assert expected_blend_method == actual_blend_method, ( | ||
f'"{material_name}" material is not "{expected_blend_method}"' | ||
+ f" but {actual_blend_method}" | ||
) | ||
|
||
|
||
if __name__ == "__main__": | ||
test(bpy.context) |