public static void ParseMaterialDefinitionData(MaterialDefinitionData materialDefinitionData) { // Check if the object already exists in the package mapper if (PackageMapper.TokenExistsInCache(materialDefinitionData.entityToken)) { // If object exists skip update // TODO: At some point decide how we handle material updates. // Important note to consider is that we will be adding already existing // materials in Unity that STP didn't create to the material map and how to handle those updates. Debug.LogWarning("Material Definition Update not supported yet! Discarding material data!!"); return; } else { // Create a new GameObject in the hierarchy Object newMaterial = MaterialDefinitionHandler.CreateMaterial(materialDefinitionData); if (newMaterial) { PackageMapper.MapTokenToObject(materialDefinitionData.entityToken, newMaterial); // If a new material has been created go through the stored list of meshes // to see if we can create a new one with this material available IterateMeshStore(); } } }
/// <summary> /// Dependency check /// Checks if all of the dependencies of the mesh are available in Unity /// </summary> public static bool DependencyCheck(MaterialDefinitionData materialDefinitionData) { // Check if we have textures available var currentReadPtr = materialDefinitionData.parameters; var parameterDataSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(MaterialDefinitionParameterData)); for (var i = 0; i < materialDefinitionData.parameterCount; ++i) { // Marshal parameter data MaterialDefinitionParameterData parameterData = (MaterialDefinitionParameterData)System.Runtime.InteropServices.Marshal.PtrToStructure(currentReadPtr, typeof(MaterialDefinitionParameterData)); currentReadPtr = MarshalData.AddToIntPtr(currentReadPtr, parameterDataSize); // Get the parameter type ParamType type = (ParamType)parameterData.type; if (type == ParamType.Texture) { // Check if we have a texture ready for this material definition if (!PackageMapper.GetTexture2DFromToken(parameterData.textureToken)) { // TODO: messages slow down the recieve mechanism and spam the log //Debug.LogWarningFormat("Texture '{0}' for '{1}' material has not yet been created!", // parameterData.textureToken, // materialDefinitionData.entityToken); return(false); } } } return(true); }
/// <summary> /// Create and send material definition request /// Parses data for building of material deifintion request /// and invokes native plugin to send the request to the server /// </summary> public static void CreateAndSendMaterialDefinitionRequest(Material material, string token) { MaterialDefinitionData materialDefinitionData = new MaterialDefinitionData(); materialDefinitionData.displayName = material.name; materialDefinitionData.entityToken = token; System.IntPtr materialDefinitionDataPtr = System.Runtime.InteropServices.Marshal.AllocHGlobal(System.Runtime.InteropServices.Marshal.SizeOf(materialDefinitionData)); System.Runtime.InteropServices.Marshal.StructureToPtr(materialDefinitionData, materialDefinitionDataPtr, false); Debug.LogFormat("Material Definition Push - Token:{0}", materialDefinitionData.entityToken); ImportMenu.stpUnitySendMaterialDefinitionData(materialDefinitionDataPtr); System.Runtime.InteropServices.Marshal.FreeHGlobal(materialDefinitionDataPtr); }
// Iterate through material store that were missing dependants and check if we can create new material objects // or update existing material objects public static void IterateMaterialDefinitionStore() { for (int i = materialDefinitionDataStore.Count - 1; i >= 0; i--) { MaterialDefinitionData materialDefinitionData = (MaterialDefinitionData)System.Runtime.InteropServices.Marshal.PtrToStructure(materialDefinitionDataStore[i], typeof(MaterialDefinitionData)); // If all dependants are here, create the material bool dependencySuccess = MaterialDefinitionHandler.DependencyCheck(materialDefinitionData); if (dependencySuccess) { ParseMaterialDefinitionData(materialDefinitionData); // Delete object data ImportMenu.stpUnityDeleteMaterialDefinitionData(materialDefinitionDataStore[i]); // Remove from the store materialDefinitionDataStore.RemoveAt(i); } } }
public static Object CreateMaterial(MaterialDefinitionData materialDefinitionData) { ShaderModel shaderModel = (ShaderModel)materialDefinitionData.shaderModel; BlendMode blendMode = (BlendMode)materialDefinitionData.blendMode; Debug.LogFormat("Material Definition - Token:{0} Display Name:{1}, {2} shader model {3} blend mode {4} parameter count", materialDefinitionData.entityToken, materialDefinitionData.displayName, shaderModel, blendMode, materialDefinitionData.parameterCount); // Create a new Unity material with "Standard" Unity shader // Shader string names are assumed to use the Unity Standard shader code Material newMaterial = new Material(Shader.Find("Standard")); // Set blend mode options switch (blendMode) { case BlendMode.ModeUnknown: case BlendMode.Opaque: // Default blend mode, skip modification break; case BlendMode.Translucent: // Code taken from https://answers.unity.com/questions/1004666/change-material-rendering-mode-in-runtime.html // Changes what options are available in Unity shader GUI newMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.One); newMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha); newMaterial.SetInt("_ZWrite", 0); newMaterial.DisableKeyword("_ALPHATEST_ON"); newMaterial.DisableKeyword("_ALPHABLEND_ON"); newMaterial.EnableKeyword("_ALPHAPREMULTIPLY_ON"); newMaterial.renderQueue = 3000; break; } var currentReadPtr = materialDefinitionData.parameters; var parameterDataSize = System.Runtime.InteropServices.Marshal.SizeOf(typeof(MaterialDefinitionParameterData)); for (var i = 0; i < materialDefinitionData.parameterCount; ++i) { // Marshal parameter data MaterialDefinitionParameterData parameterData = (MaterialDefinitionParameterData)System.Runtime.InteropServices.Marshal.PtrToStructure(currentReadPtr, typeof(MaterialDefinitionParameterData)); currentReadPtr = MarshalData.AddToIntPtr(currentReadPtr, parameterDataSize); // Get the parameter type ParamType type = (ParamType)parameterData.type; Debug.LogFormat("Material Parameter - Name:{0} Type:{1} Target:{2}, {3} texture token", parameterData.name, type, parameterData.target, parameterData.textureToken); // Get the right shader input and connect parameter data string shaderStringTarget; Vector4 vect; int offset = 0; switch (type) { case ParamType.Float: shaderStringTarget = FindScalarInput(parameterData.target); if (System.String.IsNullOrEmpty(shaderStringTarget)) { break; } newMaterial.SetFloat(shaderStringTarget, MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset)); break; case ParamType.Float2: shaderStringTarget = FindVectorInput(parameterData.target); if (System.String.IsNullOrEmpty(shaderStringTarget)) { break; } vect.x = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); offset += MarshalData.sizeOfInt; vect.y = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); vect.z = 0.0f; vect.w = 0.0f; newMaterial.SetVector(shaderStringTarget, vect); break; case ParamType.Float3: shaderStringTarget = FindVectorInput(parameterData.target); if (System.String.IsNullOrEmpty(shaderStringTarget)) { break; } vect.x = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); offset += MarshalData.sizeOfInt; vect.y = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); offset += MarshalData.sizeOfInt; vect.z = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); vect.w = 0.0f; newMaterial.SetVector(shaderStringTarget, vect); break; case ParamType.Float4: case ParamType.RGBA8: shaderStringTarget = FindVectorInput(parameterData.target); if (System.String.IsNullOrEmpty(shaderStringTarget)) { break; } vect.x = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); offset += MarshalData.sizeOfInt; vect.y = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); offset += MarshalData.sizeOfInt; vect.z = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); offset += MarshalData.sizeOfInt; vect.w = MarshalData.GetFloatFromUnmanagedArray(parameterData.floatData, offset); newMaterial.SetVector(shaderStringTarget, vect); break; case ParamType.Texture: shaderStringTarget = FindTextureInput(parameterData.target); if (System.String.IsNullOrEmpty(shaderStringTarget)) { break; } Texture texture = PackageMapper.GetTexture2DFromToken(parameterData.textureToken); newMaterial.SetTexture(shaderStringTarget, texture); // TODO: Emission keyword doesn't work in Unity 2018.2.15f1 as it doesn't enable // emission checkbox for some reason // Special case for emission textures, enable the emission map on the shader if (shaderStringTarget == ShaderEmissionTexture) { newMaterial.EnableKeyword("_EMISSION"); } break; } } // Create material default STP folders if they don't exist PackageMapper.CreateAssetFolders(MaterialDefinitionHandler.assetPath); // Generate a unique material name string materialPath = Application.dataPath + "/" + MaterialDefinitionHandler.assetPath; string uniqueMaterialName; GenUniqueMaterialAssetName(materialPath, materialDefinitionData.displayName, out uniqueMaterialName); // Set the unique material name as the display name newMaterial.name = uniqueMaterialName; // Create a GameObject prefab object and use it as a database item of STP used materials GameObject materialPrefab = new GameObject(uniqueMaterialName); // Add Foundry unique token storage component, store unique material token var tokenStorage = materialPrefab.AddComponent <FoundryUniqueToken>(); tokenStorage.uniqueToken = materialDefinitionData.entityToken; // Create the prefab asset var localPrefabPath = System.String.Format("{0}/{1}/{2}", PackageMapper.rootPath, MaterialDefinitionHandler.assetPath, uniqueMaterialName); string prefabPath; PackageMapper.GenUniquePrefabAssetPath(localPrefabPath, out prefabPath); #if UNITY_2018_3_OR_NEWER Object prefabAsset = PrefabUtility.SaveAsPrefabAsset(materialPrefab, prefabPath); #else Object prefabAsset = PrefabUtility.CreatePrefab(prefabPath, materialPrefab); #endif // Map the prefab to the material PackageMapper.MapMaterialToPrefab(newMaterial, prefabAsset); AssetDatabase.AddObjectToAsset(newMaterial, prefabAsset); AssetDatabase.SaveAssets(); // Remove game object that's used for creating a prefab from scene hierarchy Object.DestroyImmediate(materialPrefab); return(prefabAsset); }