Skip to content

Commit 39e747d

Browse files
committed
import/export animation of visibility (bool) changed to usignedByte component type
1 parent aa6eadc commit 39e747d

4 files changed

Lines changed: 169 additions & 117 deletions

File tree

Runtime/Plugins/GLTFSerialization/GLTFHelpers.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,10 @@ public static void BuildAnimationSamplers(ref Dictionary<string, List<AttributeA
410410
switch (attributeAccessor.AccessorId.Value.Type)
411411
{
412412
case GLTFAccessorAttributeType.SCALAR:
413-
attributeAccessor.AccessorId.Value.AsFloatArray(ref resultArray, bufferViewCache);
413+
if (attributeAccessor.AccessorId.Value.ComponentType == GLTFComponentType.UnsignedByte)
414+
attributeAccessor.AccessorId.Value.AsUByteArray(ref resultArray, bufferViewCache);
415+
else
416+
attributeAccessor.AccessorId.Value.AsFloatArray(ref resultArray, bufferViewCache);
414417
break;
415418
case GLTFAccessorAttributeType.VEC2:
416419
attributeAccessor.AccessorId.Value.AsFloat2Array(ref resultArray, bufferViewCache);

Runtime/Plugins/GLTFSerialization/Schema/Accessor.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,7 +621,30 @@ internal static void GetTypeDetails(
621621
throw new Exception("Unsupported component type.");
622622
}
623623
}
624+
625+
public unsafe byte[] AsUByteArray(ref NumericArray contents, NativeArray<byte> bufferViewData, uint offset = 0)
626+
{
627+
if (contents.AsBytes != null)
628+
{
629+
return contents.AsBytes;
630+
}
631+
632+
if (Type != GLTFAccessorAttributeType.SCALAR)
633+
{
634+
return null;
635+
}
624636

637+
var arr = new byte[Count];
638+
var totalByteOffset = ByteOffset + offset;
639+
640+
var bufferPointer = NativeArrayUnsafeUtility.GetUnsafeReadOnlyPtr<byte>(bufferViewData);
641+
for (uint idx = 0; idx < Count; idx++)
642+
arr[idx] = GetUByteElement(bufferPointer, totalByteOffset + idx);
643+
644+
contents.AsBytes = arr;
645+
return arr;
646+
}
647+
625648
public unsafe uint[] AsUIntArray(ref NumericArray contents, NativeArray<byte> bufferViewData, uint offset = 0)
626649
{
627650
if (contents.AsUInts != null)
@@ -1427,6 +1450,9 @@ public static int ComponentCount(this GLTFAccessorAttributeType attrType)
14271450
[StructLayout(LayoutKind.Explicit)]
14281451
public struct NumericArray
14291452
{
1453+
[FieldOffset(0)]
1454+
public byte[] AsBytes;
1455+
14301456
[FieldOffset(0)]
14311457
public uint[] AsUInts;
14321458

Runtime/Scripts/SceneExporter/ExporterAnimationPointer.cs

Lines changed: 137 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,14 @@ public void AddAnimationData(Object animatedObject, string propertyName, GLTFAni
108108
string secondPropertyName = null;
109109
string extensionName = null;
110110
var propertyType = values[0]?.GetType();
111-
111+
bool isBoolean = propertyType == typeof(bool);
112+
if (TryGetCurrentValue(animatedObject, propertyName, out var currentValue))
113+
{
114+
// For bool, we always want to export as byte (0/1). Unity is using float for animation curves of bool properties.
115+
if (currentValue is bool)
116+
isBoolean = true;
117+
}
118+
112119
var animationPointerExportContext = _plugins.FirstOrDefault(x => x is AnimationPointerExportContext) as AnimationPointerExportContext;
113120

114121
switch (animatedObject)
@@ -336,140 +343,156 @@ public void AddAnimationData(Object animatedObject, string propertyName, GLTFAni
336343
bool actuallyNeedSecondSampler = true;
337344

338345
var val = values[0];
339-
switch (val)
346+
if (isBoolean)
340347
{
341-
case float _:
342-
if (flipValueRange)
343-
{
344-
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => 1.0f - (float)e));
345-
}
346-
else if (valueMultiplier.HasValue)
347-
{
348-
var multiplier = valueMultiplier.Value;
349-
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => ((float)e) * multiplier));
350-
}
351-
else
352-
{
353-
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (float)e));
354-
355-
if (propertyName == "orthographic/ymag")
348+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (float)e >= 0.5f ? Byte.MaxValue : Byte.MinValue));
349+
}
350+
else
351+
{
352+
switch (val)
353+
{
354+
case float _:
355+
if (flipValueRange)
356356
{
357-
Tsampler2.Output = Tsampler.Output;
357+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => 1.0f - (float)e));
358358
}
359-
}
360-
break;
361-
case float[] _:
362-
// check that all entries have the same length using a for loop
363-
var firstLength = ((float[])values[0]).Length;
364-
for (var i = 1; i < values.Length; i++)
365-
{
366-
if (((float[])values[i]).Length == firstLength) continue;
359+
else if (valueMultiplier.HasValue)
360+
{
361+
var multiplier = valueMultiplier.Value;
362+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => ((float)e) * multiplier));
363+
}
364+
else
365+
{
366+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (float)e));
367367

368-
Debug.Log(LogType.Error, "When animating float arrays, all array entries must have the same length. Skipping");
369-
return;
370-
}
368+
if (propertyName == "orthographic/ymag")
369+
{
370+
Tsampler2.Output = Tsampler.Output;
371+
}
372+
}
371373

372-
// construct a float array of all the float arrays together
373-
var floatArray = new float[values.Length * firstLength];
374+
break;
375+
case float[] _:
376+
// check that all entries have the same length using a for loop
377+
var firstLength = ((float[])values[0]).Length;
378+
for (var i = 1; i < values.Length; i++)
379+
{
380+
if (((float[])values[i]).Length == firstLength) continue;
374381

375-
// copy the individual arrays into the float array using Array.Copy
376-
for (int i = 0; i < values.Length; i++)
377-
Array.Copy((float[])values[i], 0, floatArray, i * firstLength, firstLength);
382+
Debug.Log(LogType.Error,
383+
"When animating float arrays, all array entries must have the same length. Skipping");
384+
return;
385+
}
378386

379-
// glTF weights 0..1 match to Unity weights 0..100, but Unity weights can be in arbitrary ranges
380-
if (valueMultiplier.HasValue)
381-
{
382-
for (var i = 0; i < floatArray.Length; i++)
383-
floatArray[i] *= valueMultiplier.Value;
384-
}
387+
// construct a float array of all the float arrays together
388+
var floatArray = new float[values.Length * firstLength];
385389

