usd2msd 0.8.0__py3-none-any.whl
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.
- usd2msd/__init__.py +31 -0
- usd2msd/assets/usd_plugin/Physics/generatedSchema.usda +16 -0
- usd2msd/assets/usd_plugin/physics/generatedSchema.usda +16 -0
- usd2msd/assets/usd_plugin/plugInfo.json +38 -0
- usd2msd/assets/usd_plugin/shade/generatedSchema.usda +10 -0
- usd2msd/common.py +131 -0
- usd2msd/convert.py +1763 -0
- usd2msd/ibl_baker.py +49 -0
- usd2msd/material.py +407 -0
- usd2msd/mdl.py +316 -0
- usd2msd/mesh_utils.py +392 -0
- usd2msd/msd_builder.py +376 -0
- usd2msd/remote.py +185 -0
- usd2msd/usd.py +15 -0
- usd2msd-0.8.0.dist-info/METADATA +87 -0
- usd2msd-0.8.0.dist-info/RECORD +17 -0
- usd2msd-0.8.0.dist-info/WHEEL +4 -0
usd2msd/__init__.py
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Copyright (C) 2020-2025 Motphys Technology Co., Ltd. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
|
|
16
|
+
from usd2msd.convert import Converter
|
|
17
|
+
|
|
18
|
+
__all__ = ["Converter"]
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def register_plugin():
|
|
22
|
+
from importlib.resources import as_file, files
|
|
23
|
+
|
|
24
|
+
from pxr import Plug
|
|
25
|
+
|
|
26
|
+
plugin_path = files("usd2msd.assets").joinpath("usd_plugin")
|
|
27
|
+
with as_file(plugin_path) as path:
|
|
28
|
+
assert Plug.Registry().RegisterPlugins(str(path.absolute()))
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
register_plugin()
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#usda 1.0
|
|
2
|
+
(
|
|
3
|
+
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
class "MotrixPhysicsGeomAPI"
|
|
7
|
+
{
|
|
8
|
+
float motrix:physics:geom:spring_k = 2500.0
|
|
9
|
+
float motrix:physics:geom:spring_d = 100.0
|
|
10
|
+
float motrix:physics:geom:impedance_d0 = 0.9
|
|
11
|
+
float motrix:physics:geom:impedance_dmax = 0.95
|
|
12
|
+
float motrix:physics:geom:impedance_width = 0.001
|
|
13
|
+
float motrix:physics:geom:impedance_middle = 0.5
|
|
14
|
+
float motrix:physics:geom:impedance_power = 2.0
|
|
15
|
+
int motrix:physics:geom:priority = 20
|
|
16
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#usda 1.0
|
|
2
|
+
(
|
|
3
|
+
|
|
4
|
+
)
|
|
5
|
+
|
|
6
|
+
class "MotrixPhysicsGeomAPI"
|
|
7
|
+
{
|
|
8
|
+
float motrix:physics:geom:spring_k = 2500.0
|
|
9
|
+
float motrix:physics:geom:spring_d = 100.0
|
|
10
|
+
float motrix:physics:geom:impedance_d0 = 0.9
|
|
11
|
+
float motrix:physics:geom:impedance_dmax = 0.95
|
|
12
|
+
float motrix:physics:geom:impedance_width = 0.001
|
|
13
|
+
float motrix:physics:geom:impedance_middle = 0.5
|
|
14
|
+
float motrix:physics:geom:impedance_power = 2.0
|
|
15
|
+
int motrix:physics:geom:priority = 20
|
|
16
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Plugins": [
|
|
3
|
+
{
|
|
4
|
+
"Info": {
|
|
5
|
+
"Types": {
|
|
6
|
+
"MotrixShaderAPI": {
|
|
7
|
+
"apiSchemaCanOnlyApplyTo": ["UsdShadeShader"],
|
|
8
|
+
"autoGenerated": false,
|
|
9
|
+
"bases": ["UsdAPISchemaBase"],
|
|
10
|
+
"schemaIdentifier": "MotrixShaderAPI",
|
|
11
|
+
"schemaKind": "singleApplyAPI"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"Name": "MotrixShade",
|
|
16
|
+
"ResourcePath": ".",
|
|
17
|
+
"Root": "shade",
|
|
18
|
+
"Type": "resource"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"Info": {
|
|
22
|
+
"Types": {
|
|
23
|
+
"MotrixPhysicsGeomAPI": {
|
|
24
|
+
"apiSchemaCanOnlyApplyTo": ["GPrim"],
|
|
25
|
+
"autoGenerated": false,
|
|
26
|
+
"bases": ["UsdAPISchemaBase"],
|
|
27
|
+
"schemaIdentifier": "MotrixPhysicsGeomAPI",
|
|
28
|
+
"schemaKind": "singleApplyAPI"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
},
|
|
32
|
+
"Name": "MotrixPhysics",
|
|
33
|
+
"ResourcePath": ".",
|
|
34
|
+
"Root": "physics",
|
|
35
|
+
"Type": "resource"
|
|
36
|
+
}
|
|
37
|
+
]
|
|
38
|
+
}
|
usd2msd/common.py
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Copyright (C) 2020-2025 Motphys Technology Co., Ltd. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
|
|
16
|
+
from collections.abc import Iterable
|
|
17
|
+
from math import isinf, pi
|
|
18
|
+
from pathlib import Path
|
|
19
|
+
|
|
20
|
+
import numpy as np
|
|
21
|
+
from numpy.typing import NDArray
|
|
22
|
+
from PIL import Image as pil
|
|
23
|
+
from PIL.Image import Image
|
|
24
|
+
from pxr.Sdf import PropertySpec, Spec
|
|
25
|
+
from pxr.Usd import Prim
|
|
26
|
+
|
|
27
|
+
import motrixsim.msd as msd
|
|
28
|
+
|
|
29
|
+
degree2radians = pi / 180
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def linear_rgb_to_srgb(linear_rgb: NDArray) -> NDArray:
|
|
33
|
+
"""Convert linear RGB values to sRGB space (vectorized).
|
|
34
|
+
|
|
35
|
+
USD's default source color space is Linear Rec.709 (lin_rec709_scene).
|
|
36
|
+
Bevy expects sRGB values for base_color, so we convert linear to sRGB.
|
|
37
|
+
|
|
38
|
+
Reference: https://openusd.org/release/user_guides/color_user_guide.html
|
|
39
|
+
"""
|
|
40
|
+
linear_rgb = np.asarray(linear_rgb)
|
|
41
|
+
return np.where(
|
|
42
|
+
linear_rgb <= 0.0031308,
|
|
43
|
+
linear_rgb * 12.92,
|
|
44
|
+
1.055 * np.power(linear_rgb, 1.0 / 2.4) - 0.055,
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def rgb_append_a(rgb: NDArray) -> NDArray:
|
|
49
|
+
# Convert from linear to sRGB before storing
|
|
50
|
+
srgb = linear_rgb_to_srgb(rgb)
|
|
51
|
+
return np.append(srgb, 1)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def tint_brightness_to_rgba(tint: NDArray, brightness: float) -> NDArray:
|
|
55
|
+
"""Combine OmniPBR diffuse_tint and albedo_brightness into RGBA color.
|
|
56
|
+
|
|
57
|
+
This is used as the base color multiplier when a diffuse texture is present.
|
|
58
|
+
Final color = diffuse_texture * diffuse_tint * albedo_brightness
|
|
59
|
+
|
|
60
|
+
Color space note:
|
|
61
|
+
- USD's default source color space is Linear Rec.709 (lin_rec709_scene).
|
|
62
|
+
- Reference: https://openusd.org/release/user_guides/color_user_guide.html
|
|
63
|
+
- We convert to sRGB because Bevy expects sRGB values for base_color.
|
|
64
|
+
"""
|
|
65
|
+
rgb = tint * brightness
|
|
66
|
+
srgb = linear_rgb_to_srgb(rgb)
|
|
67
|
+
return np.append(srgb, 1.0)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def merge_rgba(rgb: NDArray, alpha: float, enable_opacity: bool) -> NDArray:
|
|
71
|
+
# Convert from linear to sRGB before storing
|
|
72
|
+
srgb = linear_rgb_to_srgb(rgb)
|
|
73
|
+
return np.append(srgb, alpha if enable_opacity else 1)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def merge_rgba_texture(rgb: Path | None, alpha: Path | None, enable_opacity: bool) -> Image | Path | None:
|
|
77
|
+
if enable_opacity:
|
|
78
|
+
if alpha is not None:
|
|
79
|
+
alpha_img = pil.open(alpha).convert("L")
|
|
80
|
+
if rgb is not None:
|
|
81
|
+
rgba_img = pil.open(rgb).convert("RGB")
|
|
82
|
+
rgba_img.putalpha(alpha_img)
|
|
83
|
+
return rgba_img
|
|
84
|
+
else:
|
|
85
|
+
rgba_img = pil.new("RGB", alpha_img.size, (255, 255, 255))
|
|
86
|
+
rgba_img.putalpha(alpha_img)
|
|
87
|
+
return rgba_img
|
|
88
|
+
else:
|
|
89
|
+
return rgb
|
|
90
|
+
else:
|
|
91
|
+
return rgb
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def opacity_threshold2alpha_mode(threshold: float) -> msd.AlphaMode:
|
|
95
|
+
if threshold >= 1.0:
|
|
96
|
+
return msd.AlphaMode.opaque()
|
|
97
|
+
elif threshold > 0.0:
|
|
98
|
+
return msd.AlphaMode.mask(threshold)
|
|
99
|
+
else:
|
|
100
|
+
# Use Opaque instead of Blend when opacity_threshold <= 0.
|
|
101
|
+
# Blend mode causes incorrect depth sorting with double-sided materials,
|
|
102
|
+
# resulting in back faces being rendered in front of front faces.
|
|
103
|
+
return msd.AlphaMode.opaque()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def common_parent(paths: Iterable[Path]) -> Path:
|
|
107
|
+
split_paths = [i.parts for i in paths]
|
|
108
|
+
common_parts = []
|
|
109
|
+
for parts in zip(*split_paths):
|
|
110
|
+
if all(part == parts[0] for part in parts):
|
|
111
|
+
common_parts.append(parts[0])
|
|
112
|
+
else:
|
|
113
|
+
break
|
|
114
|
+
|
|
115
|
+
return Path(*common_parts)
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
def inf2None(x: float) -> float | None:
|
|
119
|
+
if isinf(x):
|
|
120
|
+
return None
|
|
121
|
+
return x
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
def last_spec(prim: Prim, prop_names: set[str] | None = None) -> Spec:
|
|
125
|
+
prim_specs = prim.GetPrimStack()
|
|
126
|
+
for prim_spec in prim_specs:
|
|
127
|
+
prop_spec: PropertySpec
|
|
128
|
+
for prop_spec in prim_spec.properties:
|
|
129
|
+
if not prop_names or prop_spec.name in prop_names:
|
|
130
|
+
return prim_spec
|
|
131
|
+
return prim_specs[-1]
|