Add support for global custom numeric fields.
PiperOrigin-RevId: 495865065 Change-Id: I59ed65e84a0bcaa90220b938ed34fdc26165aa09
This commit is contained in:
committed by
Copybara-Service
parent
516d13d678
commit
f70403d00a
@@ -143,32 +143,18 @@ public struct MjcfOptionFlag {
|
||||
|
||||
[Serializable]
|
||||
public struct MjSizeStruct {
|
||||
public int Njmax;
|
||||
public int Nconmax;
|
||||
public int Nstack;
|
||||
public String Memory;
|
||||
public static MjSizeStruct Default = new MjSizeStruct() {
|
||||
Njmax = 0,
|
||||
Nconmax = 0,
|
||||
Nstack = 0
|
||||
Memory = "-1"
|
||||
};
|
||||
|
||||
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);
|
||||
Memory = mjcf.GetAttribute("memory", localDefault.Memory);
|
||||
}
|
||||
|
||||
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}");
|
||||
}
|
||||
mjcf.SetAttribute("memory", $"{Memory}");
|
||||
return mjcf;
|
||||
}
|
||||
}
|
||||
@@ -327,6 +313,13 @@ public struct MjOptionStruct {
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class NumericEntry {
|
||||
public String Name;
|
||||
[Tooltip("Space-separated list of floats.")]
|
||||
public String Data;
|
||||
}
|
||||
|
||||
public class MjGlobalSettings : MonoBehaviour {
|
||||
|
||||
[Tooltip("Filename for the generated scene XML.")]
|
||||
@@ -339,6 +332,8 @@ public class MjGlobalSettings : MonoBehaviour {
|
||||
|
||||
public MjSizeStruct GlobalSizes = MjSizeStruct.Default;
|
||||
|
||||
public List<NumericEntry> CustomNumeric = new List<NumericEntry>() {};
|
||||
|
||||
public static MjGlobalSettings Instance {
|
||||
get {
|
||||
if (_instance == null) {
|
||||
@@ -365,18 +360,44 @@ public class MjGlobalSettings : MonoBehaviour {
|
||||
}
|
||||
}
|
||||
|
||||
public void ParseOptionSizeMjcf(XmlElement option, XmlElement size) {
|
||||
if (option != null) {
|
||||
GlobalOptions.ParseMjcf(option);
|
||||
public void ParseGlobalMjcfSections(XmlElement mujocoNode) {
|
||||
|
||||
var optionNode = mujocoNode.SelectSingleNode("option") as XmlElement;
|
||||
var sizeNode = mujocoNode.SelectSingleNode("size") as XmlElement;
|
||||
var customNode = mujocoNode.SelectSingleNode("custom") as XmlElement;
|
||||
|
||||
if (optionNode != null) {
|
||||
GlobalOptions.ParseMjcf(optionNode);
|
||||
}
|
||||
if (size != null) {
|
||||
GlobalSizes.ParseMjcf(size);
|
||||
if (sizeNode != null) {
|
||||
GlobalSizes.ParseMjcf(sizeNode);
|
||||
}
|
||||
if (customNode != null) {
|
||||
foreach (var childNode in customNode.ChildNodes) {
|
||||
var child = childNode as XmlElement;
|
||||
if (child.Name == "numeric") {
|
||||
var numeric = new NumericEntry();
|
||||
numeric.Name = child.GetAttribute("name");
|
||||
numeric.Data = child.GetAttribute("data");
|
||||
CustomNumeric.Add(numeric);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OptionSizeToMjcf(XmlElement option, XmlElement size) {
|
||||
GlobalOptions.ToMjcf(option);
|
||||
GlobalSizes.ToMjcf(size);
|
||||
public void GlobalsToMjcf(XmlElement mjcf) {
|
||||
var doc = mjcf.OwnerDocument;
|
||||
var optionMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("option"));
|
||||
GlobalOptions.ToMjcf(optionMjcf);
|
||||
var sizeMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("size"));
|
||||
GlobalSizes.ToMjcf(sizeMjcf);
|
||||
var customMjcf = (XmlElement)mjcf.AppendChild(doc.CreateElement("custom"));
|
||||
foreach (var numeric in CustomNumeric) {
|
||||
var numericMjcf = (XmlElement)customMjcf.AppendChild(doc.CreateElement("numeric"));
|
||||
numericMjcf.SetAttribute("name", numeric.Name);
|
||||
// TODO: add validation that data is a space-separated list of floating numbers?
|
||||
numericMjcf.SetAttribute("data", numeric.Data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,30 +133,25 @@ public class MjcfImporter {
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void ParseRoot(GameObject parentObject, XmlElement parentNode) {
|
||||
protected virtual void ParseRoot(GameObject rootObject, XmlElement mujocoNode) {
|
||||
|
||||
// This makes no references nor being referred into, so it can be parsed whenever.
|
||||
var optionNode = parentNode.SelectSingleNode("option") as XmlElement;
|
||||
var sizeNode = parentNode.SelectSingleNode("size") as XmlElement;
|
||||
if (optionNode != null || sizeNode != null) {
|
||||
var globalsObject = CreateGameObjectInParent("Global Settings", parentObject);
|
||||
var settingsComponent = globalsObject.AddComponent<MjGlobalSettings>();
|
||||
settingsComponent.ParseOptionSizeMjcf(optionNode, sizeNode);
|
||||
}
|
||||
var globalsObject = CreateGameObjectInParent("Global Settings", rootObject);
|
||||
var settingsComponent = globalsObject.AddComponent<MjGlobalSettings>();
|
||||
settingsComponent.ParseGlobalMjcfSections(mujocoNode);
|
||||
|
||||
// This makes references to assets.
|
||||
var worldBodyNode = parentNode.SelectSingleNode("worldbody") as XmlElement;
|
||||
ParseBodyChildren(parentObject, worldBodyNode);
|
||||
var worldBodyNode = mujocoNode.SelectSingleNode("worldbody") as XmlElement;
|
||||
ParseBodyChildren(rootObject, worldBodyNode);
|
||||
|
||||
// This section references bodies, must be parsed after worldbody.
|
||||
var excludeNode = parentNode.SelectSingleNode("contact") as XmlElement;
|
||||
var excludeNode = mujocoNode.SelectSingleNode("contact") as XmlElement;
|
||||
if (excludeNode != null) {
|
||||
var excludesParentObject = CreateGameObjectInParent("excludes", parentObject);
|
||||
var excludesParentObject = CreateGameObjectInParent("excludes", rootObject);
|
||||
foreach (var child in excludeNode.OfType<XmlElement>()) {
|
||||
if (child.Name != "exclude") {
|
||||
Debug.LogWarning(
|
||||
$"Only 'exclude' is supported - {child.Name} isn't supported yet.",
|
||||
parentObject);
|
||||
rootObject);
|
||||
} else {
|
||||
_modifiers.ApplyModifiersToElement(child);
|
||||
CreateGameObjectWithUniqueName<MjExclude>(excludesParentObject, child);
|
||||
@@ -165,9 +160,9 @@ public class MjcfImporter {
|
||||
}
|
||||
|
||||
// This section references joints/sites/geoms, must be parsed after worldbody.
|
||||
var tendonNode = parentNode.SelectSingleNode("tendon") as XmlElement;
|
||||
var tendonNode = mujocoNode.SelectSingleNode("tendon") as XmlElement;
|
||||
if (tendonNode != null) {
|
||||
var tendonsParentObject = CreateGameObjectInParent("tendons", parentObject);
|
||||
var tendonsParentObject = CreateGameObjectInParent("tendons", rootObject);
|
||||
foreach (var child in tendonNode.OfType<XmlElement>()) {
|
||||
if (child.Name == "fixed") {
|
||||
CreateGameObjectWithUniqueName<MjFixedTendon>(tendonsParentObject, child);
|
||||
@@ -180,9 +175,9 @@ public class MjcfImporter {
|
||||
}
|
||||
|
||||
// This section references worldbody elements + tendons, must be parsed after them.
|
||||
var equalityNode = parentNode.SelectSingleNode("equality") as XmlElement;
|
||||
var equalityNode = mujocoNode.SelectSingleNode("equality") as XmlElement;
|
||||
if (equalityNode != null) {
|
||||
var equalitiesParentObject = CreateGameObjectInParent("equality constraints", parentObject);
|
||||
var equalitiesParentObject = CreateGameObjectInParent("equality constraints", rootObject);
|
||||
foreach (var child in equalityNode.OfType<XmlElement>()) {
|
||||
var equalityType = ParseEqualityType(child);
|
||||
_modifiers.ApplyModifiersToElement(child);
|
||||
@@ -191,9 +186,9 @@ public class MjcfImporter {
|
||||
}
|
||||
|
||||
// This section references joints and tendons, must be parsed after worldbody and tendon.
|
||||
var actuatorNode = parentNode.SelectSingleNode("actuator") as XmlElement;
|
||||
var actuatorNode = mujocoNode.SelectSingleNode("actuator") as XmlElement;
|
||||
if (actuatorNode != null) {
|
||||
var actuatorsParentObject = CreateGameObjectInParent("actuators", parentObject);
|
||||
var actuatorsParentObject = CreateGameObjectInParent("actuators", rootObject);
|
||||
foreach (var child in actuatorNode.OfType<XmlElement>()) {
|
||||
_modifiers.ApplyModifiersToElement(child);
|
||||
CreateGameObjectWithUniqueName<MjActuator>(actuatorsParentObject, child);
|
||||
@@ -201,9 +196,9 @@ public class MjcfImporter {
|
||||
}
|
||||
|
||||
// This section references tendons, actuators and worldbody elements, must be parsed last.
|
||||
var sensorNode = parentNode.SelectSingleNode("sensor") as XmlElement;
|
||||
var sensorNode = mujocoNode.SelectSingleNode("sensor") as XmlElement;
|
||||
if (sensorNode != null) {
|
||||
var sensorParentObject = CreateGameObjectInParent("sensors", parentObject);
|
||||
var sensorParentObject = CreateGameObjectInParent("sensors", rootObject);
|
||||
foreach (var child in sensorNode.OfType<XmlElement>()) {
|
||||
_modifiers.ApplyModifiersToElement(child);
|
||||
var sensorType = ParseSensorType(child);
|
||||
|
||||
@@ -74,7 +74,7 @@ public class MjcfGenerationContext {
|
||||
|
||||
var settings = MjGlobalSettings.Instance;
|
||||
if (settings) {
|
||||
settings.OptionSizeToMjcf(optionMjcf, null);
|
||||
settings.GlobalsToMjcf(mjcf);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user