386-
Tsampler.Output = ExportAccessor(floatArray);
387-
break;
388-
case Vector2 _:
389-
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (Vector2)e));
390-
break;
391-
case Vector3 _:
392-
if (propertyName == "translation")
393-
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e =>
394-
{
395-
var v = (Vector3)e;
396-
v.Scale(new Vector3(-1, 1, 1));
397-
return v;
398-
}));
399-
else
400-
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (Vector3)e));
401-
break;
402-
case Vector4 _:
403-
if (!isTextureTransform)
404-
{
405-
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (Vector4)e));
406-
}
407-
else
408-
{
409-
var scales = new Vector2[values.Length];
410-
var offsets = new Vector2[values.Length];
390+
// copy the individual arrays into the float array using Array.Copy
411391
for (int i = 0; i < values.Length; i++)
392+
Array.Copy((float[])values[i], 0, floatArray, i * firstLength, firstLength);
393+
394+
// glTF weights 0..1 match to Unity weights 0..100, but Unity weights can be in arbitrary ranges
395+
if (valueMultiplier.HasValue)
412396
{
413-
DecomposeScaleOffset((Vector4) values[i], out var scale, out var offset);
414-
scales[i] = scale;
415-
offsets[i] = offset;
397+
for (var i = 0; i < floatArray.Length; i++)
398+
floatArray[i] *= valueMultiplier.Value;
416399
}
417-
Tsampler.Output = ExportAccessor(scales);
418-
Tsampler2.Output = ExportAccessor(offsets);
419-
}
420-
break;
421-
case Quaternion _:
422-
var animatedNode = _root.Nodes[channelTargetId];
423-
var needsFlippedLookDirection = animatedNode.Light != null || animatedNode.Camera != null;
424-
Tsampler.Output = ExportAccessorSwitchHandedness(Array.ConvertAll(values, e => (Quaternion)e), needsFlippedLookDirection); // Vec4 for rotations
425-
break;
426-
case Color _:
427-
if (propertyName == "emissiveFactor" && secondPropertyName != null)
428-
{
429-
var colors = new Color[values.Length];
430-
var strengths = new float[values.Length];
431-
actuallyNeedSecondSampler = false;
432-
var pluginSettings = (_plugins.FirstOrDefault(x => x is MaterialExtensionsExportContext) as MaterialExtensionsExportContext)?.settings;
433-
var emissiveStrengthSupported = pluginSettings != null && pluginSettings.KHR_materials_emissive_strength;
434-
if (emissiveStrengthSupported)
400+
401+
Tsampler.Output = ExportAccessor(floatArray);
402+
break;
403+
case Vector2 _:
404+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (Vector2)e));
405+
break;
406+
case Vector3 _:
407+
if (propertyName == "translation")
408+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e =>
409+
{
410+
var v = (Vector3)e;
411+
v.Scale(new Vector3(-1, 1, 1));
412+
return v;
413+
}));
414+
else
415+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (Vector3)e));
416+
break;
417+
case Vector4 _:
418+
if (!isTextureTransform)
435419
{
420+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e => (Vector4)e));
421+
}
422+
else
423+
{
424+
var scales = new Vector2[values.Length];
425+
var offsets = new Vector2[values.Length];
436426
for (int i = 0; i < values.Length; i++)
437427
{
438-
DecomposeEmissionColor((Color) values[i], out var color, out var intensity);
439-
colors[i] = color;
440-
strengths[i] = intensity;
441-
if (intensity > 1)
442-
actuallyNeedSecondSampler = true;
428+
DecomposeScaleOffset((Vector4)values[i], out var scale, out var offset);
429+
scales[i] = scale;
430+
offsets[i] = offset;
443431
}
432+
433+
Tsampler.Output = ExportAccessor(scales);
434+
Tsampler2.Output = ExportAccessor(offsets);
444435
}
445-
else
436+
437+
break;
438+
case Quaternion _:
439+
var animatedNode = _root.Nodes[channelTargetId];
440+
var needsFlippedLookDirection = animatedNode.Light != null || animatedNode.Camera != null;
441+
Tsampler.Output = ExportAccessorSwitchHandedness(Array.ConvertAll(values, e => (Quaternion)e),
442+
needsFlippedLookDirection); // Vec4 for rotations
443+
break;
444+
case Color _:
445+
if (propertyName == "emissiveFactor" && secondPropertyName != null)
446446
{
447-
// clamp 0..1
448-
for (int i = 0; i < values.Length; i++)
447+
var colors = new Color[values.Length];
448+
var strengths = new float[values.Length];
449+
actuallyNeedSecondSampler = false;
450+
var pluginSettings =
451+
(_plugins.FirstOrDefault(x => x is MaterialExtensionsExportContext) as
452+
MaterialExtensionsExportContext)?.settings;
453+
var emissiveStrengthSupported =
454+
pluginSettings != null && pluginSettings.KHR_materials_emissive_strength;
455+
if (emissiveStrengthSupported)
456+
{
457+
for (int i = 0; i < values.Length; i++)
458+
{
459+
DecomposeEmissionColor((Color)values[i], out var color, out var intensity);
460+
colors[i] = color;
461+
strengths[i] = intensity;
462+
if (intensity > 1)
463+
actuallyNeedSecondSampler = true;
464+
}
465+
}
466+
else
449467
{
450-
var c = (Color) values[i];
451-
if (c.r > 1) c.r = 1;
452-
if (c.g > 1) c.g = 1;
453-
if (c.b > 1) c.b = 1;
454-
colors[i] = c;
468+
// clamp 0..1
469+
for (int i = 0; i < values.Length; i++)
470+
{
471+
var c = (Color)values[i];
472+
if (c.r > 1) c.r = 1;
473+
if (c.g > 1) c.g = 1;
474+
if (c.b > 1) c.b = 1;
475+
colors[i] = c;
476+
}
455477
}
478+
479+
Tsampler.Output = ExportAccessor(colors, false);
480+
if (emissiveStrengthSupported)
481+
Tsampler2.Output = ExportAccessor(strengths);
456482
}
457-
458-
Tsampler.Output = ExportAccessor(colors, false);
459-
if (emissiveStrengthSupported)
460-
Tsampler2.Output = ExportAccessor(strengths);
461-
}
462-
else
463-
{
464-
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e =>
483+
else
465484
{
466-
var c = (Color) e;
467-
if (convertToLinearColor)
468-
c = c.linear;
469-
return c;
470-
}), keepColorAlpha);
471-
}
472-
break;
485+
Tsampler.Output = ExportAccessor(Array.ConvertAll(values, e =>
486+
{
487+
var c = (Color)e;
488+
if (convertToLinearColor)
489+
c = c.linear;
490+
return c;
491+
}), keepColorAlpha);
492+
}
493+
494+
break;
495+
}
473496
}
474497

475498
if (Tsampler.Output != null) Tsampler.Output.Value.BufferView.Value.ByteStride = 0;

Runtime/Scripts/SceneImporter/ImporterAnimation.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -372,8 +372,8 @@ AttributeAccessor FindSecondaryChannel(string animationPointerPath)
372372
pointerData.primaryData = samplerCache.Output;
373373
pointerData.importAccessorContentConversion = (data, frame) =>
374374
{
375-
var v = data.primaryData.AccessorContent.AsFloats[frame];
376-
return new float[] { v };
375+
var v = data.primaryData.AccessorContent.AsBytes[frame];
376+
return new float[] { v > 0 ? 1f : 0f};
377377
};
378378
break;
379379
}

0 commit comments

Comments
 (0)