Skip to content

Commit

Permalink
feat(export): Skinning export support (atteneder#179)
Browse files Browse the repository at this point in the history
* The hierarchy is now first converted to nodes before actually adding components to nodes. This ensures joint nodes have already been added.

* fix: Updated export references.
* Camera/light orientation nodes are added at last now.
* Buffer view targets are added now.

* fix: Fixed layer mask test and updated referenences.

* fix: Skip skin when not all bone transforms are exported as well.

* fix: Draco compressed skin export.

* doc: Updated features page.

---------

Co-authored-by: Hugo Pereira <[email protected]>
  • Loading branch information
2 people authored and GitHub Enterprise committed Sep 4, 2024
1 parent d983ce6 commit a9923bd
Show file tree
Hide file tree
Showing 118 changed files with 1,703 additions and 141 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- (Import) Setting to create textures readable. This allows users to access resulting textures from their scripts.
- (Export) Non-readable meshes can be exported as well now.
- (Export) Added support for exporting meshes with vertex compression enabled (effectively converting 16-bit float positions/normals/tangents/texture coordinates to 32-bit floats).
- (Export) [Buffer view targets](https://registry.khronos.org/glTF/specs/2.0/glTF-2.0.html#_bufferview_target) are set properly now.
- (Import) Support for mesh primitive modes `TRIANGLE_STRIP` and `TRIANGLE_FAN` (thanks [Hexer611][Hexer611] for [#22](https://github.com/Unity-Technologies/com.unity.cloud.gltfast/pull/22))

### Fixed
Expand Down
6 changes: 3 additions & 3 deletions Documentation~/features.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,12 +70,12 @@ The glTF 2.0 specification is fully supported, with only a few minor remarks.
| Draco&trade; mesh compression (via [DracoForUnity]) | ✅ | ✅
| Implicit (no) indices ||
| Per primitive material | ✅ | ✅
| Joints (up to 4 per vertex) ||
| Weights (up to 4 per vertex) ||
| Joints (up to 4 per vertex) | ✅ |
| Weights (up to 4 per vertex) | ✅ |
| | |
| **Morph Targets / Blend Shapes**
| Sparse accessors | ³ ✅ |
| [Skins][Skins] ||
| [Skins][Skins] | ✅ |
| | |
| **Animation**
| via legacy Animation System ||
Expand Down
87 changes: 87 additions & 0 deletions Runtime/Scripts/Export/ExportJobs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,93 @@ public void Execute(int i)
}
}


[BurstCompile]
public unsafe struct ConvertSkinWeightsJob : IJobParallelFor
{

public uint inputByteStride;
public uint outputByteStride;

[ReadOnly]
[NativeDisableUnsafePtrRestriction]
public byte* input;

[WriteOnly]
[NativeDisableUnsafePtrRestriction]
public byte* output;

public void Execute(int i)
{
var inPtr = (float4*)(input + i * inputByteStride);
var outPtr = (float4*)(output + i * outputByteStride);

*outPtr = *inPtr;
}
}

[BurstCompile]
public struct ConvertMatrixJob : IJobParallelFor
{
public NativeArray<float4x4> matrices;

public void Execute(int i)
{

var tmp = matrices[i];
tmp.c0.y *= -1;
tmp.c0.z *= -1;
tmp.c1.x *= -1;
tmp.c2.x *= -1;
tmp.c3.x *= -1;
matrices[i] = tmp;
}
}

[BurstCompile]
public unsafe struct ConvertSkinIndicesJob : IJobParallelFor
{

struct ushort4
{
public ushort4(uint x, uint y, uint z, uint w)
{
m_X = (ushort)x;
m_Y = (ushort)y;
m_Z = (ushort)z;
m_W = (ushort)w;
}

ushort m_X;
ushort m_Y;
ushort m_Z;
ushort m_W;
}

public uint inputByteStride;
public int indicesOffset;
public uint outputByteStride;

[ReadOnly]
[NativeDisableUnsafePtrRestriction]
public byte* input;

[WriteOnly]
[NativeDisableUnsafePtrRestriction]
public byte* output;

public void Execute(int i)
{
var inputIndexPtr = (uint4*)(indicesOffset + input + i * inputByteStride);
var outIndexPtr = (ushort4*)(indicesOffset + output + i * outputByteStride);

// Set the correct values for the indices
var tmpIndex = *inputIndexPtr;
var tmpOut = new ushort4(tmpIndex[0], tmpIndex[1], tmpIndex[2], tmpIndex[3]);
*outIndexPtr = tmpOut;
}
}

[BurstCompile]
public unsafe struct ConvertGenericJob : IJobParallelFor
{
Expand Down
66 changes: 55 additions & 11 deletions Runtime/Scripts/Export/GameObjectExport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,19 +72,34 @@ public bool AddScene(ICollection<GameObject> gameObjects, float4x4 origin, strin
var rootNodes = new List<uint>(gameObjects.Count);
var tempMaterials = new List<Material>();
var success = true;

var nodesQueue = new Queue<Transform>();
var transformNodeId = new Dictionary<Transform, uint>();

foreach (var gameObject in gameObjects)
{
success &= AddGameObject(
gameObject,
origin,
tempMaterials,
nodesQueue,
transformNodeId,
out var nodeId
);
if (nodeId >= 0)
{
rootNodes.Add((uint)nodeId);
}
}

while (nodesQueue.Count > 0)
{
var transform = nodesQueue.Dequeue();
AddNodeComponents(
transform,
transformNodeId,
tempMaterials
);
}
if (rootNodes.Count > 0)
{
m_Writer.AddScene(rootNodes.ToArray(), name);
Expand Down Expand Up @@ -141,7 +156,8 @@ void CertifyNotDisposed()
bool AddGameObject(
GameObject gameObject,
float4x4? sceneOrigin,
List<Material> tempMaterials,
Queue<Transform> nodesQueue,
Dictionary<Transform, uint> transformNodeId,
out int nodeId)
{
if (m_Settings.OnlyActiveInHierarchy && !gameObject.activeInHierarchy
Expand All @@ -163,7 +179,8 @@ bool AddGameObject(
success &= AddGameObject(
child.gameObject,
null,
tempMaterials,
nodesQueue,
transformNodeId,
out var childNodeId
);
if (childNodeId >= 0)
Expand Down Expand Up @@ -200,7 +217,8 @@ out var childNodeId
rotation = transform.localRotation;
scale = transform.localScale;
}
nodeId = (int)m_Writer.AddNode(

var newNodeId = m_Writer.AddNode(
translation,
rotation,
scale,
Expand All @@ -210,8 +228,11 @@ out var childNodeId

if (onIncludedLayer)
{
AddNodeComponents(gameObject, tempMaterials, nodeId);
nodesQueue.Enqueue(transform);
}
transformNodeId[transform] = newNodeId;

nodeId = (int)newNodeId;
}
else
{
Expand All @@ -221,11 +242,17 @@ out var childNodeId
return success;
}

void AddNodeComponents(GameObject gameObject, List<Material> tempMaterials, int nodeId)
void AddNodeComponents(
Transform transform,
Dictionary<Transform, uint> transformNodeId,
List<Material> tempMaterials
)
{
var gameObject = transform.gameObject;
var nodeId = transformNodeId[transform];
tempMaterials.Clear();
Mesh mesh = null;
var skinning = false;
Transform[] bones = null;
if (gameObject.TryGetComponent(out MeshFilter meshFilter))
{
if (gameObject.TryGetComponent(out Renderer renderer))
Expand All @@ -243,9 +270,9 @@ void AddNodeComponents(GameObject gameObject, List<Material> tempMaterials, int
if (smr.enabled || m_Settings.DisabledComponents)
{
mesh = smr.sharedMesh;
bones = smr.bones;
smr.GetSharedMaterials(tempMaterials);
}
skinning = true;
}

var materialIds = new int[tempMaterials.Count];
Expand All @@ -264,7 +291,24 @@ void AddNodeComponents(GameObject gameObject, List<Material> tempMaterials, int

if (mesh != null)
{
m_Writer.AddMeshToNode(nodeId, mesh, materialIds, skinning);
uint[] joints = null;
if (bones != null)
{
joints = new uint[bones.Length];
for (var i = 0; i < bones.Length; i++)
{
var bone = bones[i];
if (!transformNodeId.TryGetValue(bone, out joints[i]))
{
#if DEBUG
Debug.LogError($"Skip skin on {transform.name}: No node ID for bone transform {bone.name} found!");
joints = null;
break;
#endif
}
}
}
m_Writer.AddMeshToNode((int)nodeId, mesh, materialIds, joints);
}

if (gameObject.TryGetComponent(out Camera camera))
Expand All @@ -273,7 +317,7 @@ void AddNodeComponents(GameObject gameObject, List<Material> tempMaterials, int
{
if (m_Writer.AddCamera(camera, out var cameraId))
{
m_Writer.AddCameraToNode(nodeId, cameraId);
m_Writer.AddCameraToNode((int)nodeId, cameraId);
}
}
}
Expand All @@ -284,7 +328,7 @@ void AddNodeComponents(GameObject gameObject, List<Material> tempMaterials, int
{
if (m_Writer.AddLight(light, out var lightId))
{
m_Writer.AddLightToNode(nodeId, lightId);
m_Writer.AddLightToNode((int)nodeId, lightId);
}
}
}
Expand Down
Loading

0 comments on commit a9923bd

Please sign in to comment.