Version 2.1.2: Python bindings, OBJ assets support, bugfixes.

PiperOrigin-RevId: 434731612
Change-Id: I0cfda3e7a3d1c72036764986efc252ffa1b8c6b0
This commit is contained in:
Saran Tunyasuvunakool
2022-03-15 14:04:44 +00:00
parent 175d25cd9f
commit 3577e2cf8b
304 changed files with 23906 additions and 1013 deletions
@@ -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,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", MjEngineTool.MakeLocaleInvariant($"{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,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", MjEngineTool.MakeLocaleInvariant($"{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,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:
+96
View File
@@ -0,0 +1,96 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// The component represents a physical shape and models its inertia and material properties.
public class MjGeom : MjShapeComponent {
[Tooltip("If larger than zero, Density has no effect.")]
public float Mass = 0.0f;
[Tooltip("Material density. Set to 0 for a zero-mass geom.")]
public float Density = 1000.0f;
[Tooltip("Advanced settings.")]
public MjGeomSettings Settings = MjGeomSettings.Default;
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_GEOM;
private MjTransformation _geomInGlobalFrame = new MjTransformation();
private MjTransformation _comTransform;
protected override void OnParseMjcf(XmlElement mjcf) {
ShapeFromMjcf(mjcf);
Mass = mjcf.GetFloatAttribute("mass", defaultValue: 0.0f);
Density = mjcf.GetFloatAttribute("density", defaultValue: 1000.0f);
MjEngineTool.ParseTransformMjcf(mjcf, transform);
Settings.FromMjcf(mjcf);
}
// The MuJoCo compiler shifts meshes' frames, so we need to cache this transformation at init and
// apply it at runtime.
protected override unsafe void OnBindToRuntime(MujocoLib.mjModel_* model, MujocoLib.mjData_* data) {
var MjParent = MjHierarchyTool.FindParentComponent<MjBaseBody>(this);
if (MjParent != null) {
var comInParentFrame = new MjTransformation(
translation: MjEngineTool.UnityVector3(model->geom_pos, MujocoId),
rotation: MjEngineTool.UnityQuaternion(model->geom_quat, MujocoId));
// We don't want to bother calculating global transform in mujoco from mjModel,
// so we'll assume it's the same as the Unity transfor (it's the beginning of simulation after
// all).
var globalParentFrame = MjTransformation.LoadGlobal(transform.parent);
var comInGlobalFrame = globalParentFrame * comInParentFrame;
var globalFrame = MjTransformation.LoadGlobal(transform);
_comTransform = comInGlobalFrame.Inverse() * globalFrame;
}
}
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("geom");
if (Mass > 0) {
mjcf.SetAttribute("mass", MjEngineTool.MakeLocaleInvariant($"{Mass}"));
} else {
mjcf.SetAttribute("density", MjEngineTool.MakeLocaleInvariant($"{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,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", MjEngineTool.MakeLocaleInvariant($"{Solver.SolMix}"));
mjcf.SetAttribute("solref", MjEngineTool.MakeLocaleInvariant($"{Solver.SolRef.TimeConst} {Solver.SolRef.DampRatio}"));
mjcf.SetAttribute(
"solimp", MjEngineTool.MakeLocaleInvariant($"{Solver.SolImp.DMin} {Solver.SolImp.DMax} {Solver.SolImp.Width}"));
mjcf.SetAttribute("margin", MjEngineTool.MakeLocaleInvariant($"{Solver.Margin}"));
mjcf.SetAttribute("gap", MjEngineTool.MakeLocaleInvariant($"{Solver.Gap}"));
// Inertia and friction settings.
mjcf.SetAttribute("friction", MjEngineTool.MakeLocaleInvariant($"{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,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,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", MjEngineTool.MakeLocaleInvariant($"{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,92 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// A facade that allows to select a type of Mujoco shape and define that shape's properties.
//
// To work around the lack of serialization support for polymorphism, the class aggregates
// the settings of all available shape types. Coupled with a set of custom property drawers,
// it will be presented in the Inspector as a single entity, encapsulating the details of
// data persistance, Mjcf parsing and generation and debug visualization.
public abstract class MjShapeComponent : MjComponent {
public enum ShapeTypes {
Sphere,
Capsule,
Ellipsoid,
Cylinder,
Box,
Plane,
Mesh
}
public ShapeTypes ShapeType;
public MjSphereShape Sphere = new MjSphereShape();
public MjCapsuleShape Capsule = new MjCapsuleShape();
public MjCylinderShape Cylinder = new MjCylinderShape();
public MjBoxShape Box = new MjBoxShape();
public MjEllipsoidShape Ellipsoid = new MjEllipsoidShape();
public MjPlaneShape Plane = new MjPlaneShape();
public MjMeshShape Mesh = new MjMeshShape();
public IMjShape Shape {
get {
switch (ShapeType) {
default:
case ShapeTypes.Sphere: return Sphere;
case ShapeTypes.Capsule: return Capsule;
case ShapeTypes.Cylinder: return Cylinder;
case ShapeTypes.Ellipsoid: return Ellipsoid;
case ShapeTypes.Box: return Box;
case ShapeTypes.Plane: return Plane;
case ShapeTypes.Mesh: return Mesh;
}
}
}
public void ShapeToMjcf(XmlElement mjcf, Transform transform) {
mjcf.SetAttribute("type", ShapeType.ToString().ToLower());
Shape.ToMjcf(mjcf, transform);
}
public void ShapeFromMjcf(XmlElement mjcf) {
ShapeType = mjcf.GetEnumAttribute<ShapeTypes>(
"type", ShapeTypes.Sphere, ignoreCase: true);
Shape.FromMjcf(mjcf);
}
public Tuple<Vector3[], int[]> BuildMesh() {
return Shape.BuildMesh();
}
public Vector4 GetChangeStamp() {
var stamp = Shape.GetChangeStamp();
stamp.w = (float)ShapeType;
return stamp;
}
public void DrawGizmos(Transform transform) {
var oldMatrix = Gizmos.matrix;
Shape.DebugDraw(transform);
Gizmos.matrix = oldMatrix;
}
}
}
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 5c4948e0eae49455caa9c131435c0b5b
timeCreated: 1547594327
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2019 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
using System.Linq;
using System.Xml;
using UnityEngine;
namespace Mujoco {
// Defines a reference frame and an anchoring point for other elements of the rig.
public class MjSite : MjShapeComponent {
public override MujocoLib.mjtObj ObjectType => MujocoLib.mjtObj.mjOBJ_SITE;
// Parse the component settings from an external Mjcf.
protected override void OnParseMjcf(XmlElement mjcf) {
ShapeFromMjcf(mjcf);
MjEngineTool.ParseTransformMjcf(mjcf, transform);
}
// Generate implementation specific XML element.
protected override XmlElement OnGenerateMjcf(XmlDocument doc) {
var mjcf = (XmlElement)doc.CreateElement("site");
ShapeToMjcf(mjcf, transform);
MjEngineTool.PositionRotationToMjcf(mjcf, this);
return mjcf;
}
// Synchronize the state of the component.
public override unsafe void OnSyncState(MujocoLib.mjData_* data) {
transform.position = MjEngineTool.UnityVector3(data->site_xpos, MujocoId);
transform.rotation = MjEngineTool.UnityQuaternionFromMatrix(data->site_xmat, MujocoId);
}
public void OnDrawGizmosSelected() {
Gizmos.color = Color.magenta;
DrawGizmos(transform);
}
}
}
@@ -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,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", MjEngineTool.MakeLocaleInvariant($"{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: