Add heightfield geom type with Unity terrain, import not yet supported
This commit is contained in:
@@ -30,7 +30,7 @@ public class MjShapeComponentEditor : Editor {
|
||||
var shapeType = serializedObject.FindProperty("ShapeType");
|
||||
EditorGUILayout.PropertyField(shapeType);
|
||||
EditorGUILayout.PropertyField(
|
||||
serializedObject.FindProperty($"{shapeType.enumDisplayNames[shapeType.enumValueIndex]}"),
|
||||
serializedObject.FindProperty($"{shapeType.enumNames[shapeType.enumValueIndex]}"),
|
||||
includeChildren: true);
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
@@ -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.IO;
|
||||
using System.Linq;
|
||||
using System.Xml;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Mujoco
|
||||
{
|
||||
|
||||
[Serializable]
|
||||
public class MjHeightFieldShape : IMjShape
|
||||
{
|
||||
|
||||
public Terrain terrain;
|
||||
|
||||
[Tooltip("The path, relative to Application.dataPath, where the heightmap data will be save in PNG format.")]
|
||||
public string heightMapExportPath;
|
||||
|
||||
public string FullHeightMapPath => Path.GetFullPath(Path.Combine(Application.dataPath, heightMapExportPath));
|
||||
public int HeightMapWidth => terrain.terrainData.heightmapTexture.width;
|
||||
public int HeightMapHeight => terrain.terrainData.heightmapTexture.height;
|
||||
public Vector3 HeightMapScale => terrain.terrainData.heightmapScale;
|
||||
|
||||
public void ToMjcf(XmlElement mjcf, Transform transform)
|
||||
{
|
||||
ExportHeightMap();
|
||||
var scene = MjScene.Instance;
|
||||
var assetName = scene.GenerationContext.AddHeightFieldAsset(this);
|
||||
mjcf.SetAttribute("hfield", assetName);
|
||||
}
|
||||
|
||||
public void FromMjcf(XmlElement mjcf)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ExportHeightMap()
|
||||
{
|
||||
RenderTexture.active = terrain.terrainData.heightmapTexture;
|
||||
Texture2D texture = new Texture2D(RenderTexture.active.width, RenderTexture.active.height);
|
||||
texture.ReadPixels(new Rect(0, 0, RenderTexture.active.width, RenderTexture.active.height), 0, 0);
|
||||
RenderTexture.active = null;
|
||||
File.WriteAllBytes(FullHeightMapPath, texture.EncodeToPNG());
|
||||
}
|
||||
|
||||
|
||||
public Vector4 GetChangeStamp()
|
||||
{
|
||||
return Vector4.one;
|
||||
}
|
||||
|
||||
public Tuple<Vector3[], int[]> BuildMesh()
|
||||
{
|
||||
return Tuple.Create(new Vector3[]{}, new int[]{});
|
||||
}
|
||||
|
||||
public void DebugDraw(Transform transform)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4572cd1b5f036db4483a214346587960
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -34,7 +34,8 @@ public abstract class MjShapeComponent : MjComponent {
|
||||
Cylinder,
|
||||
Box,
|
||||
Plane,
|
||||
Mesh
|
||||
Mesh,
|
||||
HField
|
||||
}
|
||||
|
||||
public ShapeTypes ShapeType;
|
||||
@@ -46,6 +47,7 @@ public abstract class MjShapeComponent : MjComponent {
|
||||
public MjEllipsoidShape Ellipsoid = new MjEllipsoidShape();
|
||||
public MjPlaneShape Plane = new MjPlaneShape();
|
||||
public MjMeshShape Mesh = new MjMeshShape();
|
||||
public MjHeightFieldShape HField = new MjHeightFieldShape();
|
||||
|
||||
public IMjShape Shape {
|
||||
get {
|
||||
@@ -58,6 +60,7 @@ public abstract class MjShapeComponent : MjComponent {
|
||||
case ShapeTypes.Box: return Box;
|
||||
case ShapeTypes.Plane: return Plane;
|
||||
case ShapeTypes.Mesh: return Mesh;
|
||||
case ShapeTypes.HField: return HField;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,7 @@ public class MjcfGenerationContext {
|
||||
private int _nuserSensor;
|
||||
private int _numGeneratedNames = 0;
|
||||
private Dictionary<Mesh, string> _meshAssets = new Dictionary<Mesh, string>();
|
||||
private Dictionary<MjHeightFieldShape, string> _hFieldAssets = new Dictionary<MjHeightFieldShape, string>();
|
||||
|
||||
public void GenerateMjcf(XmlElement mjcf) {
|
||||
GenerateConfigurationMjcf(mjcf);
|
||||
@@ -50,6 +51,17 @@ public class MjcfGenerationContext {
|
||||
}
|
||||
return _meshAssets[mesh];
|
||||
}
|
||||
|
||||
// Adds a mesh to the list of assets that will be added to the generated MJCF.
|
||||
// Returns the unique name that identifies this new asset.
|
||||
public string AddHeightFieldAsset(MjHeightFieldShape hField) {
|
||||
if (!_hFieldAssets.ContainsKey(hField)) {
|
||||
var uniqueName = $"hfield_{_numGeneratedNames}";
|
||||
_numGeneratedNames++;
|
||||
_hFieldAssets.Add(hField, uniqueName);
|
||||
}
|
||||
return _hFieldAssets[hField];
|
||||
}
|
||||
|
||||
public string GenerateName(Component comp) {
|
||||
var settings = MjGlobalSettings.Instance;
|
||||
@@ -81,10 +93,15 @@ public class MjcfGenerationContext {
|
||||
private void GenerateAssetsMjcf(XmlElement mjcf) {
|
||||
var doc = mjcf.OwnerDocument;
|
||||
var assetMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("asset"));
|
||||
foreach (var asset in _meshAssets) {
|
||||
foreach (var meshAsset in _meshAssets) {
|
||||
var meshMjcf = (XmlElement)assetMjcf.AppendChild(doc.CreateElement("mesh"));
|
||||
meshMjcf.SetAttribute("name", asset.Value);
|
||||
GenerateMeshMjcf(asset.Key, meshMjcf);
|
||||
meshMjcf.SetAttribute("name", meshAsset.Value);
|
||||
GenerateMeshMjcf(meshAsset.Key, meshMjcf);
|
||||
}
|
||||
foreach (var hFieldAsset in _hFieldAssets) {
|
||||
var hFieldMjcf = (XmlElement)assetMjcf.AppendChild(doc.CreateElement("hfield"));
|
||||
hFieldMjcf.SetAttribute("name", hFieldAsset.Value);
|
||||
GenerateHeightFieldMjcf(hFieldAsset.Key, hFieldMjcf);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,5 +114,15 @@ public class MjcfGenerationContext {
|
||||
}
|
||||
mjcf.SetAttribute("vertex", vertexPositionsStr.ToString());
|
||||
}
|
||||
|
||||
private static void GenerateHeightFieldMjcf(MjHeightFieldShape hFieldComponent, XmlElement mjcf) {
|
||||
mjcf.SetAttribute("nrow", "0");
|
||||
mjcf.SetAttribute("ncol", "0");
|
||||
mjcf.SetAttribute("content_type", "image/png");
|
||||
mjcf.SetAttribute("file", hFieldComponent.FullHeightMapPath);
|
||||
|
||||
mjcf.SetAttribute("size", MjEngineTool.MakeLocaleInvariant($"{hFieldComponent.HeightMapScale.x*hFieldComponent.HeightMapHeight/2} {hFieldComponent.HeightMapScale.z * hFieldComponent.HeightMapWidth/2} {hFieldComponent.HeightMapScale.y*2} {hFieldComponent.terrain.transform.position.y}"));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user