3 using System.Collections.Generic;
5 using System.Text.RegularExpressions;
21 KHR_materials_pbrSpecularGlossiness,
42 protected readonly Dictionary<MaterialType, Shader>
_shaderCache =
new Dictionary<MaterialType, Shader>();
52 private LoadType _loadType;
60 public GLTFSceneImporter(
string gltfUrl, Transform parent = null,
bool addColliders =
false)
64 _sceneParent = parent;
66 _loadType = LoadType.Uri;
67 _addColliders = addColliders;
75 _sceneParent = parent;
77 _loadType = LoadType.Stream;
78 _addColliders = addColliders;
93 _shaderCache.Add(type, shader);
102 public IEnumerator
Load(
int sceneIndex = -1,
bool isMultithreaded =
false)
104 if (_loadType == LoadType.Uri)
106 var www = UnityWebRequest.Get(_gltfUrl);
108 #if UNITY_2017_2_OR_NEWER 109 yield
return www.SendWebRequest();
111 yield
return www.Send();
114 if (www.responseCode >= 400 || www.responseCode == 0)
119 byte[] gltfData = www.downloadHandler.data;
120 _gltfStream.
Stream =
new MemoryStream(gltfData, 0, gltfData.Length,
false,
true);
122 else if (_loadType == LoadType.Stream)
128 throw new Exception(
"Invalid load type specified: " + _loadType);
132 yield
return ImportScene(sceneIndex, isMultithreaded);
141 protected IEnumerator
ImportScene(
int sceneIndex = -1,
bool isMultithreaded =
false)
144 if (sceneIndex >= 0 && sceneIndex < _root.Scenes.Count)
146 scene = _root.Scenes[sceneIndex];
150 scene = _root.GetDefaultScene();
155 throw new Exception(
"No default scene in gltf file.");
159 _root.Images != null ? _root.Images.Count : 0,
160 _root.Textures != null ? _root.Textures.Count : 0,
161 _root.Materials != null ? _root.Materials.Count : 0,
162 _root.Buffers != null ? _root.Buffers.Count : 0,
163 _root.Meshes != null ? _root.Meshes.Count : 0
166 if (_lastLoadedScene == null)
168 if (_root.Buffers != null)
171 for (
int i = 0; i < _root.Buffers.Count; ++i)
173 GLTF.Schema.Buffer buffer = _root.Buffers[i];
174 if (buffer.Uri != null)
176 yield
return LoadBuffer(_gltfDirectoryPath, buffer, i);
183 ChunkOffset = _gltfStream.
Stream.Position,
190 if (_root.Images != null)
192 for (
int i = 0; i < _root.Images.Count; ++i)
194 Image image = _root.Images[i];
195 yield
return LoadImage(_gltfDirectoryPath, image, i);
208 if (_sceneParent != null)
210 sceneObj.transform.SetParent(_sceneParent,
false);
213 _lastLoadedScene = sceneObj;
218 for (
int i = 0; i < _root.Meshes.Count; ++i)
220 GLTF.Schema.Mesh mesh = _root.Meshes[i];
226 for (
int j = 0; j < mesh.Primitives.Count; ++j)
229 var primitive = mesh.Primitives[j];
237 if (_assetCache.
MeshCache[meshID][primitiveIndex].MeshAttributes.Count == 0)
239 Dictionary<string, AttributeAccessor> attributeAccessors =
new Dictionary<string, AttributeAccessor>(primitive.Attributes.Count + 1);
240 foreach (var attributePair
in primitive.Attributes)
243 AttributeAccessor AttributeAccessor =
new AttributeAccessor()
245 AccessorId = attributePair.Value,
250 attributeAccessors[attributePair.Key] = AttributeAccessor;
253 if (primitive.Indices != null)
256 AttributeAccessor indexBuilder =
new AttributeAccessor()
258 AccessorId = primitive.Indices,
263 attributeAccessors[SemanticProperties.INDICES] = indexBuilder;
266 GLTFHelpers.BuildMeshAttributes(ref attributeAccessors);
268 _assetCache.
MeshCache[meshID][primitiveIndex].MeshAttributes = attributeAccessors;
275 if (attributeAccessors.ContainsKey(SemanticProperties.POSITION))
277 AttributeAccessor attributeAccessor = attributeAccessors[SemanticProperties.POSITION];
280 if (attributeAccessors.ContainsKey(SemanticProperties.INDICES))
282 AttributeAccessor attributeAccessor = attributeAccessors[SemanticProperties.INDICES];
285 if (attributeAccessors.ContainsKey(SemanticProperties.NORMAL))
287 AttributeAccessor attributeAccessor = attributeAccessors[SemanticProperties.NORMAL];
291 for (
int i = 0; i < 4; i++)
293 if (attributeAccessors.ContainsKey(SemanticProperties.TexCoord(i)))
295 AttributeAccessor attributeAccessor = attributeAccessors[SemanticProperties.TexCoord(i)];
300 if (attributeAccessors.ContainsKey(SemanticProperties.TANGENT))
302 AttributeAccessor attributeAccessor = attributeAccessors[SemanticProperties.TANGENT];
309 var sceneObj =
new GameObject(scene.Name ??
"GLTFScene");
311 foreach (var node
in scene.Nodes)
314 nodeObj.transform.SetParent(sceneObj.transform,
false);
322 var nodeObj =
new GameObject(node.Name ??
"GLTFNode");
327 node.GetUnityTRSProperties(out position, out rotation, out scale);
328 nodeObj.transform.localPosition = position;
329 nodeObj.transform.localRotation = rotation;
330 nodeObj.transform.localScale = scale;
333 if (node.Mesh != null)
346 if (node.Children != null)
348 foreach (var child
in node.Children)
351 childObj.transform.SetParent(nodeObj.transform,
false);
360 if (_assetCache.
MeshCache[meshId] == null)
365 for (
int i = 0; i < mesh.Primitives.Count; ++i)
367 var primitive = mesh.Primitives[i];
369 primitiveObj.transform.SetParent(parent,
false);
370 primitiveObj.SetActive(
true);
376 var primitiveObj =
new GameObject(
"Primitive");
378 var meshFilter = primitiveObj.AddComponent<MeshFilter>();
380 if (_assetCache.
MeshCache[meshID][primitiveIndex] == null)
384 if (_assetCache.
MeshCache[meshID][primitiveIndex].LoadedMesh == null)
386 if (_assetCache.
MeshCache[meshID][primitiveIndex].MeshAttributes.Count == 0)
390 var meshAttributes = _assetCache.
MeshCache[meshID][primitiveIndex].MeshAttributes;
391 var vertexCount = primitive.Attributes[SemanticProperties.POSITION].Value.Count;
396 vertices = primitive.Attributes.ContainsKey(SemanticProperties.POSITION)
397 ? meshAttributes[SemanticProperties.POSITION].AccessorContent.AsVertices.ToUnityVector3Raw()
399 normals = primitive.Attributes.ContainsKey(SemanticProperties.NORMAL)
400 ? meshAttributes[SemanticProperties.NORMAL].AccessorContent.AsNormals.ToUnityVector3Raw()
403 uv = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(0))
404 ? meshAttributes[SemanticProperties.TexCoord(0)].AccessorContent.AsTexcoords.ToUnityVector2Raw()
407 uv2 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(1))
408 ? meshAttributes[SemanticProperties.TexCoord(1)].AccessorContent.AsTexcoords.ToUnityVector2Raw()
411 uv3 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(2))
412 ? meshAttributes[SemanticProperties.TexCoord(2)].AccessorContent.AsTexcoords.ToUnityVector2Raw()
415 uv4 = primitive.Attributes.ContainsKey(SemanticProperties.TexCoord(3))
416 ? meshAttributes[SemanticProperties.TexCoord(3)].AccessorContent.AsTexcoords.ToUnityVector2Raw()
419 colors = primitive.Attributes.ContainsKey(SemanticProperties.Color(0))
420 ? meshAttributes[SemanticProperties.Color(0)].AccessorContent.AsColors.ToUnityColorRaw()
423 triangles = primitive.Indices != null
424 ? meshAttributes[SemanticProperties.INDICES].AccessorContent.AsTriangles.ToIntArrayRaw()
425 : MeshPrimitive.GenerateTriangles(vertexCount),
427 tangents = primitive.Attributes.ContainsKey(SemanticProperties.TANGENT)
428 ? meshAttributes[SemanticProperties.TANGENT].AccessorContent.AsTangents.ToUnityVector4Raw()
432 _assetCache.
MeshCache[meshID][primitiveIndex].LoadedMesh = mesh;
435 meshFilter.sharedMesh = _assetCache.
MeshCache[meshID][primitiveIndex].LoadedMesh;
438 primitive.Material != null ? primitive.Material.Value :
DefaultMaterial,
439 primitive.Material != null ? primitive.Material.Id : -1
442 var meshRenderer = primitiveObj.AddComponent<MeshRenderer>();
443 meshRenderer.material = materialWrapper.GetContents(primitive.Attributes.ContainsKey(SemanticProperties.Color(0)));
447 var meshCollider = primitiveObj.AddComponent<MeshCollider>();
448 meshCollider.sharedMesh = meshFilter.mesh;
457 if (materialIndex < 0 || _assetCache.
MaterialCache[materialIndex] == null)
464 if (_root.ExtensionsUsed != null && _root.ExtensionsUsed.Contains(
"KHR_materials_pbrSpecularGlossiness"))
465 shader = _shaderCache[
MaterialType.KHR_materials_pbrSpecularGlossiness];
466 else if (def.PbrMetallicRoughness != null)
467 shader = _shaderCache[
MaterialType.PbrMetallicRoughness];
468 else if (_root.ExtensionsUsed != null && _root.ExtensionsUsed.Contains(
"KHR_materials_common")
469 && def.CommonConstant != null)
472 shader = _shaderCache[
MaterialType.PbrMetallicRoughness];
474 catch (KeyNotFoundException)
476 Debug.LogWarningFormat(
"No shader supplied for type of glTF material {0}, using Standard fallback", def.Name);
477 shader = Shader.Find(
"Standard");
484 if (def.AlphaMode == AlphaMode.MASK)
486 material.SetOverrideTag(
"RenderType",
"TransparentCutout");
487 material.SetInt(
"_SrcBlend", (
int)
UnityEngine.Rendering.BlendMode.One);
488 material.SetInt(
"_DstBlend", (
int)
UnityEngine.Rendering.BlendMode.Zero);
489 material.SetInt(
"_ZWrite", 1);
490 material.EnableKeyword(
"_ALPHATEST_ON");
491 material.DisableKeyword(
"_ALPHABLEND_ON");
492 material.DisableKeyword(
"_ALPHAPREMULTIPLY_ON");
493 material.renderQueue = (int)
UnityEngine.Rendering.RenderQueue.AlphaTest;
494 material.SetFloat(
"_Cutoff", (
float)def.AlphaCutoff);
496 else if (def.AlphaMode == AlphaMode.BLEND)
498 material.SetOverrideTag(
"RenderType",
"Transparent");
499 material.SetInt(
"_SrcBlend", (
int)
UnityEngine.Rendering.BlendMode.SrcAlpha);
500 material.SetInt(
"_DstBlend", (
int)
UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
501 material.SetInt(
"_ZWrite", 0);
502 material.DisableKeyword(
"_ALPHATEST_ON");
503 material.EnableKeyword(
"_ALPHABLEND_ON");
504 material.DisableKeyword(
"_ALPHAPREMULTIPLY_ON");
505 material.renderQueue = (int)
UnityEngine.Rendering.RenderQueue.Transparent;
509 material.SetOverrideTag(
"RenderType",
"Opaque");
510 material.SetInt(
"_SrcBlend", (
int)
UnityEngine.Rendering.BlendMode.One);
511 material.SetInt(
"_DstBlend", (
int)
UnityEngine.Rendering.BlendMode.Zero);
512 material.SetInt(
"_ZWrite", 1);
513 material.DisableKeyword(
"_ALPHATEST_ON");
514 material.DisableKeyword(
"_ALPHABLEND_ON");
515 material.DisableKeyword(
"_ALPHAPREMULTIPLY_ON");
516 material.renderQueue = -1;
521 material.SetInt(
"_Cull", (
int)CullMode.Off);
525 material.SetInt(
"_Cull", (
int)CullMode.Back);
528 if (def.PbrMetallicRoughness != null)
530 var pbr = def.PbrMetallicRoughness;
532 material.SetColor(
"_Color", pbr.BaseColorFactor.ToUnityColorRaw());
534 if (pbr.BaseColorTexture != null)
536 var textureDef = pbr.BaseColorTexture.Index.Value;
542 material.SetFloat(
"_Metallic", (
float)pbr.MetallicFactor);
544 if (pbr.MetallicRoughnessTexture != null)
546 var texture = pbr.MetallicRoughnessTexture.Index.Value;
547 material.SetTexture(
"_MetallicRoughnessMap",
CreateTexture(texture));
552 material.SetFloat(
"_Roughness", (
float)pbr.RoughnessFactor);
555 if (def.Extensions != null && def.Extensions.ContainsKey(KHR_materials_pbrSpecularGlossinessExtensionFactory.EXTENSION_NAME))
557 KHR_materials_pbrSpecularGlossinessExtension specGloss = def.Extensions[KHR_materials_pbrSpecularGlossinessExtensionFactory.EXTENSION_NAME] as KHR_materials_pbrSpecularGlossinessExtension;
559 if (specGloss.DiffuseTexture != null)
561 var texture = specGloss.DiffuseTexture.Index.Value;
568 material.SetColor(
"_Color", specGloss.DiffuseFactor.ToUnityColorRaw());
571 if (specGloss.SpecularGlossinessTexture != null)
573 var texture = specGloss.SpecularGlossinessTexture.Index.Value;
574 material.SetTexture(
"_SpecGlossMap",
CreateTexture(texture));
575 material.EnableKeyword(
"_SPECGLOSSMAP");
581 material.SetVector(
"_SpecColor", specGloss.SpecularFactor.ToUnityVector3Raw());
582 material.SetFloat(
"_Glossiness", (
float)specGloss.GlossinessFactor);
586 if (def.CommonConstant != null)
588 material.SetColor(
"_AmbientFactor", def.CommonConstant.AmbientFactor.ToUnityColorRaw());
590 if (def.CommonConstant.LightmapTexture != null)
592 material.EnableKeyword(
"LIGHTMAP_ON");
594 var texture = def.CommonConstant.LightmapTexture.Index.Value;
596 material.SetInt(
"_LightUV", def.CommonConstant.LightmapTexture.TexCoord);
601 material.SetColor(
"_LightFactor", def.CommonConstant.LightmapFactor.ToUnityColorRaw());
604 if (def.NormalTexture != null)
606 var texture = def.NormalTexture.Index.Value;
608 material.SetFloat(
"_BumpScale", (
float)def.NormalTexture.Scale);
609 material.EnableKeyword(
"_NORMALMAP");
614 if (def.OcclusionTexture != null)
616 var texture = def.OcclusionTexture.Index;
618 material.SetFloat(
"_OcclusionStrength", (
float)def.OcclusionTexture.Strength);
620 if (def.PbrMetallicRoughness != null
621 && def.PbrMetallicRoughness.MetallicRoughnessTexture != null
622 && def.PbrMetallicRoughness.MetallicRoughnessTexture.Index.Id == texture.Id)
624 material.EnableKeyword(
"OCC_METAL_ROUGH_ON");
628 material.SetTexture(
"_OcclusionMap",
CreateTexture(texture.Value));
634 if (def.EmissiveTexture != null)
636 var texture = def.EmissiveTexture.Index.Value;
637 material.EnableKeyword(
"EMISSION_MAP_ON");
638 material.EnableKeyword(
"_EMISSION");
640 material.SetInt(
"_EmissionUV", def.EmissiveTexture.TexCoord);
645 material.SetColor(
"_EmissionColor", def.EmissiveFactor.ToUnityColorRaw());
649 UnityMaterial = material,
650 UnityMaterialWithVertexColor =
new UnityEngine.Material(material),
656 if (materialIndex > 0)
662 return materialIndex > 0 ? _assetCache.
MaterialCache[materialIndex] : materialWrapper;
667 if (_assetCache.
TextureCache[texture.Source.Id] == null)
669 var source = _assetCache.
ImageCache[texture.Source.Id];
670 var desiredFilterMode = FilterMode.Bilinear;
671 var desiredWrapMode =
UnityEngine.TextureWrapMode.Repeat;
673 if (texture.Sampler != null)
675 var sampler = texture.Sampler.Value;
676 switch (sampler.MinFilter)
678 case MinFilterMode.Nearest:
679 desiredFilterMode = FilterMode.Point;
681 case MinFilterMode.Linear:
683 desiredFilterMode = FilterMode.Bilinear;
687 switch (sampler.WrapS)
689 case GLTF.Schema.WrapMode.ClampToEdge:
690 desiredWrapMode =
UnityEngine.TextureWrapMode.Clamp;
692 case GLTF.Schema.WrapMode.Repeat:
694 desiredWrapMode =
UnityEngine.TextureWrapMode.Repeat;
699 if (source.filterMode == desiredFilterMode && source.wrapMode == desiredWrapMode)
705 var unityTexture =
UnityEngine.Object.Instantiate(source);
706 unityTexture.filterMode = desiredFilterMode;
707 unityTexture.wrapMode = desiredWrapMode;
708 _assetCache.
TextureCache[texture.Source.Id] = unityTexture;
717 IExtension extension;
718 if (_root.ExtensionsUsed != null &&
719 _root.ExtensionsUsed.Contains(ExtTextureTransformExtensionFactory.EXTENSION_NAME) &&
720 def.Extensions != null &&
721 def.Extensions.TryGetValue(ExtTextureTransformExtensionFactory.EXTENSION_NAME, out extension))
723 ExtTextureTransformExtension ext = (ExtTextureTransformExtension)extension;
725 Vector2 temp = ext.Offset.ToUnityVector2Raw();
726 temp =
new Vector2(temp.x, -temp.y);
727 mat.SetTextureOffset(texName, temp);
729 mat.SetTextureScale(texName, ext.Scale.ToUnityVector2Raw());
735 protected virtual IEnumerator
LoadImage(
string rootPath, Image image,
int imageID)
739 Texture2D texture = null;
740 if (image.Uri != null)
744 Regex regex =
new Regex(Base64StringInitializer);
745 Match match = regex.Match(uri);
748 var base64Data = uri.Substring(match.Length);
749 var textureData = Convert.FromBase64String(base64Data);
750 texture =
new Texture2D(0, 0);
751 texture.LoadImage(textureData);
753 else if (_loadType == LoadType.Uri)
755 var www = UnityWebRequest.Get(Path.Combine(rootPath, uri));
756 www.downloadHandler =
new DownloadHandlerTexture();
758 #if UNITY_2017_2_OR_NEWER 759 yield
return www.SendWebRequest();
761 yield
return www.Send();
765 var tempTexture = DownloadHandlerTexture.GetContent(www);
766 if (tempTexture != null)
768 texture =
new Texture2D(tempTexture.width, tempTexture.height, tempTexture.format,
true);
769 texture.SetPixels(tempTexture.GetPixels());
774 Debug.LogFormat(
"{0} {1}", www.responseCode, www.url);
775 texture =
new Texture2D(16, 16);
778 else if (_loadType == LoadType.Stream)
780 var pathToLoad = Path.Combine(rootPath, uri);
781 var file = File.OpenRead(pathToLoad);
782 byte[] bufferData =
new byte[file.Length];
783 file.Read(bufferData, 0, (
int)file.Length);
789 texture =
new Texture2D(0, 0);
790 texture.LoadImage(bufferData);
795 texture =
new Texture2D(0, 0);
796 var bufferView = image.BufferView.Value;
797 var data =
new byte[bufferView.ByteLength];
799 var bufferContents = _assetCache.
BufferCache[bufferView.Buffer.Id];
800 bufferContents.Stream.Position = bufferView.ByteOffset + bufferContents.ChunkOffset;
801 bufferContents.Stream.Read(data, 0, data.Length);
802 texture.LoadImage(data);
812 protected virtual IEnumerator
LoadBuffer(
string sourceUri,
GLTF.Schema.Buffer buffer,
int bufferIndex)
814 if (buffer.Uri != null)
816 Stream bufferStream = null;
817 var uri = buffer.Uri;
819 Regex regex =
new Regex(Base64StringInitializer);
820 Match match = regex.Match(uri);
823 string base64String = uri.Substring(match.Length);
824 byte[] base64ByteData = Convert.FromBase64String(base64String);
825 bufferStream =
new MemoryStream(base64ByteData, 0, base64ByteData.Length,
false,
true);
827 else if (_loadType == LoadType.Uri)
829 var www = UnityWebRequest.Get(Path.Combine(sourceUri, uri));
831 #if UNITY_2017_2_OR_NEWER 832 yield
return www.SendWebRequest();
834 yield
return www.Send();
837 bufferStream =
new MemoryStream(www.downloadHandler.data, 0, www.downloadHandler.data.Length,
false,
true);
839 else if (_loadType == LoadType.Stream)
841 var pathToLoad = Path.Combine(sourceUri, uri);
842 bufferStream = File.OpenRead(pathToLoad);
859 var uri =
new Uri(gltfPath);
860 var partialPath = uri.AbsoluteUri.Remove(uri.AbsoluteUri.Length - uri.Query.Length - uri.Segments[uri.Segments.Length - 1].Length);
871 var fileName = Path.GetFileName(gltfPath);
872 var lastIndex = gltfPath.IndexOf(fileName);
873 var partialPath = gltfPath.Substring(0, lastIndex);
virtual void BuildMeshAttributes(MeshPrimitive primitive, int meshID, int primitiveIndex)
IEnumerator ImportScene(int sceneIndex=-1, bool isMultithreaded=false)
Creates a scene based off loaded JSON. Includes loading in binary and image data to construct the mes...
static void ConvertVector3CoordinateSpace(ref AttributeAccessor attributeAccessor, GLTF.Math.Vector3 coordinateSpaceCoordinateScale)
Converts vector3 to specified coordinate space
IEnumerator Load(int sceneIndex=-1, bool isMultithreaded=false)
Loads via a web call the gltf file and then constructs a scene
UnityEngine.Material UnityMaterialWithVertexColor
string _gltfDirectoryPath
readonly GLTF.Schema.Material DefaultMaterial
virtual IEnumerator LoadBuffer(string sourceUri, GLTF.Schema.Buffer buffer, int bufferIndex)
Load the remote URI data into a byte array.
virtual IEnumerator LoadImage(string rootPath, Image image, int imageID)
readonly Transform _sceneParent
static string AbsoluteUriPath(string gltfPath)
Get the absolute path to a gltf uri reference.
List< MeshCacheData[]> MeshCache
Cache of loaded meshes
Texture2D [] ImageCache
Raw loaded images
GLTFSceneImporter(string rootPath, Stream stream, Transform parent=null, bool addColliders=false)
GameObject _lastLoadedScene
virtual GameObject CreateMeshPrimitive(MeshPrimitive primitive, int meshID, int primitiveIndex)
void TransformAttributes(ref Dictionary< string, AttributeAccessor > attributeAccessors)
static void ConvertVector4CoordinateSpace(ref AttributeAccessor attributeAccessor, GLTF.Math.Vector4 coordinateSpaceCoordinateScale)
Converts vector4 to specified coordinate space
MaterialCacheData [] MaterialCache
Cache for materials to be applied to the meshes
static string AbsoluteFilePath(string gltfPath)
Get the absolute path a gltf file directory
Caches data in order to construct a unity object
readonly Dictionary< MaterialType, Shader > _shaderCache
Dictionary< int, BufferCacheData > BufferCache
Byte buffers that represent the binary contents that get parsed
GLTFSceneImporter(string gltfUrl, Transform parent=null, bool addColliders=false)
Creates a GLTFSceneBuilder object which will be able to construct a scene based off a url ...
virtual UnityEngine.Texture CreateTexture(GLTF.Schema.Texture texture)
virtual void CreateMeshObject(GLTF.Schema.Mesh mesh, Transform parent, int meshId)
static readonly GLTF.Math.Vector4 TangentSpaceConversionScale
GameObject LastLoadedScene
virtual GameObject CreateNode(Node node)
static void FlipFaces(ref AttributeAccessor attributeAccessor)
Rewinds the indices into Unity coordinate space from glTF space
virtual void SetShaderForMaterialType(MaterialType type, Shader shader)
Configures shaders in the shader cache for a given material type
virtual void BuildAttributesForMeshes()
const string Base64StringInitializer
Creates a thread to run multithreaded operations on
IEnumerator RunOnWorkerThread(Action action)
static readonly GLTF.Math.Vector3 CoordinateSpaceConversionScale
static void FlipTexCoordArrayV(ref AttributeAccessor attributeAccessor)
Flips the V component of the UV (1-V) to put from glTF into Unity space
virtual MaterialCacheData CreateMaterial(GLTF.Schema.Material def, int materialIndex)
virtual GameObject CreateScene(Scene scene)
virtual void ApplyTextureTransform(TextureInfo def, UnityEngine.Material mat, string texName)
Texture [] TextureCache
Textures to be used for assets. Textures from image cache with samplers applied