PICO中空间锚点的制作与运用
·
通过把空间中的对象矩阵保存至json,读取数据加载对应的对象
using UnityEngine;
using System.Collections.Generic;
using System.IO;
using System;
using System.Collections;
[Serializable]
public class TransformData
{
public string name;
public TransformMatrix matrix;
}
[Serializable]
public class TransformMatrix
{
public Vector3 position;
public Vector3 rotation;
public Vector3 scale;
}
[Serializable]
public class TransformDataWrapper
{
public List<TransformData> items;
}
/// <summary>
/// 锚点加载
/// </summary>
public class AnchorLoad : MonoBehaviour
{
[Header("调试设置")]
[SerializeField] private bool debugMode = true;
[Header("回调设置")]
public System.Action<List<TransformData>> OnInitializationComplete;
private List<TransformData> currentObjectsData = new List<TransformData>();
private string jsonFilePath => Path.Combine(Application.persistentDataPath, "AnchorData.json");
private string streamingAssetsFilePath => Path.Combine(Application.streamingAssetsPath, "AnchorData.json");
void Start()
{
StartCoroutine(InitializeJSONSystem());
}
/// <summary>
/// 初始化JSON系统:检查文件是否存在,不存在则从StreamingAssets复制
/// </summary>
public IEnumerator InitializeJSONSystem()
{
yield return StartCoroutine(CheckAndCopySceneData());
bool success = false;
string message = "";
List<TransformData> loadedData = null;
if (CheckJSONFileExists())
{
try
{
LoadObjectsFromJSON();
loadedData = currentObjectsData;
success = true;
message = $"JSON系统初始化成功,加载了 {currentObjectsData.Count} 个对象";
LogMessage(message);
}
catch (Exception e)
{
success = false;
message = $"JSON系统初始化失败: {e.Message}";
Debug.LogError(message);
loadedData = new List<TransformData>();
}
}
else
{
try
{
CreateDefaultJSONFile();
LoadObjectsFromJSON();
loadedData = currentObjectsData;
success = true;
message = $"已创建默认JSON文件并初始化成功,加载了 {currentObjectsData.Count} 个对象";
LogMessage(message);
}
catch (Exception e)
{
success = false;
message = $"创建默认JSON文件失败: {e.Message}";
Debug.LogError(message);
loadedData = new List<TransformData>();
}
}
// 触发初始化完成回调,传递加载的对象数据
OnInitializationComplete?.Invoke(loadedData);
}
/// <summary>
/// 带回调的初始化方法
/// </summary>
public void InitializeWithCallback(System.Action<List<TransformData>> callback)
{
if (callback != null)
{
OnInitializationComplete += callback;
}
StartCoroutine(InitializeJSONSystem());
}
/// <summary>
/// 检查并复制场景数据文件
/// </summary>
private IEnumerator CheckAndCopySceneData()
{
if (!File.Exists(jsonFilePath))
{
LogMessage("PersistentDataPath中未找到sceneObjects.json,检查StreamingAssets...");
if (Application.platform == RuntimePlatform.Android)
{
yield return StartCoroutine(CopyFileAndroid());
}
else
{
CopyFileStandard();
}
}
else
{
LogMessage("PersistentDataPath中已存在sceneObjects.json");
}
}
/// <summary>
/// 标准文件复制方法(非Android平台)
/// </summary>
private void CopyFileStandard()
{
if (File.Exists(streamingAssetsFilePath))
{
try
{
// 确保目标目录存在
string directory = Path.GetDirectoryName(jsonFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
File.Copy(streamingAssetsFilePath, jsonFilePath, false);
LogMessage("已从StreamingAssets复制sceneObjects.json到PersistentDataPath");
}
catch (System.Exception e)
{
Debug.LogError($"复制文件时出错: {e.Message}");
}
}
else
{
LogMessage("StreamingAssets中也未找到sceneObjects.json");
}
}
/// <summary>
/// Android平台文件复制方法
/// </summary>
private IEnumerator CopyFileAndroid()
{
using (UnityEngine.Networking.UnityWebRequest www =
UnityEngine.Networking.UnityWebRequest.Get(streamingAssetsFilePath))
{
yield return www.SendWebRequest();
if (www.result == UnityEngine.Networking.UnityWebRequest.Result.Success)
{
try
{
string directory = Path.GetDirectoryName(jsonFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
}
File.WriteAllBytes(jsonFilePath, www.downloadHandler.data);
LogMessage("已从StreamingAssets复制sceneObjects.json到PersistentDataPath (Android)");
}
catch (System.Exception e)
{
Debug.LogError($"复制文件时出错: {e.Message}");
}
}
else
{
LogMessage("StreamingAssets中未找到sceneObjects.json (Android)");
}
}
}
/// <summary>
/// 检查JSON文件是否存在
/// </summary>
private bool CheckJSONFileExists()
{
bool exists = File.Exists(jsonFilePath);
LogMessage($"检查文件存在: {exists}");
return exists;
}
/// <summary>
/// 创建默认的JSON文件
/// </summary>
private void CreateDefaultJSONFile()
{
try
{
string directory = Path.GetDirectoryName(jsonFilePath);
if (!Directory.Exists(directory))
{
Directory.CreateDirectory(directory);
LogMessage($"创建目录: {directory}");
}
TransformDataWrapper wrapper = new TransformDataWrapper { items = currentObjectsData };
string jsonString = JsonUtility.ToJson(wrapper, true);
File.WriteAllText(jsonFilePath, jsonString);
LogMessage("默认JSON文件创建成功!");
LogMessage($"文件路径: {jsonFilePath}");
LogMessage($"文件内容: {jsonString}");
}
catch (Exception e)
{
Debug.LogError($"创建JSON文件失败: {e.Message}");
throw;
}
}
/// <summary>
/// 从JSON加载对象
/// </summary>
private void LoadObjectsFromJSON()
{
try
{
if (!File.Exists(jsonFilePath))
{
return;
}
string jsonString = File.ReadAllText(jsonFilePath);
TransformDataWrapper wrapper = JsonUtility.FromJson<TransformDataWrapper>(jsonString);
if (wrapper != null && wrapper.items != null)
{
currentObjectsData = wrapper.items;
LogMessage($"成功加载 {currentObjectsData.Count} 个对象");
}
else
{
Debug.LogError("JSON解析失败或数据为空");
currentObjectsData = new List<TransformData>();
}
}
catch (Exception e)
{
Debug.LogError($"加载JSON失败: {e.Message}");
currentObjectsData = new List<TransformData>();
throw;
}
}
/// <summary>
/// 检查对象是否存在,存在则更新,不存在则添加
/// </summary>
public void AddOrUpdateObject(string objectName, Vector3 position, Vector3 rotation, Vector3 scale)
{
TransformData existingData = currentObjectsData.Find(data => data.name == objectName);
if (existingData != null)
{
existingData.matrix.position = position;
existingData.matrix.rotation = rotation;
existingData.matrix.scale = scale;
LogMessage($"更新对象: {objectName}");
}
else
{
TransformData newData = new TransformData
{
name = objectName,
matrix = new TransformMatrix
{
position = position,
rotation = rotation,
scale = scale
}
};
currentObjectsData.Add(newData);
LogMessage($"添加新对象: {objectName}");
}
SaveToJSON();
}
/// <summary>
/// 动态添加新对象(在现有数据后追加)
/// </summary>
public void AddNewObject(string objectName, Vector3 position, Vector3 rotation, Vector3 scale)
{
LoadObjectsFromJSON();
if (CheckObjectExists(objectName))
{
LogMessage($"对象已存在: {objectName},使用更新方法替代");
UpdateObject(objectName, position, rotation, scale);
return;
}
TransformData newData = new TransformData
{
name = objectName,
matrix = new TransformMatrix
{
position = position,
rotation = rotation,
scale = scale
}
};
currentObjectsData.Add(newData);
SaveToJSON();
LogMessage($"成功添加新对象: {objectName}");
LogMessage($"当前对象总数: {currentObjectsData.Count}");
}
/// <summary>
/// 批量添加多个对象(在现有数据后追加)
/// </summary>
public void AddMultipleObjects(List<TransformData> newObjects)
{
LoadObjectsFromJSON();
int addedCount = 0;
int updatedCount = 0;
foreach (TransformData newObject in newObjects)
{
TransformData existingData = currentObjectsData.Find(data => data.name == newObject.name);
if (existingData != null)
{
existingData.matrix = newObject.matrix;
updatedCount++;
LogMessage($"更新对象: {newObject.name}");
}
else
{
currentObjectsData.Add(newObject);
addedCount++;
LogMessage($"添加新对象: {newObject.name}");
}
}
SaveToJSON();
LogMessage($"批量添加完成 - 新增: {addedCount}, 更新: {updatedCount}, 总计: {currentObjectsData.Count}");
}
/// <summary>
/// 从现有JSON文件读取数据,然后追加新数据
/// </summary>
public void AppendToExistingJSON(string objectName, Vector3 position, Vector3 rotation, Vector3 scale)
{
LoadObjectsFromJSON();
AddOrUpdateObject(objectName, position, rotation, scale);
}
/// <summary>
/// 更新已存在的对象
/// </summary>
public void UpdateObject(string objectName, Vector3 position, Vector3 rotation, Vector3 scale)
{
TransformData existingData = currentObjectsData.Find(data => data.name == objectName);
if (existingData != null)
{
existingData.matrix.position = position;
existingData.matrix.rotation = rotation;
existingData.matrix.scale = scale;
SaveToJSON();
LogMessage($"更新对象: {objectName}");
}
else
{
LogMessage($"未找到对象: {objectName},无法更新");
}
}
/// <summary>
/// 删除指定对象
/// </summary>
public void DeleteObject(string objectName)
{
// 先加载最新数据
LoadObjectsFromJSON();
int removedCount = currentObjectsData.RemoveAll(data => data.name == objectName);
if (removedCount > 0)
{
SaveToJSON();
LogMessage($"删除对象: {objectName}");
}
else
{
LogMessage($"未找到对象: {objectName},无法删除");
}
}
/// <summary>
/// 检查对象是否存在
/// </summary>
public bool CheckObjectExists(string objectName)
{
return currentObjectsData.Exists(data => data.name == objectName);
}
/// <summary>
/// 获取指定对象的数据
/// </summary>
public TransformData GetObjectData(string objectName)
{
return currentObjectsData.Find(data => data.name == objectName);
}
/// <summary>
/// 保存到JSON文件
/// </summary>
public void SaveToJSON()
{
try
{
TransformDataWrapper wrapper = new TransformDataWrapper { items = currentObjectsData };
string jsonString = JsonUtility.ToJson(wrapper, true);
File.WriteAllText(jsonFilePath, jsonString);
LogMessage("JSON文件已保存");
}
catch (Exception e)
{
Debug.LogError($"保存JSON失败: {e.Message}");
}
}
/// <summary>
/// 重新创建JSON文件(重置为默认)
/// </summary>
public void RecreateJSONFile()
{
LogMessage("重新创建JSON文件...");
if (File.Exists(jsonFilePath))
{
File.Delete(jsonFilePath);
LogMessage("已删除旧文件");
}
CreateDefaultJSONFile();
}
/// <summary>
/// 显示JSON文件内容(用于调试)
/// </summary>
public void DisplayJSONContent()
{
if (File.Exists(jsonFilePath))
{
string content = File.ReadAllText(jsonFilePath);
LogMessage($"JSON内容:\n{content}");
}
else
{
LogMessage("JSON文件不存在");
}
}
/// <summary>
/// 获取原始JSON数据字符串
/// </summary>
public string GetRawJSONData()
{
if (File.Exists(jsonFilePath))
{
return File.ReadAllText(jsonFilePath);
}
return "{}";
}
/// <summary>
/// 日志输出
/// </summary>
private void LogMessage(string message)
{
if (debugMode)
{
Debug.Log($"[JSONManager] {message}");
}
}
/// <summary>
/// 获取当前对象数量(用于UI显示)
/// </summary>
public int GetObjectCount()
{
return currentObjectsData?.Count ?? 0;
}
/// <summary>
/// 获取JSON文件路径(用于UI显示)
/// </summary>
public string GetJSONFilePath()
{
return jsonFilePath;
}
/// <summary>
/// 获取所有对象名称列表(用于UI显示)
/// </summary>
public List<string> GetAllObjectNames()
{
List<string> names = new List<string>();
if (currentObjectsData != null)
{
foreach (var data in currentObjectsData)
{
names.Add(data.name);
}
}
return names;
}
/// <summary>
/// 获取所有对象数据(用于外部处理)
/// </summary>
public List<TransformData> GetAllObjectData()
{
LoadObjectsFromJSON();
return new List<TransformData>(currentObjectsData);
}
/// <summary>
/// 添加初始化完成回调
/// </summary>
public void AddInitializationCallback(System.Action<List<TransformData>> callback)
{
if (callback != null)
{
OnInitializationComplete += callback;
}
}
/// <summary>
/// 移除初始化完成回调
/// </summary>
public void RemoveInitializationCallback(System.Action<List<TransformData>> callback)
{
if (callback != null)
{
OnInitializationComplete -= callback;
}
}
/// <summary>
/// 清除所有初始化回调
/// </summary>
public void ClearAllInitializationCallbacks()
{
OnInitializationComplete = null;
}
/// <summary>
/// 强制重新初始化并触发回调
/// </summary>
public void ReinitializeWithCallback(System.Action<List<TransformData>> callback = null)
{
if (callback != null)
{
OnInitializationComplete += callback;
}
StartCoroutine(InitializeJSONSystem());
}
}
使用案例如下:
using GameLogic;
using System.Collections;
using System.Collections.Generic;
using Unity.XR.PXR;
using UnityEditor;
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.XR;
public class MRSeeThrough : MonoBehaviour
{
AnchorLoad jsonMgr;
[SerializeField]
GameObject prefab;
bool butY = false;
bool btnA = false;
bool isClick = false;
int num = 0;
void Start()
{
PXR_Manager.EnableVideoSeeThrough = true; // 启用视频透视
jsonMgr = FindObjectOfType<AnchorLoad>();
jsonMgr.AddInitializationCallback(OnJSONInitialized);
}
// 处理按键事件
private void ProcessKeyEvent()
{
InputDevices.GetDeviceAtXRNode(XRNode.LeftHand).TryGetFeatureValue(CommonUsages.primaryButton, out butY);
InputDevices.GetDeviceAtXRNode(XRNode.RightHand).TryGetFeatureValue(CommonUsages.primaryButton, out btnA);
if (btnA && butY)
{
if (!isClick)
{
num++;
var go = Instantiate(prefab);
var spatialAnchor = go.GetComponent<PXRSample_SpatialAnchor>();
go.transform.position = Vector3.zero;
go.transform.rotation = Quaternion.Euler(Vector3.zero);
go.name = "新增点"+ num;
spatialAnchor.curName = go.name;
Debug.Log("两个按钮同时按下");
}
isClick = true;
}
else {
isClick = false;
}
}
private void OnJSONInitialized(List<TransformData> objectData)
{
foreach (TransformData data in objectData)
{
CreateSingleObject(data);
}
}
/// <summary>
/// 创建单个对象
/// </summary>
private void CreateSingleObject(TransformData data)
{
var go = Instantiate(prefab);
var spatialAnchor = go.GetComponent<PXRSample_SpatialAnchor>();
go.transform.position = data.matrix.position;
go.transform.rotation = Quaternion.Euler(data.matrix.rotation);
go.name = data.name;
spatialAnchor.curName = data.name;
}
private void Update()
{
ProcessKeyEvent();
}
void OnDestroy()
{
if (jsonMgr != null)
{
jsonMgr.RemoveInitializationCallback(OnJSONInitialized);
}
}
}
更多推荐
所有评论(0)