Initial release of the Unity plugin.

PiperOrigin-RevId: 425947505
This commit is contained in:
Tom Erez
2022-02-02 20:17:13 +00:00
committed by Saran Tunyasuvunakool
parent 8ec3dd97a4
commit 6de9eafa13
298 changed files with 20617 additions and 2 deletions
+46
View File
@@ -0,0 +1,46 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// Functionality that needs to be implemented for each shape type.
public interface IMjShape {
// Generate the Mjcf representation of the shape. Infer the scale of the shape from the transform.
void ToMjcf(XmlElement mjcf, Transform transform);
// Parse the shape settings from the specified Mjcf node.
void FromMjcf(XmlElement mjcf);
// Build a parametric mesh (vertices, triangles) of this shape.
Tuple<Vector3[], int[]> BuildMesh();
// Generate a timestamp that can be used to quickly compare if the settings of a shape
// have changed.
// The timestamp should also allow to distinguish between different types of shapes.
//
// Because most of shapes use at most 3 floating point values as parameters, we will
// use the first 3 components of the returned Vector4 to store those values. We will store
// the id of the shape in the 4th component. That id will be derrived from MjShapeComponent.ShapeTypes
// enum.
Vector4 GetChangeStamp();
// Draw a debug gizmo for the shape.
void DebugDraw(Transform transform);
}
}
+13
View File
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: f4b869d65e8404f3aa92042bbd7b9c43
timeCreated: 1547647082
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+360
View File
@@ -0,0 +1,360 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEngine;
namespace Mujoco {
public static class MeshGenerators {
// Creates a sphere mesh geometry.
//
// Args:
// scale: Non-uniform sphere scale. Allows to create ellipsoid shapes.
// numVerticalSlices: How many vertices should there be in a single horizontal slice.
// numHorizontalSlices: How many horizontal slices should the sphere consist of.
public static Tuple<Vector3[], int[]> BuildSphere(
Vector3 scale, int numVerticalSlices = 16, int numHorizontalSlices = 16) {
// Generate the vertices.
Vector3[] vertices;
int[] triangles;
GenerateSphereMeshSlice(
scale: scale,
numVerticalSlices: numVerticalSlices,
numHorizontalSlices: numHorizontalSlices,
firstSliceY: -1.0f,
lastSliceY: 1.0f,
vertices: out vertices,
triangles: out triangles);
return Tuple.Create(vertices, triangles);
}
// Creates a cylinder mesh geometry.
//
// Args:
// radius: Radius of the cylider's body.
// height: Height of the cylinder, from its bottom to its top base.
// numVerticalSlices: How many vertices should there be around the base's circumference.
public static Tuple<Vector3[], int[]> BuildCylinder(
float radius, float height, int numVerticalSlices = 16) {
Vector3[] bodyVertices;
int[] bodyTriangles;
GenerateCylinderBody(radius, height, numVerticalSlices, out bodyVertices, out bodyTriangles);
Vector3[] baseCapVertices;
int[] baseCapTriangles;
GenerateCylinderBaseCaps(
radius, height, numVerticalSlices, out baseCapVertices, out baseCapTriangles);
var merger = new MeshMerger();
merger.Add(bodyVertices, bodyTriangles);
merger.Add(baseCapVertices, baseCapTriangles);
return Tuple.Create(merger.Vertices, merger.Triangles);
}
// Creates a capsule mesh geometry.
//
// Args:
// radius: Radius of the capsule's body.
// height: Height of the capsule, from its bottom to its top base.
// numVerticalSlices: How many vertices should there be in a single horizontal slice.
// numHorizontalSlices: How many vertical slices should the sphere consist of.
public static Tuple<Vector3[], int[]> BuildCapsule(
float radius, float height, int numVerticalSlices = 16, int numHorizontalSlices = 16) {
var baseHalfHeight = Math.Max(0.0f, height * 0.5f - radius);
Vector3[] topCapVertices;
int[] topCapTriangles;
GenerateSphereMeshSlice(
scale: Vector3.one * radius,
numVerticalSlices: numVerticalSlices,
numHorizontalSlices: numHorizontalSlices / 2,
firstSliceY: -1.0f,
lastSliceY: 0.0f,
vertices: out topCapVertices,
triangles: out topCapTriangles);
Vector3[] bottomCapVertices;
int[] bottomCapTriangles;
GenerateSphereMeshSlice(
scale: Vector3.one * radius,
numVerticalSlices: numVerticalSlices,
numHorizontalSlices: numHorizontalSlices / 2,
firstSliceY: 0.0f,
lastSliceY: 1.0f,
vertices: out bottomCapVertices,
triangles: out bottomCapTriangles);
Vector3[] bodyVertices;
int[] bodyTriangles;
GenerateCylinderBody(
radius: radius,
height: baseHalfHeight * 2.0f,
numVerticalSlices: numVerticalSlices,
vertices: out bodyVertices,
triangles: out bodyTriangles);
var merger = new MeshMerger();
merger.AddAndTranslate(topCapVertices, topCapTriangles, Vector3.up * baseHalfHeight * -1.0f);
merger.AddAndTranslate(
bottomCapVertices, bottomCapTriangles, Vector3.up * baseHalfHeight * 1.0f);
merger.Add(bodyVertices, bodyTriangles);
return Tuple.Create(merger.Vertices, merger.Triangles);
}
// Creates a box mesh geometry.
//
// Args:
// extents: Extents of the box, along each major axis.
public static Tuple<Vector3[], int[]> BuildBox(Vector3 extents) {
// In order to ensure the box renders with flat faces, we need to make sure the triangles
// do not share vertices. We'll accomplish that by assigning a unique vertex to every triangle
// apex.
// We define a set of 8 vertex positions that form the box, and then sample from that set using
// triangle indices.
var vertexPositions = new Vector3[] {
Vector3.Scale(new Vector3(-1, -1, -1), extents),
Vector3.Scale(new Vector3(1, -1, -1), extents),
Vector3.Scale(new Vector3(-1, -1, 1), extents),
Vector3.Scale(new Vector3(1, -1, 1), extents),
Vector3.Scale(new Vector3(-1, 1, -1), extents),
Vector3.Scale(new Vector3(1, 1, -1), extents),
Vector3.Scale(new Vector3(-1, 1, 1), extents),
Vector3.Scale(new Vector3(1, 1, 1), extents),
};
var vertexSamplingPattern = new int[] {
0, 1, 3, 0, 3, 2,
4, 7, 5, 4, 6, 7,
0, 5, 1, 0, 4, 5,
1, 7, 3, 1, 5, 7,
3, 6, 2, 3, 7, 6,
2, 4, 0, 2, 6, 4,
};
var vertices = vertexSamplingPattern.Select(index => vertexPositions[index]).ToArray();
var triangles = Enumerable.Range(0, vertexSamplingPattern.Length).ToArray();
return Tuple.Create(vertices, triangles);
}
// Creates a plane mesh geometry.
//
// Args:
// width: Width of the plane, along the OX axis.
// height: Height of the plane, along the OZ axis.
public static Tuple<Vector3[], int[]> BuildPlane(float width, float height) {
var vertices = new Vector3[] {
new Vector3(-0.5f * width, 0, -0.5f * height),
new Vector3(0.5f * width, 0, -0.5f * height),
new Vector3(-0.5f * width, 0, 0.5f * height),
new Vector3(0.5f * width, 0, 0.5f * height),
};
var triangles = new int[] {
0, 3, 1,
0, 2, 3,
};
return Tuple.Create(vertices, triangles);
}
// Generates a slice of a sphere mesh.
// Conceptually, the algorithm generates a sphere with a unit radius (spanning from -1 to 1 along
// each of the major axes). Then, it cuts it using 2 planes parallel to the XZ plane, located at
// distances defined by 'firstSliceY' and 'lastSliceY' parameters respectively. It then returns
// the section of the mesh contained between those planes.
//
// This allows to use the method to generate variants of the sphere - full sphere, hemispheres.
//
// Args:
// scale: Non-uniform sphere scale. Allows to create ellipsoid shapes.
// numVerticalSlices: How many vertices should there be in a single horizontal slice.
// numHorizontalSlices: How many horizontal slices should the sphere consist of.
// firstSliceY: Vertical position of the first slice. Must be a value in range <-1, 1>.
// lastSliceY: Vertical position of the last slice. Must a value in range <-1, 1>.
// vertices: (Out) Array of sphere vertex positions.
// triangles: (Out) Array with the sphere triangle connectivity.
private static void GenerateSphereMeshSlice(
Vector3 scale, int numVerticalSlices, int numHorizontalSlices, float firstSliceY,
float lastSliceY, out Vector3[] vertices, out int[] triangles) {
numVerticalSlices = Math.Max(3, numVerticalSlices);
numHorizontalSlices = Math.Max(3, numHorizontalSlices);
triangles = new int[(numHorizontalSlices - 1) * numVerticalSlices * 6];
vertices = new Vector3[numVerticalSlices * numHorizontalSlices];
if (firstSliceY < -1.0f || firstSliceY > 1.0f) {
throw new IOException("firstSliceY should be a value in range <-1, 1>");
}
if (lastSliceY < -1.0f || lastSliceY > 1.0f) {
throw new IOException("lastSliceY should be a value in range <-1, 1>");
}
if (firstSliceY > lastSliceY) {
throw new IOException("Value of firstSliceY should be lower than the value of lastSliceY.");
}
// Generate the vertices.
var deltaY = (lastSliceY - firstSliceY) / (numHorizontalSlices - 1);
var deltaYaw = 360.0f / numVerticalSlices;
for (var slice = 0; slice < numHorizontalSlices; ++slice) {
var y = firstSliceY + deltaY * slice;
var radius = (float)Math.Sqrt(1 - Math.Min(1.0f, y * y));
for (var vertex = 0; vertex < numVerticalSlices; ++vertex) {
var position = Quaternion.AngleAxis(deltaYaw * vertex, Vector3.up) * Vector3.right * radius;
position.y = y;
vertices[slice * numVerticalSlices + vertex] = Vector3.Scale(position, scale);
}
}
// Build the triangles.
for (var slice = 0; slice < (numHorizontalSlices - 1); ++slice) {
var firstVertexInSlice = slice * numVerticalSlices;
for (var vertex = 0; vertex < numVerticalSlices; ++vertex) {
var index1 = firstVertexInSlice + vertex;
var index2 = (vertex + 1 == numVerticalSlices) ? firstVertexInSlice : index1 + 1;
var index3 = index1 + numVerticalSlices;
var index4 = index2 + numVerticalSlices;
var quadBaseAddress = (slice * numVerticalSlices + vertex) * 6;
triangles[quadBaseAddress] = index1;
triangles[quadBaseAddress + 1] = index2;
triangles[quadBaseAddress + 2] = index4;
triangles[quadBaseAddress + 3] = index1;
triangles[quadBaseAddress + 4] = index4;
triangles[quadBaseAddress + 5] = index3;
}
}
}
// Generates the cylinder mesh vertices.
// This functionality will be shared between the cylinder body and cylinder base caps generators.
//
// Args:
// radius: Cylinder radius.
// height: Cylinder height.
// numVerticalSlices: How many vertices should there be around the base's circumference.
// vertices: (Out) Array of sphere vertex positions.
private static void GenerateCylinderVertices(
float radius, float height, int numVerticalSlices, out Vector3[] vertices) {
vertices = new Vector3[numVerticalSlices * 2];
var dYaw = 360.0f / numVerticalSlices;
var yaw = 0.0f;
var vertexIndex = 0;
for (var y = 0; y <= 1; ++y) {
var yPos = (y - 0.5f) * height;
for (var i = 0; i < numVerticalSlices; ++i, yaw += dYaw) {
var vertexPosition = Quaternion.AngleAxis(yaw, Vector3.up) * Vector3.right * radius;
vertexPosition.y = yPos;
vertices[vertexIndex++] = vertexPosition;
}
}
}
// Generates the meshes for the cylinder body, excluding its bases.
//
// Args:
// radius: Cylinder radius.
// height: Cylinder height.
// numVerticalSlices: How many vertices should there be around the base's circumference.
// vertices: (Out) Array of sphere vertex positions.
// triangles: (Out) Array with the sphere triangle connectivity.
private static void GenerateCylinderBody(
float radius, float height, int numVerticalSlices, out Vector3[] vertices,
out int[] triangles) {
GenerateCylinderVertices(radius, height, numVerticalSlices, out vertices);
triangles = new int[numVerticalSlices * 6];
var apexIndex = 0;
for (var i = 0; i < numVerticalSlices; ++i) {
var v1 = i;
var v2 = (i + 1 == numVerticalSlices) ? 0 : v1 + 1;
var v3 = v1 + numVerticalSlices;
var v4 = v2 + numVerticalSlices;
triangles[apexIndex++] = v1;
triangles[apexIndex++] = v2;
triangles[apexIndex++] = v4;
triangles[apexIndex++] = v1;
triangles[apexIndex++] = v4;
triangles[apexIndex++] = v3;
}
}
// Generates the meshes for the cylinder base circles.
//
// Args:
// radius: Cylinder radius.
// height: Cylinder height.
// numVerticalSlices: How many vertices should there be around the base's circumference.
// vertices: (Out) Array of sphere vertex positions.
// triangles: (Out) Array with the sphere triangle connectivity.
private static void GenerateCylinderBaseCaps(
float radius, float height, int numVerticalSlices, out Vector3[] vertices,
out int[] triangles) {
GenerateCylinderVertices(radius, height, numVerticalSlices, out vertices);
triangles = new int[(numVerticalSlices - 1) * 6];
var apexIndex = 0;
for (var baseIdx = 0; baseIdx <= 1; ++baseIdx) {
var v1 = baseIdx * numVerticalSlices;
for (var i = 1; i < numVerticalSlices; ++i) {
var v2 = v1 + (i % numVerticalSlices);
var v3 = v1 + ((i + 1) % numVerticalSlices);
triangles[apexIndex++] = v1;
triangles[apexIndex++] = baseIdx == 0 ? v3 : v2;
triangles[apexIndex++] = baseIdx == 0 ? v2 : v3;
}
}
}
}
// A tool used to merge the geometry of separate meshes.
public class MeshMerger {
private List<Vector3> _vertices = new List<Vector3>();
private List<int> _triangles = new List<int>();
// The vertices of the merged mesh.
public Vector3[] Vertices => _vertices.ToArray();
// The connectivity array of the merged mesh.
public int[] Triangles => _triangles.ToArray();
// Adds a new submesh.
//
// Args:
// vertices: Array of submesh vertices.
// vertices: Triangles connectivity array of the submesh.
public void Add(Vector3[] vertices, int[] triangles) {
var triangleOffset = _triangles.Count;
var vertexOffset = _vertices.Count;
_vertices.AddRange(vertices);
_triangles.AddRange(triangles);
for (var i = triangleOffset; i < _triangles.Count; ++i) {
_triangles[i] += vertexOffset;
}
}
// Adds a new submesh, translating its vertices by a specified amount.
//
// Args:
// vertices: Array of submesh vertices.
// vertices: Triangles connectivity array of the submesh.
// translation: Additional translation to be applied to the submesh.
public void AddAndTranslate(Vector3[] vertices, int[] triangles, Vector3 translation) {
var triangleOffset = _triangles.Count;
var vertexOffset = _vertices.Count;
_vertices.AddRange(vertices);
for (var i = vertexOffset; i < _vertices.Count; ++i) {
_vertices[i] += translation;
}
_triangles.AddRange(triangles);
for (var i = triangleOffset; i < _triangles.Count; ++i) {
_triangles[i] += vertexOffset;
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: deb4d8c01485d4e44bc815b133e707c0
timeCreated: 1539115944
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+394
View File
@@ -0,0 +1,394 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// Actuators provide means to set joints in motion.
public class MjActuator : MjComponent {
public enum ActuatorType {
General,
Motor,
Position,
Velocity,
Cylinder,
Muscle
}
// This structure holds the parameters shared by all types of actuators.
//
// All constants found in this class are copied from the official documentation, and can be found
// here: http://mujoco.org/book/XMLreference.html#actuator
[Serializable]
public class CommonParameters {
// If true, the control input to this actuator is automatically clamped to ctrlrange at runtime.
// If false, control input clamping is disabled.
public bool CtrlLimited;
// If true, the force output of this actuator is automatically clamped to forcerange at runtime.
// If false, force output clamping is disabled.
public bool ForceLimited;
// Range for clamping the control input.
public Vector2 CtrlRange;
// Range for clamping the force output.
public Vector2 ForceRange;
// Range of feasible lengths of the actuator's transmission.
public Vector2 LengthRange;
// This attribute scales the length (and consequently moment arms, velocity and force) of the
// actuator, for all transmission types. It is different from the gain in the force generation
// mechanism, because the gain only scales the force output and does not affect the length,
// moment arms and velocity.
public List<float> Gear = new List<float>() { 1.0f };
public void ToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("ctrllimited", $"{CtrlLimited}".ToLowerInvariant());
mjcf.SetAttribute("forcelimited", $"{ForceLimited}".ToLowerInvariant());
mjcf.SetAttribute(
"ctrlrange",
$"{MjEngineTool.GetSorted(CtrlRange).x} {MjEngineTool.GetSorted(CtrlRange).y}");
mjcf.SetAttribute(
"forcerange",
$"{MjEngineTool.GetSorted(ForceRange).x} {MjEngineTool.GetSorted(ForceRange).y}");
mjcf.SetAttribute(
"lengthrange",
$"{MjEngineTool.GetSorted(LengthRange).x} {MjEngineTool.GetSorted(LengthRange).y}");
mjcf.SetAttribute("gear", MjEngineTool.ListToMjcf(Gear));
}
public void FromMjcf(XmlElement mjcf) {
CtrlLimited = mjcf.GetBoolAttribute("ctrllimited", defaultValue: false);
ForceLimited = mjcf.GetBoolAttribute("forcelimited", defaultValue: false);
CtrlRange = mjcf.GetVector2Attribute("ctrlrange", defaultValue: Vector2.zero);
ForceRange = mjcf.GetVector2Attribute("forcerange", defaultValue: Vector2.zero);
LengthRange = mjcf.GetVector2Attribute("lengthrange", defaultValue: Vector2.zero);
Gear = mjcf.GetFloatArrayAttribute("gear", defaultValue: new float[] { 1.0f }).ToList();
}
}
// This structure holds all parameters unique to each type of the actuator.
//
// Because UnityEditor doesn't handle polymorphism well, I decided to put all parameters here
// and then create a custom editor (MjActuatorEditor), that will display only the values
// relevant to the selected articulation type. The choice will be made based on the value of
// the 'Type' field.
//
// All constants found in this class are copied from the official documentation, and can be found
// here: http://mujoco.org/book/XMLreference.html#actuator
[Serializable]
public class CustomParameters {
//// General actuator parameters.
// Activation dynamics type for the actuator.
public MujocoLib.mjtDyn DynType;
// The gain and bias together determine the output of the force generation mechanism, which is
// currently assumed to be affine. As already explained in Actuation model, the general formula
// is:
// scalar_force = gain_term * (act or ctrl) + bias_term.
// The formula uses the activation state when present, and the control otherwise.
public MujocoLib.mjtGain GainType;
// Bias type.
public MujocoLib.mjtBias BiasType;
// Activation dynamics parameters. The built-in activation types (except for muscle) use only
// the first parameter, but we provide additional parameters in case user callbacks implement a
// more elaborate model. The length of this array is not enforced by the parser, so the user can
// enter as many parameters as needed.
public List<float> DynPrm = new List<float>() { 1.0f, 0.0f, 0.0f };
// Gain parameters. The built-in gain types (except for muscle) use only the first parameter,
// but we provide additional parameters in case user callbacks implement a more elaborate model.
// The length of this array is not enforced by the parser, so the user can enter as many
// parameters as needed.
public List<float> GainPrm = new List<float>() { 1.0f, 0.0f, 0.0f };
// Bias parameters. The affine bias type uses three parameters. The length of this array is not
// enforced by the parser, so the user can enter as many parameters as needed.
public List<float> BiasPrm = new List<float>() { 0.0f, 0.0f, 0.0f };
public void GeneralToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("dyntype", $"{DynType}".Substring(6).ToLowerInvariant());
mjcf.SetAttribute("gaintype", $"{GainType}".Substring(7).ToLowerInvariant());
mjcf.SetAttribute("biastype", $"{BiasType}".Substring(7).ToLowerInvariant());
mjcf.SetAttribute("dynprm", MjEngineTool.ListToMjcf(DynPrm));
mjcf.SetAttribute("gainprm", MjEngineTool.ListToMjcf(GainPrm));
mjcf.SetAttribute("biasprm", MjEngineTool.ListToMjcf(BiasPrm));
}
public void GeneralFromMjcf(XmlElement mjcf) {
var dynTypeStr = mjcf.GetStringAttribute("dyntype", defaultValue: "none");
var gainTypeStr = mjcf.GetStringAttribute("gaintype", defaultValue: "fixed");
var biasTypeStr = mjcf.GetStringAttribute("biastype", defaultValue: "none");
var ignoreCase = true;
Enum.TryParse<MujocoLib.mjtDyn>($"mjdyn_{dynTypeStr}", ignoreCase, out DynType);
Enum.TryParse<MujocoLib.mjtGain>($"mjgain_{gainTypeStr}", ignoreCase, out GainType);
Enum.TryParse<MujocoLib.mjtBias>($"mjbias_{biasTypeStr}", ignoreCase, out BiasType);
DynPrm = mjcf.GetFloatArrayAttribute(
"dynprm", defaultValue: new float[] { 1.0f, 0.0f, 0.0f }).ToList();
GainPrm = mjcf.GetFloatArrayAttribute(
"gainprm", defaultValue: new float[] { 1.0f, 0.0f, 0.0f }).ToList();
BiasPrm = mjcf.GetFloatArrayAttribute(
"biasprm", defaultValue: new float[] { 0.0f, 0.0f, 0.0f }).ToList();
}
//// Position actuator parameters.
// Position feedback gain.
[AbsoluteValue]
public float Kp = 1.0f;
public void PositionToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("kp", $"{Math.Abs(Kp)}");
}
public void PositionFromMjcf(XmlElement mjcf) {
Kp = mjcf.GetFloatAttribute("kp", defaultValue: 1.0f);
}
//// Velocity actuator parameters.
// Velocity feedback gain.
[AbsoluteValue]
public float Kv = 1.0f;
public void VelocityToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("kv", $"{Math.Abs(Kv)}");
}
public void VelocityFromMjcf(XmlElement mjcf) {
Kv = mjcf.GetFloatAttribute("kv", defaultValue: 1.0f);
}
//// Cylinder actuator parameters.
// Time constant of the activation dynamics.
public float CylinderTimeConst = 1.0f;
// Area of the cylinder. This is used internally as actuator gain.
[AbsoluteValue]
public float Area = 1.0f;
// Instead of area the user can specify diameter. If both are specified, diameter has
// precedence.
[AbsoluteValue]
public float Diameter = 0.0f;
// Bias parameters, copied internally into biasprm.
public float[] Bias = new float[] { 0.0f, 0.0f, 0.0f };
public void CylinderToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("timeconst", $"{CylinderTimeConst}");
mjcf.SetAttribute("area", $"{Math.Abs(Area)}");
mjcf.SetAttribute("diameter", $"{Math.Abs(Diameter)}");
mjcf.SetAttribute("bias", MjEngineTool.ArrayToMjcf(Bias));
}
public void CylinderFromMjcf(XmlElement mjcf) {
CylinderTimeConst = mjcf.GetFloatAttribute("timeconst", defaultValue: 1.0f);
Area = mjcf.GetFloatAttribute("area", defaultValue: 1.0f);
Diameter = mjcf.GetFloatAttribute("diameter", defaultValue: 0.0f);
Bias = mjcf.GetFloatArrayAttribute("bias", defaultValue: new float[] { 0.0f, 0.0f, 0.0f });
}
//// Muscle actuator parameters.
// Time constants for activation and de-activation dynamics.
public Vector2 MuscleTimeConst = new Vector2(0.01f, 0.04f);
// Operating length range of the muscle, in units of L0.
public Vector2 Range = new Vector2(0.75f, 1.05f);
// Peak active force at rest. If this value is negative, the peak force is determined
// automatically using the scale attribute below.
public float Force = -1.0f;
// If the force attribute is negative, the peak active force for the muscle is set to this value
// divided by mjModel.actuator_acc0. The latter is the norm of the joint-space acceleration
// vector caused by unit force on the actuator's transmission in qpos0. In other words, scaling
// produces higher peak forces for muscles that pull more weight.
public float Scale = 200.0f;
// Lower position range of the normalized FLV curve, in units of L0.
public float LMin = 0.5f;
// Upper position range of the normalized FLV curve, in units of L0.
public float LMax = 1.6f;
// Shortening velocity at which muscle force drops to zero, in units of L0 per second.
public float VMax = 1.5f;
// Passive force generated at lmax, relative to the peak rest force.
public float FpMax = 1.3f;
// Active force generated at saturating lengthening velocity, relative to the peak rest force.
public float FvMax = 1.2f;
public void MuscleToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("timeconst", $"{MuscleTimeConst[0]} {MuscleTimeConst[1]}");
mjcf.SetAttribute(
"range", $"{MjEngineTool.GetSorted(Range).x} {MjEngineTool.GetSorted(Range).y}");
mjcf.SetAttribute("force", $"{Force}");
mjcf.SetAttribute("scale", $"{Scale}");
mjcf.SetAttribute("lmin", $"{LMin}");
mjcf.SetAttribute("lmax", $"{LMax}");
mjcf.SetAttribute("vmax", $"{VMax}");
mjcf.SetAttribute("fpmax", $"{FpMax}");
mjcf.SetAttribute("fvmax", $"{FvMax}");
}
public void MuscleFromMjcf(XmlElement mjcf) {
MuscleTimeConst = mjcf.GetVector2Attribute(
"timeconst", defaultValue: new Vector2(0.01f, 0.04f));
Range = mjcf.GetVector2Attribute("range", defaultValue: new Vector2(0.75f, 1.05f));
Force = mjcf.GetFloatAttribute("force", defaultValue: -1.0f);
Scale = mjcf.GetFloatAttribute("scale", defaultValue: 200.0f);
LMin = mjcf.GetFloatAttribute("lmin", defaultValue: 0.5f);
LMax = mjcf.GetFloatAttribute("lmax", defaultValue: 1.6f);
VMax = mjcf.GetFloatAttribute("vmax", defaultValue: 1.5f);
FpMax = mjcf.GetFloatAttribute("fpmax", defaultValue: 1.3f);
FvMax = mjcf.GetFloatAttribute("fvmax", defaultValue: 1.2f);
}
}
public ActuatorType Type;
[Tooltip("Joint actuation target. Mutually exclusive with tendon target.")]
public MjBaseJoint Joint;
[Tooltip("Tendon actuation target. Mutually exclusive with joint target.")]
public MjBaseTendon Tendon;
[Tooltip("Parameters specific to each actuator type.")]
[HideInInspector]
public CustomParameters CustomParams = new CustomParameters();
[Tooltip("Parameters shared by all types of actuators.")]
public CommonParameters CommonParams = new CommonParameters();
[Tooltip("Actuator control.")]
public float Control;
// Actuator length.
public float Length { get; private set; }
// Actuator velocity.
public float Velocity { get; private set; }
// Actuator force.
public float Force { get; private set; }
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_ACTUATOR;
// Parse the component settings from an external Mjcf.
protected override void OnParseMjcf(XmlElement mjcf) {
if (!Enum.TryParse(mjcf.Name, ignoreCase: true, result: out Type)) {
throw new ArgumentException($"Unknown actuator type {mjcf.Name}.");
}
CommonParams.FromMjcf(mjcf);
switch (Type) {
case MjActuator.ActuatorType.General: {
CustomParams.GeneralFromMjcf(mjcf);
break;
}
case MjActuator.ActuatorType.Position: {
CustomParams.PositionFromMjcf(mjcf);
break;
}
case MjActuator.ActuatorType.Velocity: {
CustomParams.VelocityFromMjcf(mjcf);
break;
}
case MjActuator.ActuatorType.Cylinder: {
CustomParams.CylinderFromMjcf(mjcf);
break;
}
case MjActuator.ActuatorType.Muscle: {
CustomParams.MuscleFromMjcf(mjcf);
break;
}
}
Joint = mjcf.GetObjectReferenceAttribute<MjBaseJoint>("joint");
Tendon = mjcf.GetObjectReferenceAttribute<MjBaseTendon>("tendon");
}
// Generate implementation specific XML element.
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
if (Joint == null && Tendon == null) {
throw new InvalidOperationException($"Actuator {name} is not assigned a joint nor tendon.");
}
if (Joint != null && Tendon != null) {
throw new InvalidOperationException(
$"Actuator {name} can't have both a tendon and a joint target.");
}
var mjcf = doc.CreateElement(Type.ToString().ToLowerInvariant());
if (Joint != null) {
mjcf.SetAttribute("joint", Joint.MujocoName);
} else {
mjcf.SetAttribute("tendon", Tendon.MujocoName);
}
CommonParams.ToMjcf(mjcf);
switch (Type) {
case MjActuator.ActuatorType.General: {
CustomParams.GeneralToMjcf(mjcf);
break;
}
case MjActuator.ActuatorType.Position: {
CustomParams.PositionToMjcf(mjcf);
break;
}
case MjActuator.ActuatorType.Velocity: {
CustomParams.VelocityToMjcf(mjcf);
break;
}
case MjActuator.ActuatorType.Cylinder: {
CustomParams.CylinderToMjcf(mjcf);
break;
}
case MjActuator.ActuatorType.Muscle: {
CustomParams.MuscleToMjcf(mjcf);
break;
}
}
return mjcf;
}
// Synchronize the state of the component.
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
data->ctrl[MujocoId] = Control;
Length = (float)data->actuator_length[MujocoId];
Velocity = (float)data->actuator_velocity[MujocoId];
Force = (float)data->actuator_force[MujocoId];
}
public void OnValidate() {
if (Joint != null && Tendon != null) {
Debug.LogError(
$"Actuator {name} can't have both a tendon and a joint target.", this);
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: c3f3a0cb6a6d64327b27c7d5bdd8d430
timeCreated: 1546881319
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,54 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjActuatorScalarSensor : MjBaseSensor {
// NOTE: These names must match sensor names listed on mujoco.org.
// Changing them is justified only when Mujoco is upgraded to a new version.
public enum AvailableSensors {
ActuatorPos,
ActuatorVel,
ActuatorFrc,
}
public AvailableSensors SensorType;
public MjActuator Actuator;
public double SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Actuator == null) {
throw new NullReferenceException("Missing a reference to a MjActuator.");
}
var mjcf = doc.CreateElement(SensorType.ToString().ToLower());
mjcf.SetAttribute("actuator", Actuator.MujocoName);
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
if (!Enum.TryParse(mjcf.Name, ignoreCase: true, result: out SensorType)) {
throw new ArgumentException($"Unknown sensor type {mjcf.Name}.");
}
Actuator = mjcf.GetObjectReferenceAttribute<MjActuator>("actuator");
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = data->sensordata[_sensorAddress];
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 9d6f957ac545d4e8ea581fcc861a0498
timeCreated: 1548092931
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// The component represents a joint with 1 degree of translational freedom.
public class MjBallJoint : MjBaseJoint {
[Tooltip("In radians.")]
public float RangeUpper;
[Tooltip("Joint settings.")]
public MjJointSettings Settings = MjJointSettings.Default;
protected override void OnParseMjcf(XmlElement mjcf) {
// Transform.
transform.localPosition =
MjEngineTool.UnityVector3(mjcf.GetVector3Attribute("pos", defaultValue: Vector3.zero));
Settings.FromMjcf(mjcf);
var rangeValues = mjcf.GetFloatArrayAttribute("range", defaultValue: new float[] { 0, 0 });
// rangeValues[0] is always 0 for ball joints.
RangeUpper = rangeValues[1];
}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("joint");
mjcf.SetAttribute("type", "ball");
MjEngineTool.PositionToMjcf(mjcf, this);
Settings.ToMjcf(mjcf);
mjcf.SetAttribute("range", $"0 {RangeUpper}");
return mjcf;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: bc71be844486c4586ba729c1ab4d914a
timeCreated: 1552056297
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+24
View File
@@ -0,0 +1,24 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public abstract class MjBaseBody : MjComponent {
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_BODY;
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 088eb1d485bd54fcaa1061c79b289dde
timeCreated: 1551357866
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,47 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public abstract class MjBaseConstraint : MjComponent {
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_EQUALITY;
protected abstract string _constraintName { get; }
public SolverImpedance SolverImpedanceSettings = SolverImpedance.Default;
public SolverReference SolverReferenceSettings = SolverReference.Default;
protected abstract void ToMjcf(XmlElement mjcf);
protected abstract void FromMjcf(XmlElement mjcf);
protected override void OnParseMjcf(XmlElement mjcf) {
FromMjcf(mjcf);
SolverReferenceSettings.FromMjcf(mjcf, "solref");
SolverImpedanceSettings.FromMjcf(mjcf, "solimp");
}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement(_constraintName);
ToMjcf(mjcf);
SolverReferenceSettings.ToMjcf(mjcf, "solref");
SolverImpedanceSettings.ToMjcf(mjcf, "solimp");
return mjcf;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: a34f7c43f90c84e64a45942e605c0a2b
timeCreated: 1552309644
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+63
View File
@@ -0,0 +1,63 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public abstract class MjBaseJoint : MjComponent {
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_JOINT;
public int QposAddress { get; private set; } = -1;
public int DofAddress { get; private set; } = -1;
// Joint will add Degrees of Freedom to this MjBaseBody.
// It's the MjBaseBody located immediately above this joint in the scene tree.
// NOTE: This property won't be initialized until runtime.
public MjBaseBody ParentBody { get; private set; }
// Joint will constrain the ParentBody to this MjBaseBody.
// It's the MjBaseBody located two levels above this joint in the scene tree.
// For some joints, such as MjFreeJoint, this can be null.
// NOTE: This property won't be initialized until runtime.
public MjBaseBody GrandParentBody { get; private set; }
// Return the bodies connected by this joint.
public void GetConnectedBodies(out MjBaseBody grandParent, out MjBaseBody parent) {
parent = MjHierarchyTool.FindParentComponent<MjBaseBody>(this);
if (parent != null) {
grandParent = MjHierarchyTool.FindParentComponent<MjBaseBody>(parent);
} else {
grandParent = null;
}
}
protected override unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
QposAddress = model->jnt_qposadr[MujocoId];
DofAddress = model->jnt_dofadr[MujocoId];
}
protected override void Start() {
base.Start();
MjBaseBody grandparentBody, parentBody;
GetConnectedBodies(out grandparentBody, out parentBody);
GrandParentBody = grandparentBody;
ParentBody = parentBody;
if (ParentBody == null) {
throw new Exception("The joint doesn't have a ParentBody.");
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 07bd997db28964e5daf6af0ff47e157f
timeCreated: 1538399740
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+80
View File
@@ -0,0 +1,80 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// The base class for Mujoco sensors.
//
// Mujoco offers a very wide range of sensors, each contingent on the following three aspects:
// 1. the Mujoco Component it observes: Body, Joint, etc.
// 2. the type of data it returns: scalar, Vector3, quaternion, etc.
// 3. the field it reads to retreive the data: xpos, xquat, cfrc, etc.
//
// In Mujoco proper, names of some of the sensors repeat for many data types. In order to get rid
// of this ambiguity, we chose to split the sensors into groups.
// Each sensor class represents a group of aspects (1) and (2), which is reflected in its name.
// For example, the class of sensors that listen to Bodies and produce Vector3 observations is
// called MjBodyVectorSensor.
//
// That very class contains a wide range of sensing capabilities - as in fact most of the classes
// do. What each sensor can sense can be controlled by the sensor's Type field. Using the
// MjBodyVectorSensor as an example, one can set it to SubtreeCom, FramePos or any of the other
// supported observation types.
public abstract class MjBaseSensor : MjComponent {
[Tooltip("The standard deviation of zero-mean Gaussian noise added to the sensor output.")]
[AbsoluteValue]
public float Noise = 0.0f;
[Tooltip("When this value is positive, it limits the absolute value of the sensor output.")]
[AbsoluteValue]
public float Cutoff = 0.0f;
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_SENSOR;
// Address of the sensor, that can be used to index into MujocoLib.mjData_.sensordata.
protected int _sensorAddress;
// Parse the component settings from an external Mjcf.
protected override void OnParseMjcf(XmlElement mjcf) {
Noise = mjcf.GetFloatAttribute("noise", defaultValue: 0.0f);
Cutoff = mjcf.GetFloatAttribute("cutoff", defaultValue: 0.0f);
FromMjcf(mjcf);
}
// Generate implementation specific XML element.
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = ToMjcf(doc);
mjcf.SetAttribute("noise", Noise.ToString());
mjcf.SetAttribute("cutoff", Cutoff.ToString());
return mjcf;
}
// Perform bind time initialization of the component.
protected override unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
_sensorAddress = model->sensor_adr[MujocoId];
}
// Create the implementation dependent Mjcf node.
protected abstract XmlElement ToMjcf(XmlDocument doc);
// Parse the implementation dependent details from the provided Mjcf node.
protected abstract void FromMjcf(XmlElement mjcf);
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 9535e8d4bdb484c4dbd07806fcae7568
timeCreated: 1548084206
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+65
View File
@@ -0,0 +1,65 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public abstract class MjBaseTendon : MjComponent {
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_TENDON;
public SolverSettings Solver = SolverSettings.Default;
[Tooltip("Length at zero spring force. If negative, this resting length is computed at qpos0.")]
public float SpringLength = -1.0f;
public float Stiffness = 0.0f;
public float Damping = 0.0f;
// Tendon length.
public float Length { get; private set; }
// Create the implementation dependent Mjcf node.
protected abstract XmlElement ToMjcf(XmlDocument doc);
// Parse the implementation dependent details from the provided Mjcf node.
protected abstract void FromMjcf(XmlElement mjcf);
// Parse the component settings from an external Mjcf.
protected override void OnParseMjcf(XmlElement mjcf) {
Solver.FromMjcf(mjcf);
SpringLength = mjcf.GetFloatAttribute("springlength", defaultValue: -1.0f);
Stiffness = mjcf.GetFloatAttribute("damping");
Damping = mjcf.GetFloatAttribute("stiffness");
FromMjcf(mjcf);
}
// Generate implementation specific XML element.
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = ToMjcf(doc);
Solver.ToMjcf(mjcf);
mjcf.SetAttribute("springlength", $"{SpringLength}");
mjcf.SetAttribute("damping", $"{Damping}");
mjcf.SetAttribute("stiffness", $"{Stiffness}");
return mjcf;
}
// Synchronize the state of the component.
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
Length = (float)data->ten_length[MujocoId];
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 2d585fcecff4e4b13b8647ad4d18c5b5
timeCreated: 1551348729
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// The component represents the apex of hierarchy that defines a single rigid body.
public class MjBody : MjBaseBody {
protected override void OnParseMjcf(XmlElement mjcf) {
// Transform
transform.localPosition =
MjEngineTool.UnityVector3(mjcf.GetVector3Attribute("pos", defaultValue: Vector3.zero));
transform.localRotation = MjEngineTool.UnityQuaternion(
mjcf.GetQuaternionAttribute("quat", defaultValue: MjEngineTool.MjQuaternionIdentity));
}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("body");
MjEngineTool.PositionRotationToMjcf(mjcf, this);
return mjcf;
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
transform.position = MjEngineTool.UnityVector3(data->xpos, MujocoId);
transform.rotation = MjEngineTool.UnityQuaternion(data->xquat, MujocoId);
}
}
}
+13
View File
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 4ef51a360e7c24695800e2d06f70db49
timeCreated: 1537462857
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,52 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjBodyQuaternionSensor : MjBaseSensor {
public MjBody Body;
[Tooltip("Should the Frame sensors use the inertial or the regular frame of reference.")]
public bool UseInertialFrame;
public Quaternion SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Body == null) {
throw new NullReferenceException("Missing a reference to a MjBody.");
}
var mjcf = doc.CreateElement("framequat");
mjcf.SetAttribute("objtype", UseInertialFrame ? "body" : "xbody");
mjcf.SetAttribute("objname", Body.MujocoName);
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
UseInertialFrame = mjcf.HasAttribute("body");
Body = mjcf.GetObjectReferenceAttribute<MjBody>("objname");
if (Body == null) {
throw new NullReferenceException("Missing a reference to a MjBody.");
}
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = MjEngineTool.UnityQuaternion(data->sensordata, _sensorAddress);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: af03f553fc93c44ec8d1cc3fbbcce947
timeCreated: 1548170856
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,77 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjBodyVectorSensor : MjBaseSensor {
// NOTE: These names must match sensor names listed on mujoco.org.
// Changing them is justified only when Mujoco is upgraded to a new version.
public enum AvailableSensors {
SubtreeCom,
SubtreeLinVel,
SubtreeAngMom,
FramePos,
FrameXAxis,
FrameYAxis,
FrameZAxis,
FrameLinVel,
FrameAngVel,
FrameLinAcc,
FrameAngAcc,
}
public AvailableSensors SensorType;
public MjBody Body;
[Tooltip("Should the Frame sensors use the inertial or the regular frame of reference.")]
public bool UseInertialFrame;
public Vector3 SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Body == null) {
throw new NullReferenceException("Missing a reference to a MjBody.");
}
var tag = SensorType.ToString().ToLower();
var mjcf = doc.CreateElement(tag);
if (tag.Contains("frame")) {
mjcf.SetAttribute("objtype", UseInertialFrame ? "body" : "xbody");
mjcf.SetAttribute("objname", Body.MujocoName);
} else {
mjcf.SetAttribute("body", Body.MujocoName);
}
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
if (!Enum.TryParse(mjcf.Name, ignoreCase: true, result: out SensorType)) {
throw new ArgumentException($"Unknown sensor type {mjcf.Name}.");
}
if (mjcf.Name.Contains("frame")) {
UseInertialFrame = mjcf.HasAttribute("body"); // as opposed to xbody
Body = mjcf.GetObjectReferenceAttribute<MjBody>("objname");
} else {
Body = mjcf.GetObjectReferenceAttribute<MjBody>("body");
}
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = MjEngineTool.UnityVector3(data->sensordata, _sensorAddress);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 537df637b11f44df2a20bea718a015a6
timeCreated: 1548092931
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class MjBoxShape : IMjShape {
public Vector3 Extents = Vector3.one * 0.5f;
public void ToMjcf(XmlElement mjcf, Transform transform) {
var scaledExtents = MjEngineTool.MjExtents(Vector3.Scale(Extents, transform.lossyScale));
mjcf.SetAttribute("size", MjEngineTool.Vector3ToMjcf(scaledExtents));
}
public void FromMjcf(XmlElement mjcf) {
Extents = MjEngineTool.UnityExtents(
mjcf.GetVector3Attribute("size", defaultValue: Vector3.one * 0.5f));
Vector3 fromPoint, toPoint;
if (MjEngineTool.ParseFromToMjcf(mjcf, out fromPoint, out toPoint)) {
var extent = (toPoint - fromPoint).magnitude * 0.5f;
Extents = Vector3.one * extent;
}
}
public Tuple<Vector3[], int[]> BuildMesh() {
return MeshGenerators.BuildBox(extents: Extents);
}
public Vector4 GetChangeStamp() {
return Extents;
}
public void DebugDraw(Transform transform) {
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);
Gizmos.DrawWireCube(Vector3.zero, Extents * 2.0f);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 9783bb0e781e341e5914cdbac095b35e
timeCreated: 1547647081
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,63 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class MjCapsuleShape : IMjShape {
public float Radius = 0.5f;
public float HalfHeight = 0.5f;
private const float _scaleTolerance = 1e-5f;
public void ToMjcf(XmlElement mjcf, Transform transform) {
if (Math.Abs(transform.lossyScale.x - transform.lossyScale.z) > _scaleTolerance) {
Debug.LogWarning(
$"{transform.name}: Capsule shapes require uniform scaling of XZ plane. Using the" +
" value of X and Y components.", transform);
}
mjcf.SetAttribute(
"size", $"{Radius * transform.lossyScale.x} {HalfHeight * transform.lossyScale.y}");
}
public void FromMjcf(XmlElement mjcf) {
var components = mjcf.GetFloatArrayAttribute("size", defaultValue: new float[] { 0.5f, 0.5f });
Radius = components[0];
HalfHeight = components[1];
Vector3 fromPoint, toPoint;
if (MjEngineTool.ParseFromToMjcf(mjcf, out fromPoint, out toPoint)) {
HalfHeight = 0.5f * (toPoint - fromPoint).magnitude;
}
}
public Tuple<Vector3[], int[]> BuildMesh() {
return MeshGenerators.BuildCapsule(radius: Radius, height: (HalfHeight + Radius) * 2.0f);
}
public Vector4 GetChangeStamp() {
return new Vector4(Radius, HalfHeight, 1, 0);
}
public void DebugDraw(Transform transform) {
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
MjGizmos.DrawWireCapsule(
Vector3.zero, Radius * transform.lossyScale.x, 2 * HalfHeight * transform.lossyScale.y);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 9b0a2054e1eec409fbf34c796a572b38
timeCreated: 1547647081
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+108
View File
@@ -0,0 +1,108 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// The base class for all components that represent Mujoco scene nodes.
[DisallowMultipleComponent]
public abstract class MjComponent : MonoBehaviour {
// Unique name assigned to each Mujoco component.
public string MujocoName { get; private set; }
// Id of the geom in Mujoco's internal data structures.
public int MujocoId { get; protected set; }
public abstract MujocoLib.mjtObj ObjectType { get; }
// Some components (Inertial frames for example) cannot have the name attribute
// added to the generated Mjcf.
protected virtual bool _suppressNameAttribute => false;
// Binds this component to the compiled Mujoco model.
public unsafe void BindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
MujocoId = MujocoLib.mj_name2id(model, (int)ObjectType, MujocoName);
if (MujocoId == -1 && !_suppressNameAttribute) {
throw new NullReferenceException($"element name {MujocoName} not found");
}
OnBindToRuntime(model, data);
}
// Generates the XML element that corresponds to this scene node.
public XmlElement GenerateMjcf(string name, XmlDocument doc) {
MujocoName = name;
var mjcf = OnGenerateMjcf(doc);
if (!_suppressNameAttribute) {
mjcf.SetAttribute("name", name);
}
return mjcf;
}
// Parse the component settings from an external Mjcf.
public void ParseMjcf(XmlElement mjcf) {
// I would like to preserve the naming dualism - external mechanisms
// calling a method, and the internal implementation implementing
// the method with an "On" prefix.
OnParseMjcf(mjcf);
}
// Parse the component settings from an external Mjcf.
protected abstract void OnParseMjcf(XmlElement mjcf);
// Generate implementation specific XML element.
protected abstract XmlElement OnGenerateMjcf(XmlDocument doc);
// Perform bind time initialization of the component.
protected virtual unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {}
// Synchronize the state of the component.
public virtual unsafe void OnSyncState(MujocoLib.mjData_* data) {}
private bool _sceneExcludesMe = false;
protected unsafe virtual void Start() {
if (MjScene.Instance == null) {
throw new Exception("MuJoCo Scene not found");
}
if (MjScene.Instance.Model != null) {
_sceneExcludesMe = true;
}
}
protected void Update() {
if (_sceneExcludesMe) {
MjScene.Instance.SceneRecreationAtLateUpdateRequested = true;
_sceneExcludesMe = false;
}
}
private bool _exiting = false;
public void OnApplicationQuit() {
_exiting = true;
}
public void OnDisable() {
if (!_exiting) {
MjScene.Instance.SceneRecreationAtLateUpdateRequested = true;
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 7cb8afbea854147a8bf92a08d5f6577b
timeCreated: 1536879723
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+51
View File
@@ -0,0 +1,51 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjConnect : MjBaseConstraint {
public MjBaseBody Body1;
public MjBaseBody Body2;
protected override string _constraintName => "connect";
protected override void FromMjcf(XmlElement mjcf) {
Body1 = mjcf.GetObjectReferenceAttribute<MjBaseBody>("body1");
Body2 = mjcf.GetObjectReferenceAttribute<MjBaseBody>("body2");
if (mjcf.GetStringAttribute("anchor") != null) {
Debug.Log($"anchor in connect {name} ignored. Set Transforms in the editor.");
}
}
// Generate implementation specific XML element.
protected override void ToMjcf(XmlElement mjcf) {
if (Body1 == null || Body2 == null) {
throw new NullReferenceException($"Both bodies in connect {name} are required.");
}
mjcf.SetAttribute("body1", Body1.MujocoName);
mjcf.SetAttribute("body2", Body2.MujocoName);
}
public void OnValidate() {
if (Body1 != null && Body1 == Body2) {
Debug.LogError("Body1 and Body2 can't be the same - resetting Body2.", this);
Body2 = null;
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: ee6081d65578643bf8a26f200299a51a
timeCreated: 1552313909
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,63 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class MjCylinderShape : IMjShape {
public float Radius = 0.5f;
public float HalfHeight = 1.0f;
private const float _scaleTolerance = 1e-6f;
public void ToMjcf(XmlElement mjcf, Transform transform) {
if (Math.Abs(transform.lossyScale.x - transform.lossyScale.z) > _scaleTolerance) {
Debug.LogWarning(
$"{transform.name}: Cylinder shapes require uniform scaling of XZ plane. Using the" +
" value of X and Y components.", transform);
}
mjcf.SetAttribute(
"size", $"{Radius * transform.lossyScale.x} {HalfHeight * transform.lossyScale.y}");
}
public void FromMjcf(XmlElement mjcf) {
var components = mjcf.GetFloatArrayAttribute("size", defaultValue: new float[] { 0.5f, 1.0f });
Radius = components[0];
HalfHeight = components[1];
Vector3 fromPoint, toPoint;
if (MjEngineTool.ParseFromToMjcf(mjcf, out fromPoint, out toPoint)) {
HalfHeight = (toPoint - fromPoint).magnitude * 0.5f;
}
}
public Tuple<Vector3[], int[]> BuildMesh() {
return MeshGenerators.BuildCylinder(radius: Radius, height: HalfHeight * 2);
}
public Vector4 GetChangeStamp() {
return new Vector4(Radius, HalfHeight, 1, 0);
}
public void DebugDraw(Transform transform) {
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
MjGizmos.DrawWireCylinder(
Vector3.zero, Radius * transform.lossyScale.x, HalfHeight * 2 * transform.lossyScale.y);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: bd3a2b00a0a2f4ba9be8bd2f054a3835
timeCreated: 1547647081
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+48
View File
@@ -0,0 +1,48 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjDistance : MjBaseConstraint {
public MjGeom Geom1;
public MjGeom Geom2;
protected override string _constraintName => "distance";
protected override void FromMjcf(XmlElement mjcf) {
Geom1 = mjcf.GetObjectReferenceAttribute<MjGeom>("geom1");
Geom2 = mjcf.GetObjectReferenceAttribute<MjGeom>("geom2");
}
protected override void ToMjcf(XmlElement mjcf) {
if (Geom1 == null || Geom2 == null) {
throw new NullReferenceException($"Both geoms in distance {name} must be assigned.");
}
mjcf.SetAttribute("geom1", Geom1.MujocoName);
mjcf.SetAttribute("geom2", Geom2.MujocoName);
}
public void OnValidate() {
if (Geom1 != null && Geom1 == Geom2) {
Debug.LogError("Geom1 and Geom2 can't be the same - resetting Geom2.", this);
Geom2 = null;
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: ad0689a32f102481fb189836c11931f9
timeCreated: 1552309644
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,58 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class MjEllipsoidShape : IMjShape {
public Vector3 Radiuses = Vector3.one * 0.5f;
public void ToMjcf(XmlElement mjcf, Transform transform) {
var scaledRadiuses = MjEngineTool.MjExtents(Vector3.Scale(Radiuses, transform.lossyScale));
mjcf.SetAttribute("size", MjEngineTool.Vector3ToMjcf(scaledRadiuses));
}
public void FromMjcf(XmlElement mjcf) {
Radiuses = MjEngineTool.UnityExtents(
mjcf.GetVector3Attribute("size", defaultValue: Vector3.one * 0.5f));
Vector3 fromPoint, toPoint;
if (MjEngineTool.ParseFromToMjcf(mjcf, out fromPoint, out toPoint)) {
var radius = (toPoint - fromPoint).magnitude * 0.5f;
Radiuses = Vector3.one * radius;
}
}
public Tuple<Vector3[], int[]> BuildMesh() {
return MeshGenerators.BuildSphere(scale: Radiuses);
}
public Vector4 GetChangeStamp() {
return Radiuses;
}
public void DebugDraw(Transform transform) {
Gizmos.matrix = Matrix4x4.TRS(
transform.position,
transform.rotation,
Vector3.Scale(Radiuses, transform.lossyScale));
Gizmos.DrawWireSphere(Vector3.zero, 1.0f);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 8316fb5037f4a450c9270267e5428567
timeCreated: 1547647081
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+54
View File
@@ -0,0 +1,54 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjExclude : MjComponent {
[Tooltip("A body whose contacts with other body are ignored")]
public MjBody Body1;
[Tooltip("Other body whose contacts with first body are ignored")]
public MjBody Body2;
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_EXCLUDE;
protected override void OnParseMjcf(XmlElement mjcf) {
var body1Name = mjcf.GetStringAttribute("body1", defaultValue: string.Empty);
if (!string.IsNullOrEmpty(body1Name)) {
Body1 = MjHierarchyTool.FindComponentOfTypeAndName<MjBody>(body1Name);
}
var body2Name = mjcf.GetStringAttribute("body2", defaultValue: string.Empty);
if (!string.IsNullOrEmpty(body2Name)) {
Body2 = MjHierarchyTool.FindComponentOfTypeAndName<MjBody>(body2Name);
}
}
// Generate implementation specific XML element.
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
if (Body1 == null || Body2 == null) {
throw new NullReferenceException($"Both bodies in {name} must be assigned.");
}
var mjcf = (XmlElement)doc.CreateElement("exclude");
mjcf.SetAttribute("body1", Body1.MujocoName);
mjcf.SetAttribute("body2", Body2.MujocoName);
return mjcf;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 8d271c366e5c04a259f36a15b42f78a5
timeCreated: 1550051492
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+81
View File
@@ -0,0 +1,81 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class FixedTendonEntry {
[Tooltip("Only scalar joints can be used - hinge and slide.")]
public MjBaseJoint Joint;
[Tooltip("Multiplier for the value of the joint.")]
public float Coefficient = 1.0f;
}
public class MjFixedTendon : MjBaseTendon {
[Tooltip("In (scaled) radians/meters.")]
public float RangeLower;
[Tooltip("In (scaled) radians/meters.")]
public float RangeUpper;
public List<FixedTendonEntry> JointList = new List<FixedTendonEntry>() {};
protected override void FromMjcf(XmlElement mjcf) {
foreach (var child in mjcf.Cast<XmlNode>().OfType<XmlElement>()) {
var fixedTendonEntry = new FixedTendonEntry();
fixedTendonEntry.Joint = child.GetObjectReferenceAttribute<MjBaseJoint>("joint");
fixedTendonEntry.Coefficient = child.GetFloatAttribute("coef", defaultValue: 1.0f);
JointList.Add(fixedTendonEntry);
}
var rangeValues = mjcf.GetFloatArrayAttribute("range", defaultValue: new float[] { 0, 0 });
RangeLower = rangeValues[0];
RangeUpper = rangeValues[1];
}
protected override XmlElement ToMjcf(XmlDocument doc) {
if (JointList.Count < 1) {
throw new ArgumentOutOfRangeException($"Fixed tendon {name} needs at least one joint.");
}
var mjcf = doc.CreateElement("fixed");
foreach (FixedTendonEntry fixedTendonEntry in JointList) {
var jointMjcf = doc.CreateElement("joint");
jointMjcf.SetAttribute("joint", fixedTendonEntry.Joint.MujocoName);
jointMjcf.SetAttribute("coef", $"{fixedTendonEntry.Coefficient}");
mjcf.AppendChild(jointMjcf);
}
if (RangeLower > RangeUpper) {
throw new ArgumentException("Lower range value can't be bigger than Higher");
}
mjcf.SetAttribute("range", $"{RangeLower} {RangeUpper}");
return mjcf;
}
public void OnValidate() {
foreach (FixedTendonEntry fixedTendonEntry in JointList) {
if (!(fixedTendonEntry.Joint is MjHingeJoint) &&
!(fixedTendonEntry.Joint is MjSlideJoint)) {
Debug.LogError("Only scalar joints (hinge or slide) are allowed.", this);
fixedTendonEntry.Joint = null;
}
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: e49529c3d80714a368699287bbdd8f72
timeCreated: 1549990455
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+29
View File
@@ -0,0 +1,29 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// The component represents a joint with 6 degrees of freedom.
public class MjFreeJoint : MjBaseJoint {
protected override void OnParseMjcf(XmlElement mjcf) {}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
return (XmlElement)doc.CreateElement("freejoint");
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 7ef627bd3075d42d886135a149a187a2
timeCreated: 1537540954
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+96
View File
@@ -0,0 +1,96 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// The component represents a physical shape and models its inertia and material properties.
public class MjGeom : MjShapeComponent {
[Tooltip("If larger than zero, Density has no effect.")]
public float Mass = 0.0f;
[Tooltip("Material density. Set to 0 for a zero-mass geom.")]
public float Density = 1000.0f;
[Tooltip("Advanced settings.")]
public MjGeomSettings Settings = MjGeomSettings.Default;
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_GEOM;
private MjTransformation _geomInGlobalFrame = new MjTransformation();
private MjTransformation _comTransform;
protected override void OnParseMjcf(XmlElement mjcf) {
ShapeFromMjcf(mjcf);
Mass = mjcf.GetFloatAttribute("mass", defaultValue: 0.0f);
Density = mjcf.GetFloatAttribute("density", defaultValue: 1000.0f);
MjEngineTool.ParseTransformMjcf(mjcf, transform);
Settings.FromMjcf(mjcf);
}
// The MuJoCo compiler shifts meshes' frames, so we need to cache this transformation at init and
// apply it at runtime.
protected override unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
var MjParent = MjHierarchyTool.FindParentComponent<MjBaseBody>(this);
if (MjParent != null) {
var comInParentFrame = new MjTransformation(
translation: MjEngineTool.UnityVector3(model->geom_pos, MujocoId),
rotation: MjEngineTool.UnityQuaternion(model->geom_quat, MujocoId));
// We don't want to bother calculating global transform in mujoco from mjModel,
// so we'll assume it's the same as the Unity transfor (it's the beginning of simulation after
// all).
var globalParentFrame = MjTransformation.LoadGlobal(transform.parent);
var comInGlobalFrame = globalParentFrame * comInParentFrame;
var globalFrame = MjTransformation.LoadGlobal(transform);
_comTransform = comInGlobalFrame.Inverse() * globalFrame;
}
}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("geom");
if (Mass > 0) {
mjcf.SetAttribute("mass", $"{Mass}");
} else {
mjcf.SetAttribute("density", $"{Density}");
}
ShapeToMjcf(mjcf, transform);
MjEngineTool.PositionRotationToMjcf(mjcf, this);
Settings.ToMjcf(mjcf);
return mjcf;
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
if (ShapeType == ShapeTypes.Mesh) {
_geomInGlobalFrame.Set(
translation: MjEngineTool.UnityVector3(data->geom_xpos, MujocoId),
rotation: MjEngineTool.UnityQuaternionFromMatrix(data->geom_xmat, MujocoId));
var comInGlobalFrame = _geomInGlobalFrame * _comTransform;
comInGlobalFrame.StoreGlobal(transform);
} else {
transform.position = MjEngineTool.UnityVector3(data->geom_xpos, MujocoId);
transform.rotation = MjEngineTool.UnityQuaternionFromMatrix(data->geom_xmat, MujocoId);
}
}
public void OnDrawGizmosSelected() {
Gizmos.color = Color.blue;
DrawGizmos(transform);
}
}
}
+13
View File
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: ba8757a90afe442d9acfbd600758b843
timeCreated: 1536743564
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,47 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjGeomQuaternionSensor : MjBaseSensor {
public MjGeom Geom;
public Quaternion SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Geom == null) {
throw new NullReferenceException("Missing a reference to a MjGeom.");
}
var mjcf = doc.CreateElement("framequat");
mjcf.SetAttribute("objtype", "geom");
mjcf.SetAttribute("objname", Geom.MujocoName);
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
Geom = mjcf.GetObjectReferenceAttribute<MjGeom>("objname");
if (Geom == null) {
throw new NullReferenceException("Missing a reference to a MjGeom.");
}
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = MjEngineTool.UnityQuaternion(data->sensordata, _sensorAddress);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 71b28b4bc4c27423aaba5b98863e0c92
timeCreated: 1548170856
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+148
View File
@@ -0,0 +1,148 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// Advanced settings of MjGeom component.
[Serializable]
public struct MjGeomSettings {
[Tooltip("Solver accuracy settings.")]
public GeomSolver Solver;
[Tooltip("Collision filtering settings.")]
public CollisionFiltering Filtering;
[Tooltip("Contact friction parameters for dynamically generated contact pairs.")]
public GeomFriction Friction;
// Default geom settings.
public static MjGeomSettings Default = new MjGeomSettings() {
Solver = GeomSolver.Default,
Filtering = CollisionFiltering.Default,
Friction = GeomFriction.Default
};
public void FromMjcf(XmlElement mjcf) {
// Contact filtering settings.
Filtering.Contype = (int)mjcf.GetFloatAttribute("contype", CollisionFiltering.Default.Contype);
Filtering.Conaffinity = (int)mjcf.GetFloatAttribute(
"conaffinity", CollisionFiltering.Default.Conaffinity);
Filtering.Group = (int)mjcf.GetFloatAttribute("group", CollisionFiltering.Default.Group);
// Solver settings.
Solver.ConDim = (int)mjcf.GetFloatAttribute("condim", GeomSolver.Default.ConDim);
Solver.SolMix = mjcf.GetFloatAttribute("solmix", GeomSolver.Default.SolMix);
var solref = mjcf.GetFloatArrayAttribute(
"solref", new float[] { GeomSolver.Default.SolRef.TimeConst,
GeomSolver.Default.SolRef.DampRatio });
Solver.SolRef.TimeConst = solref[0];
Solver.SolRef.DampRatio = solref[1];
var solimp = mjcf.GetFloatArrayAttribute(
"solimp", new float[] { GeomSolver.Default.SolImp.DMin, GeomSolver.Default.SolImp.DMax,
GeomSolver.Default.SolImp.Width });
Solver.SolImp.DMin = solimp[0];
Solver.SolImp.DMax = solimp[1];
Solver.SolImp.Width = solimp[2];
Solver.Margin = mjcf.GetFloatAttribute("margin", GeomSolver.Default.Margin);
Solver.Gap = mjcf.GetFloatAttribute("gap", GeomSolver.Default.Gap);
// Inertia and friction settings.
var friction = mjcf.GetFloatArrayAttribute(
"friction", new float[] { GeomFriction.Default.Sliding, GeomFriction.Default.Torsional,
GeomFriction.Default.Rolling });
Friction.Sliding = friction[0];
Friction.Torsional = friction[1];
Friction.Rolling = friction[2];
}
public void ToMjcf(XmlElement mjcf) {
// Contact filtering settings.
mjcf.SetAttribute("contype", $"{Filtering.Contype}");
mjcf.SetAttribute("conaffinity", $"{Filtering.Conaffinity}");
mjcf.SetAttribute("group", $"{Filtering.Group}");
// Solver settings.
mjcf.SetAttribute("condim", $"{Solver.ConDim}");
mjcf.SetAttribute("solmix", $"{Solver.SolMix}");
mjcf.SetAttribute("solref", $"{Solver.SolRef.TimeConst} {Solver.SolRef.DampRatio}");
mjcf.SetAttribute(
"solimp", $"{Solver.SolImp.DMin} {Solver.SolImp.DMax} {Solver.SolImp.Width}");
mjcf.SetAttribute("margin", $"{Solver.Margin}");
mjcf.SetAttribute("gap", $"{Solver.Gap}");
// Inertia and friction settings.
mjcf.SetAttribute("friction", $"{Friction.Sliding} {Friction.Torsional} {Friction.Rolling}");
}
}
[Serializable]
public struct GeomFriction {
public float Sliding;
public float Torsional;
public float Rolling;
public static GeomFriction Default = new GeomFriction {
Sliding = 1.0f, Torsional = 0.005f, Rolling = 0.0001f
};
}
[Serializable]
public struct CollisionFiltering {
[Tooltip("Bitmasks used for contact filtering of dynamically generated contact pairs.")]
public int Contype;
[Tooltip("Bitmask for contact filtering")]
public int Conaffinity;
// The only effect on the physics is at compile time, when body masses and inertias are inferred
// from geoms selected based on their group.
[Tooltip("Group to which the geom belongs.")]
public int Group;
public static CollisionFiltering Default = new CollisionFiltering() {
Contype = 1, Conaffinity = 1, Group = 0
};
}
[Serializable]
public struct GeomSolver {
[Tooltip("The dimensionality of the contact space.")]
public int ConDim;
[Tooltip("Weight used for averaging of constraint solver parameters.")]
public float SolMix;
[Tooltip("Solver function d(r) reference parameters.")]
public SolverReference SolRef;
[Tooltip("Solver function d(r) impedance parameters.")]
public SolverImpedance SolImp;
[Tooltip("Distance threshold below which contacts are detected.")]
public float Margin;
[Tooltip("Positive value enables generation of inactive contacts.")]
public float Gap;
public static GeomSolver Default = new GeomSolver() {
ConDim = 3, SolMix = 1.0f, SolRef = SolverReference.Default, SolImp = SolverImpedance.Default,
Margin = 0.0f, Gap = 0.0f
};
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: d472b07eedb654ed5a83bfd6822587a3
timeCreated: 1538655839
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,63 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjGeomVectorSensor : MjBaseSensor {
// NOTE: These names must match sensor names listed on mujoco.org.
// Changing them is justified only when Mujoco is upgraded to a new version.
public enum AvailableSensors {
FramePos,
FrameXAxis,
FrameYAxis,
FrameZAxis,
FrameLinVel,
FrameAngVel,
FrameLinAcc,
FrameAngAcc,
}
public AvailableSensors SensorType;
public MjGeom Geom;
public Vector3 SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Geom == null) {
throw new NullReferenceException("Missing a reference to a MjGeom.");
}
var mjcf = doc.CreateElement(SensorType.ToString().ToLower());
mjcf.SetAttribute("objtype", "geom");
mjcf.SetAttribute("objname", Geom.MujocoName);
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
if (!Enum.TryParse(mjcf.Name, ignoreCase: true, result: out SensorType)) {
throw new ArgumentException($"Unknown sensor type {mjcf.Name}.");
}
Geom = mjcf.GetObjectReferenceAttribute<MjGeom>("objname");
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = MjEngineTool.UnityVector3(data->sensordata, _sensorAddress);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: c63b35fff51454145b2c5cabf4a81669
timeCreated: 1548107238
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+116
View File
@@ -0,0 +1,116 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using UnityEngine;
namespace Mujoco {
// Additional Debug Gizmos.
public static class MjGizmos {
private const float _vectorPerpendicularityMagnitudeThreshold = 1e-6f;
public static int NumCircleSegments = 32;
private static Vector3[] _circumferenceVertices = new Vector3[] {
Vector3.right, -Vector3.right, Vector3.forward, -Vector3.forward,
};
public static Action<Vector3 /*from*/, Vector3 /*to*/> DrawLine { get; set; } = Gizmos.DrawLine;
public static Action<Vector3 /*position*/, float /*radius*/, Vector3 /*axis*/, float /*length*/,
float /*startAngle*/> DrawArc { get; set; } = MjGizmos.DrawArcInternal;
// Draws a wireframe capsule of the specified radius and height.
// The capsule's height will be aligned with the global Y axis.
// The specified height represents the height of the cylinder between two hemisphere bases.
public static void DrawWireCapsule(Vector3 position, float radius, float height) {
var offset = DrawHollowWireCylinder(position, radius, height);
// Arches marking the bases of the capsule.
DrawArc(position - offset, radius, Vector3.right, 0.5f, 0.0f);
DrawArc(position + offset, radius, Vector3.right, 0.5f, 180.0f);
DrawArc(position + offset, radius, Vector3.forward, 0.5f, -90.0f);
DrawArc(position - offset, radius, Vector3.forward, 0.5f, 90.0f);
}
// Draws a wireframe cylinder of the specified radius and height.
// The cylinder's height will be aligned with the global Y axis.
public static void DrawWireCylinder(Vector3 position, float radius, float height) {
var offset = DrawHollowWireCylinder(position, radius, height);
// Lines marking the bases of the cylinder.
for (var i = 0; i < _circumferenceVertices.Length / 2; ++i) {
var vertex = _circumferenceVertices[i * 2] * radius;
var nextVertex = _circumferenceVertices[i * 2 + 1] * radius;
DrawLine(position + offset + vertex, position + offset + nextVertex);
DrawLine(position - offset + vertex, position - offset + nextVertex);
}
}
private static Vector3 DrawHollowWireCylinder(Vector3 position, float radius, float height) {
var offset = Vector3.up * (height * 0.5f);
// Cylinder bases.
DrawArc(position + offset, radius, Vector3.up, 1.0f, 0.0f);
DrawArc(position - offset, radius, Vector3.up, 1.0f, 0.0f);
// Lines marking the sides of the cylinder.
for (var i = 0; i < _circumferenceVertices.Length; ++i) {
// Lines marking the sides of the cylinder.
var vertex = _circumferenceVertices[i] * radius;
DrawLine(position + offset + vertex, position - offset + vertex);
}
return offset;
}
// Draws an arc in the XZ plane.
// 'length' parameter, in range (0, 1], allows to define how much of the circumference should be
// drawn. In other words, it allows to draw arbitrary arcs.
// Two additional parameters, 'axis' and 'startAngle', allow to orient the figure without having
// to manipulate the value of Gizmos.matrix.
public static void DrawArcInternal(
Vector3 position, float radius, Vector3 axis, float length, float startAngle) {
var deltaAngle = 360.0f / NumCircleSegments;
var numSegments = Math.Ceiling(length * NumCircleSegments);
var perpendicular = Vector3.Cross(axis, Vector3.right);
if (perpendicular.magnitude <= _vectorPerpendicularityMagnitudeThreshold) {
perpendicular = Vector3.Cross(axis, Vector3.up);
}
perpendicular.Normalize();
var offset = perpendicular * radius;
var start = Quaternion.AngleAxis(startAngle, axis) * offset;
var angle = startAngle + deltaAngle;
for (var segment = 0; segment < numSegments; ++segment, angle += deltaAngle) {
var end = Quaternion.AngleAxis(angle, axis) * offset;
DrawLine(position + start, position + end);
start = end;
}
}
public static void DrawWirePlane(Vector3 position, float width, float height) {
var quadPoints = new Vector3[] {
new Vector3(-0.5f * width, 0, -0.5f * height),
new Vector3(0.5f * width, 0, -0.5f * height),
new Vector3(0.5f * width, 0, 0.5f * height),
new Vector3(-0.5f * width, 0, 0.5f * height),
new Vector3(-0.5f * width, 0, -0.5f * height),
new Vector3(0.5f * width, 0, 0.5f * height),
};
for (var i = 0; i < quadPoints.Length - 1; ++i) {
DrawLine(position + quadPoints[i], position + quadPoints[i + 1]);
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: f9b1794ad59f445418c86157f57519bd
timeCreated: 1536771527
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,378 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using UnityEngine;
using UnityEngine.Profiling;
namespace Mujoco {
// The MuJoCo parser is case-sensitive. The case format of the entries in the enums below is
// exactly what the documentation specifies: http://mujoco.org/book/XMLreference.html#option .
public enum IntegratorType {
Euler,
RK4
}
public enum CollisionCheckType {
all
}
public enum FrictionConeType {
pyramidal,
elliptic
}
public enum JacobianType {
dense,
sparse,
auto
}
public enum ConstraintSolverType {
PGS,
CG,
Newton
}
public enum EnableDisableFlag {
enable,
disable
}
[Serializable]
public struct MjcfOptionFlag {
public EnableDisableFlag Constraint;
public EnableDisableFlag Equality;
public EnableDisableFlag FrictionLoss;
public EnableDisableFlag Limit;
public EnableDisableFlag Contact;
public EnableDisableFlag Passive;
public EnableDisableFlag Gravity;
public EnableDisableFlag ClampCtrl;
public EnableDisableFlag WarmStart;
public EnableDisableFlag FilterParent;
public EnableDisableFlag Actuation;
public EnableDisableFlag RefSafe;
public EnableDisableFlag Override;
public EnableDisableFlag Energy;
public EnableDisableFlag FwdInv;
public EnableDisableFlag SensorNoise;
public static MjcfOptionFlag Default = new MjcfOptionFlag() {
Constraint = EnableDisableFlag.enable,
Equality = EnableDisableFlag.enable,
FrictionLoss = EnableDisableFlag.enable,
Limit = EnableDisableFlag.enable,
Contact = EnableDisableFlag.enable,
Passive = EnableDisableFlag.enable,
Gravity = EnableDisableFlag.enable,
ClampCtrl = EnableDisableFlag.enable,
WarmStart = EnableDisableFlag.enable,
FilterParent = EnableDisableFlag.enable,
Actuation = EnableDisableFlag.enable,
RefSafe = EnableDisableFlag.enable,
Override = EnableDisableFlag.disable,
Energy = EnableDisableFlag.disable,
FwdInv = EnableDisableFlag.disable,
SensorNoise = EnableDisableFlag.disable
};
public void FromMjcf(XmlElement mjcf) {
var localDefault = MjcfOptionFlag.Default;
Constraint = mjcf.GetEnumAttribute<EnableDisableFlag>("constraint", localDefault.Constraint);
Equality = mjcf.GetEnumAttribute<EnableDisableFlag>("equality", localDefault.Equality);
FrictionLoss = mjcf.GetEnumAttribute<EnableDisableFlag>("frictionloss",
localDefault.FrictionLoss);
Limit = mjcf.GetEnumAttribute<EnableDisableFlag>("limit", localDefault.Limit);
Contact = mjcf.GetEnumAttribute<EnableDisableFlag>("contact", localDefault.Contact);
Passive = mjcf.GetEnumAttribute<EnableDisableFlag>("passive", localDefault.Passive);
Gravity = mjcf.GetEnumAttribute<EnableDisableFlag>("gravity", localDefault.Gravity);
ClampCtrl = mjcf.GetEnumAttribute<EnableDisableFlag>("clampctrl", localDefault.ClampCtrl);
WarmStart = mjcf.GetEnumAttribute<EnableDisableFlag>("warmstart", localDefault.WarmStart);
FilterParent = mjcf.GetEnumAttribute<EnableDisableFlag>("filterparent",
localDefault.FilterParent);
Actuation = mjcf.GetEnumAttribute<EnableDisableFlag>("actuation", localDefault.Actuation);
RefSafe = mjcf.GetEnumAttribute<EnableDisableFlag>("refsafe", localDefault.RefSafe);
Override = mjcf.GetEnumAttribute<EnableDisableFlag>("override", localDefault.Override);
Energy = mjcf.GetEnumAttribute<EnableDisableFlag>("energy", localDefault.Energy);
FwdInv = mjcf.GetEnumAttribute<EnableDisableFlag>("fwdinv", localDefault.FwdInv);
SensorNoise = mjcf.GetEnumAttribute<EnableDisableFlag>("sensornoise", localDefault.SensorNoise);
}
public void ToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("constraint", Constraint.ToString());
mjcf.SetAttribute("equality", Equality.ToString());
mjcf.SetAttribute("frictionloss", FrictionLoss.ToString());
mjcf.SetAttribute("limit", Limit.ToString());
mjcf.SetAttribute("contact", Contact.ToString());
mjcf.SetAttribute("passive", Passive.ToString());
mjcf.SetAttribute("gravity", Gravity.ToString());
mjcf.SetAttribute("clampctrl", ClampCtrl.ToString());
mjcf.SetAttribute("warmstart", WarmStart.ToString());
mjcf.SetAttribute("filterparent", FilterParent.ToString());
mjcf.SetAttribute("actuation", Actuation.ToString());
mjcf.SetAttribute("refsafe", RefSafe.ToString());
mjcf.SetAttribute("override", Override.ToString());
mjcf.SetAttribute("energy", Energy.ToString());
mjcf.SetAttribute("fwdinv", FwdInv.ToString());
mjcf.SetAttribute("sensornoise", SensorNoise.ToString());
}
}
[Serializable]
public struct MjSizeStruct {
public int Njmax;
public int Nconmax;
public int Nstack;
public static MjSizeStruct Default = new MjSizeStruct() {
Njmax = 0,
Nconmax = 0,
Nstack = 0
};
public void ParseMjcf(XmlElement mjcf) {
var localDefault = MjSizeStruct.Default;
Njmax = (int)mjcf.GetFloatAttribute("njmax", localDefault.Njmax);
Nconmax = (int)mjcf.GetFloatAttribute("nconmax", localDefault.Nconmax);
Nstack = (int)mjcf.GetFloatAttribute("nstack", localDefault.Nstack);
}
public XmlElement ToMjcf(XmlElement mjcf) {
if (Njmax > 0) {
mjcf.SetAttribute("njmax", $"{Njmax}");
}
if (Nconmax > 0) {
mjcf.SetAttribute("nconmax", $"{Nconmax}");
}
if (Nstack > 0) {
mjcf.SetAttribute("nstack", $"{Nstack}");
}
return mjcf;
}
}
[Serializable]
public struct MjOptionStruct {
// "timestep" and "gravity" come from global settings.
// "apirate" is only relevant to HAPTIX.
[Tooltip("Ratio of frictional-to-normal constraint impedance.")]
public float ImpRatio;
[Tooltip("Global magnetic flux used by magnetometer sensors.")]
public Vector3 Magnetic;
[Tooltip("Velocity vector of the medium, scales with the values of Density and Viscosity below.")]
public Vector3 Wind;
[Tooltip("Density of the medium for lift and drag forces. 0 disables lift and drag forces.")]
public float Density;
[Tooltip("Viscosity of the medium for viscous forces. 0 disables viscous forces.")]
public float Viscosity;
[Tooltip("Contact pair margin used when ContactOverride flag is set.")]
public float OverrideMargin;
[Tooltip("Contact pair solref used when ContactOverride flag is set.")]
public SolverReference OverrideSolRef;
[Tooltip("Contact pair solimp used when ContactOverride flag is set.")]
public SolverImpedance OverrideSolImp;
[Tooltip("Numerical integrator.")]
public IntegratorType Integrator;
[Tooltip("What collision types should be checked.")]
public CollisionCheckType Collision;
[Tooltip("How to model the friction cone.")]
public FrictionConeType Cone;
[Tooltip("How to represent the constraint Jacobian.")]
public JacobianType Jacobian;
[Tooltip("Constraint solver algorithm.")]
public ConstraintSolverType Solver;
[Tooltip("Maximum iterations for the constraint solver.")]
public int Iterations;
[Tooltip("Threshold used for early termination of the constraint solver.")]
public float Tolerance;
[Tooltip("Maximum iterations for the no-slip phase of the constraint solver.")]
public int NoSlipIterations;
[Tooltip("Threshold used for early termination of the Noslip solver.")]
public float NoSlipTolerance;
[Tooltip("Maximum iterations for convex mesh collisions.")]
public int MprIterations;
[Tooltip("Threshold used for early termination of the MPR algorithm.")]
public float MprTolerance;
public MjcfOptionFlag Flag;
// Default values copied from the "XML reference" page in the MuJoCo documentation.
public static MjOptionStruct Default = new MjOptionStruct() {
ImpRatio = 1.0f,
Magnetic = Vector3.zero,
Wind = new Vector3(0.0f, -0.5f, 0.0f),
Density = 0.0f,
Viscosity = 0.0f,
OverrideMargin = 0.0f,
OverrideSolRef = SolverReference.Default,
OverrideSolImp = SolverImpedance.Default,
Integrator = IntegratorType.Euler,
Collision = CollisionCheckType.all,
Cone = FrictionConeType.pyramidal,
Jacobian = JacobianType.auto,
Solver = ConstraintSolverType.Newton,
Iterations = 100,
Tolerance = 1e-8f,
NoSlipIterations = 0,
NoSlipTolerance = 1e-6f,
MprIterations = 50,
MprTolerance = 1e-6f,
Flag = MjcfOptionFlag.Default
};
public void ParseMjcf(XmlElement mjcf) {
if (mjcf.HasAttribute("timestep")) {
var mjTimestep = mjcf.GetFloatAttribute("timestep", Time.fixedDeltaTime);
if (mjTimestep != Time.fixedDeltaTime) {
Debug.unityLogger.LogWarning(
"MuJoCo",
$"MuJoCo's timestep ({mjTimestep}s) ignored, please set fixedDeltaTime manually.",
null);
}
}
if (mjcf.HasAttribute("gravity")) {
var mjGravity = mjcf.GetVector3Attribute("gravity", Vector3.zero);
Debug.unityLogger.LogWarning(
"MuJoCo",
$"MuJoCo's gravity ({mjGravity.x} {mjGravity.z} {mjGravity.y}) ignored, " +
"please set gravity in the Physics Manager.",
null);
}
var localDefault = MjOptionStruct.Default;
ImpRatio = mjcf.GetFloatAttribute("impratio", localDefault.ImpRatio);
Magnetic = mjcf.GetVector3Attribute("magnetic", localDefault.Magnetic);
Wind = mjcf.GetVector3Attribute("wind", localDefault.Wind);
Density = mjcf.GetFloatAttribute("density", localDefault.Density);
Viscosity = mjcf.GetFloatAttribute("viscosity", localDefault.Viscosity);
OverrideMargin = mjcf.GetFloatAttribute("o_margin", localDefault.OverrideMargin);
OverrideSolRef.FromMjcf(mjcf, "o_solref");
OverrideSolImp.FromMjcf(mjcf, "o_solimp");
Integrator = mjcf.GetEnumAttribute<IntegratorType>("integrator", localDefault.Integrator);
Collision = mjcf.GetEnumAttribute<CollisionCheckType>("collision", localDefault.Collision);
Cone = mjcf.GetEnumAttribute<FrictionConeType>("cone", localDefault.Cone);
Jacobian = mjcf.GetEnumAttribute<JacobianType>("jacobian", localDefault.Jacobian);
Solver = mjcf.GetEnumAttribute<ConstraintSolverType>("solver", localDefault.Solver);
Iterations = (int)mjcf.GetFloatAttribute("iterations", localDefault.Iterations);
Tolerance = mjcf.GetFloatAttribute("tolerance", localDefault.Tolerance);
NoSlipIterations = (int)mjcf.GetFloatAttribute(
"noslip_iterations", localDefault.NoSlipIterations);
NoSlipTolerance = mjcf.GetFloatAttribute("noslip_tolerance", localDefault.NoSlipTolerance);
MprIterations = (int)mjcf.GetFloatAttribute("mpr_iterations", localDefault.MprIterations);
MprTolerance = mjcf.GetFloatAttribute("mpr_tolerance", localDefault.MprTolerance);
var flagElements = mjcf.GetElementsByTagName("flag");
if (flagElements.Count == 1) {
Flag.FromMjcf(flagElements[0] as XmlElement);
} else if (flagElements.Count > 1) {
throw new ArgumentException("More than one <flag> node is not supported.");
}
}
public XmlElement ToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("impratio", $"{ImpRatio}");
mjcf.SetAttribute("magnetic", $"{Magnetic.x} {Magnetic.y} {Magnetic.z}");
mjcf.SetAttribute("wind", $"{Wind.x} {Wind.y} {Wind.z}");
mjcf.SetAttribute("density", $"{Density}");
mjcf.SetAttribute("viscosity", $"{Viscosity}");
mjcf.SetAttribute("o_margin", $"{OverrideMargin}");
OverrideSolRef.ToMjcf(mjcf, "o_solref");
OverrideSolImp.ToMjcf(mjcf, "o_solimp");
mjcf.SetAttribute("integrator", Integrator.ToString());
mjcf.SetAttribute("collision", Collision.ToString());
mjcf.SetAttribute("cone", Cone.ToString());
mjcf.SetAttribute("jacobian", Jacobian.ToString());
mjcf.SetAttribute("solver", Solver.ToString());
mjcf.SetAttribute("iterations", $"{Iterations}");
mjcf.SetAttribute("tolerance", $"{Tolerance}");
mjcf.SetAttribute("noslip_iterations", $"{NoSlipIterations}");
mjcf.SetAttribute("noslip_tolerance", $"{NoSlipTolerance}");
mjcf.SetAttribute("mpr_iterations", $"{MprIterations}");
mjcf.SetAttribute("mpr_tolerance", $"{MprTolerance}");
var flags = (XmlElement)mjcf.AppendChild(
mjcf.OwnerDocument.CreateElement("flag"));
Flag.ToMjcf(flags);
return mjcf;
}
}
public class MjGlobalSettings : MonoBehaviour {
[Tooltip("Filename for the generated scene XML.")]
public string DebugFileName;
[Tooltip("Scales the force applied by the mouse spring.")]
public float MouseSpringStiffness = 100;
public MjOptionStruct GlobalOptions = MjOptionStruct.Default;
public MjSizeStruct GlobalSizes = MjSizeStruct.Default;
public static MjGlobalSettings Instance {
get {
if (_instance == null) {
var instances = FindObjectsOfType<MjGlobalSettings>();
if (instances.Length > 1) {
throw new InvalidOperationException(
"Only one MjGlobalSettings instance is allowed - please resolve manually.");
} else if (instances.Length == 1) {
_instance = instances[0];
}
}
return _instance;
}
}
private static MjGlobalSettings _instance = null;
public void Awake() {
if (_instance == null) {
_instance = this;
} else if (_instance != this) {
throw new InvalidOperationException(
"At most one MjGlobalSettings should be present.");
}
}
public void ParseOptionSizeMjcf(XmlElement option, XmlElement size) {
if (option != null) {
GlobalOptions.ParseMjcf(option);
}
if (size != null) {
GlobalSizes.ParseMjcf(size);
}
}
public void OptionSizeToMjcf(XmlElement option, XmlElement size) {
GlobalOptions.ToMjcf(option);
GlobalSizes.ToMjcf(size);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: aafd577af429d4011831f681fe16df0b
timeCreated: 1548950233
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+88
View File
@@ -0,0 +1,88 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjHingeJoint : MjBaseJoint {
[Tooltip("In degrees.")]
public float RangeLower;
[Tooltip("In degrees.")]
public float RangeUpper;
[Tooltip("The current joint angle, in degrees. Read-only at play time.")]
public float Configuration;
[Tooltip("Joint movement, in rad/sec. Read-only at play time.")]
public float Velocity;
[Tooltip("Joint settings.")]
public MjJointSettings Settings = MjJointSettings.Default;
// World space rotation axis.
public Vector3 RotationAxis => transform.rotation * Vector3.right;
protected override unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
base.OnBindToRuntime(model, data);
data->qvel[DofAddress] = Velocity;
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
var qpos = (float)data->qpos[QposAddress];
Configuration = (qpos % (2 * Mathf.PI)) * Mathf.Rad2Deg;
Velocity = (float)data->qvel[DofAddress];
}
protected override void OnParseMjcf(XmlElement mjcf) {
transform.localPosition =
MjEngineTool.UnityVector3(mjcf.GetVector3Attribute("pos", defaultValue: Vector3.zero));
var rotationAxis =
MjEngineTool.UnityVector3(mjcf.GetVector3Attribute("axis", defaultValue: Vector3.right));
transform.localRotation = Quaternion.FromToRotation(Vector3.right, rotationAxis);
var rangeValues = mjcf.GetFloatArrayAttribute("range", defaultValue: new float[] { 0, 0 });
RangeLower = rangeValues[0];
RangeUpper = rangeValues[1];
if (!MjSceneImportSettings.AnglesInDegrees) {
RangeLower *= Mathf.Rad2Deg;
RangeUpper *= Mathf.Rad2Deg;
}
Configuration = mjcf.GetFloatAttribute("ref", 0.0f);
Settings.FromMjcf(mjcf);
}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("joint");
mjcf.SetAttribute("type", "hinge");
MjEngineTool.PositionAxisToMjcf(mjcf, this);
Settings.ToMjcf(mjcf);
if (RangeLower > RangeUpper) {
throw new ArgumentException("Lower range value can't be bigger than Higher");
}
mjcf.SetAttribute("range", $"{RangeLower} {RangeUpper}");
mjcf.SetAttribute("ref", $"{Configuration}");
return mjcf;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 517cde9d618b143a19f0ad61355a7f31
timeCreated: 1537542636
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+64
View File
@@ -0,0 +1,64 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// Defines an inertial frame of a body.
public class MjInertial : MjComponent {
[Tooltip("Mass assigned to the parent body.")]
public float Mass = 1.0f;
[Tooltip("Diagonal inertia matrix, expressing the body inertia relative to the inertial frame.")]
public Vector3 DiagInertia = Vector3.one;
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_BODY;
protected override bool _suppressNameAttribute => true;
// Parse the component settings from an external Mjcf.
protected override void OnParseMjcf(XmlElement mjcf) {
MjEngineTool.ParseTransformMjcf(mjcf, transform);
Mass = mjcf.GetFloatAttribute("mass", defaultValue: 1.0f);
DiagInertia = MjEngineTool.UnityExtents(
mjcf.GetVector3Attribute("diaginertia", defaultValue: Vector3.one));
}
// Generate implementation specific XML element.
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("inertial");
MjEngineTool.PositionRotationToMjcf(mjcf, this);
mjcf.SetAttribute("mass", $"{Mass}");
mjcf.SetAttribute("diaginertia",
MjEngineTool.Vector3ToMjcf(MjEngineTool.MjExtents(DiagInertia)));
return mjcf;
}
protected void OnDrawGizmosSelected() {
Gizmos.color = Color.yellow;
var oldMatrix = Gizmos.matrix;
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);
var box = new Vector3(
Mathf.Sqrt((DiagInertia[1] + DiagInertia[2] - DiagInertia[0]) / Mass * 6.0f),
Mathf.Sqrt((DiagInertia[0] + DiagInertia[2] - DiagInertia[1]) / Mass * 6.0f),
Mathf.Sqrt((DiagInertia[0] + DiagInertia[1] - DiagInertia[2]) / Mass * 6.0f));
Gizmos.DrawWireCube(Vector3.zero, box);
Gizmos.matrix = oldMatrix;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 0fdc02620a5cf483ea8ca90a983aa0bc
timeCreated: 1550587293
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,59 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjJointConstraint : MjBaseConstraint {
[Tooltip("Mandatory.")]
public MjBaseJoint Joint1;
[Tooltip("Optional - if empty, constrain the value of Joint1")]
public MjBaseJoint Joint2;
public float[] PolynomialCoefficients = new float[5] { 0, 1, 0, 0, 0 };
protected override string _constraintName => "joint";
protected override void FromMjcf(XmlElement mjcf) {
Joint1 = mjcf.GetObjectReferenceAttribute<MjBaseJoint>("joint1");
Joint2 = mjcf.GetObjectReferenceAttribute<MjBaseJoint>("joint2");
PolynomialCoefficients =
mjcf.GetFloatArrayAttribute("polycoef", defaultValue: new float[] { 0, 1, 0, 0, 0 });
}
// Generate implementation specific XML element.
protected override void ToMjcf(XmlElement mjcf) {
if (Joint1 == null) {
throw new NullReferenceException($"At least Joint1 in constraint {name} must be assigned.");
}
mjcf.SetAttribute("joint1", Joint1.MujocoName);
if (Joint2 != null) {
mjcf.SetAttribute("joint2", Joint2.MujocoName);
}
mjcf.SetAttribute("polycoef", MjEngineTool.ArrayToMjcf(PolynomialCoefficients));
}
public void OnValidate() {
if (Joint1 != null && Joint1 == Joint2) {
Debug.LogError("Joint1 and Joint2 can't be the same - resetting Joint2.", this);
Joint2 = null;
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 1cf109d843189466880870d026d0c2c7
timeCreated: 1552309644
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,56 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjJointScalarSensor : MjBaseSensor {
// NOTE: These names must match sensor names listed on mujoco.org.
// Changing them is justified only when Mujoco is upgraded to a new version.
public enum AvailableSensors {
JointPos,
JointVel,
JointLimitPos,
JointLimitVel,
JointLimitFrc,
}
public AvailableSensors SensorType;
public MjBaseJoint Joint;
public double SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Joint == null) {
throw new NullReferenceException("Missing a reference to a Joint.");
}
var mjcf = doc.CreateElement(SensorType.ToString().ToLower());
mjcf.SetAttribute("joint", Joint.MujocoName);
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
if (!Enum.TryParse(mjcf.Name, ignoreCase: true, result: out SensorType)) {
throw new ArgumentException($"Unknown sensor type {mjcf.Name}.");
}
Joint = mjcf.GetObjectReferenceAttribute<MjBaseJoint>("joint");
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = data->sensordata[_sensorAddress];
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: a4f0b9237548c452e8a050f3e4cba63e
timeCreated: 1548092931
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+171
View File
@@ -0,0 +1,171 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public struct MjJointSettings {
[Tooltip("Added inertia of all DoFs created by this joint.")]
public float Armature;
[Tooltip("Joint spring settings.")]
public SpringSettings Spring;
[Tooltip("Joint solver settings.")]
public SolverSettings Solver;
// Default joint settings.
public static MjJointSettings Default = new MjJointSettings() {
Solver = SolverSettings.Default,
};
public void FromMjcf(XmlElement mjcf) {
Armature = mjcf.GetFloatAttribute("armature", 0.0f);
Spring.FromMjcf(mjcf);
Solver.FromMjcf(mjcf);
}
public void ToMjcf(XmlElement mjcf) {
mjcf.SetAttribute("armature", $"{Armature}");
Spring.ToMjcf(mjcf);
Solver.ToMjcf(mjcf);
}
}
[Serializable]
public struct SpringSettings {
public float TimeConstant;
public float DampingRatio;
[Tooltip("Joint stiffness. If this value is positive, a spring will be created.")]
public float Stiffness;
[Tooltip("Damping applied to all degrees of freedom created by this joint.")]
public float Damping;
[Tooltip("Spring equilibrium pose.")]
public float EquilibriumPose;
public void ToMjcf(XmlElement mjcf) {
// Spring settings.
mjcf.SetAttribute("springref", $"{EquilibriumPose}");
mjcf.SetAttribute("springdamper", $"{TimeConstant} {DampingRatio}");
mjcf.SetAttribute("damping", $"{Damping}");
mjcf.SetAttribute("stiffness", $"{Stiffness}");
}
public void FromMjcf(XmlElement mjcf) {
var springDamper = mjcf.GetVector2Attribute("springdamper", Vector2.zero);
TimeConstant = springDamper.x;
DampingRatio = springDamper.y;
EquilibriumPose = mjcf.GetFloatAttribute("springref", 0.0f);
Damping = mjcf.GetFloatAttribute("damping", 0.0f);
Stiffness = mjcf.GetFloatAttribute("stiffness", 0.0f);
}
}
[Serializable]
public struct SolverImpedance {
public float DMin;
public float DMax;
public float Width;
public float Midpoint;
public float Power;
public static SolverImpedance Default =
new SolverImpedance() { DMin = 0.9f, DMax = 0.95f, Width = 0.001f, Midpoint = 0.5f,
Power = 2.0f };
public void FromMjcf(XmlElement element, string attributeName) {
var values = element.GetFloatArrayAttribute(
attributeName, new float[] { Default.DMin, Default.DMax, Default.Width, Default.Midpoint,
Default.Power });
DMin = values[0];
DMax = values[1];
Width = values[2];
Midpoint = values[3];
Power = values[4];
}
public void ToMjcf(XmlElement element, string attributeName) {
element.SetAttribute(attributeName, $"{DMin} {DMax} {Width} {Midpoint} {Power}");
}
}
[Serializable]
public struct SolverReference {
public float TimeConst;
public float DampRatio;
public static SolverReference Default =
new SolverReference() { TimeConst = 0.02f, DampRatio = 1.0f };
public void FromMjcf(XmlElement element, string attributeName) {
var values = element.GetFloatArrayAttribute(
attributeName, new float[] { Default.TimeConst, Default.DampRatio });
TimeConst = values[0];
DampRatio = values[1];
}
public void ToMjcf(XmlElement element, string attributeName) {
element.SetAttribute(attributeName, $"{TimeConst} {DampRatio}");
}
}
[Serializable]
public struct SolverSettings {
[Tooltip("Does the joint have limits.")]
public bool Limited;
[Tooltip("Limit margin - always in radians/meters.")]
public float Margin;
public SolverReference RefLimit;
public SolverImpedance ImpLimit;
[Tooltip("Friction loss due to dry friction.")]
public float FrictionLoss;
public SolverImpedance ImpFriction;
public SolverReference RefFriction;
public static SolverSettings Default = new SolverSettings() {
ImpFriction = SolverImpedance.Default,
ImpLimit = SolverImpedance.Default,
RefFriction = SolverReference.Default,
RefLimit = SolverReference.Default,
};
public void ToMjcf(XmlElement mjcf) {
RefLimit.ToMjcf(mjcf, "solreflimit");
ImpLimit.ToMjcf(mjcf, "solimplimit");
RefFriction.ToMjcf(mjcf, "solreffriction");
ImpFriction.ToMjcf(mjcf, "solimpfriction");
mjcf.SetAttribute("frictionloss", $"{FrictionLoss}");
mjcf.SetAttribute("limited", $"{Limited}".ToLower());
mjcf.SetAttribute("margin", $"{Margin}");
}
public void FromMjcf(XmlElement mjcf) {
RefLimit.FromMjcf(mjcf, "solreflimit");
ImpLimit.FromMjcf(mjcf, "solimplimit");
RefFriction.FromMjcf(mjcf, "solreffriction");
ImpFriction.FromMjcf(mjcf, "solimpfriction");
FrictionLoss = mjcf.GetFloatAttribute("frictionloss", 0.0f);
Limited = mjcf.GetBoolAttribute("limited", false);
Margin = mjcf.GetFloatAttribute("margin", defaultValue: 0.0f);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: c02a22208190149a6a949f4247c77155
timeCreated: 1537542636
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+78
View File
@@ -0,0 +1,78 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace Mujoco {
[RequireComponent(typeof(MjShapeComponent))]
[RequireComponent(typeof(MeshFilter))]
[ExecuteInEditMode]
public class MjMeshFilter : MonoBehaviour {
private MjShapeComponent _geom;
private Vector4 _shapeChangeStamp;
private MeshFilter _meshFilter;
protected void Awake() {
_geom = GetComponent<MjShapeComponent>();
_shapeChangeStamp = new Vector4(0, 0, 0, -1);
_meshFilter = GetComponent<MeshFilter>();
}
protected void Update() {
var currentChangeStamp = _geom.GetChangeStamp();
if ((_shapeChangeStamp - currentChangeStamp).magnitude <= 1e-3f) {
return;
}
_shapeChangeStamp = currentChangeStamp;
Tuple<Vector3[], int[]> meshData = _geom.BuildMesh();
if (meshData == null) {
throw new ArgumentException("Unsupported geom shape detected");
}
DisposeCurrentMesh();
var mesh = new Mesh();
// Name this mesh to easily track resources in Unity analysis tools.
mesh.name = $"Mujoco mesh for {gameObject.name}, id:{mesh.GetInstanceID()}";
_meshFilter.sharedMesh = mesh;
mesh.vertices = meshData.Item1;
mesh.triangles = meshData.Item2;
mesh.RecalculateNormals();
mesh.RecalculateTangents();
}
protected void OnDestroy() {
DisposeCurrentMesh();
}
// Dynamically created meshes with no references are only disposed automatically on scene changes.
// This prevents resource leaks in case the host environment doesn't reload scenes.
private void DisposeCurrentMesh() {
if (_meshFilter.sharedMesh != null) {
#if UNITY_EDITOR
DestroyImmediate(_meshFilter.sharedMesh);
#else
Destroy(_meshFilter.sharedMesh);
#endif
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: c762400e63d394f6fa8f9f7885edb79e
timeCreated: 1539770521
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+56
View File
@@ -0,0 +1,56 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class MjMeshShape : IMjShape {
public Mesh Mesh;
public void ToMjcf(XmlElement mjcf, Transform transform) {
var scene = MjScene.Instance;
var assetName = scene.GenerationContext.AddMeshAsset(Mesh);
mjcf.SetAttribute("mesh", assetName);
}
public void FromMjcf(XmlElement mjcf) {
// When the asset was parsed and stored its name was sanitized, so we should load it using a
// sanitized name:
var assetName = MjEngineTool.Sanitize(
mjcf.GetStringAttribute("mesh", defaultValue: string.Empty));
if (!string.IsNullOrEmpty(assetName)) {
Mesh = (Mesh)Resources.Load(assetName);
}
}
public Tuple<Vector3[], int[]> BuildMesh() {
return Tuple.Create(Mesh.vertices, Mesh.triangles);
}
public Vector4 GetChangeStamp() {
return Vector4.one;
}
public void DebugDraw(Transform transform) {
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, transform.lossyScale);
Gizmos.DrawWireMesh(Mesh);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 74b6655bbc8424b73ab3428b5ea018e6
timeCreated: 1549902766
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+42
View File
@@ -0,0 +1,42 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjMocapBody : MjBaseBody {
protected override void OnParseMjcf(XmlElement mjcf) {
throw new Exception("parsing mocap bodies isn't supported.");
}
protected override unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
var bodyId = MujocoLib.mj_name2id(model, (int)ObjectType, MujocoName);
MujocoId = model->body_mocapid[bodyId];
}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = doc.CreateElement("body");
MjEngineTool.PositionRotationToMjcf(mjcf, this);
mjcf.SetAttribute("mocap", "true");
return mjcf;
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
MjEngineTool.SetMjVector3(data->mocap_pos, transform.position, MujocoId);
MjEngineTool.SetMjQuaternion(data->mocap_quat, transform.rotation, MujocoId);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 70484c223582e443890dac6faef67046
timeCreated: 1551357866
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+50
View File
@@ -0,0 +1,50 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class MjPlaneShape : IMjShape {
public Vector2 Extents = Vector3.one;
public void ToMjcf(XmlElement mjcf, Transform transform) {
var extents = new Vector3(Extents.x, Extents.y, 1.0f);
var scaledExtents = Vector3.Scale(extents, transform.lossyScale);
mjcf.SetAttribute("size", $"{scaledExtents.x} {scaledExtents.y} {scaledExtents.z}");
}
public void FromMjcf(XmlElement mjcf) {
var components = mjcf.GetFloatArrayAttribute("size", defaultValue: new float[] { 1, 1, 1 });
Extents = new Vector2(components[0], components[1]);
}
public Tuple<Vector3[], int[]> BuildMesh() {
return MeshGenerators.BuildPlane(Extents.x * 2.0f, Extents.y * 2.0f);
}
public Vector4 GetChangeStamp() {
return new Vector4(Extents.x, Extents.y, 1, 0);
}
public void DebugDraw(Transform transform) {
Gizmos.matrix = Matrix4x4.TRS(transform.position, transform.rotation, Vector3.one);
MjGizmos.DrawWirePlane(Vector3.zero, Extents.x * 2.0f, Extents.y * 2.0f);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 8f4c670eb5b2f4a97826a6a22705ed4d
timeCreated: 1547647081
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+451
View File
@@ -0,0 +1,451 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Xml;
using UnityEngine;
using UnityEngine.Profiling;
namespace Mujoco {
public class PhysicsRuntimeException : Exception {
public PhysicsRuntimeException(string message) : base(message) {}
}
public class MjScene : MonoBehaviour {
public unsafe MujocoLib.mjModel_* Model = null;
public unsafe MujocoLib.mjData_* Data = null;
// Public and global access to the active MjSceneGenerationContext.
// Throws an exception if accessed when the scene is not being generated.
public MjcfGenerationContext GenerationContext {
get {
if (_generationContext == null) {
throw new InvalidOperationException(
"This property can only be accessed from the scope of MjComponent.GenerateMjcf().");
}
return _generationContext;
}
}
public static MjScene Instance {
get {
if (_instance == null) {
var instances = FindObjectsOfType<MjScene>();
if (instances.Length >= 1) { // even one is too much - _instance shouldn't have been null.
throw new InvalidOperationException(
"A MjScene singleton is created automatically, yet multiple instances exist.");
} else {
GameObject go = new GameObject("MjScene");
_instance = go.AddComponent<MjScene>();
}
}
return _instance;
}
}
public void Awake() {
if (_instance == null) {
_instance = this;
} else if (_instance != this) {
throw new InvalidOperationException(
"MjScene is a singleton, yet multiple instances found.");
}
}
private static MjScene _instance = null;
private List<MjComponent> _orderedComponents;
protected unsafe void Start() {
CreateScene();
}
protected unsafe void OnDestroy() {
DestroyScene();
}
protected unsafe void FixedUpdate() {
StepScene();
}
public bool SceneRecreationAtLateUpdateRequested = false;
protected unsafe void LateUpdate() {
if (SceneRecreationAtLateUpdateRequested) {
RecreateScene();
SceneRecreationAtLateUpdateRequested = false;
}
}
// Context used during scene generation where components will store their shared dependencies
// (such as the mesh assets they reference, or common compiler settings that need to be resolved
// globally).
// The field will be initialized with a class instance only during the scene generation.
// A public read-only property will provide MjComponents with access to the instance
// of that field.
private MjcfGenerationContext _generationContext;
// Builds a new Mujoco scene.
public unsafe XmlDocument CreateScene(bool skipCompile=false) {
if (_generationContext != null) {
throw new InvalidOperationException(
"The scene is currently being generated on another thread.");
}
// Linearize the hierarchy of transforms of the components.
// We will use this list to update the transforms of the associated GameObject in a way that
// ensures we first update the parent transforms, and then we progress down the hierarchy
// tree and update the children.
// We're doing this, because we will use Unity's hierarchical transforms system to translate
// Mujoco elements' world transforms directly to Unity's world coordinates. That however
// will only work if we can guarantee that for every child, the parent transforms have already
// been recalculated.
//
// DESIGN: An alternative to that would be to operate in local space on the Unity side.
// I briefly explored that approach, but decided against it. It increases the amount of code
// on the side of the individual components. This solution allows to restrict the code in the
// components to a bare minimum, at the expense of one extra method here.
var hierarchyRoots = FindObjectsOfType<MjComponent>()
.Where(component => MjHierarchyTool.FindParentComponent(component) == null)
.Select(component => component.transform)
.Distinct();
_orderedComponents = new List<MjComponent>();
foreach (var root in hierarchyRoots) {
_orderedComponents.AddRange(MjHierarchyTool.LinearizeHierarchyBFS(root));
}
XmlDocument sceneMjcf = null;
try {
_generationContext = new MjcfGenerationContext();
sceneMjcf = GenerateSceneMjcf(_orderedComponents);
} catch (Exception e) {
_generationContext = null;
Debug.LogException(e);
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
throw;
}
_generationContext = null;
// Save the Mjcf to a file for debug purposes.
var settings = MjGlobalSettings.Instance;
if (settings && !string.IsNullOrEmpty(settings.DebugFileName)) {
SaveToFile(sceneMjcf, Path.Combine(Application.temporaryCachePath, settings.DebugFileName));
}
if (!skipCompile) {
// Compile the scene from the Mjcf.
CompileScene(sceneMjcf, _orderedComponents);
}
return sceneMjcf;
}
private unsafe void CompileScene(
XmlDocument mjcf, IEnumerable<MjComponent> components) {
Model = MjEngineTool.LoadModelFromString(mjcf.OuterXml);
if (Model == null) {
throw new NullReferenceException("Failed to create Mujoco runtime model.");
} else {
Data = MujocoLib.mj_makeData(Model);
}
if (Data == null) {
throw new NullReferenceException("Failed to create Mujoco runtime data.");
}
// Bind the components to their Mujoco counterparts.
foreach (var component in components) {
component.BindToRuntime(Model, Data);
}
}
public unsafe void SyncUnityToMjState() {
foreach (var component in _orderedComponents) {
if (component != null && component.isActiveAndEnabled) {
component.OnSyncState(Data);
}
}
}
// This must be called after every change in the Unity scene during runtime, in order to keep the
// MuJoCo physics scene in sync. The spatial arrangement in the MJCF that creates the new physics
// is defined by the Unity transforms; therefore, we:
// 1. cache the joint states;
// 2. reset the Unity scene to its configuration at initialization;
// 3. recreate the scene in this pristine configuration;
// 4. rehydrate the physics scene, and sync the Unity scene to it.
public unsafe void RecreateScene() {
// cache joint states in order to re-apply it to the new scene
var joints = FindObjectsOfType<MjBaseJoint>();
var positions = new Dictionary<MjBaseJoint, double[]>();
var velocities = new Dictionary<MjBaseJoint, double[]>();
foreach (var joint in joints) {
if (joint.QposAddress > -1) { // newly added components shouldn't be cached
switch (Model->jnt_type[joint.MujocoId]) {
default:
case (int)MujocoLib.mjtJoint.mjJNT_HINGE:
case (int)MujocoLib.mjtJoint.mjJNT_SLIDE:
positions[joint] = new double[] {Data->qpos[joint.QposAddress]};
velocities[joint] = new double[] {Data->qvel[joint.DofAddress]};
break;
case (int)MujocoLib.mjtJoint.mjJNT_BALL:
positions[joint] = new double[] {
Data->qpos[joint.QposAddress],
Data->qpos[joint.QposAddress+1],
Data->qpos[joint.QposAddress+2],
Data->qpos[joint.QposAddress+3]};
velocities[joint] = new double[] {
Data->qvel[joint.DofAddress],
Data->qvel[joint.DofAddress+1],
Data->qvel[joint.DofAddress+2]};
break;
case (int)MujocoLib.mjtJoint.mjJNT_FREE:
positions[joint] = new double[] {
Data->qpos[joint.QposAddress],
Data->qpos[joint.QposAddress+1],
Data->qpos[joint.QposAddress+2],
Data->qpos[joint.QposAddress+3],
Data->qpos[joint.QposAddress+4],
Data->qpos[joint.QposAddress+5],
Data->qpos[joint.QposAddress+6]};
velocities[joint] = new double[] {
Data->qvel[joint.DofAddress],
Data->qvel[joint.DofAddress+1],
Data->qvel[joint.DofAddress+2],
Data->qvel[joint.DofAddress+3],
Data->qvel[joint.DofAddress+4],
Data->qvel[joint.DofAddress+5]};
break;
}
}
}
// update unity transforms according to qpos0, so they're ready to create the new MJCF
MujocoLib.mj_resetData(Model, Data);
MujocoLib.mj_kinematics(Model, Data);
SyncUnityToMjState();
// Delete previous model, data
DestroyScene();
// Create a new MJCF and new model+data, indices may be different
CreateScene();
// for joints that persisted, set state of the new MuJoCo scene according to the cached state
foreach (var joint in joints) {
try {
var position = positions[joint]; // this will fail for new joints, hence try/catch
var velocity = velocities[joint];
switch (Model->jnt_type[joint.MujocoId]) {
default:
case (int)MujocoLib.mjtJoint.mjJNT_HINGE:
case (int)MujocoLib.mjtJoint.mjJNT_SLIDE:
Data->qpos[joint.QposAddress] = position[0];
Data->qvel[joint.DofAddress] = velocity[0];
break;
case (int)MujocoLib.mjtJoint.mjJNT_BALL:
Data->qpos[joint.QposAddress] = position[0];
Data->qpos[joint.QposAddress+1] = position[1];
Data->qpos[joint.QposAddress+2] = position[2];
Data->qpos[joint.QposAddress+3] = position[3];
Data->qvel[joint.DofAddress] = velocity[0];
Data->qvel[joint.DofAddress+1] = velocity[1];
Data->qvel[joint.DofAddress+2] = velocity[2];
break;
case (int)MujocoLib.mjtJoint.mjJNT_FREE:
Data->qpos[joint.QposAddress] = position[0];
Data->qpos[joint.QposAddress+1] = position[1];
Data->qpos[joint.QposAddress+2] = position[2];
Data->qpos[joint.QposAddress+3] = position[3];
Data->qpos[joint.QposAddress+4] = position[4];
Data->qpos[joint.QposAddress+5] = position[5];
Data->qpos[joint.QposAddress+6] = position[6];
Data->qvel[joint.DofAddress] = velocity[0];
Data->qvel[joint.DofAddress+1] = velocity[1];
Data->qvel[joint.DofAddress+2] = velocity[2];
Data->qvel[joint.DofAddress+3] = velocity[3];
Data->qvel[joint.DofAddress+4] = velocity[4];
Data->qvel[joint.DofAddress+5] = velocity[5];
break;
}
} catch {}
}
// update mj transforms:
MujocoLib.mj_kinematics(Model, Data);
SyncUnityToMjState();
}
// Destroys the Mujoco scene.
public unsafe void DestroyScene() {
if (Model != null) {
MujocoLib.mj_deleteModel(Model);
Model = null;
}
if (Data != null) {
MujocoLib.mj_deleteData(Data);
Data = null;
}
}
// Updates the scene and the state of Mujoco simulation.
public unsafe void StepScene() {
if (Model == null || Data == null) {
throw new NullReferenceException("Failed to create Mujoco runtime.");
}
Profiler.BeginSample("MjStep");
Profiler.BeginSample("MjStep.mj_step");
MujocoLib.mj_step(Model, Data);
Profiler.EndSample(); // MjStep.mj_step
CheckForPhysicsException();
Profiler.BeginSample("MjStep.OnSyncState");
SyncUnityToMjState();
Profiler.EndSample(); // MjStep.OnSyncState
Profiler.EndSample(); // MjStep
}
private unsafe void CheckForPhysicsException() {
if (Data->warning0.number > 0) {
Data->warning0.number = 0;
throw new PhysicsRuntimeException("INERTIA: (Near-) Singular inertia matrix.");
}
if (Data->warning1.number > 0) {
Data->warning1.number = 0;
throw new PhysicsRuntimeException($"CONTACTFULL: nconmax {Model->nconmax} isn't sufficient.");
}
if (Data->warning2.number > 0) {
Data->warning2.number = 0;
throw new PhysicsRuntimeException("CNSTRFULL: njmax {Model.njmax} isn't sufficient.");
}
if (Data->warning3.number > 0) {
Data->warning3.number = 0;
throw new PhysicsRuntimeException("VGEOMFULL: who constructed a mjvScene?!");
}
if (Data->warning4.number > 0) {
Data->warning4.number = 0;
throw new PhysicsRuntimeException("BADQPOS: NaN/inf in qpos.");
}
if (Data->warning5.number > 0) {
Data->warning5.number = 0;
throw new PhysicsRuntimeException("BADQVEL: NaN/inf in qvel.");
}
if (Data->warning6.number > 0) {
Data->warning6.number = 0;
throw new PhysicsRuntimeException("BADQACC: NaN/inf in qacc.");
}
if (Data->warning7.number > 0) {
Data->warning7.number = 0;
throw new PhysicsRuntimeException("BADCTRL: NaN/inf in ctrl.");
}
}
// Generate a Mujoco scene description using the specified components.
private XmlDocument GenerateSceneMjcf(IEnumerable<MjComponent> components) {
var doc = new XmlDocument();
var MjRoot = (XmlElement)doc.AppendChild(doc.CreateElement("mujoco"));
// Scene definition section.
var worldMjcf = (XmlElement)MjRoot.AppendChild(doc.CreateElement("worldbody"));
BuildHierarchicalMjcf(
doc,
components.Where(component =>
(component is MjBaseBody) ||
(component is MjInertial) ||
(component is MjBaseJoint) ||
(component is MjGeom) ||
(component is MjSite)),
worldMjcf);
// Non-hierarchical sections:
MjRoot.AppendChild(GenerateMjcfSection(
doc, components.Where(component => component is MjExclude), "contact"));
MjRoot.AppendChild(GenerateMjcfSection(
doc, components.Where(component => component is MjBaseTendon), "tendon"));
MjRoot.AppendChild(GenerateMjcfSection(
doc, components.Where(component => component is MjBaseConstraint), "equality"));
MjRoot.AppendChild(GenerateMjcfSection(
doc, components.Where(component => component is MjActuator), "actuator"));
MjRoot.AppendChild(GenerateMjcfSection(
doc, components.Where(component => component is MjBaseSensor), "sensor"));
// Generate the Mjcf of the runtime dependencies added to the context.
_generationContext.GenerateMjcf(MjRoot);
return doc;
}
private XmlElement GenerateMjcfSection(
XmlDocument doc, IEnumerable<MjComponent> components, string sectionName) {
var section = doc.CreateElement(sectionName);
foreach (var component in components) {
var componentMjcf = component.GenerateMjcf(_generationContext.GenerateName(component), doc);
section.AppendChild(componentMjcf);
}
return section;
}
private void BuildHierarchicalMjcf(
XmlDocument doc, IEnumerable<MjComponent> components, XmlElement worldMjcf) {
var associations = new Dictionary<MjComponent, XmlElement>();
// Build individual Mjcfs.
foreach (var component in components) {
var componentMjcf = component.GenerateMjcf(
_generationContext.GenerateName(component), doc);
// We'll use a dictionary to define associations between the components and the corresponding
// Mjcf elements.
associations.Add(component, componentMjcf);
}
// Connect the Mjcfs into hierarchy.
foreach (var component in components) {
var componentMjcf = associations[component];
var parentComponent = MjHierarchyTool.FindParentComponent(component);
if (parentComponent != null) {
var parentComponentMjcf = associations[parentComponent];
parentComponentMjcf.AppendChild(componentMjcf);
} else {
worldMjcf.AppendChild(componentMjcf);
}
}
}
// Saves an XML document to the specified file.
private void SaveToFile(XmlDocument document, string filePath) {
try {
using (var stream = File.Open(filePath, FileMode.Create)) {
using (var writer = new XmlTextWriter(stream, new UTF8Encoding(false))) {
writer.Formatting = Formatting.Indented;
document.WriteContentTo(writer);
Debug.Log($"MJCF saved to {filePath}");
}
}
} catch (IOException ex) {
Debug.LogWarning("Failed to save Xml to a file: " + ex.ToString(), this);
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: dc0e4847259184563a80db5e2e581464
timeCreated: 1532377765
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,92 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// A facade that allows to select a type of Mujoco shape and define that shape's properties.
//
// To work around the lack of serialization support for polymorphism, the class aggregates
// the settings of all available shape types. Coupled with a set of custom property drawers,
// it will be presented in the Inspector as a single entity, encapsulating the details of
// data persistance, Mjcf parsing and generation and debug visualization.
public abstract class MjShapeComponent : MjComponent {
public enum ShapeTypes {
Sphere,
Capsule,
Ellipsoid,
Cylinder,
Box,
Plane,
Mesh
}
public ShapeTypes ShapeType;
public MjSphereShape Sphere = new MjSphereShape();
public MjCapsuleShape Capsule = new MjCapsuleShape();
public MjCylinderShape Cylinder = new MjCylinderShape();
public MjBoxShape Box = new MjBoxShape();
public MjEllipsoidShape Ellipsoid = new MjEllipsoidShape();
public MjPlaneShape Plane = new MjPlaneShape();
public MjMeshShape Mesh = new MjMeshShape();
public IMjShape Shape {
get {
switch (ShapeType) {
default:
case ShapeTypes.Sphere: return Sphere;
case ShapeTypes.Capsule: return Capsule;
case ShapeTypes.Cylinder: return Cylinder;
case ShapeTypes.Ellipsoid: return Ellipsoid;
case ShapeTypes.Box: return Box;
case ShapeTypes.Plane: return Plane;
case ShapeTypes.Mesh: return Mesh;
}
}
}
public void ShapeToMjcf(XmlElement mjcf, Transform transform) {
mjcf.SetAttribute("type", ShapeType.ToString().ToLower());
Shape.ToMjcf(mjcf, transform);
}
public void ShapeFromMjcf(XmlElement mjcf) {
ShapeType = mjcf.GetEnumAttribute<ShapeTypes>(
"type", ShapeTypes.Sphere, ignoreCase: true);
Shape.FromMjcf(mjcf);
}
public Tuple<Vector3[], int[]> BuildMesh() {
return Shape.BuildMesh();
}
public Vector4 GetChangeStamp() {
var stamp = Shape.GetChangeStamp();
stamp.w = (float)ShapeType;
return stamp;
}
public void DrawGizmos(Transform transform) {
var oldMatrix = Gizmos.matrix;
Shape.DebugDraw(transform);
Gizmos.matrix = oldMatrix;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 5c4948e0eae49455caa9c131435c0b5b
timeCreated: 1547594327
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// Defines a reference frame and an anchoring point for other elements of the rig.
public class MjSite : MjShapeComponent {
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_SITE;
// Parse the component settings from an external Mjcf.
protected override void OnParseMjcf(XmlElement mjcf) {
ShapeFromMjcf(mjcf);
MjEngineTool.ParseTransformMjcf(mjcf, transform);
}
// Generate implementation specific XML element.
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("site");
ShapeToMjcf(mjcf, transform);
MjEngineTool.PositionRotationToMjcf(mjcf, this);
return mjcf;
}
// Synchronize the state of the component.
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
transform.position = MjEngineTool.UnityVector3(data->site_xpos, MujocoId);
transform.rotation = MjEngineTool.UnityQuaternionFromMatrix(data->site_xmat, MujocoId);
}
public void OnDrawGizmosSelected() {
Gizmos.color = Color.magenta;
DrawGizmos(transform);
}
}
}
+13
View File
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 1f92b229515774d928f13cd3faead49a
timeCreated: 1547220273
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,49 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjSiteQuaternionSensor : MjBaseSensor {
public MjSite Site;
public Quaternion SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Site == null) {
throw new NullReferenceException("Missing a reference to a MjSite.");
}
var mjcf = doc.CreateElement("framequat");
mjcf.SetAttribute("objtype", "site");
mjcf.SetAttribute("objname", Site.MujocoName);
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
Site = mjcf.GetObjectReferenceAttribute<MjSite>("objname");
if (Site == null) {
throw new NullReferenceException("Missing a reference to a MjSite.");
}
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = MjEngineTool.UnityQuaternion(data->sensordata, _sensorAddress);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 9184adbba0c7046b49d799f28d26c8a8
timeCreated: 1548170856
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,54 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjSiteScalarSensor : MjBaseSensor {
// NOTE: These names must match sensor names listed on mujoco.org.
// Changing them is justified only when Mujoco is upgraded to a new version.
public enum AvailableSensors {
Touch,
RangeFinder,
}
public AvailableSensors SensorType;
public MjSite Site;
public double SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Site == null) {
throw new NullReferenceException("Missing a reference to a MjSite.");
}
var mjcf = doc.CreateElement(SensorType.ToString().ToLower());
mjcf.SetAttribute("site", Site.MujocoName);
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
if (!Enum.TryParse(mjcf.Name, ignoreCase: true, result: out SensorType)) {
throw new ArgumentException($"Unknown sensor type {mjcf.Name}.");
}
Site = mjcf.GetObjectReferenceAttribute<MjSite>("site");
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = data->sensordata[_sensorAddress];
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b9d61f371ce8e4821ac8c64a5bd90232
timeCreated: 1548167404
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,75 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjSiteVectorSensor : MjBaseSensor {
// NOTE: These names must match sensor names listed on mujoco.org.
// Changing them is justified only when Mujoco is upgraded to a new version.
public enum AvailableSensors {
Accelerometer,
Velocimeter,
Gyro,
Force,
Torque,
Magnetometer,
FramePos,
FrameXAxis,
FrameYAxis,
FrameZAxis,
FrameLinVel,
FrameAngVel,
FrameLinAcc,
FrameAngAcc,
}
public AvailableSensors SensorType;
public MjSite Site;
public Vector3 SensorReading { get; private set; }
protected override XmlElement ToMjcf(XmlDocument doc) {
if (Site == null) {
throw new NullReferenceException("Missing a reference to a MjSite.");
}
var tag = SensorType.ToString().ToLower();
var mjcf = doc.CreateElement(tag);
if (tag.Contains("frame")) {
mjcf.SetAttribute("objtype", "site");
mjcf.SetAttribute("objname", Site.MujocoName);
} else {
mjcf.SetAttribute("site", Site.MujocoName);
}
return mjcf;
}
protected override void FromMjcf(XmlElement mjcf) {
if (!Enum.TryParse(mjcf.Name, ignoreCase: true, result: out SensorType)) {
throw new ArgumentException($"Unknown sensor type {mjcf.Name}.");
}
if (mjcf.Name.Contains("frame")) {
Site = mjcf.GetObjectReferenceAttribute<MjSite>("objname");
} else {
Site = mjcf.GetObjectReferenceAttribute<MjSite>("site");
}
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
SensorReading = MjEngineTool.UnityVector3(data->sensordata, _sensorAddress);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 8ed49bd87930f40b9aaaf5b77beead64
timeCreated: 1548168043
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+85
View File
@@ -0,0 +1,85 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// The component represents a joint with 1 degree of translational freedom.
public class MjSlideJoint : MjBaseJoint {
[Tooltip("In meters.")]
public float RangeLower;
[Tooltip("In meters.")]
public float RangeUpper;
[Tooltip("The current joint angle, in degrees. Read-only at play time.")]
public float Configuration;
[Tooltip("Joint movement, in rad/sec. Read-only at play time.")]
public float Velocity;
[Tooltip("Joint settings.")]
public MjJointSettings Settings = MjJointSettings.Default;
// World space slide axis.
public Vector3 SlideAxis => transform.rotation * Vector3.right;
protected override unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
base.OnBindToRuntime(model, data);
data->qvel[DofAddress] = Velocity;
}
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
var qpos = (float)data->qpos[QposAddress];
Configuration = (qpos % (2 * Mathf.PI)) * Mathf.Rad2Deg;
Velocity = (float)data->qvel[DofAddress];
}
protected override void OnParseMjcf(XmlElement mjcf) {
// Transform.
transform.localPosition =
MjEngineTool.UnityVector3(mjcf.GetVector3Attribute("pos", defaultValue: Vector3.zero));
var rotationAxis =
MjEngineTool.UnityVector3(mjcf.GetVector3Attribute("axis", defaultValue: Vector3.right));
transform.localRotation = Quaternion.FromToRotation(Vector3.right, rotationAxis);
var rangeValues = mjcf.GetFloatArrayAttribute("range", defaultValue: new float[] { 0, 0 });
RangeLower = rangeValues[0];
RangeUpper = rangeValues[1];
Configuration = mjcf.GetFloatAttribute("ref", 0.0f);
Settings.FromMjcf(mjcf);
}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("joint");
mjcf.SetAttribute("type", "slide");
MjEngineTool.PositionAxisToMjcf(mjcf, this);
Settings.ToMjcf(mjcf);
if (RangeLower > RangeUpper) {
throw new ArgumentException("Lower range value can't be bigger than Higher");
}
mjcf.SetAttribute("range", $"{RangeLower} {RangeUpper}");
mjcf.SetAttribute("ref", $"{Configuration}");
return mjcf;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 0f0920b38d2fe4e21bb645eff3f73be4
timeCreated: 1537527115
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+131
View File
@@ -0,0 +1,131 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class SpatialTendonEntry {
[Tooltip("Only one of site/geom/pulley can be specified at each entry.")]
public MjSite Site;
[Tooltip("Only one of site/geom/pulley can be specified at each entry.")]
public MjGeom WrapGeom;
[Tooltip("Only used if wrap geom is specified.")]
public MjSite WrapSideSite;
[Tooltip("Only one of site/geom/pulley can be specified at each entry.")]
public float PulleyDivisor;
}
public class MjSpatialTendon : MjBaseTendon {
[Tooltip("In meters.")]
public float RangeLower;
[Tooltip("In meters.")]
public float RangeUpper;
public List<SpatialTendonEntry> ViapointsList = new List<SpatialTendonEntry>() {};
protected override void FromMjcf(XmlElement mjcf) {
foreach (var child in mjcf.Cast<XmlNode>().OfType<XmlElement>()) {
var viapoint = new SpatialTendonEntry();
viapoint.Site = child.GetObjectReferenceAttribute<MjSite>("site");
viapoint.WrapGeom = child.GetObjectReferenceAttribute<MjGeom>("geom");
viapoint.WrapSideSite = child.GetObjectReferenceAttribute<MjSite>("sidesite");
viapoint.PulleyDivisor = child.GetFloatAttribute("pulley");
ViapointsList.Add(viapoint);
}
var rangeValues = mjcf.GetFloatArrayAttribute("range", defaultValue: new float[] { 0, 0 });
RangeLower = rangeValues[0];
RangeUpper = rangeValues[1];
}
protected override XmlElement ToMjcf(XmlDocument doc) {
if (ViapointsList.Count() < 2) {
throw new ArgumentOutOfRangeException($"Spatial tendon {name} needs at least 2 sites.");
}
if (ViapointsList[0].Site == null) {
throw new NullReferenceException(
$"The first entry of a spatial tendon {name} must be a site.");
}
if (ViapointsList[ViapointsList.Count - 1].Site == null) {
throw new NullReferenceException(
$"The last entry of a spatial tendon {name} must be a site.");
}
var mjcf = doc.CreateElement("spatial");
foreach (SpatialTendonEntry spatialTendonEntry in ViapointsList) {
XmlElement elementMjcf;
if (spatialTendonEntry.Site) {
if (spatialTendonEntry.WrapGeom || spatialTendonEntry.PulleyDivisor != 0) {
throw new ArgumentException(
$"Only one of site/wrap geom/pulley {name} is allowed at each entry.");
}
elementMjcf = doc.CreateElement("site");
elementMjcf.SetAttribute("site", spatialTendonEntry.Site.MujocoName);
} else if (spatialTendonEntry.WrapGeom) {
if (spatialTendonEntry.PulleyDivisor != 0) {
throw new ArgumentException(
$"Only one of site/wrap geom/pulley {name} is allowed at each entry.");
}
elementMjcf = doc.CreateElement("geom");
elementMjcf.SetAttribute("geom", spatialTendonEntry.WrapGeom.MujocoName);
if (spatialTendonEntry.WrapSideSite) {
elementMjcf.SetAttribute("sidesite", spatialTendonEntry.WrapSideSite.MujocoName);
}
} else {
if (spatialTendonEntry.PulleyDivisor == 0) {
throw new ArgumentException(
$"Exactly one of site/wrap geom/pulley {name} is required at each entry.");
}
elementMjcf = doc.CreateElement("pulley");
elementMjcf.SetAttribute("divisor", $"{spatialTendonEntry.PulleyDivisor}");
}
mjcf.AppendChild(elementMjcf);
}
if (RangeLower > RangeUpper) {
throw new ArgumentException("Lower range value can't be bigger than Higher");
}
mjcf.SetAttribute("range", $"{RangeLower} {RangeUpper}");
return mjcf;
}
public unsafe void OnDrawGizmos() {
if (Application.isPlaying) {
var scene = MjScene.Instance;
var segmentCount = scene.Model->nwrap - 1;
var data = scene.Data;
int readHead = 0;
for (int i = 0; i < segmentCount; ++i) {
// Skip drawing of pulley:
if (data->wrap_obj[readHead] == -2 || data->wrap_obj[readHead + 1] == -2) {
readHead += 1;
} else {
Vector3 start = MjEngineTool.UnityVector3(data->wrap_xpos, readHead);
Vector3 end = MjEngineTool.UnityVector3(data->wrap_xpos, readHead + 1);
Gizmos.DrawLine(start, end);
if (data->wrap_obj[readHead + 1] >= 0) { // a wrap geom
readHead += 2;
} else { // site or pulley
readHead += 1;
}
}
}
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: c057416978f884ffbb63af370eed69dd
timeCreated: 1551348731
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
[Serializable]
public class MjSphereShape : IMjShape {
public float Radius = 0.5f;
private const float _scaleTolerance = 1e-6f;
public void ToMjcf(XmlElement mjcf, Transform transform) {
if (Math.Abs(transform.lossyScale.x - transform.lossyScale.y) > _scaleTolerance ||
Math.Abs(transform.lossyScale.y - transform.lossyScale.z) > _scaleTolerance) {
Debug.LogWarning(
$"{transform.name}: Sphere shapes work only with uniform scaling. Using the value of X" +
" component.\n Consider using Ellipsoid shape if you want to use non-uniform scaling.",
transform);
}
mjcf.SetAttribute("size", $"{Radius * transform.lossyScale.x}");
}
public void FromMjcf(XmlElement mjcf) {
var values = mjcf.GetFloatArrayAttribute("size", defaultValue: new float[] { 0.5f });
Radius = values[0];
}
public Tuple<Vector3[], int[]> BuildMesh() {
return MeshGenerators.BuildSphere(scale: Vector3.one * Radius);
}
public Vector4 GetChangeStamp() {
return new Vector4(Radius, 1, 1, 0);
}
public void DebugDraw(Transform transform) {
Gizmos.DrawWireSphere(transform.position, Radius * transform.lossyScale.x);
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: accf5ed21337c4fe38417b01fe8c5468
timeCreated: 1547647081
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,57 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjTendonConstraint : MjBaseConstraint {
public MjBaseTendon Tendon1;
public MjBaseTendon Tendon2;
public float[] PolynomialCoefficients = new float[5] { 0, 1, 0, 0, 0 };
protected override string _constraintName => "tendon";
protected override void FromMjcf(XmlElement mjcf) {
Tendon1 = mjcf.GetObjectReferenceAttribute<MjBaseTendon>("tendon1");
Tendon2 = mjcf.GetObjectReferenceAttribute<MjBaseTendon>("tendon2");
PolynomialCoefficients =
mjcf.GetFloatArrayAttribute("polycoef", new Single[] { 0, 1, 0, 0, 0 });
}
// Generate implementation specific XML element.
protected override void ToMjcf(XmlElement mjcf) {
if (Tendon1 == null) {
throw new NullReferenceException(
$"At least Tendon1 in constraint {name} must be assigned.");
}
mjcf.SetAttribute("tendon1", Tendon1.MujocoName);
if (Tendon2 != null) {
mjcf.SetAttribute("tendon2", Tendon2.MujocoName);
}
mjcf.SetAttribute("polycoef", MjEngineTool.ArrayToMjcf(PolynomialCoefficients));
}
public void OnValidate() {
if (Tendon1 != null && Tendon1 == Tendon2) {
Debug.LogWarning(
"Tendon1 and Tendon2 can't be the same - resetting Tendon2.", this);
Tendon2 = null;
}
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 81536160634694c9f8b78d0de2fe6fde
timeCreated: 1552309644
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+61
View File
@@ -0,0 +1,61 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
public class MjWeld : MjBaseConstraint {
public MjBaseBody Body1;
public MjBaseBody Body2;
public Transform WeldOffset;
protected override string _constraintName => "weld";
protected override unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
if (WeldOffset) {
MjEngineTool.SetMjTransform(model->eq_data, WeldOffset.localPosition,
WeldOffset.localRotation, MujocoId);
}
}
protected override void FromMjcf(XmlElement mjcf) {
Body1 = mjcf.GetObjectReferenceAttribute<MjBaseBody>("body1");
Body2 = mjcf.GetObjectReferenceAttribute<MjBaseBody>("body2");
var relpose = mjcf.GetStringAttribute("relpose");
if (relpose != null) {
Debug.Log(
$"relpose {relpose} in weld {name} ignored. Set WeldOffset in the editor.");
}
}
protected override void ToMjcf(XmlElement mjcf) {
if (Body1 == null || Body2 == null) {
throw new NullReferenceException($"Both bodies in weld {name} must be assigned.");
}
mjcf.SetAttribute("body1", Body1.MujocoName);
mjcf.SetAttribute("body2", Body2.MujocoName);
}
public void OnValidate() {
if (Body1 != null && Body1 == Body2) {
Debug.LogWarning("Body1 and Body2 can't be the same - resetting Body2.", this);
Body2 = null;
}
}
}
}
+13
View File
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b6f83e13e2c454767a785a138674c84f
timeCreated: 1550663136
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: