开发3D解剖相关功能

This commit is contained in:
shenjianxing 2025-02-12 17:36:00 +08:00
parent dabe54a5c7
commit 701f90314c
26 changed files with 3671 additions and 20 deletions

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 0cc951fa11e31944fbd42d553403b8b8
PrefabImporter:
externalObjects: {}
userData:
assetBundleName: ui3dbodyinfo_prefab
assetBundleVariant:

View File

@ -294,4 +294,122 @@ public class Utility
}
}
// 枚举定义渲染模式
public enum RenderMode
{
Opaque,
Cutout,
Fade,
Transparent
}
// 设置材质的渲染模式
public static void SetRenderMode(Material material, RenderMode mode, float alpha = 0.2f)
{
Color color = material.color;
switch (mode)
{
case RenderMode.Opaque:
material.SetOverrideTag("RenderType", "");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = -1;
color.a = 1;
material.color = color;
break;
case RenderMode.Cutout:
material.SetOverrideTag("RenderType", "TransparentCutout");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.Zero);
material.SetInt("_ZWrite", 1);
material.EnableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.AlphaTest;
break;
case RenderMode.Fade:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.EnableKeyword("_ALPHABLEND_ON");
material.DisableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
break;
case RenderMode.Transparent:
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
material.SetInt("_ZWrite", 0);
material.DisableKeyword("_ALPHATEST_ON");
material.DisableKeyword("_ALPHABLEND_ON");
material.EnableKeyword("_ALPHAPREMULTIPLY_ON");
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
color.a = alpha;
material.color = color;
break;
}
}
public static void SetSurfaceType(Material material, bool isTransparent)
{
if (isTransparent)
{
// 设置 SurfaceType 为 Transparent
material.SetFloat("_Surface", 1); // 1 代表 Transparent0 代表 Opaque
// 设置 Blend Mode 为 Alpha Blend使用枚举
material.SetOverrideTag("RenderType", "Transparent");
material.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
material.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
// 禁用深度写入
material.SetInt("_ZWrite", 0);
// 设置渲染队列
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Transparent;
// 启用相应的着色器关键字
material.EnableKeyword("_SURFACE_TYPE_TRANSPARENT");
material.DisableKeyword("_SURFACE_TYPE_OPAQUE");
Color color = material.color;
color.a = 0.2f;
material.color = color;
}
else
{
// 设置 SurfaceType 为 Opaque
material.SetFloat("_Surface", 0);
// 恢复默认的 Blend Mode这里假设默认是不透明模式对应的 Blend Mode
material.SetFloat("_Blend", 0);
// 启用深度写入
material.SetInt("_ZWrite", 1);
// 恢复默认的渲染队列
material.renderQueue = (int)UnityEngine.Rendering.RenderQueue.Geometry;
// 启用相应的着色器关键字
material.EnableKeyword("_SURFACE_TYPE_OPAQUE");
material.DisableKeyword("_SURFACE_TYPE_TRANSPARENT");
Color color = material.color;
color.a = 1;
material.color = color;
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 3f60d30421c64344cb0972e5a3584119
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,164 @@
using QFramework;
using QFramework.Example;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using XMLTool;
using static UnityEditor.Progress;
public class Body3DController : MonoSingleton<Body3DController>
{
Body3DController() { }
Dictionary<GameObject, Body3DOjbItem> objs = new Dictionary<GameObject, Body3DOjbItem>();
bool selectIsGroup = false;
public List<GameObject> isOnList = new List<GameObject>();
public override void OnSingletonInit()
{
base.OnSingletonInit();
TypeEventSystem.Global.Register<OnBody3DStart>((arg) =>
{
Refresh();
}).UnRegisterWhenGameObjectDestroyed(gameObject);
TypeEventSystem.Global.Register<OnModuleQuit>(OnClear);
TypeEventSystem.Global.Register<OnBody3DGroupTypeChanged>(OnToggleSelectType);
TypeEventSystem.Global.Register<OnBody3DSelected>(OnBody3DSelectedHandler);
}
private void OnBody3DSelectedHandler(OnBody3DSelected selected)
{
if (selected.isOn)
{
if (isOnList.Contains(selected.obj) == false)
{
if (selectIsGroup == false)
{
ClearObjectToggle();
}
isOnList.Add(selected.obj);
}
}
else
{
if (isOnList.Contains(selected.obj))
{
isOnList.Remove(selected.obj);
selected.obj.GetComponent<ObjectToggle>().Set(false);
}
}
}
public void Active(GameObject obj, bool isActive, bool isOther)
{
if (isOther)
{
foreach (var item in objs)
{
if (item.Key != obj)
{
item.Key.SetActive(isOther);
}
}
}
else
{
obj.SetActive(isActive);
}
}
public void Transparent(GameObject obj, bool isTransparent, bool isOther)
{
if (isOther)
{
foreach (var item in objs)
{
if (item.Key != obj)
{
Utility.SetSurfaceType(item.Key.GetComponent<MeshRenderer>().material, isTransparent);
}
}
}
else
{
Utility.SetSurfaceType(obj.GetComponent<MeshRenderer>().material, isTransparent);
}
}
private void OnToggleSelectType(OnBody3DGroupTypeChanged type)
{
selectIsGroup = type.isGroup;
}
private void OnClear(OnModuleQuit quit)
{
Clear();
}
public void Refresh()
{
Parser(Global.Instance.cur3DPart);
}
public void Parser(Body3D.Body body)
{
GameObject obj = Utility.FindObj(body.Path);
var bodyObjItem = obj.GetOrAddComponent<Body3DOjbItem>();
bodyObjItem.Init(body);
objs.Add(obj, bodyObjItem);
if (body.subBody != null)
{
foreach (var item in body.subBody)
{
Parser(item.Value);
}
}
}
private void Update()
{
if (Input.GetMouseButtonDown(0) && EventSystem.current.IsPointerOverGameObject() == false)
{
// 从相机发射一条射线到当前鼠标位置
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
GameObject obj = hit.collider.gameObject;
}
else
{
if (selectIsGroup == false)
{
ClearObjectToggle();
}
}
}
}
public void ClearObjectToggle()
{
for (int i = isOnList.Count - (1); i >= 0; i--)
{
isOnList[i].GetComponent<ObjectToggle>().Set(false);
}
}
public void Clear()
{
objs.Clear();
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3e0f94aba8f7e424d945ba2f28f894a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -26,7 +26,7 @@ public struct OnModuleStart
public struct OnLoadingShow
{
}
public struct OnLoadingHide
@ -37,4 +37,26 @@ public struct OnLoadingHide
public struct OnPoint3DQuestionDestroy
{
}
}
public struct OnBody3DStart
{
}
public struct OnBody3DDrag
{
public bool isAllow;
}
public struct OnBody3DGroupTypeChanged
{
public bool isGroup;
}
public struct OnBody3DSelected
{
public bool isOn;
public GameObject obj;
}

View File

@ -12,7 +12,7 @@ public class Global : Singleton<Global>
public XMLTool.AppData appData;
public Module curModule;
public Body3D.Body cur3DBody;
public Body3D.Body cur3DPart;
public static string dataPath = Application.dataPath + "/../Data";
public static string deviceIconsPath = dataPath + "/DeviceIcons/";

View File

@ -0,0 +1,60 @@
using QFramework;
using QFramework.Example;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using XMLTool;
public class Body3DOjbItem : MonoBehaviour
{
Body3D.Body body;
private void Awake()
{
TypeEventSystem.Global.Register<OnBody3DDrag>(OnBody3DDragHandler);
}
private void OnBody3DDragHandler(OnBody3DDrag drag)
{
}
public void Init(Body3D.Body body)
{
this.body = body;
if (body.subBody == null || body.subBody.Count == 0)
{
if (body.toggle != null)
{
var objToggle = gameObject.GetOrAddComponent<ObjectToggle>();
ObjectColorToggle colorToggle = null;
if (body.toggle.color != null)
{
colorToggle = gameObject.GetOrAddComponent<ObjectColorToggle>();
colorToggle.Init(Utility.ToColor(body.toggle.color.isOn), Utility.ToColor(body.toggle.color.isOff));
}
objToggle.OnValueChanged.AddListener(isOn =>
{
colorToggle?.SetColor(isOn);
var drag = gameObject.GetOrAddComponent<ObjDrag>();
drag.isOn = isOn;
if (isOn)
{
UI3DBodyInfoData data = new UI3DBodyInfoData();
data.body = body;
UIKit.OpenPanelAsync<UI3DBodyInfo>(UILevel.PopUI, data).ToAction().Start(this);
}
TypeEventSystem.Global.Send<OnBody3DSelected>(new OnBody3DSelected() { isOn = isOn, obj = gameObject });
});
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 297f30dc51736414695fa9fd6ad43dd6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,65 @@
using UnityEngine;
public class ObjDrag : MonoBehaviour
{
private Vector3 offset;
private Camera mainCamera;
public bool isOn = false;
void Start()
{
// 获取主相机引用
mainCamera = Camera.main;
}
void OnMouseDown()
{
if (isOn)
{
// 获取鼠标在相机视角平面上的世界坐标
Vector3 mouseWorldPos = GetMouseWorldPositionOnPlane();
// 计算物体位置与鼠标点击点在世界坐标中的偏移量
offset = transform.position - mouseWorldPos;
}
}
void OnMouseDrag()
{
if (isOn)
{
// 获取鼠标在相机视角平面上的世界坐标
Vector3 mouseWorldPos = GetMouseWorldPositionOnPlane();
// 根据偏移量更新物体的位置
transform.position = mouseWorldPos + offset;
}
}
private Vector3 GetMouseWorldPositionOnPlane()
{
// 获取鼠标在屏幕上的位置
Vector3 mouseScreenPos = Input.mousePosition;
mouseScreenPos.z = mainCamera.WorldToScreenPoint(transform.position).z; // 保持物体与相机的深度一致
// 将鼠标的屏幕坐标转换为世界坐标
Vector3 mouseWorldPos = mainCamera.ScreenToWorldPoint(mouseScreenPos);
// 计算相机视角平面的法线方向(相机的正前方)
Vector3 cameraForward = mainCamera.transform.forward;
// 创建一个平面,法线方向为相机的正前方,平面通过物体的当前位置
Plane plane = new Plane(cameraForward, transform.position);
// 从相机发射一条射线,指向鼠标的世界坐标
Ray ray = mainCamera.ScreenPointToRay(mouseScreenPos);
float distance;
if (plane.Raycast(ray, out distance))
{
// 返回射线与平面的交点
return ray.GetPoint(distance);
}
// 如果没有相交,返回物体的当前位置
return transform.position;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4bc81b557a686064482ca97c33f03504
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ObjectColorToggle : MonoBehaviour
{
Color isOnColor;
Color isOffColor;
MeshRenderer mesh;
private void Awake()
{
mesh = gameObject.GetComponent<MeshRenderer>();
}
public void Init(Color isOnColor, Color isOffColor)
{
this.isOnColor = isOnColor;
this.isOffColor = isOffColor;
}
public void SetColor(bool isOn)
{
float alpha = mesh.material.color.a;
if (isOn)
{
isOnColor.a = alpha;
mesh.material.color = isOnColor;
}
else
{
isOffColor.a = alpha;
mesh.material.color = isOffColor;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f7a034293f9fb56428fbd3c0772ff83c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,45 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
public class ObjectToggle : MonoBehaviour
{
public bool isOn = false;
//EventHandler OnValueChanged
public UnityEvent<bool> OnValueChanged = new UnityEvent<bool>();
private float mouseDownTime;
private bool isMouseDown;
private void OnMouseDown()
{
// 记录鼠标按下的时间
mouseDownTime = Time.time;
isMouseDown = true;
}
private void OnMouseUp()
{
if (isMouseDown)
{
// 计算鼠标按下和抬起的时间间隔
float clickDuration = Time.time - mouseDownTime;
// 检查时间间隔是否大于 0.2 秒
if (clickDuration < 0.2f)
{
// 执行原本 OnMouseUpAsButton 的逻辑
isOn = !isOn;
OnValueChanged?.Invoke(isOn);
}
isMouseDown = false;
}
}
public void Set(bool isOn)
{
this.isOn = isOn;
OnValueChanged?.Invoke(isOn);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fce67a81459948d43bb40992a12c83ec
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,61 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using QFramework;
namespace QFramework.Example
{
// Generate Id:66f1daf0-51f7-4184-b1fa-8903438d5b48
public partial class UI3DBodyInfo
{
public const string Name = "UI3DBodyInfo";
[SerializeField]
public UnityEngine.UI.Toggle Group;
[SerializeField]
public TMPro.TextMeshProUGUI PartName;
[SerializeField]
public UnityEngine.UI.Toggle Active;
[SerializeField]
public UnityEngine.UI.Toggle Transparent;
[SerializeField]
public UnityEngine.UI.Button Single;
[SerializeField]
public UnityEngine.UI.Toggle TransparentOther;
private UI3DBodyInfoData mPrivateData = null;
protected override void ClearUIComponents()
{
Group = null;
PartName = null;
Active = null;
Transparent = null;
Single = null;
TransparentOther = null;
mData = null;
}
public UI3DBodyInfoData Data
{
get
{
return mData;
}
}
UI3DBodyInfoData mData
{
get
{
return mPrivateData ?? (mPrivateData = new UI3DBodyInfoData());
}
set
{
mUIData = value;
mPrivateData = value;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b80aaf4bf2b27ef4bbf394d5183a96d5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,94 @@
using UnityEngine;
using UnityEngine.UI;
using QFramework;
using XMLTool;
using DG.Tweening;
using TMPro;
namespace QFramework.Example
{
public class UI3DBodyInfoData : UIPanelData
{
public Body3D.Body body;
}
public partial class UI3DBodyInfo : UIPanel
{
protected override void OnInit(IUIData uiData = null)
{
}
protected override void OnOpen(IUIData uiData = null)
{
mData = uiData as UI3DBodyInfoData ?? new UI3DBodyInfoData();
PartName.text = mData.body.Name;
Group.onValueChanged.AddListener(isOn =>
{
TypeEventSystem.Global.Send<OnBody3DGroupTypeChanged>(new OnBody3DGroupTypeChanged() { isGroup = isOn });
if (isOn)
{
Group.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = "多选";
}
else
{
Group.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = "单选";
}
});
GameObject obj = Utility.FindObj(mData.body.Path);
Active.onValueChanged.AddListener(isOn =>
{
obj.SetActive(isOn);
if (isOn)
{
Active.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = "隐藏";
}
else
{
Active.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = "显示";
}
});
Transparent.onValueChanged.AddListener(isOn =>
{
if (isOn)
{
Transparent.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = "实体";
}
else
{
Transparent.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = "透明";
}
Utility.SetSurfaceType(obj.GetComponent<MeshRenderer>().material, isOn);
});
Single.onClick.AddListener(() =>
{
Body3DController.Instance.Active(obj, false, true);
});
TransparentOther.onValueChanged.AddListener(isOn =>
{
if (isOn)
{
TransparentOther.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = "实体其他";
}
else
{
TransparentOther.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = "透明其他";
}
Body3DController.Instance.Transparent(obj, isOn, true);
});
}
protected override void OnShow()
{
}
protected override void OnHide()
{
}
protected override void OnClose()
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c8ce0f6197762174eb582255a26c5fb9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -22,15 +22,16 @@ namespace QFramework.Example
{
Content.RemoveAllChildren();
int index = 0;
foreach (var item in Global.Instance.curModule.body3d.datas)
foreach (var item in Global.Instance.curModule.body3d.parts)
{
GameObject obj = GameObject.Instantiate(BtnItem.gameObject, Content);
obj.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = item.Key;
obj.GetComponent<Button>().onClick.AddListener(() =>
{
Global.Instance.cur3DBody = Global.Instance.curModule.body3d.datas[item.Key];
Global.Instance.cur3DPart = Global.Instance.curModule.body3d.parts[item.Key];
TypeEventSystem.Global.Send<OnBody3DStart>();
UIBody3DData data = new UIBody3DData();
data.body = Global.Instance.cur3DBody;
data.body = Global.Instance.cur3DPart;
UIKit.OpenPanelAsync<UIBody3D>(canvasLevel: UILevel.PopUI, uiData: data).ToAction().StartGlobal(() =>
{
Hide();

View File

@ -5,6 +5,7 @@ using XMLTool;
using TMPro;
using System.Drawing;
using System.Collections.Generic;
using DG.Tweening;
namespace QFramework.Example
{
@ -24,18 +25,19 @@ namespace QFramework.Example
mData = uiData as UIBody3DData ?? new UIBody3DData();
BodyContent.RemoveAllChildren();
Utility.FindObj(mData.body.Path).SetActive(true);
foreach (var body in mData.body.Children)
foreach (var bodyData in mData.body.subBody)
{
var body = bodyData.Value;
var bodyItem = GameObject.Instantiate(BodyItem.gameObject, BodyContent);
bodyItem.transform.Find("Label").GetComponent<TextMeshProUGUI>().text = body.Name;
var bodyToggle = bodyItem.GetComponent<Toggle>();
bodyToggle.isOn = body.isShow;
GameObject obj = Utility.FindObj(body.Path);
obj.SetActive(body.isShow);
bodyToggle.onValueChanged.AddListener(isOn =>
{
Utility.FindObj(body.Path).SetActive(isOn);
obj.SetActive(isOn);
});
Utility.FindObj(body.Path).SetActive(body.isShow);
}
}

View File

@ -84,6 +84,7 @@ namespace QFramework.Example
var machin = StateMachineController.Instance;
var op = OperationController.Instance;
var dev = DeviceController.Instance;
var body3d = Body3DController.Instance;
ScoreController.Instance.Init();
UIKit.OpenPanelAsync<UIRightTop>().ToAction().StartGlobal(() =>
{

View File

@ -168,16 +168,32 @@ namespace XMLTool
public string Icon { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public string Tip { get; set; }
public string Audio { get; set; }
public bool isShow = false;
public List<Body> Children { get; set; } = new List<Body>();
public ObjectToggle toggle;
public Dictionary<string, Body> subBody { get; set; } = new Dictionary<string, Body>();
}
public Dictionary<string, Body> datas = new Dictionary<string, Body>();
public Dictionary<string, Body> parts = new Dictionary<string, Body>();
}
public class ObjectToggle
{
public ColorToggle color;
}
public class ColorToggle
{
public string isOn;
public string isOff;
}
public class XmlParser
{
@ -348,8 +364,8 @@ namespace XMLTool
module.body3d = new Body3D();
foreach (var item in body3d.Elements("Body"))
{
var body = ParseBody(item);
module.body3d.datas.Add(body.Name, body);
var part = ParseBody(item);
module.body3d.parts.Add(part.Name, part);
}
}
@ -380,7 +396,9 @@ namespace XMLTool
{
Icon = bodyElement.Attribute("icon")?.Value,
Name = bodyElement.Attribute("name")?.Value,
Path = bodyElement.Attribute("path")?.Value
Path = bodyElement.Attribute("path")?.Value,
Tip = bodyElement.Attribute("tip")?.Value,
Audio = bodyElement.Attribute("audio")?.Value
};
var isShow = bodyElement.Attribute("isShow");
@ -388,9 +406,22 @@ namespace XMLTool
{
bool.TryParse(isShow.Value, out body.isShow);
}
var toggle = bodyElement.Element("ObjectToggle");
if (toggle != null)
{
body.toggle = new ObjectToggle();
var color = toggle.Element("Color");
if (color != null)
{
body.toggle.color = new ColorToggle();
body.toggle.color.isOn = color.Attribute("isOn")?.Value;
body.toggle.color.isOff = color.Attribute("isOff")?.Value;
}
}
foreach (var childElement in bodyElement.Elements("Body"))
{
body.Children.Add(ParseBody(childElement));
var subBody = ParseBody(childElement);
body.subBody.Add(subBody.Name, subBody);
}
return body;

View File

@ -27,12 +27,28 @@
<Body name="骨骼系统" path="Ren/Tou/GuGe" isShow="false">
<Body name="肋骨" path="Ren/Tou/GuGe/LeiGu">
<Body name="左肋" path="Ren/Tou/GuGe/LeiGu/ZuoLei">
<Body name="左一" path="Ren/Tou/GuGe/LeiGu/ZuoLei/1"></Body>
<Body name="左二" path="Ren/Tou/GuGe/LeiGu/ZuoLei/2"></Body>
<Body name="左一" path="Ren/Tou/GuGe/LeiGu/ZuoLei/1" Tip="左一肋骨描述">
<ObjectToggle>
<Color isOn="0,255,255" isOff="255,255,255"></Color>
</ObjectToggle>
</Body>
<Body name="左二" path="Ren/Tou/GuGe/LeiGu/ZuoLei/2" Tip="左二肋骨描述">
<ObjectToggle>
<Color isOn="0,255,255" isOff="255,255,255"></Color>
</ObjectToggle>
</Body>
</Body>
<Body name="右肋" path="Ren/Tou/GuGe/LeiGu/YouLei">
<Body name="右一" path="Ren/Tou/GuGe/LeiGu/YouLei/1"></Body>
<Body name="右二" path="Ren/Tou/GuGe/LeiGu/YouLei/2"></Body>
<Body name="右一" path="Ren/Tou/GuGe/LeiGu/YouLei/1" Tip="7右一肋骨描述">
<ObjectToggle>
<Color isOn="0,255,255" isOff="255,255,255"></Color>
</ObjectToggle>
</Body>
<Body name="右二" path="Ren/Tou/GuGe/LeiGu/YouLei/2" Tip="右二肋骨描述">
<ObjectToggle>
<Color isOn="0,255,255" isOff="255,255,255"></Color>
</ObjectToggle>
</Body>
</Body>
</Body>
</Body>