Initial release of the Unity plugin.
PiperOrigin-RevId: 425947505
This commit is contained in:
committed by
Saran Tunyasuvunakool
parent
8ec3dd97a4
commit
6de9eafa13
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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:
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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:
|
||||
Reference in New Issue
Block a user