initial upload

This commit is contained in:
tom.hempel
2025-09-21 22:42:26 +02:00
commit d03bcd4ba5
6231 changed files with 351582 additions and 0 deletions

View File

@ -0,0 +1,331 @@
using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using Newtonsoft.Json;
[System.Serializable]
public class SerializableVector3
{
public float x, y, z;
public SerializableVector3() { }
public SerializableVector3(Vector3 vector)
{
x = vector.x;
y = vector.y;
z = vector.z;
}
public Vector3 ToVector3()
{
return new Vector3(x, y, z);
}
}
[System.Serializable]
public class SerializableQuaternion
{
public float x, y, z, w;
public SerializableQuaternion() { }
public SerializableQuaternion(Quaternion quaternion)
{
x = quaternion.x;
y = quaternion.y;
z = quaternion.z;
w = quaternion.w;
}
public Quaternion ToQuaternion()
{
return new Quaternion(x, y, z, w);
}
}
[System.Serializable]
public class RootTransformData
{
public SerializableVector3 worldPosition;
public SerializableQuaternion worldRotation;
public SerializableVector3 localScale;
}
[System.Serializable]
public class BoneData
{
public string boneName; // e.g. "LeftArm", "RightHand"
public SerializableVector3 position;
public SerializableQuaternion rotation;
public SerializableVector3 scale;
}
[System.Serializable]
public class BlendShapeData
{
public string meshName;
public float[] weights;
}
[System.Serializable]
public class AvatarSyncData
{
public RootTransformData rootTransform;
public List<BoneData> bones;
public List<BlendShapeData> blendShapes;
public float timestamp;
}
public class AvatarDataWriter : MonoBehaviour
{
[Header("Avatar Configuration")]
[SerializeField] private Transform avatarRoot;
[SerializeField] private string fileName = "avatar_sync_data.json";
[SerializeField] private bool writeEveryFrame = true;
[SerializeField] private float updateRate = 60f; // Updates per second
[Header("Synchronization Options")]
[SerializeField] private bool syncWorldPosition = true; // Sync avatar world position
[SerializeField] private bool syncWorldRotation = true; // Sync avatar world rotation
[SerializeField] private bool syncLocalScale = false; // Sync avatar local scale
[Header("Debug")]
[SerializeField] private bool enableDebugMode = false;
[SerializeField] private string debugBoneName = "LeftArm"; // Bone to monitor
private string filePath;
private float lastUpdateTime;
private List<Transform> allBones;
private List<SkinnedMeshRenderer> skinnedMeshRenderers;
private Vector3 lastDebugPosition;
private Quaternion lastDebugRotation;
private Vector3 lastRootWorldPosition;
void Start()
{
// Create Sync-Files directory if it doesn't exist
string syncFilesPath = Path.Combine(Application.dataPath, "Sync-Files");
if (!Directory.Exists(syncFilesPath))
{
Directory.CreateDirectory(syncFilesPath);
}
filePath = Path.Combine(syncFilesPath, fileName);
// If avatarRoot is not assigned, try to find it automatically
if (avatarRoot == null)
{
avatarRoot = transform;
}
// Cache all bones and skinned mesh renderers
CacheAvatarComponents();
// Initialize debug tracking
if (enableDebugMode)
{
Transform debugBone = FindBoneByName(debugBoneName);
if (debugBone != null)
{
lastDebugPosition = debugBone.localPosition;
lastDebugRotation = debugBone.localRotation;
Debug.Log($"Debug mode enabled. Monitoring bone: {debugBoneName}");
}
else
{
Debug.LogWarning($"Debug bone '{debugBoneName}' not found!");
}
lastRootWorldPosition = avatarRoot.position;
}
Debug.Log($"Avatar Data Writer initialized. Writing to: {filePath}");
Debug.Log($"World Position Sync: {syncWorldPosition}, World Rotation Sync: {syncWorldRotation}");
}
void CacheAvatarComponents()
{
allBones = new List<Transform>();
skinnedMeshRenderers = new List<SkinnedMeshRenderer>();
// Get all skinned mesh renderers
skinnedMeshRenderers.AddRange(avatarRoot.GetComponentsInChildren<SkinnedMeshRenderer>());
// Get all unique bones from all SkinnedMeshRenderers
HashSet<Transform> uniqueBones = new HashSet<Transform>();
foreach (SkinnedMeshRenderer smr in skinnedMeshRenderers)
{
if (smr.bones != null)
{
foreach (Transform bone in smr.bones)
{
if (bone != null)
{
uniqueBones.Add(bone);
}
}
}
}
allBones.AddRange(uniqueBones);
Debug.Log($"Cached {allBones.Count} bones and {skinnedMeshRenderers.Count} skinned mesh renderers");
// Debug: Print some bone names to help with troubleshooting
if (enableDebugMode)
{
Debug.Log("Found bones:");
for (int i = 0; i < Mathf.Min(10, allBones.Count); i++)
{
Debug.Log($" Bone {i}: {allBones[i].name}");
}
}
}
Transform FindBoneByName(string name)
{
foreach (Transform bone in allBones)
{
if (bone.name.Contains(name))
{
return bone;
}
}
return null;
}
void Update()
{
// Debug mode: Check if the monitored bone has changed
if (enableDebugMode)
{
Transform debugBone = FindBoneByName(debugBoneName);
if (debugBone != null)
{
if (Vector3.Distance(debugBone.localPosition, lastDebugPosition) > 0.001f ||
Quaternion.Angle(debugBone.localRotation, lastDebugRotation) > 0.1f)
{
Debug.Log($"Bone {debugBoneName} changed! Pos: {debugBone.localPosition}, Rot: {debugBone.localRotation}");
lastDebugPosition = debugBone.localPosition;
lastDebugRotation = debugBone.localRotation;
}
}
// Debug: Check if avatar root world position has changed
if (Vector3.Distance(avatarRoot.position, lastRootWorldPosition) > 0.01f)
{
Debug.Log($"Avatar root world position changed! From: {lastRootWorldPosition} To: {avatarRoot.position}");
lastRootWorldPosition = avatarRoot.position;
}
}
if (writeEveryFrame)
{
WriteAvatarData();
}
else
{
// Rate-limited updates
if (Time.time - lastUpdateTime >= 1f / updateRate)
{
WriteAvatarData();
lastUpdateTime = Time.time;
}
}
}
void WriteAvatarData()
{
try
{
AvatarSyncData syncData = new AvatarSyncData
{
rootTransform = new RootTransformData(),
bones = new List<BoneData>(),
blendShapes = new List<BlendShapeData>(),
timestamp = Time.time
};
// Capture root transform data
if (syncWorldPosition)
{
syncData.rootTransform.worldPosition = new SerializableVector3(avatarRoot.position);
}
else
{
syncData.rootTransform.worldPosition = new SerializableVector3(Vector3.zero);
}
if (syncWorldRotation)
{
syncData.rootTransform.worldRotation = new SerializableQuaternion(avatarRoot.rotation);
}
else
{
syncData.rootTransform.worldRotation = new SerializableQuaternion(Quaternion.identity);
}
if (syncLocalScale)
{
syncData.rootTransform.localScale = new SerializableVector3(avatarRoot.localScale);
}
else
{
syncData.rootTransform.localScale = new SerializableVector3(Vector3.one);
}
// Capture bone data
foreach (Transform bone in allBones)
{
BoneData boneData = new BoneData
{
boneName = bone.name,
position = new SerializableVector3(bone.localPosition),
rotation = new SerializableQuaternion(bone.localRotation),
scale = new SerializableVector3(bone.localScale)
};
syncData.bones.Add(boneData);
}
// Capture blendshape data
foreach (SkinnedMeshRenderer smr in skinnedMeshRenderers)
{
if (smr.sharedMesh != null && smr.sharedMesh.blendShapeCount > 0)
{
float[] weights = new float[smr.sharedMesh.blendShapeCount];
for (int i = 0; i < weights.Length; i++)
{
weights[i] = smr.GetBlendShapeWeight(i);
}
BlendShapeData blendShapeData = new BlendShapeData
{
meshName = smr.gameObject.name, // Use GameObject name instead of path
weights = weights
};
syncData.blendShapes.Add(blendShapeData);
}
}
// Convert to JSON and write to file
string json = JsonConvert.SerializeObject(syncData, Formatting.Indented);
File.WriteAllText(filePath, json);
}
catch (Exception e)
{
Debug.LogError($"Error writing avatar data: {e.Message}");
}
}
void OnDisable()
{
// Write final data when component is disabled
if (allBones != null && allBones.Count > 0)
{
WriteAvatarData();
}
}
}