public static void Export(GameObject[] gameObjects, string saveFileName, ExportSettings settings) { MeshConverter.ClearCaches(); TextureConverter.ClearCaches(); MaterialConverter.ClearCaches(); ShaderMappingIO.ClearCaches(); GraphBuilderInterface.unity2vsg_BeginExport(); List <PipelineData> storePipelines = new List <PipelineData>(); bool insideLODGroup = false; bool firstNodeAdded = false; System.Action <GameObject> processGameObject = null; processGameObject = (GameObject go) => { // determine the gameObject type Transform gotrans = go.transform; bool nodeAdded = false; // does it have a none identiy local matrix if (gotrans.localPosition != Vector3.zero || gotrans.localRotation != Quaternion.identity || gotrans.localScale != Vector3.one) { if (firstNodeAdded || !settings.zeroRootTransform) { // add as a transform TransformData transformdata = TransformConverter.CreateTransformData(gotrans); GraphBuilderInterface.unity2vsg_AddTransformNode(transformdata); nodeAdded = true; } } // do we need to insert a group if (!nodeAdded)// && gotrans.childCount > 0) { //add as a group GraphBuilderInterface.unity2vsg_AddGroupNode(); nodeAdded = true; } firstNodeAdded = true; bool meshexported = false; // get the meshrender here so we can check if the LOD exports the the mesh MeshFilter meshFilter = go.GetComponent <MeshFilter>(); MeshRenderer meshRenderer = go.GetComponent <MeshRenderer>(); // does this node have an LOD group LODGroup lodgroup = go.GetComponent <LODGroup>(); if (lodgroup != null && !insideLODGroup) { // rather than process the children we figure out which renderers are in which children and add them as LOD children LOD[] lods = lodgroup.GetLODs(); if (lods.Length > 0) { // get bounds from first renderer if (lods[0].renderers.Length > 0) { CullData lodCullData = new CullData(); Bounds bounds = new Bounds(lods[0].renderers[0].bounds.center, lods[0].renderers[0].bounds.size); foreach (Renderer boundsrenderer in lods[0].renderers) { if (boundsrenderer != null) { bounds.Encapsulate(boundsrenderer.bounds); } } Vector3 center = bounds.center - gotrans.position; CoordSytemConverter.Convert(ref center); lodCullData.center = NativeUtils.ToNative(center); lodCullData.radius = bounds.size.magnitude * 0.5f; GraphBuilderInterface.unity2vsg_AddLODNode(lodCullData); insideLODGroup = true; for (int i = 0; i < lods.Length; i++) { // for now just support one renderer and assume it's under a seperate child gameObject if (lods[i].renderers.Length == 0) { continue; } LODChildData lodChild = new LODChildData(); lodChild.minimumScreenHeightRatio = lods[i].screenRelativeTransitionHeight; GraphBuilderInterface.unity2vsg_AddLODChild(lodChild); foreach (Renderer lodrenderer in lods[i].renderers) { if (lodrenderer == meshRenderer) { meshexported = true; ExportMesh(meshFilter.sharedMesh, meshRenderer, gotrans, settings, storePipelines); } else if (lodrenderer != null) { // now process the renderers gameobject, it'll be added to the group we just created by adding an LOD child processGameObject(lodrenderer.gameObject); } } GraphBuilderInterface.unity2vsg_EndNode(); } insideLODGroup = false; GraphBuilderInterface.unity2vsg_EndNode(); // end the lod node } } } else { // transverse any children for (int i = 0; i < gotrans.childCount; i++) { processGameObject(gotrans.GetChild(i).gameObject); } } // does it have a mesh if (!meshexported && meshFilter && meshFilter.sharedMesh && meshRenderer) { Mesh mesh = meshFilter.sharedMesh; ExportMesh(mesh, meshRenderer, gotrans, settings, storePipelines); } // does this node have a terrain Terrain terrain = go.GetComponent <Terrain>(); if (terrain != null) { ExportTerrainMesh(terrain, settings, storePipelines); } // if we added a group or transform step out if (nodeAdded) { GraphBuilderInterface.unity2vsg_EndNode(); } }; foreach (GameObject go in gameObjects) { processGameObject(go); } //GraphBuilderInterface.unity2vsg_EndNode(); // step out of convert coord system node GraphBuilderInterface.unity2vsg_EndExport(saveFileName); NativeLog.PrintReport(); }
/// <summary> /// Create a new material data based off of the pass material also adds the new data to the cache /// </summary> /// <param name="material"></param> /// <returns></returns> public static MaterialInfo CreateMaterialData(Material material, ShaderMapping mapping = null) { // fetch the shadermapping for this materials shader if (mapping == null && material != null) { mapping = ShaderMappingIO.ReadFromJsonFile(material.shader); if (mapping == null) // if we fail to find a mapping try and load the default { mapping = ShaderMappingIO.ReadFromJsonFile(ShaderMappingIO.GetPathForShaderMappingFile("Default")); } } MaterialInfo matdata = new MaterialInfo { id = material != null?material.GetInstanceID() : 0, mapping = mapping }; // process uniforms UniformMappedData[] uniformDatas = mapping.GetUniformDatasFromMaterial(material); foreach (UniformMappedData uniData in uniformDatas) { VkDescriptorType descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_MAX_ENUM; uint descriptorCount = 1; if (uniData.mapping.uniformType == UniformMapping.UniformType.Texture2DUniform) { Texture tex = uniData.data as Texture; if (tex == null) { continue; } // get imagedata for the texture ImageData imageData = TextureConverter.GetOrCreateImageData(tex); // get descriptor for the image data DescriptorImageData descriptorImage = GetOrCreateDescriptorImageData(imageData, uniData.mapping.vsgBindingIndex); matdata.imageDescriptors.Add(descriptorImage); descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; } else if (uniData.mapping.uniformType == UniformMapping.UniformType.Texture2DArrayUniform) { Texture2DArray tex = uniData.data as Texture2DArray; if (tex == null) { continue; } ImageData[] imageDatas = TextureConverter.GetOrCreateImageData(tex); DescriptorImageData descriptorImage = GetOrCreateDescriptorImageData(imageDatas, uniData.mapping.vsgBindingIndex); matdata.imageDescriptors.Add(descriptorImage); descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; descriptorCount = (uint)imageDatas.Length; } else if (uniData.mapping.uniformType == UniformMapping.UniformType.FloatUniform) { float value = (float)uniData.data; if (value == float.NaN) { continue; } // get descriptor for the image data DescriptorFloatUniformData descriptorFloat = new DescriptorFloatUniformData { id = material.GetInstanceID(), binding = uniData.mapping.vsgBindingIndex, value = value }; matdata.floatDescriptors.Add(descriptorFloat); descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; } else if (uniData.mapping.uniformType == UniformMapping.UniformType.Vec4Uniform || uniData.mapping.uniformType == UniformMapping.UniformType.ColorUniform) { Vector4 vector = Vector4.zero; if (uniData.mapping.uniformType == UniformMapping.UniformType.Vec4Uniform) { vector = (Vector4)uniData.data; } if (uniData.mapping.uniformType == UniformMapping.UniformType.ColorUniform) { Color color = (Color)uniData.data; vector = new Vector4(color.r, color.g, color.b, color.a); } if (vector == null) { continue; } // get descriptor for the image data DescriptorVectorUniformData descriptorVector = new DescriptorVectorUniformData { id = material.GetInstanceID(), binding = uniData.mapping.vsgBindingIndex, value = NativeUtils.ToNative(vector) }; matdata.vectorDescriptors.Add(descriptorVector); descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER; } if (descriptorType == VkDescriptorType.VK_DESCRIPTOR_TYPE_MAX_ENUM) { continue; } // add any custom defines related to the texture if (uniData.mapping.vsgDefines != null && uniData.mapping.vsgDefines.Count > 0) { matdata.customDefines.AddRange(uniData.mapping.vsgDefines); } // create the descriptor binding to match the descriptor image VkDescriptorSetLayoutBinding descriptorBinding = new VkDescriptorSetLayoutBinding { binding = (uint)uniData.mapping.vsgBindingIndex, descriptorType = descriptorType, descriptorCount = descriptorCount, stageFlags = uniData.mapping.stages, pImmutableSamplers = System.IntPtr.Zero }; matdata.descriptorBindings.Add(descriptorBinding); } if (material != null) { string rendertype = material.GetTag("RenderType", true, "Opaque"); matdata.useAlpha = rendertype.Contains("Transparent") ? 1 : 0; if (matdata.useAlpha == 1) { matdata.customDefines.Add("VSG_BLEND"); } string lightmode = material.GetTag("LightMode", true, "ForwardBase"); if (lightmode != "Always") { matdata.customDefines.Add("VSG_LIGHTING"); } } // lastly process shaders now we know the defines etc it will use string customDefinesStr = string.Join(",", matdata.customDefines.ToArray()); matdata.shaderStages = GetOrCreateShaderStagesInfo(mapping.shaders.ToArray(), customDefinesStr, null); // add to the cache (double check it doesn't exist already) if (material != null && !_materialDataCache.ContainsKey(matdata.id)) { _materialDataCache[matdata.id] = matdata; } return(matdata); }
public static TerrainInfo CreateTerrainInfo(Terrain terrain, GraphBuilder.ExportSettings settings) { TerrainInfo terrainInfo = new TerrainInfo(); bool usingCustomMaterial = false; if (terrain.materialType == Terrain.MaterialType.Custom) { // try and load a shader mapping file to match the custom terrain material terrainInfo.shaderMapping = ShaderMappingIO.ReadFromJsonFile(terrain.materialTemplate.shader); if (terrainInfo.shaderMapping != null) { usingCustomMaterial = true; } } else { // load the default terrain shader mapping file terrainInfo.shaderMapping = ShaderMappingIO.ReadFromJsonFile(ShaderMappingIO.GetPathForShaderMappingFile("DefaultTerrain")); } if (terrainInfo.shaderMapping == null) { // no mapping loaded, use a default shader so we can at least export and render the terrain mesh NativeLog.WriteLine("GraphBuilder: Failed to load Terrain Shader Mapping file for terrain '" + terrain.name + "'."); terrainInfo.shaderMapping = ShaderMappingIO.ReadFromJsonFile(ShaderMappingIO.GetPathForShaderMappingFile("Default")); usingCustomMaterial = true; return(null); } terrainInfo.shaderDefines.Add("VSG_LIGHTING"); // build mesh int samplew = terrain.terrainData.heightmapWidth; int sampleh = terrain.terrainData.heightmapHeight; int cellw = terrain.terrainData.heightmapWidth - 1; int cellh = terrain.terrainData.heightmapHeight - 1; Vector3 size = terrain.terrainData.size; Vector2 cellsize = new Vector3(size.x / cellw, size.z / cellh); Vector2 uvcellsize = new Vector2(1.0f / cellw, 1.0f / cellh); float[,] terrainHeights = terrain.terrainData.GetHeights(0, 0, samplew, sampleh); int vertcount = samplew * sampleh; Vector3[] verts = new Vector3[vertcount]; Vector3[] normals = new Vector3[vertcount]; Vector2[] uvs = new Vector2[vertcount]; int[] indicies = new int[(cellw * cellh) * 6]; // vertices and UVs for (int y = 0; y < samplew; y++) { for (int x = 0; x < sampleh; x++) { verts[y * samplew + x].Set(x * cellsize.x, terrainHeights[y, x] * size.y, y * cellsize.y); normals[y * samplew + x] = terrain.terrainData.GetInterpolatedNormal((float)x / (float)samplew, (float)y / (float)sampleh); uvs[y * samplew + x].Set(x * uvcellsize.x, y * uvcellsize.y); } } CoordSytemConverter.Convert(verts); CoordSytemConverter.Convert(normals); // triangles int index = 0; for (int y = 0; y < cellw; y++) { for (int x = 0; x < cellh; x++) { indicies[index++] = (y * samplew) + x; indicies[index++] = ((y + 1) * samplew) + x; indicies[index++] = (y * samplew) + x + 1; indicies[index++] = ((y + 1) * samplew) + x; indicies[index++] = ((y + 1) * samplew) + x + 1; indicies[index++] = (y * samplew) + x + 1; } } CoordSytemConverter.FlipTriangleFaces(indicies); // convert to meshinfo MeshInfo mesh = null; if (!MeshConverter.GetMeshInfoFromCache(terrain.GetInstanceID(), out mesh)) { mesh = new MeshInfo { id = terrain.GetInstanceID(), verticies = NativeUtils.WrapArray(verts), normals = NativeUtils.WrapArray(normals), uv0 = NativeUtils.WrapArray(uvs), triangles = NativeUtils.WrapArray(indicies), use32BitIndicies = 1 }; MeshConverter.AddMeshInfoToCache(mesh, terrain.GetInstanceID()); } terrainInfo.terrainMesh = mesh; terrainInfo.terrainSize = size; // gather material info if (!usingCustomMaterial) { // use standard terrain layers TerrainLayer[] layers = terrain.terrainData.terrainLayers; for (int i = 0; i < layers.Length; i++) { ImageData layerData = TextureConverter.GetOrCreateImageData(layers[i].diffuseTexture); terrainInfo.diffuseTextureDatas.Add(layerData); terrainInfo.diffuseScales.Add(new Vector4(1.0f / layers[i].tileSize.x, 1.0f / layers[i].tileSize.y)); } for (int i = 0; i < terrain.terrainData.alphamapTextureCount; i++) { Texture2D srcmask = terrain.terrainData.GetAlphamapTexture(i); ImageData splatData = TextureConverter.GetOrCreateImageData(srcmask); terrainInfo.maskTextureDatas.Add(splatData); } if (terrainInfo.diffuseTextureDatas.Count > 0) { terrainInfo.descriptorBindings.Add(new VkDescriptorSetLayoutBinding() { binding = 0, descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stageFlags = VkShaderStageFlagBits.VK_SHADER_STAGE_FRAGMENT_BIT, descriptorCount = (uint)terrainInfo.diffuseTextureDatas.Count }); terrainInfo.descriptorBindings.Add(new VkDescriptorSetLayoutBinding() { binding = 2, descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, stageFlags = VkShaderStageFlagBits.VK_SHADER_STAGE_FRAGMENT_BIT, descriptorCount = (uint)terrainInfo.diffuseScales.Count }); terrainInfo.shaderConsts.Add(terrainInfo.diffuseTextureDatas.Count); terrainInfo.shaderDefines.Add("VSG_TERRAIN_LAYERS"); } terrainInfo.descriptorBindings.Add(new VkDescriptorSetLayoutBinding() { binding = 3, descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, stageFlags = VkShaderStageFlagBits.VK_SHADER_STAGE_FRAGMENT_BIT, descriptorCount = 1 }); if (terrainInfo.maskTextureDatas.Count > 0) { terrainInfo.descriptorBindings.Add(new VkDescriptorSetLayoutBinding() { binding = 1, descriptorType = VkDescriptorType.VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER, stageFlags = VkShaderStageFlagBits.VK_SHADER_STAGE_FRAGMENT_BIT, descriptorCount = (uint)terrainInfo.maskTextureDatas.Count }); terrainInfo.shaderConsts.Add(terrainInfo.maskTextureDatas.Count); } } else { Material customMaterial = terrain.materialTemplate; terrainInfo.customMaterial = MaterialConverter.CreateMaterialData(customMaterial, terrainInfo.shaderMapping); terrainInfo.customMaterial.customDefines = terrainInfo.shaderDefines; } return(terrainInfo); }