Merge pull request #2315 from ousttrue/export_null_material

Export null material
This commit is contained in:
ousttrue 2024-06-08 01:11:32 +09:00 committed by GitHub
commit 47ee539554
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
13 changed files with 120 additions and 35 deletions

View File

@ -90,7 +90,7 @@ namespace UniGLTF
if (info.Materials.Take(info.Mesh.subMeshCount).Any(x => x == null))
{
// material に null が含まれる(unity で magenta になっているはず)
yield return Validation.Error(Messages.MATERIALS_CONTAINS_NULL.Msg(), ValidationContext.Create(info.Renderers[0].Item1));
yield return Validation.Warning(Messages.MATERIALS_CONTAINS_NULL.Msg(), ValidationContext.Create(info.Renderers[0].Item1));
}
}

View File

@ -15,5 +15,24 @@ namespace UniGLTF
}
return true;
}
public static bool HasValidIndex(this int? self, int collectionLength)
{
if (!self.HasValue)
{
return false;
}
if (self.Value < 0)
{
// 古いモデルで index の無効値に -1 を使っている場合がある
return false;
}
if (self.Value >= collectionLength)
{
// ついでに上限もチェック
return false;
}
return true;
}
}
}

View File

@ -972,9 +972,9 @@ public static void Serialize_gltf_meshes__primitives_ITEM(JsonFormatter f, glTFP
Serialize_gltf_meshes__primitives__attributes(f, value.attributes);
}
if(value.material>=0){
if(value.material.HasValidIndex()){
f.Key("material");
f.Value(value.material);
f.Value(value.material.Value);
}
if(value.targets!=null&&value.targets.Count>=1){

View File

@ -85,7 +85,7 @@ namespace UniGLTF
public glTFAttributes attributes;
[JsonSchema(Minimum = 0)]
public int material;
public int? material;
[JsonSchema(MinItems = 1, ExplicitIgnorableItemLength = 0)]
[ItemJsonSchema(SkipSchemaComparison = true)]

View File

@ -49,7 +49,8 @@ namespace UniGLTF
Data.MigrationFlags.IsRoughnessTextureValueSquared);
MaterialFactory = new MaterialFactory(ExternalObjectMap
.Where(x => x.Value is Material)
.ToDictionary(x => x.Key, x => (Material)x.Value));
.ToDictionary(x => x.Key, x => (Material)x.Value),
MaterialDescriptorGenerator.GetGltfDefault());
AnimationClipFactory = new AnimationClipFactory(ExternalObjectMap
.Where(x => x.Value is AnimationClip)
.ToDictionary(x => x.Key, x => (AnimationClip)x.Value));
@ -285,14 +286,7 @@ namespace UniGLTF
throw new ArgumentNullException();
}
if (Data.GLTF.materials == null || Data.GLTF.materials.Count == 0)
{
// no material. work around.
// TODO: https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#default-material
var param = MaterialDescriptorGenerator.GetGltfDefault();
await MaterialFactory.LoadAsync(param, TextureFactory.GetTextureAsync, awaitCaller);
}
else
if (Data.GLTF.materials != null)
{
for (int i = 0; i < Data.GLTF.materials.Count; ++i)
{
@ -313,7 +307,18 @@ namespace UniGLTF
{
using (MeasureTime("BuildMesh"))
{
var meshWithMaterials = await MeshUploader.BuildMeshAndUploadAsync(awaitCaller, meshData, MaterialFactory.GetMaterial);
var meshWithMaterials = await MeshUploader.BuildMeshAndUploadAsync(awaitCaller, meshData,
(int? materialIndex) =>
{
if (materialIndex.HasValidIndex())
{
return MaterialFactory.GetMaterial(materialIndex.Value);
}
else
{
return MaterialFactory.DefaultMaterial;
}
});
var mesh = meshWithMaterials.Mesh;
// mesh name

View File

@ -12,16 +12,16 @@ namespace UniGLTF
{
private int _currentVertexCount = 0;
private int _currentIndexCount = 0;
private NativeArray<int> _indices;
private NativeArray<MeshVertex0> _vertices0;
private NativeArray<MeshVertex1> _vertices1;
private NativeArray<MeshVertex2> _vertices2;
private readonly List<SubMeshDescriptor> _subMeshes = new List<SubMeshDescriptor>();
private readonly List<int> _materialIndices = new List<int>();
private readonly List<int?> _materialIndices = new List<int?>();
private readonly List<BlendShape> _blendShapes = new List<BlendShape>();
public NativeArray<MeshVertex0> Vertices0 => _vertices0.GetSubArray(0, _currentVertexCount);
public NativeArray<MeshVertex1> Vertices1 => _vertices1.GetSubArray(0, _currentVertexCount);
public NativeArray<MeshVertex2> Vertices2 => _vertices2.GetSubArray(0, _currentVertexCount);
@ -29,7 +29,7 @@ namespace UniGLTF
public NativeArray<int> Indices => _indices.GetSubArray(0, _currentIndexCount);
public IReadOnlyList<SubMeshDescriptor> SubMeshes => _subMeshes;
public IReadOnlyList<int> MaterialIndices => _materialIndices;
public IReadOnlyList<int?> MaterialIndices => _materialIndices;
public IReadOnlyList<BlendShape> BlendShapes => _blendShapes;
@ -336,7 +336,7 @@ namespace UniGLTF
var texCoord1 = texCoords1 != null ? texCoords1.Value[i].ReverseUV() : Vector2.zero;
var color = colors != null ? colors.Value[i] : Color.white;
_vertices0[_currentVertexCount] = new MeshVertex0(
position,
normal

View File

@ -110,7 +110,7 @@ namespace UniGLTF
m_weights.Add(new Vector4(boneWeight.weight0, boneWeight.weight1, boneWeight.weight2, boneWeight.weight3));
}
public glTFPrimitives ToGltfPrimitive(ExportingGltfData data, int materialIndex, IEnumerable<int> indices)
public glTFPrimitives ToGltfPrimitive(ExportingGltfData data, int? materialIndex, IEnumerable<int> indices)
{
var indicesAccessorIndex = data.ExtendBufferAndGetAccessorIndex(indices.Select(x => (uint)m_vertexIndexMap[x]).ToArray(), glBufferTarget.ELEMENT_ARRAY_BUFFER);
var positions = m_positions.ToArray();

View File

@ -91,7 +91,7 @@ namespace UniGLTF
public static async Task<MeshWithMaterials> BuildMeshAndUploadAsync(
IAwaitCaller awaitCaller,
MeshData data,
Func<int, Material> materialFromIndex)
Func<int?, Material> materialFromIndex)
{
//Debug.Log(prims.ToJson());

View File

@ -602,10 +602,10 @@ namespace UniGLTF
Assert.AreEqual(2, gltf.meshes.Count);
var red = gltf.materials[gltf.meshes[0].primitives[0].material];
var red = gltf.materials[gltf.meshes[0].primitives[0].material.Value];
Assert.AreEqual(new float[] { 1, 0, 0, 1 }, red.pbrMetallicRoughness.baseColorFactor);
var blue = gltf.materials[gltf.meshes[1].primitives[0].material];
var blue = gltf.materials[gltf.meshes[1].primitives[0].material.Value];
Assert.AreEqual(new float[] { 0, 0, 1, 1 }, blue.pbrMetallicRoughness.baseColorFactor);
Assert.AreEqual(2, gltf.nodes.Count);

View File

@ -112,6 +112,10 @@ namespace UniVRM10
var materials = renderer.sharedMaterials; // avoid copy
foreach (var material in materials)
{
if (material == null)
{
continue;
}
if (Materials.Contains(material))
{
continue;

View File

@ -188,7 +188,19 @@ namespace UniVRM10
Meshes.Add(new MeshWithMaterials
{
Mesh = mesh,
Materials = src.Meshes[0].Submeshes.Select(x => MaterialFactory.Materials[x.Material].Asset).ToArray(),
Materials = src.Meshes[0].Submeshes.Select(
x =>
{
if (x.Material.HasValidIndex())
{
return MaterialFactory.Materials[x.Material.Value].Asset;
}
else
{
return null;
}
}
).ToArray(),
});
@ -228,7 +240,7 @@ namespace UniVRM10
continue;
}
CreateRenderer(node, go, map, MaterialFactory.Materials);
CreateRenderer(node, go, map, MaterialFactory);
await awaitCaller.NextFrame();
}
}
@ -790,8 +802,7 @@ namespace UniVRM10
/// <summary>
/// MeshFilter + MeshRenderer もしくは SkinnedMeshRenderer を構築する
/// </summary>
public static Renderer CreateRenderer(VrmLib.Node node, GameObject go, ModelMap map,
IReadOnlyList<VRMShaders.MaterialFactory.MaterialLoadInfo> materialLoadInfos)
public static Renderer CreateRenderer(VrmLib.Node node, GameObject go, ModelMap map, MaterialFactory materialFactory)
{
Renderer renderer = null;
var hasBlendShape = node.MeshGroup.Meshes[0].MorphTargets.Any();
@ -825,12 +836,35 @@ namespace UniVRM10
}
else if (node.MeshGroup.Meshes.Count == 1)
{
var materials = node.MeshGroup.Meshes[0].Submeshes.Select(x => materialLoadInfos[x.Material].Asset).ToArray();
var materials = node.MeshGroup.Meshes[0].Submeshes.Select(
x =>
{
if (x.Material.HasValidIndex())
{
return materialFactory.Materials[x.Material.Value].Asset;
}
else
{
return materialFactory.DefaultMaterial;
}
}
).ToArray();
renderer.sharedMaterials = materials;
}
else
{
var materials = node.MeshGroup.Meshes.Select(x => materialLoadInfos[x.Submeshes[0].Material].Asset).ToArray();
var materials = node.MeshGroup.Meshes.Select(x =>
{
if (x.Submeshes[0].Material.HasValidIndex())
{
return materialFactory.Materials[x.Submeshes[0].Material.Value].Asset;
}
else
{
return materialFactory.DefaultMaterial;
}
}
).ToArray();
renderer.sharedMaterials = materials;
}

View File

@ -35,18 +35,18 @@ namespace VrmLib
{
public int Offset;
public int DrawCount;
public int Material;
public int? Material;
public override string ToString()
{
return $"{Material}({DrawCount})";
}
public Submesh(int material) : this(0, 0, material)
public Submesh(int? material) : this(0, 0, material)
{
}
public Submesh(int offset, int drawCount, int material)
public Submesh(int offset, int drawCount, int? material)
{
Offset = offset;
DrawCount = drawCount;

View File

@ -1,6 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;
@ -13,9 +12,33 @@ namespace VRMShaders
{
private readonly IReadOnlyDictionary<SubAssetKey, Material> m_externalMap;
public MaterialFactory(IReadOnlyDictionary<SubAssetKey, Material> externalMaterialMap)
MaterialDescriptor m_defaultMaterialParams;
/// <summary>
/// gltfPritmitive.material が無い場合のデフォルトマテリアル
/// https://www.khronos.org/registry/glTF/specs/2.0/glTF-2.0.html#default-material
/// </summary>
Material m_defaultMaterial;
public Material DefaultMaterial
{
get
{
if (m_defaultMaterial == null)
{
// default material にバリエーションがある?
var task = LoadAsync(m_defaultMaterialParams, (_x, _y) => Task.FromResult<Texture>(null), new ImmediateCaller());
task.Wait();
m_defaultMaterial = task.Result;
}
return m_defaultMaterial;
}
}
public MaterialFactory(IReadOnlyDictionary<SubAssetKey, Material> externalMaterialMap, MaterialDescriptor defaultMaterialParams)
{
m_externalMap = externalMaterialMap;
m_defaultMaterialParams = defaultMaterialParams;
}
public struct MaterialLoadInfo