public override void OnImportAsset(AssetImportContext ctx) { var path = ctx.assetPath; var data = VoxFileImport.Load(path); var palleteTexture = VoxFileImport.CreateTextureFromColor16x16(VoxFileImport.CreateColor32FromPelatte(data.palette.values)); var boundsCube = GameObject.CreatePrimitive(PrimitiveType.Cube); var bounds = data.chunkChild .Select(chunk => new Vector3(chunk.size.x, chunk.size.z, chunk.size.y)).Aggregate( Vector3.zero, (result, chunk) => new Vector3( Mathf.Max(result.x, chunk.x), Mathf.Max(result.z, chunk.z), Mathf.Max(result.y, chunk.y) )); boundsCube.transform.localScale = bounds; for (var chunkIndex = 0; chunkIndex < data.chunkChild.Length; chunkIndex++) { var chunk = data.chunkChild[chunkIndex]; var volumeTexture = new Texture3D(chunk.size.x, chunk.size.z, chunk.size.y, TextureFormat.RGBA32, false); var volumePixels = new Color32[chunk.size.x * chunk.size.z * chunk.size.y]; for (int z = 0; z < chunk.size.y; z++) { var zSliceTexture = new Texture2D(chunk.size.x, chunk.size.z, TextureFormat.RGBA32, false); var pixels = new Color32[chunk.size.x * chunk.size.z]; for (int x = 0; x < chunk.size.x; x++) { for (int y = 0; y < chunk.size.z; y++) { var voxel = chunk.xyzi.voxels.voxels[x, y, z]; volumePixels[z * chunk.size.x * chunk.size.z + y * chunk.size.x + x] = pixels[y * chunk.size.x + x] = voxel == Int32.MaxValue ? new Color32(0, 0, 0, 0) : new Color32(255, 255, 255, 255); } } zSliceTexture.SetPixels32(pixels); zSliceTexture.Apply(); zSliceTexture.name = $"slice-{chunkIndex}-{z}"; ctx.AddObjectToAsset(zSliceTexture.name, zSliceTexture); } volumeTexture.SetPixels32(volumePixels); volumeTexture.Apply(); volumeTexture.name = $"volume-{chunkIndex}"; ctx.AddObjectToAsset(volumeTexture.name, volumeTexture); if (chunkIndex == 0) { ctx.SetMainObject(volumeTexture); } } boundsCube.name = "bounds"; ctx.AddObjectToAsset(boundsCube.name, boundsCube); palleteTexture.name = "pallete"; ctx.AddObjectToAsset(palleteTexture.name, palleteTexture); // for (int z = 0; z < data.; z++) // { // // } // var content = File.ReadAllBytes(path); // // var cube = GameObject.CreatePrimitive(PrimitiveType.Cube); // ctx.AddObjectToAsset("cube", cube); // ctx.SetMainObject(cube); // // var material = new Material(Shader.Find("Standard")); // material.color = Color.red; // // // Assets must be assigned a unique identifier string consistent across imports // ctx.AddObjectToAsset("my Material", material); }
public override void OnImportAsset(AssetImportContext ctx) { var oldShader = AssetDatabase.LoadAssetAtPath <Shader>(ctx.assetPath); if (oldShader != null) { ShaderUtil.ClearShaderMessages(oldShader); } List <PropertyCollector.TextureInfo> configuredTextures; string path = ctx.assetPath; AssetCollection assetCollection = new AssetCollection(); MinimalGraphData.GatherMinimalDependenciesFromFile(assetPath, assetCollection); var textGraph = File.ReadAllText(path, Encoding.UTF8); var graph = new GraphData { messageManager = new MessageManager(), assetGuid = AssetDatabase.AssetPathToGUID(path) }; MultiJson.Deserialize(graph, textGraph); graph.OnEnable(); graph.ValidateGraph(); Shader shader = null; #if VFX_GRAPH_10_0_0_OR_NEWER if (!graph.isOnlyVFXTarget) #endif { // build the shader text // this will also add Target dependencies into the asset collection var text = GetShaderText(path, out configuredTextures, assetCollection, graph); #if UNITY_2021_1_OR_NEWER // 2021.1 or later is guaranteed to have the new version of this function shader = ShaderUtil.CreateShaderAsset(ctx, text, false); #else // earlier builds of Unity may or may not have it // here we try to invoke the new version via reflection var createShaderAssetMethod = typeof(ShaderUtil).GetMethod( "CreateShaderAsset", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.ExactBinding, null, new Type[] { typeof(AssetImportContext), typeof(string), typeof(bool) }, null); if (createShaderAssetMethod != null) { shader = createShaderAssetMethod.Invoke(null, new Object[] { ctx, text, false }) as Shader; } else { // method doesn't exist in this version of Unity, call old version // this doesn't create dependencies properly, but is the best that we can do shader = ShaderUtil.CreateShaderAsset(text, false); } #endif if (graph.messageManager.nodeMessagesChanged) { foreach (var pair in graph.messageManager.GetNodeMessages()) { var node = graph.GetNodeFromId(pair.Key); MessageManager.Log(node, path, pair.Value.First(), shader); } } EditorMaterialUtility.SetShaderDefaults( shader, configuredTextures.Where(x => x.modifiable).Select(x => x.name).ToArray(), configuredTextures.Where(x => x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray()); EditorMaterialUtility.SetShaderNonModifiableDefaults( shader, configuredTextures.Where(x => !x.modifiable).Select(x => x.name).ToArray(), configuredTextures.Where(x => !x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray()); } UnityEngine.Object mainObject = shader; #if VFX_GRAPH_10_0_0_OR_NEWER ShaderGraphVfxAsset vfxAsset = null; if (graph.hasVFXTarget) { vfxAsset = GenerateVfxShaderGraphAsset(graph); if (mainObject == null) { mainObject = vfxAsset; } else { //Correct main object if we have a shader and ShaderGraphVfxAsset : save as sub asset vfxAsset.name = Path.GetFileNameWithoutExtension(path); ctx.AddObjectToAsset("VFXShaderGraph", vfxAsset); } } #endif Texture2D texture = Resources.Load <Texture2D>("Icons/sg_graph_icon@64"); ctx.AddObjectToAsset("MainAsset", mainObject, texture); ctx.SetMainObject(mainObject); foreach (var target in graph.activeTargets) { if (target is IHasMetadata iHasMetadata) { var metadata = iHasMetadata.GetMetadataObject(); if (metadata == null) { continue; } metadata.hideFlags = HideFlags.HideInHierarchy; ctx.AddObjectToAsset($"{iHasMetadata.identifier}:Metadata", metadata); } } var sgMetadata = ScriptableObject.CreateInstance <ShaderGraphMetadata>(); sgMetadata.hideFlags = HideFlags.HideInHierarchy; sgMetadata.assetDependencies = new List <UnityEngine.Object>(); foreach (var asset in assetCollection.assets) { if (asset.Value.HasFlag(AssetCollection.Flags.IncludeInExportPackage)) { // this sucks that we have to fully load these assets just to set the reference, // which then gets serialized as the GUID that we already have here. :P var dependencyPath = AssetDatabase.GUIDToAssetPath(asset.Key); if (!string.IsNullOrEmpty(dependencyPath)) { sgMetadata.assetDependencies.Add( AssetDatabase.LoadAssetAtPath(dependencyPath, typeof(UnityEngine.Object))); } } } ctx.AddObjectToAsset("SGInternal:Metadata", sgMetadata); // declare dependencies foreach (var asset in assetCollection.assets) { if (asset.Value.HasFlag(AssetCollection.Flags.SourceDependency)) { ctx.DependsOnSourceAsset(asset.Key); // I'm not sure if this warning below is actually used or not, keeping it to be safe var assetPath = AssetDatabase.GUIDToAssetPath(asset.Key); // Ensure that dependency path is relative to project if (!string.IsNullOrEmpty(assetPath) && !assetPath.StartsWith("Packages/") && !assetPath.StartsWith("Assets/")) { Debug.LogWarning($"Invalid dependency path: {assetPath}", mainObject); } } // NOTE: dependencies declared by GatherDependenciesFromSourceFile are automatically registered as artifact dependencies // HOWEVER: that path ONLY grabs dependencies via MinimalGraphData, and will fail to register dependencies // on GUIDs that don't exist in the project. For both of those reasons, we re-declare the dependencies here. if (asset.Value.HasFlag(AssetCollection.Flags.ArtifactDependency)) { ctx.DependsOnArtifact(asset.Key); } } }
GameObject GenerateModel(VoxModel model, AssetImportContext ctx) { var parser = new MagicaVoxelParser(); parser.LoadModel(ctx.assetPath, model, s => EditorUtility.DisplayProgressBar("vox", s, 0)); var subAssets = new List <Object>(); ctx.GetObjects(subAssets); var assetMeshes = subAssets .Select(s => s as Mesh) .Where(s => s != null) .ToArray(); var updateOpaque = false; var updateTransparent = false; var uv3 = new List <Vector4>(); var assetIndex = 0; for (int i = 0; i < model.meshes.Count; i++) { for (int l = 0; l < model.meshes[i].LODs.Count; l++) { MeshSet m; //get mesh m.opaque = assetIndex < assetMeshes.Length ? assetMeshes[assetIndex++] : null; m.transparent = assetIndex < assetMeshes.Length ? assetMeshes[assetIndex++] : null; updateOpaque = m.opaque == null; if (updateOpaque) { m.opaque = new Mesh(); } updateTransparent = m.transparent == null; if (updateTransparent) { m.transparent = new Mesh(); } //turn temp meshes into assets EditorUtility.DisplayProgressBar("vox", $"asset: frame={i}/{model.meshes.Count}, lod={l}/{model.meshes[i].LODs.Count}", .5f + (.5f * i) / model.voxelFrames.Count); var frame = model.meshes[i].LODs[l]; BuildMesh(m.opaque, frame.opaque, $"{name}.{i}.{l}.opaque", uv3, model.Settings.OmitsUVUnwrapping); BuildMesh(m.transparent, frame.transparent, $"{name}.{i}.{l}.transparent", uv3, model.Settings.OmitsUVUnwrapping); //new mesh if (updateOpaque) { ctx.AddObjectToAsset(m.opaque.name, m.opaque); } if (updateTransparent) { ctx.AddObjectToAsset(m.transparent.name, m.transparent); } model.meshes[i].LODs[l] = m; } } var baseGO = ctx.mainObject as GameObject; if (baseGO == null) { baseGO = new GameObject(); ctx.AddObjectToAsset("main", baseGO); ctx.SetMainObject(baseGO); } var gos = Enumerable.Range(0, baseGO.transform.childCount) .Select(i => baseGO.transform.GetChild(i)) .Select(t => t.gameObject) .ToList(); var gosCount = gos.Count; for (int i = gosCount; i < model.meshes.Count; i++) { var target = new GameObject(); target.transform.SetParent(baseGO.transform); gos.Add(target.gameObject); } BuildLODGroups(model, gos); if (model.Settings.asSceneGraph) { var root = BuildSceneGraph(model, gos); DestroyImmediate(baseGO); baseGO = root; ctx.AddObjectToAsset("main", root); ctx.SetMainObject(root); } //destroy unneeded meshes var meshSetContained = model.meshes.SelectMany(x => x.LODs).ToArray(); foreach (var go in subAssets .Where(s => (s as Mesh) != null) .Where(s => !meshSetContained.Any(x => x.Contains(s as Mesh)))) { DestroyImmediate(go, true); } //DestroyImmediate(baseGO); return(baseGO); }
public override void OnImportAsset(AssetImportContext ctx) { try { PCache pcache = PCache.FromFile(ctx.assetPath); PointCacheAsset cache = ScriptableObject.CreateInstance <PointCacheAsset>(); cache.name = "PointCache"; ctx.AddObjectToAsset("PointCache", cache); ctx.SetMainObject(cache); List <InProperty> inProperties = new List <InProperty>(); Dictionary <string, OutProperty> outProperties = new Dictionary <string, OutProperty>(); Dictionary <OutProperty, Texture2D> surfaces = new Dictionary <OutProperty, Texture2D>(); foreach (var prop in pcache.properties) { OutProperty p_out; if (outProperties.ContainsKey(prop.ComponentName)) { p_out = outProperties[prop.ComponentName]; p_out.Size = Math.Max(p_out.Size, prop.ComponentIndex + 1); } else { p_out = new OutProperty(prop.Type, prop.ComponentName, prop.ComponentIndex + 1); outProperties.Add(prop.ComponentName, p_out); } inProperties.Add(new InProperty(prop.Type, prop.Name, prop.ComponentIndex, p_out)); } int width, height; FindBestSize(pcache.elementCount, out width, out height); // Output Surface Creation foreach (var kvp in outProperties) { TextureFormat surfaceFormat = TextureFormat.Alpha8; switch (kvp.Value.PropertyType) { case "uchar": if (kvp.Value.Size == 1) { surfaceFormat = TextureFormat.Alpha8; } else { surfaceFormat = TextureFormat.RGBA32; } break; case "float": if (kvp.Value.Size == 1) { surfaceFormat = TextureFormat.RHalf; } else { surfaceFormat = TextureFormat.RGBAHalf; } break; default: throw new NotImplementedException("Types other than uchar/float are not supported yet"); } Texture2D surface = new Texture2D(width, height, surfaceFormat, false); surface.name = kvp.Key; surfaces.Add(kvp.Value, surface); } cache.PointCount = pcache.elementCount; cache.surfaces = new Texture2D[surfaces.Count]; Dictionary <OutProperty, Color> outValues = new Dictionary <OutProperty, Color>(); foreach (var kvp in outProperties) { outValues.Add(kvp.Value, new Color()); } for (int i = 0; i < pcache.elementCount; i++) { int idx = 0; foreach (var prop in inProperties) { float val = 0.0f; switch (prop.PropertyType) { case "uchar": val = Mathf.Clamp01(((byte)pcache.buckets[idx][i]) / 255.0f); break; case "float": val = ((float)pcache.buckets[idx][i]); break; default: throw new NotImplementedException("Types other than uchar/float are not supported yet"); } SetPropValue(prop.Index, outValues, prop.OutProperty, val); idx++; } foreach (var kvp in outProperties) { surfaces[kvp.Value].SetPixel(i % width, i / width, outValues[kvp.Value]); } } int k = 0; foreach (var kvp in surfaces) { kvp.Value.Apply(); ctx.AddObjectToAsset(kvp.Key.Name, kvp.Value); cache.surfaces[k] = kvp.Value; k++; } } catch (System.Exception e) { Debug.LogException(e); } }
/// <inheritdoc /> public override void OnImportAsset(AssetImportContext ctx) { if (ctx == null) { return; } var outputFilePath = Path.Combine(Path.GetDirectoryName(ctx.assetPath), Path.GetFileNameWithoutExtension(ctx.assetPath) + ".cs"); var src = File.ReadAllText(ctx.assetPath); TemplateGenerator generator; switch (importerVersion) { case ImporterVersion.Stable: generator = new TemplateGenerator(); break; case ImporterVersion.Beta: { generator = UnityDataHost <Object> .CreateInstance(embeddedData, additionalTypes); break; } default: throw new InvalidOperationException(); } if (generator.ProcessTemplate(ctx.assetPath, src, ref outputFilePath, out string dst)) { if (!removeIfEmptyGeneration || dst.Length > 0) { File.WriteAllText(outputFilePath, dst); } EditorUtils.Once(() => { // TODO(bengreenier): is there a less expensive way to force it to reload scripts/appdomain? AssetDatabase.Refresh(ImportAssetOptions.ForceUpdate); }); } else { for (var i = 0; i < generator.Errors.Count; i++) { var err = generator.Errors[i]; Debug.LogError(err.ToString()); } } // core asset import var asset = new TextAsset(src); ctx.AddObjectToAsset("text", asset); ctx.SetMainObject(asset); // setup data dependency if (embeddedData != null && importerVersion == ImporterVersion.Beta) { var dataPath = AssetDatabase.GetAssetPath(embeddedData); var dataGuid = AssetDatabase.GUIDFromAssetPath(dataPath); ctx.DependsOnArtifact(dataGuid); // needed to enforce the dependency AssetDatabase.LoadAssetAtPath <Object>(dataPath); } }
public override void OnImportAsset(AssetImportContext ctx) { // We're using a hardcoded window size of 100x100. This way, using a pixels per point value of 100 // results in a sprite of size 1 when the SVG file has a viewbox specified. SVGParser.SceneInfo sceneInfo; using (StreamReader stream = new StreamReader(ctx.assetPath)) { sceneInfo = SVGParser.ImportSVG(stream, 0, 1, 100, 100, PreserveViewport); } if (sceneInfo.Scene == null || sceneInfo.Scene.Root == null) { throw new Exception("Wowzers!"); } float stepDist = StepDistance; float samplingStepDist = SamplingStepDistance; float maxCord = MaxCordDeviationEnabled ? MaxCordDeviation : float.MaxValue; float maxTangent = MaxTangentAngleEnabled ? MaxTangentAngle : Mathf.PI * 0.5f; if (!AdvancedMode) { // Automatically compute sensible tessellation options from the // vector scene's bouding box and target resolution ComputeTessellationOptions(sceneInfo, TargetResolution, ResolutionMultiplier, out stepDist, out maxCord, out maxTangent); } var tessOptions = new ShapeUtils.TessellationOptions(); tessOptions.MaxCordDeviation = maxCord; tessOptions.MaxTanAngleDeviation = maxTangent; tessOptions.SamplingStepSize = 1.0f / (float)samplingStepDist; tessOptions.StepDistance = stepDist; var rect = Rect.zero; if (PreserveViewport) { rect = sceneInfo.SceneViewport; } var geometry = ShapeUtils.TessellateScene(sceneInfo.Scene, tessOptions, sceneInfo.NodeOpacity); string name = System.IO.Path.GetFileNameWithoutExtension(ctx.assetPath); var gameObject = new GameObject("Shape" + name, typeof(MeshFilter), typeof(MeshRenderer)); var mesh = new Mesh(); mesh.name = "Mesh" + name; CalculateSideExtrusion(mesh, geometry); mesh.RecalculateBounds(); mesh.RecalculateNormals(); var mat = new Material(Shader.Find("Standard")); mat.name = "Material" + name; gameObject.GetComponent <MeshFilter>().mesh = mesh; gameObject.GetComponent <MeshRenderer>().material = mat; ctx.AddObjectToAsset("shape", gameObject); ctx.AddObjectToAsset("mesh", mesh); ctx.AddObjectToAsset("material", mat); ctx.SetMainObject(gameObject); }
public override void OnImportAsset(AssetImportContext ctx) { var currentTime = DateTime.Now.Ticks; if (ctx.assetPath != path) { ctx.LogImportError("The sgpostsubgraph extension may only be used internally by Shader Graph."); return; } if (SubGraphDatabase.instance == null) { SubGraphDatabase.instance = ScriptableObject.CreateInstance <SubGraphDatabase>(); } var database = SubGraphDatabase.instance; var allSubGraphGuids = AssetDatabase.FindAssets($"t:{nameof(SubGraphAsset)}").ToList(); allSubGraphGuids.Sort(); var subGraphMap = new Dictionary <string, SubGraphData>(); var graphDataMap = new Dictionary <string, GraphData>(); foreach (var subGraphData in database.subGraphs) { if (allSubGraphGuids.BinarySearch(subGraphData.assetGuid) >= 0) { subGraphMap.Add(subGraphData.assetGuid, subGraphData); } } var dirtySubGraphGuids = new List <string>(); foreach (var subGraphGuid in allSubGraphGuids) { var subGraphAsset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphGuid)); if (!subGraphMap.TryGetValue(subGraphGuid, out var subGraphData)) { subGraphData = new SubGraphData(); } if (subGraphAsset.importedAt > subGraphData.processedAt) { dirtySubGraphGuids.Add(subGraphGuid); subGraphData.Reset(); subGraphData.processedAt = currentTime; var subGraphPath = AssetDatabase.GUIDToAssetPath(subGraphGuid); var textGraph = File.ReadAllText(subGraphPath, Encoding.UTF8); var graphData = new GraphData { isSubGraph = true, assetGuid = subGraphGuid }; JsonUtility.FromJsonOverwrite(textGraph, graphData); subGraphData.children.AddRange(graphData.GetNodes <SubGraphNode>().Select(x => x.subGraphGuid).Distinct()); subGraphData.assetGuid = subGraphGuid; subGraphMap[subGraphGuid] = subGraphData; graphDataMap[subGraphGuid] = graphData; } else { subGraphData.ancestors.Clear(); subGraphData.descendents.Clear(); subGraphData.isRecursive = false; } } database.subGraphs.Clear(); database.subGraphs.AddRange(subGraphMap.Values); database.subGraphs.Sort((s1, s2) => s1.assetGuid.CompareTo(s2.assetGuid)); database.subGraphGuids.Clear(); database.subGraphGuids.AddRange(database.subGraphs.Select(x => x.assetGuid)); var permanentMarks = new HashSet <string>(); var stack = new Stack <string>(allSubGraphGuids.Count); // Detect recursion, and populate `ancestors` and `descendents` per sub graph. foreach (var rootSubGraphData in database.subGraphs) { var rootSubGraphGuid = rootSubGraphData.assetGuid; stack.Push(rootSubGraphGuid); while (stack.Count > 0) { var subGraphGuid = stack.Pop(); if (!permanentMarks.Add(subGraphGuid)) { continue; } var subGraphData = subGraphMap[subGraphGuid]; if (subGraphData != rootSubGraphData) { subGraphData.ancestors.Add(rootSubGraphGuid); rootSubGraphData.descendents.Add(subGraphGuid); } foreach (var childSubGraphGuid in subGraphData.children) { if (childSubGraphGuid == rootSubGraphGuid) { rootSubGraphData.isRecursive = true; } else if (subGraphMap.ContainsKey(childSubGraphGuid)) { stack.Push(childSubGraphGuid); } } } permanentMarks.Clear(); } // Next up we build a list of sub graphs to be processed, which will later be sorted topologically. var sortedSubGraphs = new List <SubGraphData>(); foreach (var subGraphGuid in dirtySubGraphGuids) { var subGraphData = subGraphMap[subGraphGuid]; if (permanentMarks.Add(subGraphGuid)) { sortedSubGraphs.Add(subGraphData); } // Note that we're traversing up the graph via ancestors rather than descendents, because all Sub Graphs using the current sub graph needs to be re-processed. foreach (var ancestorGuid in subGraphData.ancestors) { if (permanentMarks.Add(ancestorGuid)) { var ancestorSubGraphData = subGraphMap[ancestorGuid]; sortedSubGraphs.Add(ancestorSubGraphData); } } } permanentMarks.Clear(); // Sort topologically. At this stage we can assume there are no loops because all recursive sub graphs have been filtered out. sortedSubGraphs.Sort((s1, s2) => s1.descendents.Contains(s2.assetGuid) ? 1 : s2.descendents.Contains(s1.assetGuid) ? -1 : 0); // Finally process the topologically sorted sub graphs without recursion. var registry = new FunctionRegistry(new ShaderStringBuilder(), true); var messageManager = new MessageManager(); foreach (var subGraphData in sortedSubGraphs) { try { var subGraphPath = AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid); if (!graphDataMap.TryGetValue(subGraphData.assetGuid, out var graphData)) { var textGraph = File.ReadAllText(subGraphPath, Encoding.UTF8); graphData = new GraphData { isSubGraph = true, assetGuid = subGraphData.assetGuid }; JsonUtility.FromJsonOverwrite(textGraph, graphData); } graphData.messageManager = messageManager; ProcessSubGraph(subGraphMap, registry, subGraphData, graphData); if (messageManager.nodeMessagesChanged) { var subGraphAsset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid)); foreach (var pair in messageManager.GetNodeMessages()) { var node = graphData.GetNodeFromTempId(pair.Key); foreach (var message in pair.Value) { MessageManager.Log(node, subGraphPath, message, subGraphAsset); } } } } catch (Exception e) { subGraphData.isValid = false; var subGraphAsset = AssetDatabase.LoadAssetAtPath <SubGraphAsset>(AssetDatabase.GUIDToAssetPath(subGraphData.assetGuid)); Debug.LogException(e, subGraphAsset); } finally { subGraphData.processedAt = currentTime; messageManager.ClearAll(); } } // Carry over functions used by sub-graphs that were not re-processed in this import. foreach (var subGraphData in database.subGraphs) { foreach (var functionName in subGraphData.functionNames) { if (!registry.sources.ContainsKey(functionName)) { registry.sources.Add(functionName, database.functionSources[database.functionNames.BinarySearch(functionName)]); } } } var functions = registry.sources.ToList(); functions.Sort((p1, p2) => p1.Key.CompareTo(p2.Key)); database.functionNames.Clear(); database.functionSources.Clear(); foreach (var pair in functions) { database.functionNames.Add(pair.Key); database.functionSources.Add(pair.Value); } ctx.AddObjectToAsset("MainAsset", database); ctx.SetMainObject(database); SubGraphDatabase.instance = null; }
public static async void OnImportGltfAsset(AssetImportContext context) { var importedObject = await GltfUtility.ImportGltfObjectFromPathAsync(context.assetPath); if (importedObject == null || importedObject.GameObjectReference == null) { Debug.LogError("Failed to import glTF object"); return; } var gltfAsset = (GltfAsset)ScriptableObject.CreateInstance(typeof(GltfAsset)); gltfAsset.GltfObject = importedObject; gltfAsset.name = $"{gltfAsset.GltfObject.Name}{Path.GetExtension(context.assetPath)}"; gltfAsset.Model = importedObject.GameObjectReference; context.AddObjectToAsset("main", gltfAsset.Model); context.SetMainObject(importedObject.GameObjectReference); context.AddObjectToAsset("glTF data", gltfAsset); bool reImport = false; for (var i = 0; i < gltfAsset.GltfObject.textures?.Length; i++) { GltfTexture gltfTexture = gltfAsset.GltfObject.textures[i]; if (gltfTexture == null) { continue; } var path = AssetDatabase.GetAssetPath(gltfTexture.Texture); if (string.IsNullOrWhiteSpace(path)) { var textureName = gltfTexture.name; if (string.IsNullOrWhiteSpace(textureName)) { textureName = $"Texture_{i}"; gltfTexture.Texture.name = textureName; } context.AddObjectToAsset(textureName, gltfTexture.Texture); } else { if (!gltfTexture.Texture.isReadable) { var textureImporter = AssetImporter.GetAtPath(path) as TextureImporter; if (textureImporter != null) { textureImporter.isReadable = true; textureImporter.SetPlatformTextureSettings(new TextureImporterPlatformSettings { format = TextureImporterFormat.RGBA32 }); textureImporter.SaveAndReimport(); reImport = true; } } } } if (reImport) { var importer = AssetImporter.GetAtPath(context.assetPath); importer.SaveAndReimport(); return; } for (var i = 0; i < gltfAsset.GltfObject.meshes?.Length; i++) { GltfMesh gltfMesh = gltfAsset.GltfObject.meshes[i]; string meshName = string.IsNullOrWhiteSpace(gltfMesh.name) ? $"Mesh_{i}" : gltfMesh.name; gltfMesh.Mesh.name = meshName; context.AddObjectToAsset($"{meshName}", gltfMesh.Mesh); } if (gltfAsset.GltfObject.materials != null) { foreach (GltfMaterial gltfMaterial in gltfAsset.GltfObject.materials) { if (context.assetPath.EndsWith(".glb")) { context.AddObjectToAsset(gltfMaterial.name, gltfMaterial.Material); } else { var relativePath = Path.GetFullPath(Path.GetDirectoryName(context.assetPath)).Replace(Path.GetFullPath(Application.dataPath), "Assets"); relativePath = Path.Combine(relativePath, $"{gltfMaterial.name}.mat"); AssetDatabase.CreateAsset(gltfMaterial.Material, relativePath); gltfMaterial.Material = AssetDatabase.LoadAssetAtPath <Material>(relativePath); } } } }
public override void OnImportAsset(AssetImportContext ctx) { var mesh = new Mesh(); ctx.AddObjectToAsset("mesh0", mesh); ctx.SetMainObject(mesh); using (BinaryReader reader = new BinaryReader(File.Open(ctx.assetPath, FileMode.Open))) { byte[] searchBuf = new byte[32]; var markerStr = "DatasmithMeshSourceModel"; byte[] marker = System.Text.Encoding.ASCII.GetBytes(markerStr); uint markerLength = (uint)markerStr.Length; bool didFindMarker = false; while (reader.BaseStream.Position < (reader.BaseStream.Length - markerLength)) { reader.BaseStream.Read(searchBuf, 0, (int)markerLength); if (0 == memcmp(searchBuf, marker, markerLength)) { reader.BaseStream.Position += 2; // Skip 2 extra null bytes after the marker didFindMarker = true; break; } // rewind to 1 byte after the previous read position reader.BaseStream.Position -= (markerLength - 1); } if (!didFindMarker) { throw new Exception("Couldn't find marker " + markerStr + " in file " + ctx.assetPath); } for (uint i = 0; i < 6; ++i) { if (reader.ReadUInt32() != 0) { Console.Out.WriteLine("Warning: expected all zeros between marker and start of material index array"); } } reader.ReadUInt32(); // length1 reader.ReadUInt32(); // length2 reader.ReadUInt32(); // unknown 9c 00 00 00 reader.ReadUInt32(); // unknown 00 00 00 00 reader.ReadUInt32(); // unknown 01 00 00 00 reader.ReadUInt32(); // unknown 00 00 00 00 uint materialIndexCount = reader.ReadUInt32(); uint[] materialIndices = new uint[materialIndexCount]; for (uint i = 0; i < materialIndexCount; ++i) { materialIndices[i] = reader.ReadUInt32(); } uint unknownCount = reader.ReadUInt32(); uint[] unknownData = new uint[unknownCount]; for (uint i = 0; i < unknownCount; ++i) { unknownData[i] = reader.ReadUInt32(); } List <Vector3> vertices = new List <Vector3>(); Dictionary <int, int> indexRemap = new Dictionary <int, int>(); { // Collapse vertices and generate an index remapping table Dictionary <Vector3, int> uniqueVertices = new Dictionary <Vector3, int>(); int fileVertexCount = (int)reader.ReadUInt32(); int vertexLimit = 524288; if (fileVertexCount > vertexLimit) { ctx.LogImportError(String.Format("UdsMeshImporter: Sanity check failed: File {0} has too many vertices ({1}, limit is {2}) -- returning empty mesh.", ctx.assetPath, fileVertexCount, vertexLimit)); return; } for (int i = 0; i < fileVertexCount; ++i) { Vector3 v = new Vector3(); // Adjust scale from cm -> meters v.x = reader.ReadSingle() * 0.01f; v.y = reader.ReadSingle() * 0.01f; v.z = reader.ReadSingle() * 0.01f; if (!uniqueVertices.ContainsKey(v)) { vertices.Add(v); uniqueVertices.Add(v, vertices.Count - 1); } indexRemap.Add(i, uniqueVertices[v]); } /* * if (vertices.Count < fileVertexCount) { * Debug.Log(String.Format("Vertex position remapping removed {0} nonunique positions", fileVertexCount - vertices.Count)); * } */ } uint indexCount = reader.ReadUInt32(); int[] triangleIndices = new int[indexCount]; for (uint triIdx = 0; triIdx < (indexCount / 3); ++triIdx) { triangleIndices[(triIdx * 3) + 0] = indexRemap[(int)reader.ReadUInt32()]; triangleIndices[(triIdx * 3) + 1] = indexRemap[(int)reader.ReadUInt32()]; triangleIndices[(triIdx * 3) + 2] = indexRemap[(int)reader.ReadUInt32()]; } reader.ReadUInt32(); // unknown-zero, maybe a count of an unused field reader.ReadUInt32(); // unknown-zero, maybe a count of an unused field uint normalCount = reader.ReadUInt32(); Vector3[] normals = new Vector3[normalCount]; for (uint i = 0; i < normalCount; ++i) { normals[i].x = reader.ReadSingle(); normals[i].y = reader.ReadSingle(); normals[i].z = reader.ReadSingle(); } uint uvCount = reader.ReadUInt32(); Vector2[] uvs = new Vector2[uvCount]; for (uint i = 0; i < uvCount; ++i) { uvs[i].x = reader.ReadSingle(); uvs[i].y = reader.ReadSingle(); } // Datasmith hands us per-face-vertex normals and UVs, which Unity can't handle. // Use the Datasmith-supplied index array to write new per-submesh (material group) position/normal/UV buffers. { var materialToSubmesh = new SortedDictionary <uint, uint>(); uint submeshCount = 0; for (uint triIdx = 0; triIdx < materialIndexCount; ++triIdx) { uint midx = materialIndices[triIdx]; if (!materialToSubmesh.ContainsKey(midx)) { materialToSubmesh[midx] = submeshCount; submeshCount += 1; } } List <Vector3> cookedPositions = new List <Vector3>(); List <Vector2> cookedUVs = new List <Vector2>(); List <Vector3> cookedNormals = new List <Vector3>(); List <List <int> > cookedSubmeshIndices = new List <List <int> >(); List <Dictionary <Hash128, int> > vertexCollapseData = new List <Dictionary <Hash128, int> >(vertices.Count); // Prepopulate the vertex-collapse list with empty dicts for (int vIdx = 0; vIdx < vertices.Count; ++vIdx) { vertexCollapseData.Add(new Dictionary <Hash128, int>()); } for (uint submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex) { List <int> thisSubmeshIndices = new List <int>(); for (uint triIdx = 0; triIdx < materialIndexCount; ++triIdx) { if (materialToSubmesh[materialIndices[triIdx]] != submeshIndex) { continue; // this triangle is not relevant in this submesh. } for (uint triVIdx = 0; triVIdx < 3; ++triVIdx) { uint triVIdx_adj = 2 - triVIdx; // Adjusted to swap winding order int positionIndex = triangleIndices[(triIdx * 3) + triVIdx_adj]; Vector3 fvP = vertices[positionIndex]; Vector2 fvUV = uvs[(triIdx * 3) + triVIdx_adj]; Vector3 fvN = normals[(triIdx * 3) + triVIdx_adj]; // Try and find an existing vertex/normal/UV set to reuse // We already collapsed coincident positions while reading the vertex and index buffers, so we can partition our search by position index. Dictionary <Hash128, int> collapseData = vertexCollapseData[positionIndex]; Hash128 targetHash = NUVHash(fvN, fvUV); int targetVIdx; if (collapseData.ContainsKey(targetHash)) { // Match found, reuse the previous vertex targetVIdx = collapseData[targetHash]; } else { // No match found, so we add it cookedPositions.Add(fvP); cookedUVs.Add(fvUV); cookedNormals.Add(fvN); targetVIdx = cookedPositions.Count - 1; collapseData.Add(targetHash, targetVIdx); } thisSubmeshIndices.Add(targetVIdx); } } cookedSubmeshIndices.Add(thisSubmeshIndices); } mesh.Clear(); if (cookedPositions.Count > 65535) { ctx.LogImportWarning(String.Format("Mesh \"{0}\" has more than 65535 vertices ({1}) and requires a 32-bit index buffer. This mesh may not render correctly on all platforms.", ctx.assetPath, cookedPositions.Count)); mesh.indexFormat = UnityEngine.Rendering.IndexFormat.UInt32; } mesh.SetVertices(cookedPositions); mesh.SetUVs(0, cookedUVs); mesh.SetNormals(cookedNormals); mesh.subMeshCount = (int)submeshCount; for (uint submeshIndex = 0; submeshIndex < submeshCount; ++submeshIndex) { mesh.SetIndices(cookedSubmeshIndices[(int)submeshIndex].ToArray(), MeshTopology.Triangles, (int)submeshIndex); } // Generate lightmap UVs if (materialIndexCount > 50000 /*triangles*/) { if (m_ForceLightmapUVGeneration) { UnityEditor.Unwrapping.GenerateSecondaryUVSet(mesh); } else { ctx.LogImportWarning(String.Format("Mesh \"{0}\": lightmap UVs won't automatically be generated due to complexity limits. Turn on \"Force Lightmap UV generation\" to override.", ctx.assetPath)); } } mesh.RecalculateBounds(); mesh.RecalculateTangents(); } } }
public void Add(string identifier, Object asset) { m_ctx.AddObjectToAsset(identifier, asset); }
// [SerializeField] private bool _useJpgTextures = false; public override void OnImportAsset(AssetImportContext ctx) { string sceneName = null; GameObject gltfScene = null; UnityEngine.Mesh[] meshes = null; try { sceneName = Path.GetFileNameWithoutExtension(ctx.assetPath); gltfScene = CreateGLTFScene(ctx.assetPath); // Remove empty roots if (_removeEmptyRootObjects) { var t = gltfScene.transform; while ( gltfScene.transform.childCount == 1 && gltfScene.GetComponents <Component>().Length == 1) { var parent = gltfScene; gltfScene = gltfScene.transform.GetChild(0).gameObject; t = gltfScene.transform; t.parent = null; // To keep transform information in the new parent Object.DestroyImmediate(parent); // Get rid of the parent } } // Ensure there are no hide flags present (will cause problems when saving) gltfScene.hideFlags &= ~(HideFlags.HideAndDontSave); foreach (Transform child in gltfScene.transform) { child.gameObject.hideFlags &= ~(HideFlags.HideAndDontSave); } // Zero position gltfScene.transform.position = Vector3.zero; // Get meshes var meshNames = new List <string>(); var meshHash = new HashSet <UnityEngine.Mesh>(); var meshFilters = gltfScene.GetComponentsInChildren <MeshFilter>().Select(x => (x.gameObject, x.sharedMesh)).ToList(); meshFilters.AddRange(gltfScene.GetComponentsInChildren <SkinnedMeshRenderer>().Select(x => (x.gameObject, x.sharedMesh))); var vertexBuffer = new List <Vector3>(); meshes = meshFilters.Select(mf => { var mesh = mf.sharedMesh; vertexBuffer.Clear(); mesh.GetVertices(vertexBuffer); for (var i = 0; i < vertexBuffer.Count; ++i) { vertexBuffer[i] *= _scaleFactor; } mesh.SetVertices(vertexBuffer); if (_swapUvs) { var uv = mesh.uv; var uv2 = mesh.uv2; mesh.uv = uv2; mesh.uv2 = uv2; } if (_importNormals == GLTFImporterNormals.None) { mesh.normals = new Vector3[0]; } if (_importNormals == GLTFImporterNormals.Calculate && mesh.GetTopology(0) == MeshTopology.Triangles) { mesh.RecalculateNormals(); } mesh.UploadMeshData(!_readWriteEnabled); if (_generateColliders) { var collider = mf.gameObject.AddComponent <MeshCollider>(); collider.sharedMesh = mesh; } if (meshHash.Add(mesh)) { var meshName = string.IsNullOrEmpty(mesh.name) ? mf.gameObject.name : mesh.name; mesh.name = ObjectNames.GetUniqueName(meshNames.ToArray(), meshName); meshNames.Add(mesh.name); } return(mesh); }).ToArray(); var animations = gltfScene.GetComponentsInChildren <Animation>(); var clips = animations.SelectMany(x => AnimationUtility.GetAnimationClips(x.gameObject)); foreach (var clip in clips) { ctx.AddObjectToAsset(clip.name, clip); } var renderers = gltfScene.GetComponentsInChildren <Renderer>(); if (_importMaterials) { // Get materials var materialNames = new List <string>(); var materialHash = new HashSet <UnityEngine.Material>(); var materials = renderers.SelectMany(r => { return(r.sharedMaterials.Select(mat => { if (materialHash.Add(mat)) { var matName = string.IsNullOrEmpty(mat.name) ? mat.shader.name : mat.name; if (matName == mat.shader.name) { matName = matName.Substring(Mathf.Min(matName.LastIndexOf("/") + 1, matName.Length - 1)); } // Ensure name is unique matName = ObjectNames.NicifyVariableName(matName); matName = ObjectNames.GetUniqueName(materialNames.ToArray(), matName); mat.name = matName; materialNames.Add(matName); } return mat; })); }).Distinct().ToArray(); // Get textures var textureNames = new List <string>(); var textureHash = new HashSet <Texture2D>(); var texMaterialMap = new Dictionary <Texture2D, List <TexMaterialMap> >(); var textures = materials.SelectMany(mat => { var shader = mat.shader; if (!shader) { return(Enumerable.Empty <Texture2D>()); } var matTextures = new List <Texture2D>(); for (var i = 0; i < ShaderUtil.GetPropertyCount(shader); ++i) { if (ShaderUtil.GetPropertyType(shader, i) == ShaderUtil.ShaderPropertyType.TexEnv) { var propertyName = ShaderUtil.GetPropertyName(shader, i); var tex = mat.GetTexture(propertyName) as Texture2D; if (tex) { if (textureHash.Add(tex)) { var texName = tex.name; if (string.IsNullOrEmpty(texName)) { if (propertyName.StartsWith("_")) { texName = propertyName.Substring(Mathf.Min(1, propertyName.Length - 1)); } } // Ensure name is unique texName = string.Format("{0} {1}", sceneName, ObjectNames.NicifyVariableName(texName)); texName = ObjectNames.GetUniqueName(textureNames.ToArray(), texName); tex.name = texName; textureNames.Add(texName); matTextures.Add(tex); } List <TexMaterialMap> materialMaps; if (!texMaterialMap.TryGetValue(tex, out materialMaps)) { materialMaps = new List <TexMaterialMap>(); texMaterialMap.Add(tex, materialMaps); } materialMaps.Add(new TexMaterialMap(mat, propertyName, propertyName == "_BumpMap")); } } } return(matTextures); }).Distinct().ToArray(); // var folderName = Path.GetDirectoryName(ctx.assetPath); // Save textures as separate assets and rewrite refs // TODO: Support for other texture types if (textures.Length > 0) { // var texturesRoot = string.Concat(folderName, "/", "Textures/"); // Directory.CreateDirectory(texturesRoot); foreach (var tex in textures) { // var ext = _useJpgTextures ? ".jpg" : ".png"; // var texPath = string.Concat(texturesRoot, tex.name, ext); // File.WriteAllBytes(texPath, _useJpgTextures ? tex.EncodeToJPG() : tex.EncodeToPNG()); // // AssetDatabase.ImportAsset(texPath); ctx.AddObjectToAsset(tex.name, tex); } } AssetDatabase.Refresh(); // Save materials as separate assets and rewrite refs if (materials.Length > 0) { // var materialRoot = string.Concat(folderName, "/", "Materials/"); // Directory.CreateDirectory(materialRoot); foreach (var mat in materials) { // var materialPath = string.Concat(materialRoot, mat.name, ".mat"); // var newMat = mat; // CopyOrNew(mat, materialPath, m => // { // // Fix references // newMat = m; // foreach (var r in renderers) // { // var sharedMaterials = r.sharedMaterials; // for (var i = 0; i < sharedMaterials.Length; ++i) // { // var sharedMaterial = sharedMaterials[i]; // if (sharedMaterial.name == mat.name) sharedMaterials[i] = m; // } // sharedMaterials = sharedMaterials.Where(sm => sm).ToArray(); // r.sharedMaterials = sharedMaterials; // } // }); ctx.AddObjectToAsset(mat.name, mat); // Fix textures // HACK: This needs to be a delayed call. // Unity needs a frame to kick off the texture import so we can rewrite the ref // if (textures.Length > 0) // { // EditorApplication.delayCall += () => // { // for (var i = 0; i < textures.Length; ++i) // { // var tex = textures[i]; // var texturesRoot = string.Concat(folderName, "/", "Textures/"); // var ext = _useJpgTextures ? ".jpg" : ".png"; // var texPath = string.Concat(texturesRoot, tex.name, ext); // // // Grab new imported texture // var materialMaps = texMaterialMap[tex]; // var importer = (TextureImporter)TextureImporter.GetAtPath(texPath); // var importedTex = AssetDatabase.LoadAssetAtPath<Texture2D>(texPath); // if (importer != null) // { // var isNormalMap = false; // foreach (var materialMap in materialMaps) // { // if (materialMap.Material == mat) // { // isNormalMap |= materialMap.IsNormalMap; // newMat.SetTexture(materialMap.Property, importedTex); // } // }; // // if (isNormalMap) // { // // Try to auto-detect normal maps // importer.textureType = TextureImporterType.NormalMap; // } // else if (importer.textureType == TextureImporterType.Sprite) // { // // Force disable sprite mode, even for 2D projects // importer.textureType = TextureImporterType.Default; // } // } // else // { // Debug.LogWarning("GLTFImporter: Unable to import texture from path reference"); // } // } // }; // } } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); } else { var temp = GameObject.CreatePrimitive(PrimitiveType.Plane); temp.SetActive(false); var defaultMat = new[] { temp.GetComponent <Renderer>().sharedMaterial }; DestroyImmediate(temp); foreach (var rend in renderers) { rend.sharedMaterials = defaultMat; } } } catch { if (gltfScene) { DestroyImmediate(gltfScene); } throw; } #if UNITY_2017_3_OR_NEWER // Set main asset ctx.AddObjectToAsset("main asset", gltfScene); // Add meshes foreach (var mesh in meshes) { try { ctx.AddObjectToAsset("mesh " + mesh.name, mesh); } catch (System.InvalidOperationException e) { Debug.LogWarning(e.ToString(), mesh); } } ctx.SetMainObject(gltfScene); #else // Set main asset ctx.SetMainAsset("main asset", gltfScene); // Add meshes foreach (var mesh in meshes) { try { ctx.AddSubAsset("mesh " + mesh.name, mesh); } catch (System.InvalidOperationException e) { Debug.LogWarning(e.ToString(), mesh); } } #endif }
public override void OnImportAsset(AssetImportContext ctx) { if (ctx == null) { return; } var path = ctx.assetPath; AlembicStream.DisconnectStreamsWithPath(path); var fileName = Path.GetFileNameWithoutExtension(path); var previousGoName = fileName; if (!string.IsNullOrEmpty(rootGameObjectName)) { previousGoName = rootGameObjectName; } var go = new GameObject(previousGoName); var streamDescriptor = ScriptableObject.CreateInstance <AlembicStreamDescriptor>(); streamDescriptor.name = go.name + "_ABCDesc"; streamDescriptor.PathToAbc = path; streamDescriptor.Settings = StreamSettings; using (new RuntimeUtils.DisableUndoGuard(true)) { using (var abcStream = new AlembicStream(go, streamDescriptor)) { abcStream.AbcLoad(true, true); abcStream.GetTimeRange(out abcStartTime, out abcEndTime); if (firstImport) { startTime = abcStartTime; endTime = abcEndTime; } streamDescriptor.MediaStartTime = (float)abcStartTime; streamDescriptor.MediaEndTime = (float)abcEndTime; var streamPlayer = go.AddComponent <AlembicStreamPlayer>(); streamPlayer.StreamSource = AlembicStreamPlayer.AlembicStreamSource.Internal; streamPlayer.StreamDescriptor = streamDescriptor; streamPlayer.StartTime = (float)StartTime; streamPlayer.EndTime = (float)EndTime; var subassets = new Subassets(ctx); subassets.Add(streamDescriptor.name, streamDescriptor); GenerateSubAssets(subassets, abcStream.abcTreeRoot, streamDescriptor); AlembicStream.ReconnectStreamsWithPath(path); var prevIdName = fileName; if (!string.IsNullOrEmpty(rootGameObjectId)) { prevIdName = rootGameObjectId; } ctx.AddObjectToAsset(prevIdName, go); ctx.SetMainObject(go); isHDF5 = abcStream.IsHDF5(); if (IsHDF5) { Debug.LogError(path + ": Unsupported HDF5 file format detected. Please convert to Ogawa."); } } } firstImport = false; }
public override void OnImportAsset(AssetImportContext ctx) { var width = 64; var height = 64; var mipmapEnabled = true; var textureFormat = TextureFormat.ARGB32; var srgbTexture = true; // Check if the input textures are valid to be used to build the texture array. var isValid = Verify(ctx, false); if (isValid) { // Use the texture assigned to the first slice as "master". // This means all other textures have to use same settings as the master texture. var sourceTexture = m_Textures[0]; width = sourceTexture.width; height = sourceTexture.height; textureFormat = sourceTexture.format; var sourceTexturePath = AssetDatabase.GetAssetPath(sourceTexture); var textureImporter = (TextureImporter)AssetImporter.GetAtPath(sourceTexturePath); mipmapEnabled = textureImporter.mipmapEnabled; srgbTexture = textureImporter.sRGBTexture; } // Create the texture array. // When the texture array asset is being created, there are no input textures added yet, // thus we do Max(1, Count) to make sure to add at least 1 slice. var texture2DArray = new Texture2DArray(width, height, Mathf.Max(1, m_Textures.Count), textureFormat, mipmapEnabled, !srgbTexture); texture2DArray.wrapMode = m_WrapMode; texture2DArray.filterMode = m_FilterMode; texture2DArray.anisoLevel = m_AnisoLevel; if (isValid) { // If everything is valid, copy source textures over to the texture array. for (var n = 0; n < m_Textures.Count; ++n) { var source = m_Textures[n]; Graphics.CopyTexture(source, 0, texture2DArray, n); } } else { // If there is any error, copy a magenta colored texture into every slice. // I was thinking to only make the invalid slice magenta, but then it's way less obvious that // something isn't right with the texture array. Thus I mark the entire texture array as broken. var errorTexture = new Texture2D(width, height, textureFormat, mipmapEnabled); try { var errorPixels = errorTexture.GetPixels32(); for (var n = 0; n < errorPixels.Length; ++n) { errorPixels[n] = Color.magenta; } errorTexture.SetPixels32(errorPixels); errorTexture.Apply(); for (var n = 0; n < texture2DArray.depth; ++n) { Graphics.CopyTexture(errorTexture, 0, texture2DArray, n); } } finally { DestroyImmediate(errorTexture); } } // Mark all input textures as dependency to the texture array. // This causes the texture array to get re-generated when any input texture changes or when the build target changed. for (var n = 0; n < m_Textures.Count; ++n) { var source = m_Textures[n]; if (source != null) { var path = AssetDatabase.GetAssetPath(source); ctx.DependsOnSourceAsset(path); } } ctx.AddObjectToAsset("Texture2DArray", texture2DArray); ctx.SetMainObject(texture2DArray); if (!isValid) { // Run the verify step again, but this time we have the main object asset. // Console logs should ping the asset, but they don't in 2019.3 beta, bug? Verify(ctx, true); } }
/// <summary> /// Common method performing the import of the asset /// </summary> /// <param name="ctx">Asset importer context.</param> public override void OnImportAsset(AssetImportContext ctx) { engine.TextureGenerationType = TextureImporterType.Default; Texture cookieTextureCube = null; Texture cookieTexture2D = null; string iesFilePath = Path.Combine(Path.GetDirectoryName(Application.dataPath), ctx.assetPath); string errorMessage = engine.ReadFile(iesFilePath); if (string.IsNullOrEmpty(errorMessage)) { iesMetaData.FileFormatVersion = engine.FileFormatVersion; iesMetaData.IESPhotometricType = engine.GetPhotometricType(); iesMetaData.Manufacturer = engine.GetKeywordValue("MANUFAC"); iesMetaData.LuminaireCatalogNumber = engine.GetKeywordValue("LUMCAT"); iesMetaData.LuminaireDescription = engine.GetKeywordValue("LUMINAIRE"); iesMetaData.LampCatalogNumber = engine.GetKeywordValue("LAMPCAT"); iesMetaData.LampDescription = engine.GetKeywordValue("LAMP"); (iesMetaData.IESMaximumIntensity, iesMetaData.IESMaximumIntensityUnit) = engine.GetMaximumIntensity(); string warningMessage; (warningMessage, cookieTextureCube) = engine.GenerateCubeCookie(iesMetaData.CookieCompression, (int)iesMetaData.iesSize); if (!string.IsNullOrEmpty(warningMessage)) { ctx.LogImportWarning($"Cannot properly generate IES Cube texture: {warningMessage}"); } cookieTextureCube.IncrementUpdateCount(); (warningMessage, cookieTexture2D) = engine.Generate2DCookie(iesMetaData.CookieCompression, iesMetaData.SpotAngle, (int)iesMetaData.iesSize, iesMetaData.ApplyLightAttenuation); if (!string.IsNullOrEmpty(warningMessage)) { ctx.LogImportWarning($"Cannot properly generate IES 2D texture: {warningMessage}"); } cookieTexture2D.IncrementUpdateCount(); } else { ctx.LogImportError($"Cannot read IES file '{iesFilePath}': {errorMessage}"); } string iesFileName = Path.GetFileNameWithoutExtension(ctx.assetPath); var iesObject = ScriptableObject.CreateInstance <IESObject>(); iesObject.iesMetaData = iesMetaData; GameObject lightObject = new GameObject(iesFileName); lightObject.transform.localEulerAngles = new Vector3(90f, 0f, iesMetaData.LightAimAxisRotation); Light light = lightObject.AddComponent <Light>(); light.type = (iesMetaData.PrefabLightType == IESLightType.Point) ? LightType.Point : LightType.Spot; light.intensity = 1f; // would need a better intensity value formula light.range = 10f; // would need a better range value formula light.spotAngle = iesMetaData.SpotAngle; ctx.AddObjectToAsset("IES", iesObject); ctx.SetMainObject(iesObject); IESImporter.createRenderPipelinePrefabLight?.Invoke(ctx, iesFileName, iesMetaData.UseIESMaximumIntensity, iesMetaData.IESMaximumIntensityUnit, iesMetaData.IESMaximumIntensity, light, (iesMetaData.PrefabLightType == IESLightType.Point) ? cookieTextureCube : cookieTexture2D); if (cookieTextureCube != null) { cookieTextureCube.name = iesFileName + "-Cube-IES"; ctx.AddObjectToAsset(cookieTextureCube.name, cookieTextureCube); } if (cookieTexture2D != null) { cookieTexture2D.name = iesFileName + "-2D-IES"; ctx.AddObjectToAsset(cookieTexture2D.name, cookieTexture2D); } }
public override void OnImportAsset(AssetImportContext ctx) { ////REVIEW: need to check with version control here? // Read file. string text; try { text = File.ReadAllText(ctx.assetPath); } catch (Exception exception) { ctx.LogImportError(string.Format("Could read file '{0}' ({1})", ctx.assetPath, exception)); return; } // Create asset. var asset = ScriptableObject.CreateInstance<InputActionAsset>(); // Parse JSON. try { ////TODO: make sure action names are unique asset.LoadFromJson(text); } catch (Exception exception) { ctx.LogImportError(string.Format("Could not parse input actions in JSON format from '{0}' ({1})", ctx.assetPath, exception)); DestroyImmediate(asset); return; } ctx.AddObjectToAsset("<root>", asset); ctx.SetMainObject(asset); // Make sure every map and every action has a stable ID assigned to it. var maps = asset.actionMaps; foreach (var map in maps) { if (map.idDontGenerate == Guid.Empty) { // Generate and remember GUID. var id = map.id; ArrayHelpers.Append(ref m_ActionMapGuids, new RememberedGuid { guid = id.ToString(), name = map.name, }); } else { // Retrieve remembered GUIDs. if (m_ActionMapGuids != null) { for (var i = 0; i < m_ActionMapGuids.Length; ++i) { if (string.Compare(m_ActionMapGuids[i].name, map.name, StringComparison.InvariantCultureIgnoreCase) == 0) { map.m_Guid = Guid.Empty; map.m_Id = m_ActionMapGuids[i].guid; break; } } } } foreach (var action in map.actions) { var actionName = string.Format("{0}/{1}", map.name, action.name); if (action.idDontGenerate == Guid.Empty) { // Generate and remember GUID. var id = action.id; ArrayHelpers.Append(ref m_ActionGuids, new RememberedGuid { guid = id.ToString(), name = actionName, }); } else { // Retrieve remembered GUIDs. if (m_ActionGuids != null) { for (var i = 0; i < m_ActionGuids.Length; ++i) { if (string.Compare(m_ActionGuids[i].name, actionName, StringComparison.InvariantCultureIgnoreCase) == 0) { action.m_Guid = Guid.Empty; action.m_Id = m_ActionGuids[i].guid; break; } } } } } } // Create subasset for each action. foreach (var map in maps) { var haveSetName = !string.IsNullOrEmpty(map.name); foreach (var action in map.actions) { var actionReference = ScriptableObject.CreateInstance<InputActionReference>(); actionReference.Set(action); var objectName = action.name; if (haveSetName) objectName = string.Format("{0}/{1}", map.name, action.name); actionReference.name = objectName; ctx.AddObjectToAsset(objectName, actionReference); } } // Generate wrapper code, if enabled. if (m_GenerateWrapperCode) { var wrapperFilePath = m_WrapperCodePath; if (string.IsNullOrEmpty(wrapperFilePath)) { var assetPath = ctx.assetPath; var directory = Path.GetDirectoryName(assetPath); var fileName = Path.GetFileNameWithoutExtension(assetPath); wrapperFilePath = Path.Combine(directory, fileName) + ".cs"; } var options = new InputActionCodeGenerator.Options { sourceAssetPath = ctx.assetPath, namespaceName = m_WrapperCodeNamespace, className = m_WrapperClassName, generateEvents = m_GenerateActionEvents, generateInterfaces = m_GenerateInterfaces, }; if (InputActionCodeGenerator.GenerateWrapperCode(wrapperFilePath, maps, asset.controlSchemes, options)) { // Inform database that we modified a source asset *during* import. AssetDatabase.ImportAsset(wrapperFilePath); } } // Refresh editors. AssetInspectorWindow.RefreshAllOnAssetReimport(); }
/// <summary> /// Import a .htre file. /// </summary> /// <param name="ctx"></param> public override void OnImportAsset(AssetImportContext ctx) { // Get the corresponding TerrainAsset. var baseName = Path.GetFileNameWithoutExtension(ctx.assetPath).Substring(0, 4); var terrainAssets = (from tile in UnityFileUtils.GetAllAssetsOfType <TerrainAsset>() where tile.name.StartsWith(baseName) select tile).ToArray(); if (terrainAssets.Length == 0) { ctx.LogImportError("Corresponding TerrainAsset could not be found for " + ctx.assetPath + ". Did you forget to import its .tre2 file?"); return; } var terrainAsset = terrainAssets[0]; var heightTiles = new List <float[, ]>(4); var materialWeightMapTiles = new List <Color[, ]>(4); var materialIdMapTiles = new List <Color[, ]>(4); var materialSelectMapTiles = new List <Color[, ]>(4); const int HalfWidth = HEIGHTMAP_WIDTH / 2; var asset = ScriptableObject.CreateInstance <TerrainTileAsset>(); asset.name = Path.GetFileNameWithoutExtension(ctx.assetPath); ctx.AddObjectToAsset("Main", asset); ctx.SetMainObject(asset); using (var reader = new BinaryReader(new FileStream(ctx.assetPath, FileMode.Open))) { var version = reader.ReadUInt32(); if (version == 3) { reader.BaseStream.Seek(HEIGHTMAP_OFFSET_VERSION3, SeekOrigin.Begin); } else if (version == 4) { reader.BaseStream.Seek(HEIGHTMAP_OFFSET_VERSION4, SeekOrigin.Begin); } else { Debug.LogError("Unrecognized htre version number: " + version); } // Read heightmap for (var tile = 0; tile < 4; tile++) { var heightValues = new float[HEIGHTMAP_WIDTH / 2, HEIGHTMAP_HEIGHT / 2]; heightTiles.Add(heightValues); for (var i = 0; i < HalfWidth; i++) { for (var j = 0; j < HalfWidth; j++) { var height = reader.ReadSingle(); heightValues[j, i] = (height - terrainAsset.HeightRangeMin) / (terrainAsset.HeightRangeMax - terrainAsset.HeightRangeMin); } } } // Read material weight map for (var tile = 0; tile < 4; tile++) { var materialWeightValues = new Color[HEIGHTMAP_WIDTH / 2, HEIGHTMAP_HEIGHT / 2]; materialWeightMapTiles.Add(materialWeightValues); for (var i = 0; i < HalfWidth; i++) { for (var j = 0; j < HalfWidth; j++) { var r = reader.ReadByte(); var g = reader.ReadByte(); var b = reader.ReadByte(); var a = reader.ReadByte(); materialWeightValues[j, i] = new Color(r, g, b, a); } } } // Skip unknown section reader.BaseStream.Position += 64L; // Read material ID map // This can't be only 2x2, can it? for (var tile = 0; tile < 4; tile++) { var materialIdValues = new Color[2, 2]; materialIdMapTiles.Add(materialIdValues); for (var i = 0; i < 1; i++) { for (var j = 0; j < 1; j++) { var r = reader.ReadByte(); var g = reader.ReadByte(); var b = reader.ReadByte(); var a = reader.ReadByte(); materialIdValues[j, i] = new Color(r, g, b, a); } } } // Skip unknown (heightmap LOD?) section reader.BaseStream.Position += 32L; // Read material select map // This can't be only 2x2, can it? for (var tile = 0; tile < 4; tile++) { var materialSelectValues = new Color[2, 2]; materialSelectMapTiles.Add(materialSelectValues); for (var i = 0; i < 1; i++) { for (var j = 0; j < 1; j++) { var r = reader.ReadByte(); var g = reader.ReadByte(); var b = reader.ReadByte(); var a = reader.ReadByte(); materialSelectValues[j, i] = new Color(r, g, b, a); } } } } var name = Path.GetFileNameWithoutExtension(ctx.assetPath); // Create material weight map. var materialWeightMap = new Texture2D(64, 64, TextureFormat.ARGB32, true) { name = name + "_MaterialWeightMap" }; materialWeightMap.wrapMode = TextureWrapMode.Clamp; materialWeightMap.SetPixels(0, 0, HalfWidth, HalfWidth, materialWeightMapTiles[0].Cast <Color>().ToArray()); materialWeightMap.SetPixels(HalfWidth, 0, HalfWidth, HalfWidth, materialWeightMapTiles[2].Cast <Color>().ToArray()); materialWeightMap.SetPixels(0, HalfWidth, HalfWidth, HalfWidth, materialWeightMapTiles[1].Cast <Color>().ToArray()); materialWeightMap.SetPixels(HalfWidth, HalfWidth, HalfWidth, HalfWidth, materialWeightMapTiles[3].Cast <Color>().ToArray()); ctx.AddObjectToAsset(name + "MaterialWeightMap", materialWeightMap); // Create material ID map. var materialIndicesMap = new Texture2D(2, 2, TextureFormat.ARGB32, true) { name = name + "_MaterialIndicesMap" }; materialIndicesMap.wrapMode = TextureWrapMode.Clamp; materialIndicesMap.SetPixels(0, 0, 1, 1, materialIdMapTiles[0].Cast <Color>().ToArray()); materialIndicesMap.SetPixels(1, 0, 1, 1, materialIdMapTiles[2].Cast <Color>().ToArray()); materialIndicesMap.SetPixels(0, 1, 1, 1, materialIdMapTiles[1].Cast <Color>().ToArray()); materialIndicesMap.SetPixels(1, 1, 1, 1, materialIdMapTiles[3].Cast <Color>().ToArray()); ctx.AddObjectToAsset(name + "MaterialIndicesMap", materialIndicesMap); // Create material select map. var materialSelectMap = new Texture2D(2, 2, TextureFormat.ARGB32, true) { name = name + "_MaterialSelectMap" }; materialSelectMap.wrapMode = TextureWrapMode.Clamp; materialSelectMap.SetPixels(0, 0, 1, 1, materialSelectMapTiles[0].Cast <Color>().ToArray()); materialSelectMap.SetPixels(1, 0, 1, 1, materialSelectMapTiles[2].Cast <Color>().ToArray()); materialSelectMap.SetPixels(0, 1, 1, 1, materialSelectMapTiles[1].Cast <Color>().ToArray()); materialSelectMap.SetPixels(1, 1, 1, 1, materialSelectMapTiles[3].Cast <Color>().ToArray()); ctx.AddObjectToAsset(name + "MaterialSelectMap", materialSelectMap); // Create heightmap. var heightMap = new Texture2D(HEIGHTMAP_WIDTH, HEIGHTMAP_HEIGHT, TextureFormat.RGBAFloat, true, true); heightMap.name = name + "_Heightmap"; heightMap.wrapMode = TextureWrapMode.Clamp; heightMap.filterMode = FilterMode.Bilinear; var colors = from height in heightTiles[0].Cast <float>() select new Color(height, height, height); heightMap.SetPixels(0, 0, HalfWidth, HalfWidth, colors.ToArray()); colors = from height in heightTiles[2].Cast <float>() select new Color(height, height, height); heightMap.SetPixels(HalfWidth, 0, HalfWidth, HalfWidth, colors.ToArray()); colors = from height in heightTiles[1].Cast <float>() select new Color(height, height, height); heightMap.SetPixels(0, HalfWidth, HalfWidth, HalfWidth, colors.ToArray()); colors = from height in heightTiles[3].Cast <float>() select new Color(height, height, height); heightMap.SetPixels(HalfWidth, HalfWidth, HalfWidth, HalfWidth, colors.ToArray()); ctx.AddObjectToAsset(name + "HeightMap", heightMap); asset.Heightmap = heightMap; asset.MaterialSelectMap = materialSelectMap; asset.MaterialIndicesMap = materialIndicesMap; asset.MaterialWeightMap = materialWeightMap; }
public override void OnImportAsset(AssetImportContext ctx) { var width = 8; var height = 8; var mipmapEnabled = true; var textureFormat = TextureFormat.ARGB32; //var srgbTexture = true; // Check if the input textures are valid to be used to build the texture array. var isValid = Verify(ctx, false); if (isValid) { // Use the texture assigned to the first slice as "master". // This means all other textures have to use same settings as the master texture. var sourceTexture = m_Textures[0]; width = sourceTexture.width; height = sourceTexture.height; textureFormat = sourceTexture.format; var sourceTexturePath = AssetDatabase.GetAssetPath(sourceTexture); var textureImporter = (TextureImporter)AssetImporter.GetAtPath(sourceTexturePath); mipmapEnabled = textureImporter.mipmapEnabled; //srgbTexture = textureImporter.sRGBTexture; } // Create the texture array. // When the texture array asset is being created, there are no input textures added yet, // thus we do Max(1, Count) to make sure to add at least 1 slice. var texture3D = new Texture3D(width, height, Mathf.Max(1, m_Textures.Count), textureFormat, mipmapEnabled);//, !srgbTexture); texture3D.wrapMode = m_WrapMode; texture3D.filterMode = m_FilterMode; texture3D.anisoLevel = m_AnisoLevel; if (isValid) { // If everything is valid, copy source textures over to the texture array. for (var n = 0; n < m_Textures.Count; ++n) { var source = m_Textures[n]; Graphics.CopyTexture(source, 0, texture3D, n); } } else { // If there is any error, copy a magenta colored texture into every slice. // I was thinking to only make the invalid slice magenta, but then it's way less obvious that // something isn't right with the texture array. Thus I mark the entire texture array as broken. var errorPixels = new Color32[width * height]; for (var n = 0; n < errorPixels.Length; ++n) { errorPixels[n] = Color.magenta; } var texture3DPixels = new Color32[width * height * texture3D.depth]; for (var n = 0; n < texture3D.depth; ++n) { System.Array.Copy(errorPixels, 0, texture3DPixels, width * height * n, errorPixels.Length); } texture3D.SetPixels32(texture3DPixels); texture3D.Apply(); } // Mark all input textures as dependency to the texture array. // This causes the texture array to get re-generated when any input texture changes or when the build target changed. for (var n = 0; n < m_Textures.Count; ++n) { var source = m_Textures[n]; if (source != null) { var path = AssetDatabase.GetAssetPath(source); #if UNITY_2020_1_OR_NEWER ctx.DependsOnArtifact(path); #else ctx.DependsOnSourceAsset(path); #endif } } #if !UNITY_2020_1_OR_NEWER // This value is not really used in this importer, // but getting the build target here will add a dependency to the current active buildtarget. // Because DependsOnArtifact does not exist in 2019.4, adding this dependency on top of the DependsOnSourceAsset // will force a re-import when the target platform changes in case it would have impacted any texture this importer depends on. var buildTarget = ctx.selectedBuildTarget; #endif // this should have been named "MainAsset" to be conform with Unity, but changing it now // would break all existing Texture3DAtlas assets, so we don't touch it. ctx.AddObjectToAsset("Texture3D", texture3D); ctx.SetMainObject(texture3D); if (!isValid) { // Run the verify step again, but this time we have the main object asset. // Console logs should ping the asset, but they don't in 2019.3 beta, bug? Verify(ctx, true); } }
public override void OnImportAsset(AssetImportContext ctx) { var graphAsset = ScriptableObject.CreateInstance <SubGraphAsset>(); var subGraphPath = ctx.assetPath; var subGraphGuid = AssetDatabase.AssetPathToGUID(subGraphPath); graphAsset.assetGuid = subGraphGuid; var textGraph = File.ReadAllText(subGraphPath, Encoding.UTF8); var messageManager = new MessageManager(); var graphData = new GraphData { isSubGraph = true, assetGuid = subGraphGuid, messageManager = messageManager }; MultiJson.Deserialize(graphData, textGraph); try { ProcessSubGraph(graphAsset, graphData); } catch (Exception e) { graphAsset.isValid = false; Debug.LogException(e, graphAsset); } finally { if (messageManager.AnyError()) { graphAsset.isValid = false; foreach (var pair in messageManager.GetNodeMessages()) { var node = graphData.GetNodeFromId(pair.Key); foreach (var message in pair.Value) { MessageManager.Log(node, subGraphPath, message, graphAsset); } } } messageManager.ClearAll(); } Texture2D texture = Resources.Load <Texture2D>("Icons/sg_subgraph_icon"); ctx.AddObjectToAsset("MainAsset", graphAsset, texture); ctx.SetMainObject(graphAsset); var metadata = ScriptableObject.CreateInstance <ShaderSubGraphMetadata>(); metadata.hideFlags = HideFlags.HideInHierarchy; metadata.assetDependencies = new List <UnityEngine.Object>(); AssetCollection assetCollection = new AssetCollection(); MinimalGraphData.GatherMinimalDependenciesFromFile(assetPath, assetCollection); foreach (var asset in assetCollection.assets) { if (asset.Value.HasFlag(AssetCollection.Flags.IncludeInExportPackage)) { // this sucks that we have to fully load these assets just to set the reference, // which then gets serialized as the GUID that we already have here. :P var dependencyPath = AssetDatabase.GUIDToAssetPath(asset.Key); if (!string.IsNullOrEmpty(dependencyPath)) { metadata.assetDependencies.Add( AssetDatabase.LoadAssetAtPath(dependencyPath, typeof(UnityEngine.Object))); } } } ctx.AddObjectToAsset("Metadata", metadata); // declare dependencies foreach (var asset in assetCollection.assets) { if (asset.Value.HasFlag(AssetCollection.Flags.SourceDependency)) { ctx.DependsOnSourceAsset(asset.Key); // I'm not sure if this warning below is actually used or not, keeping it to be safe var assetPath = AssetDatabase.GUIDToAssetPath(asset.Key); // Ensure that dependency path is relative to project if (!string.IsNullOrEmpty(assetPath) && !assetPath.StartsWith("Packages/") && !assetPath.StartsWith("Assets/")) { Debug.LogWarning($"Invalid dependency path: {assetPath}", graphAsset); } } // NOTE: dependencies declared by GatherDependenciesFromSourceFile are automatically registered as artifact dependencies // HOWEVER: that path ONLY grabs dependencies via MinimalGraphData, and will fail to register dependencies // on GUIDs that don't exist in the project. For both of those reasons, we re-declare the dependencies here. if (asset.Value.HasFlag(AssetCollection.Flags.ArtifactDependency)) { ctx.DependsOnArtifact(asset.Key); } } }
public override void OnImportAsset(AssetImportContext ctx) { byte[] bytes = File.ReadAllBytes(ctx.assetPath); int width = 1, height = 1, depth = 1; try { int channels = 0; string fourcc = Encoding.UTF8.GetString(SubArray <byte>(bytes, 0, 4)); if (fourcc != "VF_F" && fourcc != "VF_V") { throw new Exception("Invalid VF File Header. Need VF_F or VF_V, found :" + fourcc); } else { if (fourcc == "VF_F") { channels = 1; } if (fourcc == "VF_V") { channels = 3; } } TextureFormat outFormat = TextureFormat.Alpha8; switch (m_OutputFormat) { case VectorFieldOutputFormat.Byte: outFormat = channels == 3 ? TextureFormat.RGBA32 : TextureFormat.Alpha8; break; case VectorFieldOutputFormat.Half: outFormat = channels == 3 ? TextureFormat.RGBAHalf : TextureFormat.RHalf; break; case VectorFieldOutputFormat.Float: outFormat = channels == 3 ? TextureFormat.RGBAFloat : TextureFormat.RFloat; break; } if (bytes.Length < 10) { throw new Exception("Malformed VF File, invalid header (less than 10 bytes)"); } width = BitConverter.ToUInt16(bytes, 4); height = BitConverter.ToUInt16(bytes, 6); depth = BitConverter.ToUInt16(bytes, 8); int requiredLength = 10 + (4 * channels * (width * height * depth)); if (bytes.Length != requiredLength) { throw new Exception("Malformed VF File, invalid length (expected :" + requiredLength + ", found :" + bytes.Length + ")"); } Texture3D texture = new Texture3D(width, height, depth, outFormat, m_GenerateMipMaps); texture.wrapMode = m_WrapMode; texture.filterMode = m_FilterMode; texture.anisoLevel = m_AnisoLevel; int count = width * height * depth; Color[] colors = new Color[count]; for (int i = 0; i < count; i++) { Color c; if (channels == 1) { float x = BitConverter.ToSingle(bytes, 10 + (i * 4 * channels)); c = new Color(x, 0, 0); } else { float x = BitConverter.ToSingle(bytes, 10 + (i * 4 * channels)); float y = BitConverter.ToSingle(bytes, 14 + (i * 4 * channels)); float z = BitConverter.ToSingle(bytes, 18 + (i * 4 * channels)); c = new Color(x, y, z); } colors[i] = c; } texture.SetPixels(colors); texture.Apply(true, true); ctx.AddObjectToAsset("VectorField", texture); ctx.SetMainObject(texture); } catch (System.Exception e) { Debug.LogException(e); } }
/// <summary> /// Import a .lpsh file. /// </summary> /// <param name="ctx"></param> public override void OnImportAsset(AssetImportContext ctx) { // Note: Doesn't seem to always load coefficients? Look at avr_stage.lpsh. var asset = ScriptableObject.CreateInstance <LightProbeSHCoefficientsAsset>(); asset.name = Path.GetFileNameWithoutExtension(ctx.assetPath); using (var reader = new BinaryReader(new FileStream(ctx.assetPath, FileMode.Open), Encoding.ASCII)) { var version = reader.ReadUInt32(); Assert.IsTrue(version == 4, "Unsupported lpsh file format."); var unknown1 = reader.ReadUInt32(); var fileSize = reader.ReadUInt32(); reader.BaseStream.Seek(124L, SeekOrigin.Begin); var numLightProbes = reader.ReadUInt32(); reader.BaseStream.Seek(140L, SeekOrigin.Begin); var numDivs = reader.ReadUInt32(); reader.BaseStream.Seek(208L, SeekOrigin.Begin); for (var i = 0; i < numDivs; i++) { asset.TimeValues.Add(reader.ReadUInt32()); } AlignRead(reader.BaseStream, 16); var lpMetadata = new List <LightProbeMetadata>(); for (var i = 0; i < numLightProbes; i++) { lpMetadata.Add(new LightProbeMetadata(reader.ReadUInt32(), reader.ReadUInt32(), reader.ReadUInt32())); } var shSets = new List <LightProbeSHCoefficientsAsset.LightProbe.ShCoefficientsSet>(); for (var i = 0; i < lpMetadata.Count; i++) { var metadata = lpMetadata[i]; reader.BaseStream.Seek(metadata.NameAddress, SeekOrigin.Begin); var nameBuilder = new StringBuilder(); var nextChar = reader.ReadChar(); while (nextChar != '\0') { nameBuilder.Append(nextChar); nextChar = reader.ReadChar(); } var lightProbe = new LightProbeSHCoefficientsAsset.LightProbe { Name = nameBuilder.ToString() }; var shSet = new LightProbeSHCoefficientsAsset.LightProbe.ShCoefficientsSet(); lightProbe.CoefficientsSets.Add(shSet); asset.LightProbes.Add(lightProbe); shSets.Add(shSet); } for (var i = 0; i < shSets.Count; i++) { var metadata = lpMetadata[i]; reader.BaseStream.Seek(metadata.ShDataAddress, SeekOrigin.Begin); var shSet = shSets[i]; var isLastProbe = i == shSets.Count - 1; while (isLastProbe || reader.BaseStream.Position < lpMetadata[i + 1].ShDataAddress) { for (var coefficientIndex = 0; coefficientIndex < 9; coefficientIndex++) { Func <float> readHalf = () => Half.ToHalf(reader.ReadUInt16()); var r = readHalf(); var g = readHalf(); var b = readHalf(); var skyOcclusion = readHalf(); SetMatrixValue(ref shSet.TermR, 15 - coefficientIndex, r); SetMatrixValue(ref shSet.TermG, 15 - coefficientIndex, g); SetMatrixValue(ref shSet.TermB, 15 - coefficientIndex, b); SetMatrixValue(ref shSet.SkyOcclusion, 15 - coefficientIndex, skyOcclusion); } if (reader.BaseStream.Position + 32L > fileSize) { break; } } } } ctx.AddObjectToAsset(asset.name, asset); ctx.SetMainObject(asset); }
public override void OnImportAsset(AssetImportContext ctx) { var texture = Resources.Load <Texture2D>("zepeto-studio-icon"); ctx.AddObjectToAsset("Texture", texture, texture); }
public override void OnImportAsset(AssetImportContext ctx) { IndexedTextureData texture = ParseLBM.ImportFile(ctx.assetPath); { texture.pixelsPerUnit = pixelsPerUnit; texture.indexedImage.name = "Indexed image"; ctx.AddObjectToAsset("Indexed image", texture.indexedImage); texture.pallete.name = "Pallete"; ctx.AddObjectToAsset("Palette", texture.pallete); if (ignoreFirstAnimation) { texture.animations.RemoveAt(0); } texture.name = "texture data"; ctx.AddObjectToAsset("texture data", texture); texture.image.name = "Color image"; ctx.AddObjectToAsset("image", texture.image); } Sprite sprite = Sprite.Create(texture.image, new Rect(0, 0, texture.width, texture.height), new Vector2(1f / 2, 1f / 2), pixelsPerUnit); { sprite.name = "Sprite"; ctx.AddObjectToAsset("Sprite", sprite); } // Atlas - image for segmentation if (generatePNG) { // adds a secondary image for segmentation string filename = Path.GetFileNameWithoutExtension(ctx.assetPath); string imagepath = Path.GetDirectoryName(ctx.assetPath) + "\\" + filename + "-atlas.png"; File.WriteAllBytes(imagepath, texture.image.EncodeToPNG()); // Create image metadata // TODO FIX: this is not called the first time, as the image might still be under creation TextureImporter ti = (TextureImporter)TextureImporter.GetAtPath(imagepath); if (ti) { ti.textureType = TextureImporterType.Sprite; ti.spritePixelsPerUnit = pixelsPerUnit; ti.spriteImportMode = SpriteImportMode.Multiple; ti.filterMode = FilterMode.Point; var spriteData = new SpriteMetaData[1]; spriteData[0] = new SpriteMetaData(); spriteData[0].pivot = new Vector2(1f / 2, 1f / 2); spriteData[0].rect = new Rect(0, 0, texture.width, texture.height); spriteData[0].name = "sprite"; ti.spritesheet = spriteData; AssetDatabase.ImportAsset(imagepath, ImportAssetOptions.ForceUpdate); } } var prefab = new GameObject(); { var material = new Material(Shader.Find("Sprites/IndexedPallete")); { material.name = "Material"; material.SetTexture("_Indexed", texture.indexedImage); material.SetTexture("_Pallete", texture.pallete); ctx.AddObjectToAsset("material", material); } SpriteRenderer renderer = prefab.AddComponent <SpriteRenderer>(); { renderer.sprite = sprite; renderer.material = material; } IndexedTextureAnimator itr = prefab.AddComponent <IndexedTextureAnimator>(); { itr.texture = texture; } ctx.AddObjectToAsset("prefab", prefab, texture.image); ctx.SetMainObject(prefab); } // Assets that are not passed into the context as import outputs must be destroyed //DestroyImmediate(<unused>); }
public override void OnImportAsset(AssetImportContext ctx) { var oldShader = AssetDatabase.LoadAssetAtPath <Shader>(ctx.assetPath); if (oldShader != null) { ShaderUtil.ClearShaderMessages(oldShader); } List <PropertyCollector.TextureInfo> configuredTextures; string path = ctx.assetPath; var sourceAssetDependencyPaths = new List <string>(); UnityEngine.Object mainObject; var textGraph = File.ReadAllText(path, Encoding.UTF8); var graph = new GraphData { messageManager = new MessageManager(), assetGuid = AssetDatabase.AssetPathToGUID(path) }; MultiJson.Deserialize(graph, textGraph); graph.OnEnable(); graph.ValidateGraph(); // TODO: How to handle this? if (graph.isVFXTarget) { var vfxAsset = GenerateVfxShaderGraphAsset(graph); mainObject = vfxAsset; } else { var text = GetShaderText(path, out configuredTextures, sourceAssetDependencyPaths, graph); var shader = ShaderUtil.CreateShaderAsset(text, false); if (graph != null && graph.messageManager.nodeMessagesChanged) { foreach (var pair in graph.messageManager.GetNodeMessages()) { var node = graph.GetNodeFromId(pair.Key); MessageManager.Log(node, path, pair.Value.First(), shader); } } EditorMaterialUtility.SetShaderDefaults( shader, configuredTextures.Where(x => x.modifiable).Select(x => x.name).ToArray(), configuredTextures.Where(x => x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray()); EditorMaterialUtility.SetShaderNonModifiableDefaults( shader, configuredTextures.Where(x => !x.modifiable).Select(x => x.name).ToArray(), configuredTextures.Where(x => !x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray()); mainObject = shader; } Texture2D texture = Resources.Load <Texture2D>("Icons/sg_graph_icon@64"); ctx.AddObjectToAsset("MainAsset", mainObject, texture); ctx.SetMainObject(mainObject); if (graph != null) { foreach (var target in graph.activeTargets) { if (target is IHasMetadata iHasMetadata) { var metadata = iHasMetadata.GetMetadataObject(); if (metadata == null) { continue; } metadata.hideFlags = HideFlags.HideInHierarchy; ctx.AddObjectToAsset($"{iHasMetadata.identifier}:Metadata", metadata); } } } var sgMetadata = ScriptableObject.CreateInstance <ShaderGraphMetadata>(); sgMetadata.hideFlags = HideFlags.HideInHierarchy; sgMetadata.assetDependencies = new List <UnityEngine.Object>(); var deps = GatherDependenciesFromSourceFile(ctx.assetPath); foreach (string dependency in deps) { sgMetadata.assetDependencies.Add(AssetDatabase.LoadAssetAtPath(dependency, typeof(UnityEngine.Object))); } ctx.AddObjectToAsset("SGInternal:Metadata", sgMetadata); foreach (var sourceAssetDependencyPath in sourceAssetDependencyPaths.Distinct()) { // Ensure that dependency path is relative to project if (!sourceAssetDependencyPath.StartsWith("Packages/") && !sourceAssetDependencyPath.StartsWith("Assets/")) { Debug.LogWarning($"Invalid dependency path: {sourceAssetDependencyPath}", mainObject); continue; } ctx.DependsOnSourceAsset(sourceAssetDependencyPath); } }
public override void OnImportAsset(AssetImportContext ctx) { var assetName = Path.GetFileNameWithoutExtension(ctx.assetPath); var mainAsset = new GameObject(); ctx.AddObjectToAsset("main obj", mainAsset); ctx.SetMainObject(mainAsset); var matProps = mainAsset.AddComponent <MaterialProperties>(); // Parse object var v = new List <float[]>(); var vn = new List <float[]>(); var f = new List <int[]>(); var e = new List <int[]>(); using (StreamReader sr = File.OpenText(ctx.assetPath)) { string s; while ((s = sr.ReadLine()) != null) { var line = s.Trim().Split(' '); if (line[0].Equals("o")) { assetName = s.Remove(0, 2); } else if (line[0].Equals("prop")) { if (line[1].Equals("color")) { var values = Array.ConvertAll(line.Skip(3).ToArray(), float.Parse); if (line[2].Equals("diffuse")) { matProps.SolidColor = new Color(values[0], values[1], values[2]); } } else if (line[1].Equals("opacity")) { matProps.Opacity = float.Parse(line[2]); } } else if (line[0].Equals("v")) { v.Add(Array.ConvertAll(s.Split(' ').Skip(1).ToArray(), float.Parse)); } else if (line[0].Equals("vn")) { vn.Add(Array.ConvertAll(s.Split(' ').Skip(1).ToArray(), float.Parse)); } else if (line[0].Equals("f")) { line = s.Split(' '); if (line.Length > 4) { Debug.LogError("Your model must be exported with triangulated faces."); continue; } f.Add(Array.ConvertAll(s.Split(' ').Skip(1).ToArray(), int.Parse)); } else if (line[0].Equals("l")) { // Convert 1-based obj indices to 0-based // TODO: switch to 0-based? Would break general obj. compatibility e.Add(Array.ConvertAll(line.Skip(1).ToArray(), int.Parse).Select(i => i - 1).ToArray()); } } } // Construct mesh Mesh mesh; var triangleSubmeshExists = false; if (f.Count > 0 && e.Count > 0) { mesh = new Mesh { subMeshCount = 2 }; triangleSubmeshExists = true; } else if (f.Count > 0) { mesh = new Mesh { subMeshCount = 1 }; triangleSubmeshExists = true; } else if (e.Count > 0) { mesh = new Mesh { subMeshCount = 1 }; } else { return; } var vertices = new Vector3[v.Count]; for (var i = 0; i < v.Count; i++) { vertices[i] = new Vector3(v[i][0], v[i][1], v[i][2]); } mesh.vertices = vertices; // TODO: subMesh 0 is like a regular mesh which uses MeshTopology.Triangles //if (f.Count > 0) { // int[] triangleIndices = new int[f.Count * 3]; // for (int i = 0; i < f.Count; i++) { // string[] raw = f[i]; // string s1 = raw[0]; // string s2 = raw[1]; // string s3 = raw[2]; // if (s1.Contains("//")) { // s1 = s1.Remove(s1.IndexOf("//")); // } // if (s2.Contains("//")) { // s2 = s2.Remove(s2.IndexOf("//")); // } // if (s3.Contains("//")) { // s3 = s3.Remove(s3.IndexOf("//")); // } // int v1 = int.Parse(s1) - 1; // int v2 = int.Parse(s2) - 1; // int v3 = int.Parse(s3) - 1; // triangleIndices[i * 3] = v1; // triangleIndices[i * 3 + 1] = v2; // triangleIndices[i * 3 + 2] = v3; // } // mesh.SetIndices(triangleIndices, MeshTopology.Triangles, 0, false); // mesh.RecalculateNormals(); //} // subMesh 1 is the line mesh which uses MeshTopology.Lines if (e.Count > 0) { var indicesList = new List <int>(); foreach (var indices in e) { for (var i = 0; i < indices.Length - 1; i++) { indicesList.Add(indices[i]); indicesList.Add(indices[i + 1]); } } mesh.SetIndices(indicesList.ToArray(), MeshTopology.Lines, triangleSubmeshExists ? 1 : 0, false); } mesh.RecalculateBounds(); mesh.name = assetName; var meshFilter = mainAsset.AddComponent <MeshFilter>(); meshFilter.sharedMesh = mesh; ctx.AddObjectToAsset("Mesh", mesh); mainAsset.AddComponent <MeshRenderer>(); matProps.ColorBy = MaterialProperties.ColorMode.SolidColor; matProps.Lighting = MaterialProperties.LightingMode.Unlit; }
public override void OnImportAsset(AssetImportContext ctx) { var oldShader = AssetDatabase.LoadAssetAtPath <Shader>(ctx.assetPath); if (oldShader != null) { ShaderUtil.ClearShaderMessages(oldShader); } List <PropertyCollector.TextureInfo> configuredTextures; string path = ctx.assetPath; var sourceAssetDependencyPaths = new List <string>(); UnityEngine.Object mainObject; var textGraph = File.ReadAllText(path, Encoding.UTF8); GraphData graph = JsonUtility.FromJson <GraphData>(textGraph); graph.messageManager = new MessageManager(); graph.assetGuid = AssetDatabase.AssetPathToGUID(path); graph.OnEnable(); graph.ValidateGraph(); if (graph.outputNode is VfxMasterNode vfxMasterNode) { var vfxAsset = GenerateVfxShaderGraphAsset(vfxMasterNode); mainObject = vfxAsset; } else { var text = GetShaderText(path, out configuredTextures, sourceAssetDependencyPaths, graph); var shader = ShaderUtil.CreateShaderAsset(text, false); if (graph != null && graph.messageManager.nodeMessagesChanged) { foreach (var pair in graph.messageManager.GetNodeMessages()) { var node = graph.GetNodeFromTempId(pair.Key); MessageManager.Log(node, path, pair.Value.First(), shader); } } EditorMaterialUtility.SetShaderDefaults( shader, configuredTextures.Where(x => x.modifiable).Select(x => x.name).ToArray(), configuredTextures.Where(x => x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray()); EditorMaterialUtility.SetShaderNonModifiableDefaults( shader, configuredTextures.Where(x => !x.modifiable).Select(x => x.name).ToArray(), configuredTextures.Where(x => !x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray()); mainObject = shader; } Texture2D texture = Resources.Load <Texture2D>("Icons/sg_graph_icon@64"); ctx.AddObjectToAsset("MainAsset", mainObject, texture); ctx.SetMainObject(mainObject); var metadata = ScriptableObject.CreateInstance <ShaderGraphMetadata>(); metadata.hideFlags = HideFlags.HideInHierarchy; if (graph != null) { metadata.outputNodeTypeName = graph.outputNode.GetType().FullName; } ctx.AddObjectToAsset("Metadata", metadata); foreach (var sourceAssetDependencyPath in sourceAssetDependencyPaths.Distinct()) { // Ensure that dependency path is relative to project if (!sourceAssetDependencyPath.StartsWith("Packages/") && !sourceAssetDependencyPath.StartsWith("Assets/")) { Debug.LogWarning($"Invalid dependency path: {sourceAssetDependencyPath}", mainObject); continue; } ctx.DependsOnSourceAsset(sourceAssetDependencyPath); } }
public void AddObjectToAsset(string identifier, UnityEngine.Object obj) { m_Context.AddObjectToAsset(identifier, obj); }
public override void OnImportAsset(AssetImportContext ctx) { var shortAssetPath = ctx.assetPath.Replace("Assets", ""); AlembicStream.DisconnectStreamsWithPath(shortAssetPath); var sourcePath = Application.dataPath + shortAssetPath; var destPath = Application.streamingAssetsPath + shortAssetPath; var directoryPath = Path.GetDirectoryName(destPath); if (!Directory.Exists(directoryPath)) { Directory.CreateDirectory(directoryPath); } if (File.Exists(destPath)) { File.SetAttributes(destPath, FileAttributes.Normal); } File.Copy(sourcePath, destPath, true); var fileName = Path.GetFileNameWithoutExtension(destPath); var go = new GameObject(fileName); go.transform.localScale *= scaleFactor; AlembicStreamDescriptor streamDescriptor = ScriptableObject.CreateInstance <AlembicStreamDescriptor>(); streamDescriptor.name = go.name + "_ABCDesc"; streamDescriptor.pathToAbc = destPath; streamDescriptor.settings = streamSettings; using (var abcStream = new AlembicStream(go, streamDescriptor)) { abcStream.AbcLoad(); AbcStartTime = abcStream.AbcStartTime; AbcEndTime = abcStream.AbcEndTime; AbcFrameCount = abcStream.AbcFrameCount; startFrame = startFrame < 0 ? 0 : startFrame; endFrame = endFrame > AbcFrameCount - 1 ? AbcFrameCount - 1 : endFrame; streamDescriptor.minFrame = startFrame; streamDescriptor.maxFrame = endFrame; streamDescriptor.abcFrameCount = AbcFrameCount; streamDescriptor.abcDuration = AbcEndTime - AbcStartTime; streamDescriptor.abcStartTime = AbcStartTime; var streamPlayer = go.AddComponent <AlembicStreamPlayer>(); streamPlayer.streamDescriptor = streamDescriptor; streamPlayer.startFrame = startFrame; streamPlayer.endFrame = endFrame; AddObjectToAsset(ctx, streamDescriptor.name, streamDescriptor); GenerateSubAssets(ctx, abcStream.alembicTreeRoot, streamDescriptor); AlembicStream.ReconnectStreamsWithPath(shortAssetPath); #if UNITY_2017_3_OR_NEWER ctx.AddObjectToAsset(go.name, go); ctx.SetMainObject(go); #else ctx.SetMainAsset(go.name, go); #endif } }
public override void OnImportAsset(AssetImportContext ctx) { string[] text = ReadFile(ctx.assetPath); this.Populate(text); var root = new GameObject(); root.name = Path.GetFileNameWithoutExtension(ctx.assetPath); GameObject[] nodes = this.GenerateNodes(); this.GenerateMarkers(nodes); nodes[0].transform.parent = root.transform; Material[] materials = this.materials.Select( m => { var material = new Material(Shader.Find("Diffuse")); material.name = m.name; return(material); } ).ToArray(); Mesh[] meshes = this.GenerateMeshesh(); GameObject[] models = meshes.Select( mesh => { var model = new GameObject(mesh.name); MeshFilter meshFilter = model.AddComponent <MeshFilter>(); SkinnedMeshRenderer skinnedMeshRenderer = model.AddComponent <SkinnedMeshRenderer>(); meshFilter.sharedMesh = mesh; skinnedMeshRenderer.sharedMesh = mesh; skinnedMeshRenderer.quality = SkinQuality.Bone2; mesh.bindposes = nodes.Select( node => node.transform.worldToLocalMatrix * model.transform.localToWorldMatrix ).ToArray(); skinnedMeshRenderer.bones = nodes.Select(e => e.transform).ToArray(); skinnedMeshRenderer.rootBone = nodes[0].transform; skinnedMeshRenderer.sharedMaterials = materials; model.transform.parent = root.transform; return(model); } ).ToArray(); foreach (Material mat in materials) { ctx.AddObjectToAsset(mat.name, mat); } foreach (Mesh mesh in meshes) { ctx.AddObjectToAsset(mesh.name, mesh); } // avatar Avatar avatar = AvatarBuilder.BuildGenericAvatar(root, nodes[0].transform.name); avatar.name = root.name + "Avatar"; avatar.hideFlags = HideFlags.None; Animator animator = root.AddComponent <Animator>(); animator.avatar = avatar; AvatarMask mask = new AvatarMask(); mask.name = root.name + "AvatarMask"; foreach (var node in nodes) { mask.AddTransformPath(node.transform); } ctx.AddObjectToAsset(avatar.name, avatar); ctx.AddObjectToAsset(mask.name, mask); ctx.AddObjectToAsset("root", root); ctx.SetMainObject(root); }
private void GenerateAnimations(AssetImportContext ctx, AseFile aseFile, Sprite[] sprites) { if (animationSettings == null) { animationSettings = new AseFileAnimationSettings[0]; } var animSettings = new List <AseFileAnimationSettings>(animationSettings); var animations = aseFile.GetAnimations(); if (animations.Length <= 0) { return; } if (animationSettings != null) { RemoveUnusedAnimationSettings(animSettings, animations); } int index = 0; foreach (var animation in animations) { AnimationClip animationClip = new AnimationClip(); animationClip.name = animation.TagName; animationClip.frameRate = 25; AseFileAnimationSettings importSettings = GetAnimationSettingFor(animSettings, animation); importSettings.about = GetAnimationAbout(animation); EditorCurveBinding spriteBinding = new EditorCurveBinding(); spriteBinding.type = typeof(SpriteRenderer); spriteBinding.path = ""; spriteBinding.propertyName = "m_Sprite"; int length = animation.FrameTo - animation.FrameFrom + 1; ObjectReferenceKeyframe[] spriteKeyFrames = new ObjectReferenceKeyframe[length]; float time = 0; int from = (animation.Animation != LoopAnimation.Reverse) ? animation.FrameFrom : animation.FrameTo; int step = (animation.Animation != LoopAnimation.Reverse) ? 1 : -1; int keyIndex = from; for (int i = 0; i < length; i++) { if (i >= length) { keyIndex = from; } ObjectReferenceKeyframe frame = new ObjectReferenceKeyframe(); frame.time = time; frame.value = sprites[keyIndex]; time += aseFile.Frames[keyIndex].FrameDuration / 1000f; keyIndex += step; spriteKeyFrames[i] = frame; } AnimationUtility.SetObjectReferenceCurve(animationClip, spriteBinding, spriteKeyFrames); AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(animationClip); switch (animation.Animation) { case LoopAnimation.Forward: animationClip.wrapMode = WrapMode.Loop; settings.loopTime = true; break; case LoopAnimation.Reverse: animationClip.wrapMode = WrapMode.Loop; settings.loopTime = true; break; case LoopAnimation.PingPong: animationClip.wrapMode = WrapMode.PingPong; settings.loopTime = true; break; } if (!importSettings.loopTime) { animationClip.wrapMode = WrapMode.Once; settings.loopTime = false; } AnimationUtility.SetAnimationClipSettings(animationClip, settings); ctx.AddObjectToAsset(animation.TagName, animationClip); index++; } animationSettings = animSettings.ToArray(); }
Shader BuildAllShaders( AssetImportContext importContext, AssetImportErrorLog importErrorLog, AssetCollection allImportAssetDependencies, GraphData graph) { Shader primaryShader = null; string path = importContext.assetPath; var primaryShaderName = Path.GetFileNameWithoutExtension(path); try { // this will also add Target dependencies into the asset collection Generator generator; generator = new Generator(graph, graph.outputNode, GenerationMode.ForReals, primaryShaderName, assetCollection: allImportAssetDependencies); bool first = true; foreach (var generatedShader in generator.allGeneratedShaders) { var shaderString = generatedShader.codeString; // we only care if an error was reported for a node that we actually used if (graph.messageManager.AnyError((nodeId) => NodeWasUsedByGraph(nodeId, graph)) || shaderString == null) { shaderString = k_ErrorShader.Replace("Hidden/GraphErrorShader2", generatedShader.shaderName); } var shader = ShaderUtil.CreateShaderAsset(importContext, shaderString, false); ReportErrors(graph, shader, path, importErrorLog); EditorMaterialUtility.SetShaderDefaults( shader, generatedShader.assignedTextures.Where(x => x.modifiable).Select(x => x.name).ToArray(), generatedShader.assignedTextures.Where(x => x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray()); EditorMaterialUtility.SetShaderNonModifiableDefaults( shader, generatedShader.assignedTextures.Where(x => !x.modifiable).Select(x => x.name).ToArray(), generatedShader.assignedTextures.Where(x => !x.modifiable).Select(x => EditorUtility.InstanceIDToObject(x.textureId) as Texture).ToArray()); if (first) { // first shader is always the primary shader // we return the primary shader so it can be attached to the import context at the outer level // allowing it to bind a custom icon as well primaryShader = shader; // only the main shader gets a material created Material material = new Material(shader) { name = primaryShaderName + " Material" }; importContext.AddObjectToAsset("Material", material); first = false; } else { importContext.AddObjectToAsset($"Shader-{generatedShader.shaderName}", shader); } } } catch (Exception e) { Debug.LogException(e); // ignored } return(primaryShader); }