// Adds material and sets up its dependent technique, program, shaders. This should be called // after adding meshes, but before populating lights, textures, etc. // Pass: // hack - attributes of some mesh that uses this material public void AddMaterialWithDependencies( IExportableMaterial exportableMaterial, string meshNamespace, GlTF_Attributes hack) { GlTF_Material gltfMtl = G.CreateMaterial(meshNamespace, exportableMaterial); // Set up technique. GlTF_Technique tech = GlTF_Writer.CreateTechnique(G, exportableMaterial); gltfMtl.instanceTechniqueName = tech.name; GlTF_Technique.States states = null; if (m_techniqueStates.ContainsKey(exportableMaterial)) { states = m_techniqueStates[exportableMaterial]; } if (states == null) { // Unless otherwise specified the preset, enable z-buffering. states = new GlTF_Technique.States(); states.enable = new[] { GlTF_Technique.Enable.DEPTH_TEST }.ToList(); } tech.states = states; AddAllAttributes(tech, exportableMaterial, hack); tech.AddDefaultUniforms(G.RTCCenter != null); // Add program. GlTF_Program program = new GlTF_Program(G); program.name = GlTF_Program.GetNameFromObject(exportableMaterial); tech.program = program.name; foreach (var attr in tech.attributes) { program.attributes.Add(attr.name); } G.programs.Add(program); // Add vertex and fragment shaders. GlTF_Shader vertShader = new GlTF_Shader(G); vertShader.name = GlTF_Shader.GetNameFromObject(exportableMaterial, GlTF_Shader.Type.Vertex); program.vertexShader = vertShader.name; vertShader.type = GlTF_Shader.Type.Vertex; vertShader.uri = ExportFileReference.CreateHttp(exportableMaterial.VertShaderUri); G.shaders.Add(vertShader); GlTF_Shader fragShader = new GlTF_Shader(G); fragShader.name = GlTF_Shader.GetNameFromObject(exportableMaterial, GlTF_Shader.Type.Fragment); program.fragmentShader = fragShader.name; fragShader.type = GlTF_Shader.Type.Fragment; fragShader.uri = ExportFileReference.CreateHttp(exportableMaterial.FragShaderUri); G.shaders.Add(fragShader); }
/// Returns an ExportFileReference given an absolute http:// uri. /// Depending on settings, this may become a relative reference in the gltf. private ExportFileReference CreateExportFileReferenceFromHttp(string httpUri) { if (!AllowHttpUri) { string localPath = HostedUriToLocalFilename(httpUri); if (localPath != null) { return(ExportFileReference.GetOrCreateSafeLocal( G.m_disambiguationContext, Path.GetFileName(localPath), Path.GetDirectoryName(localPath), "Brush_" + Path.GetFileName(localPath))); } Debug.LogWarning($"Cannot convert {httpUri} to local"); } return(ExportFileReference.CreateHttp(httpUri)); }
/// Adds a texture parameter + uniform to the specified material. /// As a side effect, auto-creates textures, images, and maybe a sampler if necessary. /// Pass: /// matObjName - the material /// texParam - name of the material parameter to add /// fileRef - file containing texture data public void AddTextureToMaterial( IExportableMaterial exportableMaterial, string texParam, ExportFileReference fileRef) { GlTF_Material material = G.materials[exportableMaterial]; GlTF_Sampler sampler = GlTF_Sampler.LookupOrCreate( G, GlTF_Sampler.MagFilter.LINEAR, GlTF_Sampler.MinFilter.LINEAR_MIPMAP_LINEAR); // The names only matter for gltf1, so keep them similar for easier diffing. // Essentially, this names the image and texture after the first material that wanted them. string matNameAndParam = $"{exportableMaterial.UniqueName:D}_{texParam}"; var img = GlTF_Image.LookupOrCreate(G, fileRef, proposedName: matNameAndParam); var tex = GlTF_Texture.LookupOrCreate(G, img, sampler, proposedName: matNameAndParam); material.values.Add(new GlTF_Material.TextureKV(key: texParam, texture: tex)); // Add texture-related parameter and uniform. AddUniform(exportableMaterial, texParam, GlTF_Technique.Type.SAMPLER_2D, GlTF_Technique.Semantic.UNKNOWN, null); }
// Pass: // meshNamespace - A string used as the "namespace" of the mesh that owns this material. // Useful for uniquifying names (texture file names, material names, ...) in a // human-friendly way. // hack - attributes of some mesh that uses this material private void ExportMaterial( SceneStatePayload payload, string meshNamespace, IExportableMaterial exportableMaterial, GlTF_Attributes hack) { // // Set culling and blending modes. // GlTF_Technique.States states = new GlTF_Technique.States(); m_techniqueStates[exportableMaterial] = states; // Everyone gets depth test states.enable = new[] { GlTF_Technique.Enable.DEPTH_TEST }.ToList(); if (exportableMaterial.EnableCull) { states.enable.Add(GlTF_Technique.Enable.CULL_FACE); } if (exportableMaterial.BlendMode == ExportableMaterialBlendMode.AdditiveBlend) { states.enable.Add(GlTF_Technique.Enable.BLEND); // Blend array format: [srcRGB, dstRGB, srcAlpha, dstAlpha] states.functions["blendFuncSeparate"] = new GlTF_Technique.Value(G, new Vector4(1.0f, 1.0f, 1.0f, 1.0f)); // Additive. states.functions["depthMask"] = new GlTF_Technique.Value(G, false); // No depth write. // Note: If we switch bloom to use LDR color, adding the alpha channels won't do. // GL_MIN would be a good choice for alpha, but it's unsupported by glTF 1.0. } else if (exportableMaterial.BlendMode == ExportableMaterialBlendMode.AlphaBlend) { states.enable.Add(GlTF_Technique.Enable.BLEND); // Blend array format: [srcRGB, dstRGB, srcAlpha, dstAlpha] // These enum values correspond to: [ONE, ONE_MINUS_SRC_ALPHA, ONE, ONE_MINUS_SRC_ALPHA] states.functions["blendFuncSeparate"] = new GlTF_Technique.Value(G, new Vector4(1.0f, 771.0f, 1.0f, 771.0f)); // Blend. states.functions["depthMask"] = new GlTF_Technique.Value(G, true); } else { // Standard z-buffering: Enable depth write. states.functions["depthMask"] = new GlTF_Technique.Value(G, true); } // First add the material, then export any per-material attributes, such as shader uniforms. AddMaterialWithDependencies(exportableMaterial, meshNamespace, hack); // Add lighting for this material. AddLights(exportableMaterial, payload); // // Export shader/material parameters. // foreach (var kvp in exportableMaterial.FloatParams) { ExportShaderUniform(exportableMaterial, kvp.Key, kvp.Value); } foreach (var kvp in exportableMaterial.ColorParams) { ExportShaderUniform(exportableMaterial, kvp.Key, kvp.Value); } foreach (var kvp in exportableMaterial.VectorParams) { ExportShaderUniform(exportableMaterial, kvp.Key, kvp.Value); } foreach (var kvp in exportableMaterial.TextureSizes) { float width = kvp.Value.x; float height = kvp.Value.y; ExportShaderUniform(exportableMaterial, kvp.Key + "_TexelSize", new Vector4(1 / width, 1 / height, width, height)); } // // Export textures. // foreach (var kvp in exportableMaterial.TextureUris) { string textureName = kvp.Key; string textureUri = kvp.Value; ExportFileReference fileRef; if (ExportFileReference.IsHttp(textureUri)) { // Typically this happens for textures used by BrushDescriptor materials fileRef = CreateExportFileReferenceFromHttp(textureUri); } else { fileRef = ExportFileReference.GetOrCreateSafeLocal( G.m_disambiguationContext, textureUri, exportableMaterial.UriBase, $"{meshNamespace}_{Path.GetFileName(textureUri)}"); } AddTextureToMaterial(exportableMaterial, textureName, fileRef); } }