summaryrefslogtreecommitdiffstats
path: root/DecodeVertexData.cs
diff options
context:
space:
mode:
Diffstat (limited to 'DecodeVertexData.cs')
-rw-r--r--DecodeVertexData.cs197
1 files changed, 197 insertions, 0 deletions
diff --git a/DecodeVertexData.cs b/DecodeVertexData.cs
new file mode 100644
index 0000000..32933ce
--- /dev/null
+++ b/DecodeVertexData.cs
@@ -0,0 +1,197 @@
+using UnityEngine;
+using System.Collections.Generic;
+
+public class DecodeVertexVectors : MonoBehaviour
+{
+ [Header("Edge Interpolation")]
+ [SerializeField] private int edgeSubdivisions = 5;
+ [SerializeField] private float edgeGizmoScale = 0.3f;
+ [SerializeField] private Color edgeVectorColor = new Color(0.5f, 0.8f, 1f, 0.7f);
+ [SerializeField] private Color correctedVectorColor = new Color(1f, 0.5f, 0.2f, 0.7f);
+
+ [Header("Orientation Visualization")]
+ [SerializeField] private bool showOrientations = true;
+ [SerializeField] private bool showAllAxes = true;
+ [SerializeField] private float orientationVectorLength = 1.0f;
+
+ [Header("UV Channels")]
+ [SerializeField] private int quaternionXYChannel = 1;
+ [SerializeField] private int quaternionZWChannel = 2;
+
+ [Header("Colors")]
+ [SerializeField] private Color forwardColor = Color.blue;
+ [SerializeField] private Color rightColor = Color.red;
+ [SerializeField] private Color upColor = Color.green;
+
+ private void OnDrawGizmos()
+ {
+ var meshFilter = GetComponent<MeshFilter>();
+ if (meshFilter == null) return;
+
+ var mesh = meshFilter.sharedMesh;
+ if (mesh == null) return;
+
+ var vertices = mesh.vertices;
+ var vertexColors = mesh.colors;
+
+ if (vertexColors != null && vertexColors.Length > 0)
+ {
+ DrawInterpolatedEdges(mesh, vertices, vertexColors);
+ }
+
+ if (showOrientations)
+ {
+ DrawOrientations(mesh, vertices);
+ }
+ }
+
+ void DrawInterpolatedEdges(Mesh mesh, Vector3[] vertices, Color[] vertexColors)
+ {
+ var triangles = mesh.triangles;
+ HashSet<(int, int)> drawnEdges = new HashSet<(int, int)>();
+
+ Vector2[] uvXY = GetUVData(mesh, quaternionXYChannel);
+ Vector2[] uvZW = GetUVData(mesh, quaternionZWChannel);
+ bool hasQuaternions = uvXY != null && uvZW != null && uvXY.Length > 0 && uvZW.Length > 0;
+
+ for (int i = 0; i < triangles.Length; i += 3)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ int v1 = triangles[i + j];
+ int v2 = triangles[i + ((j + 1) % 3)];
+
+ var edge = v1 < v2 ? (v1, v2) : (v2, v1);
+ if (drawnEdges.Contains(edge)) continue;
+ drawnEdges.Add(edge);
+
+ if (v1 >= vertices.Length || v2 >= vertices.Length ||
+ v1 >= vertexColors.Length || v2 >= vertexColors.Length)
+ continue;
+
+ bool canUseQuaternions = hasQuaternions &&
+ v1 < uvXY.Length && v2 < uvXY.Length &&
+ v1 < uvZW.Length && v2 < uvZW.Length;
+
+ for (int k = 0; k <= edgeSubdivisions; k++)
+ {
+ float t = k / (float)edgeSubdivisions;
+
+ Vector3 localPos = Vector3.Lerp(vertices[v1], vertices[v2], t);
+ Vector3 worldPos = transform.TransformPoint(localPos);
+
+ Color interpolatedColor = Color.Lerp(vertexColors[v1], vertexColors[v2], t);
+ Vector3 decodedVector = DecodeVectorFromColor(interpolatedColor);
+
+ Gizmos.color = edgeVectorColor;
+ Vector3 worldVector = transform.TransformDirection(decodedVector);
+ DrawVector(worldPos, worldVector, edgeGizmoScale);
+
+ if (canUseQuaternions)
+ {
+ Quaternion q1 = GetQuaternionFromUV(uvXY[v1], uvZW[v1]);
+ Quaternion q2 = GetQuaternionFromUV(uvXY[v2], uvZW[v2]);
+ // Slerp is more correct, but lerp is what we'll actually get in the shader.
+ Quaternion interpolatedQuat = Quaternion.Lerp(q1, q2, t);
+
+ Vector3 correctedVector = interpolatedQuat * decodedVector;
+ Vector3 worldCorrectedVector = transform.TransformDirection(correctedVector);
+
+ Gizmos.color = correctedVectorColor;
+ DrawVector(worldPos, worldCorrectedVector, edgeGizmoScale);
+ }
+ }
+ }
+ }
+ }
+
+ void DrawVector(Vector3 origin, Vector3 direction, float scale)
+ {
+ Vector3 end = origin + direction * scale;
+ Gizmos.DrawSphere(end, 0.02f);
+ Gizmos.DrawLine(origin, end);
+ }
+
+ Quaternion GetQuaternionFromUV(Vector2 xy, Vector2 zw)
+ {
+ float x = xy.x;
+ float y = xy.y;
+ float z = zw.x;
+ float w = zw.y;
+
+ return new Quaternion(x, y, z, w).normalized;
+ }
+
+ void DrawOrientations(Mesh mesh, Vector3[] vertices)
+ {
+ Vector2[] uvXY = GetUVData(mesh, quaternionXYChannel);
+ Vector2[] uvZW = GetUVData(mesh, quaternionZWChannel);
+
+ if (uvXY == null || uvZW == null || uvXY.Length == 0 || uvZW.Length == 0) return;
+
+ int vertexCount = Mathf.Min(vertices.Length, uvXY.Length, uvZW.Length);
+
+ for (int vertIdx = 0; vertIdx < vertexCount; vertIdx++)
+ {
+ Quaternion quat = GetQuaternionFromUV(uvXY[vertIdx], uvZW[vertIdx]);
+
+ Vector3 worldPos = transform.TransformPoint(vertices[vertIdx]);
+
+ Vector3 forward = transform.TransformDirection(quat * Vector3.forward);
+ DrawArrow(worldPos, forward, forwardColor, orientationVectorLength);
+
+ if (showAllAxes)
+ {
+ Vector3 right = transform.TransformDirection(quat * Vector3.right);
+ Vector3 up = transform.TransformDirection(quat * Vector3.up);
+ DrawArrow(worldPos, right, rightColor, orientationVectorLength * 0.8f);
+ DrawArrow(worldPos, up, upColor, orientationVectorLength * 0.8f);
+ }
+ }
+ }
+
+ void DrawArrow(Vector3 origin, Vector3 direction, Color color, float length)
+ {
+ Gizmos.color = color;
+
+ Vector3 end = origin + direction * length;
+ Gizmos.DrawLine(origin, end);
+
+ Vector3 right = Vector3.Cross(direction, Vector3.up).normalized;
+ if (right.magnitude < 0.01f)
+ right = Vector3.Cross(direction, Vector3.right).normalized;
+
+ Vector3 arrowBack = -direction * length * 0.2f;
+ Vector3 arrowSide = right * length * 0.1f;
+
+ Gizmos.DrawLine(end, end + arrowBack + arrowSide);
+ Gizmos.DrawLine(end, end + arrowBack - arrowSide);
+
+ Gizmos.DrawSphere(origin, 0.05f);
+ }
+
+ n (-1 to 1), aVectorontains scale factor.
+ /// </summary>
+
+ return new Vector3(
+ (color.r * 2.0f - 1.0f),
+ (color.g * 2.0f - 1.0f),
+ (color.b * 2.0f - 1.0f)) / color.a;
+ }
+
+ Vector2[] GetUVData(Mesh mesh, int channel)
+ {
+ switch (channel)
+ {
+ case 0: return mesh.uv;
+ case 1: return mesh.uv2;
+ case 2: return mesh.uv3;
+ case 3: return mesh.uv4;
+ case 4: return mesh.uv5;
+ case 5: return mesh.uv6;
+ case 6: return mesh.uv7;
+ case 7: return mesh.uv8;
+ default: return null;
+ }
+ }
+}