Skip to content

Commit 895d25f

Browse files
DeepMindcopybara-github
authored andcommitted
Provide a Blender plugin to export models as MuJoCo MJCF XML files with assets.
PiperOrigin-RevId: 605634755 Change-Id: I0d54efe1d83df08a2f51e66da6d9de23f640e58a
1 parent 9e360bf commit 895d25f

23 files changed

Lines changed: 2400 additions & 0 deletions
Lines changed: 229 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,229 @@
1+
# Copyright 2023 The dm_control Authors.
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+
"""Fake Blender bpy module."""
17+
18+
from __future__ import annotations # postponed evaluation of annotations
19+
20+
from typing import Any, Collection, Sequence
21+
22+
from dm_control.blender.fake_core import mathutils
23+
24+
# pylint: disable=invalid-name
25+
# pylint: disable=missing-class-docstring
26+
27+
28+
class WindowManager:
29+
30+
def progress_begin(self, start: int, end: int):
31+
pass
32+
33+
def progress_update(self, steps_done: int):
34+
pass
35+
36+
def progress_end(self):
37+
pass
38+
39+
40+
class context:
41+
42+
@property
43+
def window_manager(self) -> WindowManager:
44+
return WindowManager()
45+
46+
@staticmethod
47+
def evaluated_depsgraph_get():
48+
pass
49+
50+
51+
class types:
52+
53+
class Constraint:
54+
55+
@property
56+
def name(self):
57+
pass
58+
59+
@property
60+
def owner_space(self):
61+
pass
62+
63+
class Scene:
64+
pass
65+
66+
class Object:
67+
68+
@property
69+
def name(self) -> str:
70+
raise NotImplementedError()
71+
72+
@property
73+
def parent(self) -> types.Object | None:
74+
pass
75+
76+
@property
77+
def parent_bone(self) -> types.Bone | None:
78+
pass
79+
80+
@property
81+
def data(self):
82+
pass
83+
84+
@property
85+
def pose(self):
86+
pass
87+
88+
@property
89+
def matrix_world(self) -> mathutils.Matrix:
90+
raise NotImplementedError()
91+
92+
@matrix_world.setter
93+
def matrix_world(self, _) -> mathutils.Matrix:
94+
raise NotImplementedError()
95+
96+
def select_set(self, _):
97+
pass
98+
99+
def to_mesh(self):
100+
pass
101+
102+
def evaluated_get(self, _) -> types.Object:
103+
pass
104+
105+
@property
106+
def mode(self) -> str:
107+
return 'OBJECT'
108+
109+
@property
110+
def type(self):
111+
pass
112+
113+
def update_from_editmode(self):
114+
pass
115+
116+
class Bone:
117+
118+
@property
119+
def name(self) -> str:
120+
raise NotImplementedError()
121+
122+
@property
123+
def parent(self) -> types.Bone | None:
124+
pass
125+
126+
@property
127+
def matrix_local(self) -> mathutils.Matrix:
128+
raise NotImplementedError()
129+
130+
@property
131+
def matrix(self) -> mathutils.Matrix:
132+
raise NotImplementedError()
133+
134+
class bpy_struct:
135+
pass
136+
137+
class Context:
138+
139+
@property
140+
def scene(self) -> types.Scene:
141+
pass
142+
143+
class Light:
144+
145+
@property
146+
def type(self):
147+
pass
148+
149+
@property
150+
def use_shadow(self):
151+
pass
152+
153+
@property
154+
def color(self) -> mathutils.Color:
155+
raise NotImplementedError()
156+
157+
@property
158+
def linear_attenuation(self):
159+
pass
160+
161+
@property
162+
def quadratic_attenuation(self):
163+
pass
164+
165+
class LimitRotationConstraint(Constraint):
166+
pass
167+
168+
class LimitLocationConstraint(Constraint):
169+
pass
170+
171+
class Material:
172+
173+
@property
174+
def name(self) -> str:
175+
raise NotImplementedError()
176+
177+
@property
178+
def specular_intensity(self):
179+
pass
180+
181+
@property
182+
def metallic(self):
183+
pass
184+
185+
@property
186+
def roughness(self) -> float:
187+
raise NotImplementedError()
188+
189+
@property
190+
def diffuse_color(self) -> Sequence[float]:
191+
raise NotImplementedError()
192+
193+
class Mesh:
194+
195+
@property
196+
def name(self) -> str:
197+
raise NotImplementedError()
198+
199+
def calc_loop_triangles(self):
200+
pass
201+
202+
@property
203+
def uv_layers(self) -> Any:
204+
raise NotImplementedError()
205+
206+
@property
207+
def loop_triangles(self) -> Collection[Any]:
208+
raise NotImplementedError()
209+
210+
@property
211+
def vertices(self) -> Any:
212+
raise NotImplementedError()
213+
214+
215+
class ops:
216+
217+
class object:
218+
219+
@staticmethod
220+
def select_all(action):
221+
pass
222+
223+
class export_mesh:
224+
225+
@classmethod
226+
def stl(
227+
cls, filepath, use_selection, use_mesh_modifiers, axis_forward, axis_up
228+
):
229+
pass
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
# Copyright 2023 The dm_control Authors.
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+
"""Fake Blender mathutils module."""
17+
# pylint: disable=invalid-name
18+
19+
import numpy as np
20+
21+
22+
class Color:
23+
"""Fake color class."""
24+
25+
def __init__(self, coords):
26+
self._coords = coords
27+
28+
@property
29+
def r(self) -> float:
30+
return self._coords[0]
31+
32+
@property
33+
def g(self) -> float:
34+
return self._coords[1]
35+
36+
@property
37+
def b(self) -> float:
38+
return self._coords[2]
39+
40+
@property
41+
def a(self) -> float:
42+
return self._coords[3]
43+
44+
45+
class Vector:
46+
"""Fake vector class."""
47+
48+
def __init__(self, coords):
49+
self._coords = np.asarray(coords)
50+
51+
@property
52+
def x(self) -> float:
53+
return self._coords[0]
54+
55+
@property
56+
def y(self) -> float:
57+
return self._coords[1]
58+
59+
@property
60+
def z(self) -> float:
61+
return self._coords[2]
62+
63+
@property
64+
def w(self) -> float:
65+
return self._coords[3]
66+
67+
def __eq__(self, rhs) -> bool:
68+
if not isinstance(rhs, Vector):
69+
return False
70+
return np.linalg.norm(self._coords - rhs._coords) < 1e-6
71+
72+
def __str__(self) -> str:
73+
return 'Vector({:.2f}, {:.2f}, {:.2f})'.format(self.x, self.y, self.z)
74+
75+
def __repr__(self) -> str:
76+
return 'Vector({:.2f}, {:.2f}, {:.2f})'.format(self.x, self.y, self.z)
77+
78+
79+
class Quaternion:
80+
"""Fake quaternion class."""
81+
82+
def __init__(self, coords):
83+
self._coords = coords
84+
85+
@property
86+
def x(self) -> float:
87+
return self._coords[1]
88+
89+
@property
90+
def y(self) -> float:
91+
return self._coords[2]
92+
93+
@property
94+
def z(self) -> float:
95+
return self._coords[3]
96+
97+
@property
98+
def w(self) -> float:
99+
return self._coords[0]
100+
101+
def __matmul__(self, rhs: Vector) -> Vector:
102+
return Vector((1, 0, 0))
103+
104+
105+
class Matrix:
106+
"""Fake matrix class."""
107+
108+
def __init__(self, coords):
109+
self._coords = coords
110+
111+
@classmethod
112+
def Diagonal(cls, _):
113+
return cls((1,))
114+
115+
@property
116+
def translation(self) -> Vector:
117+
return Vector((0.0, 0.0, 0.0))
118+
119+
def to_quaternion(self) -> Quaternion:
120+
return Quaternion((1.0, 0.0, 0.0, 0.0))
121+
122+
def to_scale(self) -> Vector:
123+
return Vector((0.0, 0.0, 0.0))

0 commit comments

Comments
 (0)