// Exports all non-experimental brushes along with their material parameters // into a directory structure suitable for submission to // google3/googledata/html/external_content/tiltbrush.com/shaders/brushes // // Input: // Non-experimental brushes (from Assets/Manifest.asset) // Their materials and shaders // // Output: // An ExportManifest, writen to manifestPath // An ExportRequests instance // // The manifest is consumed by Tilt Brush at export time, and should not // be uploaded to Poly or be served by it. // // The ExportRequests is processed by a texture downsampler; see DownsampleTextures() // // Shaders are not generated here; see GenerateShaders() // private static ExportRequests WriteManifest( string manifestPath, string exportRoot) { ExportRequests exportRequests = new ExportRequests(); Debug.LogFormat("Exporting to: {0}", manifestPath); ExportGlTF.ExportManifest manifest = new ExportGlTF.ExportManifest(); Dictionary <Guid, BrushDescriptor> brushes; using (var unused = new BuildTiltBrush.TempHookUpSingletons()) { manifest.tiltBrushVersion = App.Config.m_VersionNumber; manifest.tiltBrushBuildStamp = App.Config.m_BuildStamp; brushes = GetBrushes(); } foreach (KeyValuePair <Guid, BrushDescriptor> kvp in brushes) { try { BrushDescriptor descriptor = kvp.Value; var exp = ExportBrush(exportRequests, descriptor, exportRoot); manifest.brushes.Add(exp.guid, exp); // While we're at it, maybe a sanity check of the descriptor is in order if (descriptor.m_RenderBackfaces && !exp.enableCull) { Debug.LogWarning( $"{descriptor.m_DurableName}: generates backface geometry, but disables culling", descriptor); } } catch (ExportException e) { Debug.LogException(e); } // foreach Brush + try } var serializer = new JsonSerializer(); serializer.ContractResolver = new CustomJsonContractResolver(); using (var writer = new CustomJsonWriter(new StreamWriter(manifestPath))) { writer.Formatting = Formatting.Indented; serializer.Serialize(writer, manifest); } return(exportRequests); }
// Input: the exportRequests // Output: downsampled textures, to subdirectories of exportRoot private static void ExportTextures(ExportRequests exportRequests) { string projectPath = Path.GetDirectoryName(Application.dataPath); string requestsJson = Path.Combine(projectPath, "Temp/ExportRequests.json"); var serializer = new JsonSerializer(); serializer.ContractResolver = new CustomJsonContractResolver(); using (var writer = new CustomJsonWriter(new StreamWriter(requestsJson))) { writer.Formatting = Formatting.Indented; serializer.Serialize(writer, exportRequests); } string scriptPath = Path.Combine(projectPath, "Support/bin/gltf_export_textures.py"); RunCommand("python", scriptPath, requestsJson); }
/// Add an export request to exportRequests. /// A follow-up process will actually do the export, which involves /// copying, downsampling, and/or filtering. static void AddExportTextureRequest( ExportGlTF.ExportedBrush exp, ExportRequests exportRequests, Texture tex, string texName, string exportRoot) { // Even if it weren't for b/37499109, we'd still want to do a downsample // for robustness; tex.width/height is not necessarily the size of the // source png. int desiredWidth = tex.width; int desiredHeight = tex.height; if (desiredWidth >= kLargeTextureThreshold || desiredHeight >= kLargeTextureThreshold) { desiredWidth = Mathf.Max(desiredWidth >> 1, 1); desiredHeight = Mathf.Max(desiredHeight >> 1, 1); } string projectRoot = Path.GetDirectoryName(Application.dataPath); string src = Path.Combine(projectRoot, UnityEditor.AssetDatabase.GetAssetPath(tex)); string dstName = String.Format( "{0}-v{1}-{2}{3}", exp.folderName, exp.shaderVersion, texName, Path.GetExtension(src)); exp.textures.Add(texName, dstName); exp.textureSizes.Add(texName, new Vector2(desiredWidth, desiredHeight)); string dstDir = Path.Combine(exportRoot, exp.folderName); bool isBump; { string assetPath = AssetDatabase.GetAssetPath(tex); TextureImporter importer = AssetImporter.GetAtPath(assetPath) as TextureImporter; isBump = importer.convertToNormalmap; } exportRequests.exports.Add( new ExportRequest { source = src, destination = Path.Combine(dstDir, dstName), desiredWidth = desiredWidth, desiredHeight = desiredHeight, isBump = isBump }); }
/// Returns an ExportedBrush, and appends export requests to exportRequests. public static ExportGlTF.ExportedBrush ExportBrush( ExportRequests exportRequests, BrushDescriptor descriptor, string exportRoot) { if (string.IsNullOrEmpty(descriptor.m_DurableName)) { throw new ApplicationException( string.Format("Brush {0} has no DurableName", descriptor.name)); } string brushFolderNameFmt = "{0}-{1}"; string shaderFmt = "{0}-v{1}-{2}.glsl"; var exp = new ExportGlTF.ExportedBrush(); exp.name = descriptor.m_DurableName; exp.guid = descriptor.m_Guid; exp.folderName = string.Format(brushFolderNameFmt, exp.name, exp.guid.ToString("D")); exp.shaderVersion = descriptor.m_ShaderVersion; exp.vertexShader = string.Format(shaderFmt, exp.folderName, exp.shaderVersion, "vertex"); exp.fragmentShader = string.Format(shaderFmt, exp.folderName, exp.shaderVersion, "fragment"); exp.enableCull = GetEnableCull(descriptor); exp.blendMode = descriptor.m_BlendMode; // And the material { Material material = descriptor.Material; Shader shader = material.shader; for (int i = 0; i < ShaderUtil.GetPropertyCount(shader); i++) { string internalName = ShaderUtil.GetPropertyName(shader, i); int propId = Shader.PropertyToID(internalName); string propName = SanitizeName(internalName); switch (ShaderUtil.GetPropertyType(shader, i)) { case ShaderUtil.ShaderPropertyType.TexEnv: if (material.HasProperty(internalName) && material.GetTexture(propId) is Texture2D) { AddExportTextureRequest( exp, exportRequests, material.GetTexture(propId), propName, exportRoot); } break; case ShaderUtil.ShaderPropertyType.Color: exp.colorParams.Add(propName, material.GetColor(propId)); break; case ShaderUtil.ShaderPropertyType.Range: case ShaderUtil.ShaderPropertyType.Float: float value = material.GetFloat(propId); if (propName == "ScrollJitterIntensity") { value *= App.UNITS_TO_METERS; } exp.floatParams.Add(propName, value); break; case ShaderUtil.ShaderPropertyType.Vector: Vector4 vec = material.GetVector(propId); if (propName == "ScrollDistance") { vec *= App.UNITS_TO_METERS; vec.z *= -1; } exp.vectorParams.Add(propName, vec); break; default: break; } } } // A bit of sanity-checking. bool expectCutoff = (exp.blendMode == ExportableMaterialBlendMode.AlphaMask); bool hasCutoff = exp.floatParams.ContainsKey("Cutoff"); if (expectCutoff != hasCutoff) { if (expectCutoff) { Debug.LogWarning($"{descriptor.m_DurableName}: missing cutoff (or shouldn't be AlphaMask)", descriptor); } else { // Some of these warnings are caused by materials which are AdditiveBlend but also have // alpha cutoff; but exp.blendMode can only represent one or the other. Unclear how // we can get this into a gltf material. // Some are caused by materials which don't use blending at all but still use a // shader that has cutoff math in it (eg hull, wire, icing). This is a bit of wasted // work at shading time. // Debug.LogWarning($"{descriptor.m_DurableName}: {exp.blendMode} but has cutoff", // descriptor); } } return(exp); }