/// <summary> /// Per Pixel Normals is a feature in U2018.3 with LWRP 4.0.1 or newer. /// It also requires Draw Instanced to be enabled on the terrain (new in U2018.3). /// If users want different per-pixel normals for different landscapes, they should set /// terrain type to custom, and use a custom material. /// </summary> /// <param name="lbLandscape"></param> /// <returns></returns> public static bool GetTerrainPerPixelNormals(LBLandscape lbLandscape) { bool isPerPixelNormalsEnabled = false; #if UNITY_2018_3_OR_NEWER if (lbLandscape != null) { LBLandscape.TerrainMaterialType _terrainMaterialType = lbLandscape.GetTerrainMaterialType(); if (_terrainMaterialType == LBLandscape.TerrainMaterialType.URP) { #if UNITY_2019_3_OR_NEWER // Universal Render Pipeline requires U2019.3+ if (lbLandscape.GetLandscapeTerrainDrawInstanced()) { // Check the custom material on the first terrain Material _tCustomMat = lbLandscape.GetLandscapeTerrainCustomMaterial(); if (_tCustomMat != null && _tCustomMat.shader.name.Contains("Universal Render Pipeline/Terrain/Lit")) { if (_tCustomMat.HasProperty("_EnableInstancedPerPixelNormal")) { isPerPixelNormalsEnabled = (_tCustomMat.GetFloat("_EnableInstancedPerPixelNormal") > 0f); } else { Debug.LogWarning("URP material property _EnableInstancedPerPixelNormal is not available. Do you have URP 7.1.2 or newer in your project? Check Package Manager"); } } } #endif } else if (_terrainMaterialType == LBLandscape.TerrainMaterialType.LWRP) { if (lbLandscape.GetLandscapeTerrainDrawInstanced()) { // Check the custom material on the first terrain Material _tCustomMat = lbLandscape.GetLandscapeTerrainCustomMaterial(); // The shader path changed in LWRP 4.0 so make sure we have the correct version if (_tCustomMat != null && _tCustomMat.shader.name.Contains("Lightweight Render Pipeline/Terrain/Lit")) { if (_tCustomMat.HasProperty("_TERRAIN_INSTANCED_PERPIXEL_NORMAL")) { isPerPixelNormalsEnabled = (_tCustomMat.GetFloat("_TERRAIN_INSTANCED_PERPIXEL_NORMAL") > 0f); } else { Debug.LogWarning("LWRP material property _TERRAIN_INSTANCED_PERPIXEL_NORMAL is not available. Do you have LWRP 4.0.1 or newer in your project? Check Package Manager"); } } } } } #endif return(isPerPixelNormalsEnabled); }
/// <summary> /// Load a template but delay short period of time after updating /// the infoPanel text to force it to be displayed /// For URP/LWRP/HDRP all trees will be forced to be billboarded /// as currently we are only using built-in SRP trees. /// </summary> /// <param name="templateNumber"></param> /// <returns></returns> IEnumerator LoadTemplateWithUIDelay(int templateNumber) { bool showSRPWarning = false; if (lbTemplates != null) { int numTemplates = lbTemplates.Length; if (templateNumber < numTemplates) { LBTemplate lbTemplate = lbTemplates[templateNumber]; if (lbTemplate != null) { // Disable buttons EnableButton(quality1Button, false); EnableButton(quality2Button, false); EnableButton(quality3Button, false); EnableButton(quality4Button, false); EnableButton(infoButton, false); EnableButton(gpuButton, false); DisplayBackgroundPanel(true); currentTemplateName = lbTemplate.name; SetInfoTitle("Loading Template... PLEASE WAIT"); string infoText = "Applying template... "; SetInfoText(infoText); DisplayInfoPanel(true); yield return(new WaitForSeconds(0.1f)); // Remove any camera animators LBCameraAnimator.RemoveCameraAnimatorsFromScene(lbLandscape, false); yield return(new WaitForSeconds(0.1f)); // if LBLighting is in the scene, remove all references to terrains to // prevent errors when the current landscape is deleted. LBLighting lbLighting = GameObject.FindObjectOfType <LBLighting>(); if (lbLighting != null) { lbLighting.ClearAllTerrains(); } if (lbLandscape != null) { DestroyImmediate(lbLandscape.gameObject); } lbLandscape = lbTemplate.CreateLandscapeFromTemplate("DemoLandscape"); Camera mainCamera = Camera.main; if (mainCamera != null) { mainCamera.transform.position = new Vector3(2000f, 2000f, 0f); mainCamera.transform.LookAt(lbLandscape.transform); } // Currently, when applying template ignore water if LWRP, URP or HDRP are enabled // This could be updated if we had a LWRP/HDRP-compatible water asset if (lbTemplate.ApplyTemplateToLandscape(lbLandscape, ignoreStartPosition, true, (isURP || isLWRP || isHDRP) ? null : waterPrefab, true)) { infoText += "DONE\n\n"; SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); lbLandscape.showTiming = false; lbLandscape.SetLandscapeTerrains(true); // Build the landscape int numTerrains = (lbLandscape.landscapeTerrains == null ? 0 : lbLandscape.landscapeTerrains.Length); if (numTerrains > 0) { // Our older templates don't use GPU for Topography and Path. If it is fully capable // of using the GPU, list it here. bool isModernTemplate = lbTemplate.name.StartsWith("DemoStoneCottage"); // Override the template GPU settings lbLandscape.useGPUTopography = isModernTemplate ? enableGPU : false; lbLandscape.useGPUTexturing = enableGPU; lbLandscape.useGPUGrass = enableGPU; lbLandscape.useGPUPath = isModernTemplate ? enableGPU : false; // Check for URP/LWRP/HDRP or do we need to create a default material for U2019.2.0 or newer if (isURP || isLWRP || isHDRP || is201920Plus) { float pixelError = 0f; Terrain terrain = null; LBLandscape.TerrainMaterialType terrainMaterialType = isURP ? LBLandscape.TerrainMaterialType.URP : (isLWRP ? LBLandscape.TerrainMaterialType.LWRP : (terrainMaterialType = isHDRP ? LBLandscape.TerrainMaterialType.HDRP : LBLandscape.TerrainMaterialType.BuiltInStandard)); for (int tIdx = 0; tIdx < numTerrains; tIdx++) { terrain = lbLandscape.landscapeTerrains[tIdx]; lbLandscape.SetTerrainMaterial(terrain, tIdx, (tIdx == numTerrains - 1), terrain.terrainData.size.x, ref pixelError, terrainMaterialType); // For URP/LWRP/HDRP all trees will be forced to be billboarded // as currently we are only using built-in SRP trees. if (isURP || isLWRP || isHDRP) { // Force all trees to be billboards terrain.treeBillboardDistance = 0f; terrain.treeMaximumFullLODCount = 0; showSRPWarning = true; } } } // These are the cut-down versions without progress bars and minimal validation infoText += "Building Topography" + (lbLandscape.useGPUTopography ? " (GPU)..." : "..."); SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); lbLandscape.ApplyTopography(true, true); infoText += "DONE\n\n"; infoText += "Adding Textures" + (lbLandscape.useGPUTexturing ? " (GPU)..." : "..."); SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); lbLandscape.ApplyTextures(true, true); infoText += "DONE\n\n"; infoText += "Placing Trees... "; SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); lbLandscape.ApplyTrees(true, true); infoText += "DONE\n\n"; infoText += "Placing Grass" + (lbLandscape.useGPUGrass ? " (GPU)..." : "..."); SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); lbLandscape.ApplyGrass(true, true); infoText += "DONE\n\n"; SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); if (lbLandscape.lbGroupList != null && lbLandscape.lbGroupList.Count > 0) { infoText += "Placing Groups" + (lbLandscape.useGPUTopography ? " (GPU)..." : "..."); SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); lbLandscape.ApplyGroups(false, false); } // Apply lighting last as it needs the Camera Paths (and Animator camera to set up WeatherFX) if (lbTemplate.isLBLightingIncluded) { infoText += "Applying lighting... "; SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); //if (lbLighting != null) { DestroyImmediate(lbLighting.gameObject); } if (lbLighting == null) { // If LBLighting isn't already in the scene, add it. lbLighting = LBLighting.AddLightingToScene(true); } if (lbLighting != null) { // Restore the lighting settings from the template lbTemplate.ApplyLBLightingSettings(lbLandscape, ref lbLighting, mainCamera, true); } infoText += "DONE\n\n"; SetInfoText(infoText); yield return(new WaitForSeconds(0.1f)); // Prior to Unity 5.4, ImageFX and/or camera clear flags are not updated correctly // when the WeatherFX with celestials is added to the scene after a configuration without // celestials. The workaround, is to force the GameView to repaint or be re-initalised. // To be effective, a "reasonable" delay is required between switching away from Game view // and back. The exact cause of the issue is unknown... #if !UNITY_5_4_OR_NEWER && UNITY_EDITOR if (lbLighting.useCelestials) { bool wasMaximized = LBEditorHelper.GameViewMaximize(this.GetType(), false); LBEditorHelper.ShowSceneView(this.GetType(), true); yield return(new WaitForSeconds(0.5f)); LBEditorHelper.GameViewMaximize(this.GetType(), wasMaximized); } #endif } // Find the first animation and start it (there should be only one in a demo template) LBCameraAnimator lbCameraAnimator = LBCameraAnimator.GetFirstCameraAnimatorInLandscape(lbLandscape); if (lbCameraAnimator != null) { if (lbTemplate.name.StartsWith("FPS Forest Demo")) { // This uses the old Unity 4 trees which don't work so well with anti-aliasing QualitySettings.antiAliasing = 0; if (lbCameraAnimator.animatorCamera != null) { lbCameraAnimator.SetMoveSpeed(2f); lbCameraAnimator.animatorCamera.renderingPath = RenderingPath.Forward; lbCameraAnimator.animateSpeed = false; } } else if (lbTemplate.name.StartsWith("DemoStoneCottage")) { lbCameraAnimator.minMoveSpeed = 1f; lbCameraAnimator.maxMoveSpeed = 3f; lbCameraAnimator.animateSpeed = true; } else { lbCameraAnimator.animateSpeed = true; } // Reset LBImageFX timing so clouds always appear the same if (lbCameraAnimator.animatorCamera != null) { LBImageFX lbImageFX = lbCameraAnimator.animatorCamera.GetComponent <LBImageFX>(); if (lbImageFX != null) { //Debug.Log("LBDemoLoader.LoadTemplateWithUIDelay - Resetting LBImageFX cloud positions"); lbImageFX.ResetCloudPosition(); } } //Debug.Log("LBDemoLoader " + lbTemplate.name + " renderpath: " + lbCameraAnimator.animatorCamera.renderingPath); lbCameraAnimator.pauseAtEndDuration = 999f; lbCameraAnimator.BeginAnimation(true, 0f); } else { Debug.LogWarning("LBDemoLoader.LoadTemplateWithUIDelay - Couldn't find a camera animator in the demo template"); } } } // Re-enable buttons EnableButton(quality1Button, true); EnableButton(quality2Button, true); EnableButton(quality3Button, true); EnableButton(quality4Button, true); EnableButton(infoButton, true); EnableButton(gpuButton, true); UpdateInfoButtonText("Show Info"); } } } if (showSRPWarning) { SetInfoTitle("SRP WARNING"); SetInfoText("This demo scene is designed for the built-in RP.\n\nSee SRP folder for into on URP and HDRP"); } else { DisplayInfoPanel(false); } DisplayBackgroundPanel(false); }
// Use this for initialization void Awake() { #region Initialise // This line just gets the starting time of the generation so that the total generation time // can be recorded and displayed float generationStartTime = Time.realtimeSinceStartup; RuntimeSampleHelper.RemoveDefaultCamera(); RuntimeSampleHelper.RemoveDefaultLight(); // Get a link to the LBLandscape script landscape = this.GetComponent <LBLandscape>(); if (landscape == null) { Debug.Log("Cannot find LBLandscape script attached to Runtime gameobject"); return; } // Check to see if Universal Render Pipeline is installed in the project bool isURP = LBLandscape.IsURP(false); // Check to see if Light Weight Render Pipeline is installed in this project bool isLWRP = !isURP && LBLandscape.IsLWRP(false); // Check to see if High Definition Render Pipeline is installed in this project bool isHDRP = !isURP && !isLWRP && LBLandscape.IsHDRP(false); #if UNITY_2019_2_OR_NEWER bool is201920Plus = true; #else bool is201920Plus = false; #endif #endregion #region Create the terrains and store references to them terrainsList = new List <Terrain>(); int terrainNumber = 0; for (float tx = 0f; tx < landscapeSize.x - 1f; tx += 2000f) { for (float ty = 0f; ty < landscapeSize.y - 1f; ty += 2000f) { // Create a new gameobject GameObject terrainObj = new GameObject("Runtime Terrain " + (terrainNumber++).ToString("000")); // Correctly parent and position the terrain terrainObj.transform.parent = this.transform; terrainObj.transform.localPosition = new Vector3(tx, 0f, ty); // Add a terrain component Terrain newTerrain = terrainObj.AddComponent <Terrain>(); // Set terrain settings (depending on your situtation, you may need to set more or less than I have in this example) newTerrain.heightmapPixelError = 1; newTerrain.basemapDistance = 5000f; newTerrain.treeDistance = 5000f; newTerrain.treeBillboardDistance = 100f; newTerrain.detailObjectDistance = 150f; newTerrain.treeCrossFadeLength = 25f; // Set terrain data settings (same as above comment) TerrainData newTerrainData = new TerrainData(); // One thing to note here is that modfiying the heightmap resolution not only clears all terrai height data, // it also scales up or down the size of the terrain. So you should always set the heightmap resolution // BEFORE you set the terrain size newTerrainData.heightmapResolution = 513; newTerrainData.size = Vector3.one * 2000f; newTerrainData.SetDetailResolution(1024, 16); newTerrain.terrainData = newTerrainData; // Set up the terrain collider TerrainCollider newTerrainCol = terrainObj.AddComponent <TerrainCollider>(); newTerrainCol.terrainData = newTerrainData; // Add the terrain to the list of terrains terrainsList.Add(newTerrain); } } #endregion landscape.SetLandscapeTerrains(true); landscape.SetTerrainNeighbours(false); #region Set the terrain material int numTerrains = landscape.landscapeTerrains == null ? 0 : landscape.landscapeTerrains.Length; // Check for URP/LWRP/HDRP or do we need to create a default material for U2019.2.0 or newer if (isURP || isLWRP || isHDRP || is201920Plus) { float pixelError = 0f; Terrain terrain = null; LBLandscape.TerrainMaterialType terrainMaterialType = isURP ? LBLandscape.TerrainMaterialType.URP : (isLWRP ? LBLandscape.TerrainMaterialType.LWRP : (terrainMaterialType = isHDRP ? LBLandscape.TerrainMaterialType.HDRP : LBLandscape.TerrainMaterialType.BuiltInStandard)); for (int tIdx = 0; tIdx < numTerrains; tIdx++) { terrain = landscape.landscapeTerrains[tIdx]; landscape.SetTerrainMaterial(terrain, tIdx, (tIdx == numTerrains - 1), terrain.terrainData.size.x, ref pixelError, terrainMaterialType); } } #endregion // Set the topography noise variables float maskWarpAmount = 0f; float maskNoiseTileSize = 10000f; float maskNoiseOffsetX = 0f; float maskNoiseOffsetY = 0f; AnimationCurve distanceToCentreMask = new AnimationCurve(); int keyInt = distanceToCentreMask.AddKey(0f, 1f); keyInt = distanceToCentreMask.AddKey(0.529f, 0.959f); keyInt = distanceToCentreMask.AddKey(1f, 0f); Keyframe[] curveKeys = distanceToCentreMask.keys; curveKeys[0].inTangent = 0f; curveKeys[0].outTangent = 0f; curveKeys[1].inTangent = -0.25f; curveKeys[1].outTangent = -0.25f; curveKeys[2].inTangent = 0f; curveKeys[2].outTangent = 0f; distanceToCentreMask = new AnimationCurve(curveKeys); AnimationCurve maskNoiseCurveModifier = AnimationCurve.Linear(0f, 0.5f, 1f, 1f); // Avoid warning of keyInt not being used. if (keyInt == 0) { } // Create the Topography Layers // You can mix and match Perlin and Image layers landscape.topographyLayersList = new List <LBLayer>(); if (landscape.topographyLayersList != null) { // Add one or more Base layers LBLayer lbBaseLayer1 = new LBLayer(); if (lbBaseLayer1 != null) { lbBaseLayer1 = LBLayer.SetLayerFromPreset(LBLayer.LayerPreset.DesertFloorBase); landscape.topographyLayersList.Add(lbBaseLayer1); } // Add one or more Additive layers LBLayer lbAdditiveLayer1 = new LBLayer(); if (lbAdditiveLayer1 != null) { // You can manually configure a layer, or use a preset then modify it. lbAdditiveLayer1 = LBLayer.SetLayerFromPreset(LBLayer.LayerPreset.MountainRangeComplexBase); // If using using a different type of preset, must set the type after applying preset lbAdditiveLayer1.type = LBLayer.LayerType.PerlinAdditive; // Optionally override the preset settings lbAdditiveLayer1.noiseTileSize = 5000f; lbAdditiveLayer1.octaves = 8; lbAdditiveLayer1.lacunarity = 1.92f; lbAdditiveLayer1.gain = 0.45f; lbAdditiveLayer1.warpAmount = 0; lbAdditiveLayer1.removeBaseNoise = true; lbAdditiveLayer1.heightScale = 1f; lbAdditiveLayer1.additiveAmount = 0.75f; lbAdditiveLayer1.additiveCurve = LBLayer.CreateAdditiveCurve(lbAdditiveLayer1.additiveAmount); lbAdditiveLayer1.perOctaveCurveModifierPresets = new List <LBCurve.CurvePreset>(); lbAdditiveLayer1.perOctaveCurveModifierPresets.Add(LBCurve.CurvePreset.DoubleRidged); landscape.topographyLayersList.Add(lbAdditiveLayer1); } // Add a detail layer LBLayer lbDetailLayer1 = new LBLayer(); if (lbDetailLayer1 != null) { lbDetailLayer1 = LBLayer.SetLayerFromPreset(LBLayer.LayerPreset.HillsDetail); landscape.topographyLayersList.Add(lbDetailLayer1); } } // Create the terrain topographies for (int t = 0; t < terrainsList.Count && landscape.topographyLayersList != null; t++) { // Add the topography layers terrainsList[t].terrainData = LBLandscapeTerrain.HeightmapFromLayers(landscape, terrainsList[t].terrainData, terrainsList[t].transform.position, landscapeSize, landscape.transform.position, landscape.topographyLayersList); if (IsMaskingOn) { // Example of applying a mask to the terrain topography terrainsList[t].terrainData = LBLandscapeTerrain.MaskedHeightmap(terrainsList[t].terrainData, terrainsList[t].transform.position, landscapeSize, transform.position, 1, distanceToCentreMask, maskWarpAmount, maskNoiseTileSize, new Vector2(maskNoiseOffsetX, maskNoiseOffsetY), maskNoiseCurveModifier); } } // Create a list of LBTerrainTexture objects // These contain the textures and normal maps but also the rules for applying them to the terrain landscape.terrainTexturesList = new List <LBTerrainTexture>(); // Populate the list by creating temporary LBTerrainTexture objects and adjusting their settings, // then adding each one into the list // Grass Hill texture LBTerrainTexture tempTerrainTexture = new LBTerrainTexture(); tempTerrainTexture.texture = grassHillTexture; tempTerrainTexture.normalMap = grassHillNormalMap; tempTerrainTexture.tileSize = Vector2.one * 25f; tempTerrainTexture.minInclination = 0f; tempTerrainTexture.maxInclination = 45f; tempTerrainTexture.useNoise = true; tempTerrainTexture.noiseTileSize = 100f; tempTerrainTexture.texturingMode = LBTerrainTexture.TexturingMode.Inclination; landscape.terrainTexturesList.Add(tempTerrainTexture); // Rock Layered texture tempTerrainTexture = new LBTerrainTexture(); tempTerrainTexture.texture = rockLayeredTexture; tempTerrainTexture.normalMap = rockLayeredNormalMap; tempTerrainTexture.tileSize = Vector2.one * 100f; tempTerrainTexture.minInclination = 30f; tempTerrainTexture.maxInclination = 90f; tempTerrainTexture.useNoise = true; tempTerrainTexture.noiseTileSize = 100f; tempTerrainTexture.texturingMode = LBTerrainTexture.TexturingMode.Inclination; landscape.terrainTexturesList.Add(tempTerrainTexture); // Texture the terrains for (int t = 0; t < terrainsList.Count; t++) { // Use the LBLandscapeTerrain.TextureTerrain function for texturing the terrain terrainsList[t].terrainData = LBLandscapeTerrain.TextureTerrain(terrainsList[t].terrainData, landscape.terrainTexturesList, terrainsList[t].transform.position, landscapeSize, this.transform.position, false, landscape); } // Display the total time taken to generate the landscape (usually for debugging purposes) Debug.Log("Time taken to generate landscape: " + (Time.realtimeSinceStartup - generationStartTime).ToString("00.00") + " seconds."); }
/// <summary> /// Copy LB Texturing tab Textures to MicroSplat. /// Typically called from within the Texturing tab of LB Editor window. /// </summary> /// <param name="landscape"></param> /// <param name="terrainMaterialType"></param> /// <param name="terrainMat"></param> /// <param name="showErrors"></param> public static void MicroSplatCopyTextures(LBLandscape landscape, LBLandscape.TerrainMaterialType terrainMaterialType, Material terrainMat, bool showErrors) { string methodName = "LBEditorIntegration.MicroSplatCopyTextures"; // Basic validation if (landscape == null) { if (showErrors) { Debug.LogWarning(methodName + " - landscape cannot be null"); } } else if (terrainMaterialType != LBLandscape.TerrainMaterialType.MicroSplat) { if (showErrors) { Debug.LogWarning(methodName + " - The Landscape Terrain Settings needs to have a Material Type of MicroSplat. Please set and try again."); } } else if (terrainMat == null) { if (showErrors) { Debug.LogWarning(methodName + " - the landscape does not appear to have a MicroSplat material. Has it been initialised in the Landscape Terrain Settings?"); } } else { // Find the Texture Array Config file //JBooth.MicroSplat.TextureArrayConfig textureArrayConfig = LBEditorHelper.GetAsset<JBooth.MicroSplat.TextureArrayConfig>("MicroSplatData", terrainMat.name.Replace("MicroSplat","MicroSplatConfig") + ".asset"); JBooth.MicroSplat.TextureArrayConfig textureArrayConfig = GetTextureArrayConfig(terrainMat); if (textureArrayConfig == null) { if (showErrors) { Debug.LogWarning("ERROR: " + methodName + " could not find TextureArrayConfig [MicroSplatData/" + terrainMat.name.Replace("MicroSplat", "MicroSplatConfig") + ".asset]"); } } else { // Get existing list of Textures from MicroSplat List <JBooth.MicroSplat.TextureArrayConfig.TextureEntry> textureOldEntryList = textureArrayConfig.sourceTextures; //int numMSTextures = (textureOldEntryList == null ? 0 : textureOldEntryList.Count); int numLBTextures = (landscape.terrainTexturesList == null ? 0 : landscape.terrainTexturesList.Count); LBTerrainTexture lbTrnTex = null; JBooth.MicroSplat.TextureArrayConfig.TextureEntry textureEntry = null; //Debug.Log("[DEBUG] numMSTextures: " + numMSTextures + " numLBTextures:" + numLBTextures); // Create a new list List <JBooth.MicroSplat.TextureArrayConfig.TextureEntry> textureNewEntryList = new List <JBooth.MicroSplat.TextureArrayConfig.TextureEntry>(); // Loop through all the Landscape Builder Textures for (int lbTexIdx = 0; lbTexIdx < numLBTextures; lbTexIdx++) { lbTrnTex = landscape.terrainTexturesList[lbTexIdx]; if (lbTrnTex != null && !lbTrnTex.isDisabled) { // Find matching MicroSplat texture entry textureEntry = textureOldEntryList.Find(te => (lbTrnTex.texture != null && te.diffuse != null && te.diffuse.name == lbTrnTex.texture.name) && (lbTrnTex.normalMap == null && te.normal == null || (lbTrnTex.normalMap != null && te.normal != null && te.normal.name == lbTrnTex.normalMap.name)) && (lbTrnTex.heightMap == null && te.height == null || (lbTrnTex.heightMap != null && te.height != null && te.height.name == lbTrnTex.heightMap.name)) ); //textureEntry = textureOldEntryList.Find(te => lbTrnTex.texture != null && te.diffuse != null && te.diffuse.name == lbTrnTex.texture.name); if (textureEntry != null) { // update tinted texture if required textureEntry.diffuse = lbTrnTex.isTinted ? (lbTrnTex.tintedTexture == null ? lbTrnTex.texture : lbTrnTex.tintedTexture) : lbTrnTex.texture; textureNewEntryList.Add(textureEntry); //Debug.Log("[DEBUG] Added matching entry: " + textureEntry.diffuse.name); } else { // Add missing textures textureEntry = new JBooth.MicroSplat.TextureArrayConfig.TextureEntry(); if (textureEntry != null) { textureEntry.diffuse = lbTrnTex.isTinted ? (lbTrnTex.tintedTexture == null ? lbTrnTex.texture : lbTrnTex.tintedTexture) : lbTrnTex.texture; textureEntry.normal = lbTrnTex.normalMap; textureEntry.height = lbTrnTex.heightMap; textureNewEntryList.Add(textureEntry); //Debug.Log("[DEBUG] Adding new entry: " + lbTrnTex.texture.name); } } // In MicroSplat the first splatprototype sets the default tilesize if (lbTexIdx == 0) { // Convert UVs to MicroSplat tiling Vector3 terrainSize = landscape.GetLandscapeTerrainSize(); // scale, offset (default offset to 0,0) terrainMat.SetVector("_UVScale", new Vector4(1.0f / (lbTrnTex.tileSize.x / terrainSize.x), 1.0f / (lbTrnTex.tileSize.y / terrainSize.z), 0f, 0f)); } //Texture2DArray diff = textureArrayConfig.GetTexture("_Diffuse") as Texture2DArray; } } // Update the list of source textures in MicroSplat textureArrayConfig.sourceTextures = textureNewEntryList; staticMSTextureArrayConfig = textureArrayConfig; // Gets called once only, after all the Inspectors have been updated EditorApplication.delayCall += MicroSplatDelayedCompileConfig; } } }
/// <summary> /// Copy the Landscape textures from LB to MegaSplat /// EDITOR-ONLY /// </summary> /// <param name="landscape"></param> /// <param name="terrainMaterialType"></param> /// <param name="showErrors"></param> public static void MegaSplatCopyTextures(LBLandscape landscape, LBLandscape.TerrainMaterialType terrainMaterialType, bool showErrors) { string methodName = "LBEditorIntegration.MegaSplatCopyTextures"; // Basic validation if (landscape == null) { if (showErrors) { Debug.LogWarning(methodName + " - landscape cannot be null"); } } else if (terrainMaterialType != LBLandscape.TerrainMaterialType.MegaSplat) { if (showErrors) { Debug.LogWarning(methodName + " - The Landscape Terrain Settings needs to have a Material Type of Mega Splat. Please set and try again."); } } else if (landscape.terrainCustomMaterial == null) { if (showErrors) { Debug.LogWarning(methodName + " - the landscape does not appear to have a MegaSplat material. Has it been initialised in the Landscape Terrain Settings?"); } } else { UnityEngine.Object obj = UnityEditor.Selection.activeObject; if (obj != null) { System.Type cfgType = obj.GetType(); System.Type cfgEditorType = null; System.Type TerrainPainterWindowType = null; System.Type ITerrainPainterUtilityType = null; System.Type TerrainToMegaSplatConfigType = null; if (cfgType.FullName == "JBooth.MegaSplat.TextureArrayConfig") { //Debug.Log("MegaSplatCopyTextures cfgType found: " + cfgType.AssemblyQualifiedName); UnityEngine.Object objTerrainToMegaSplatConfig = LBIntegration.MegaSplatCreateTerrainToMegaSplatConfig(landscape, terrainMaterialType, obj, showErrors); // Get the textures from the landscape List <LBTerrainTexture> terrainTextureList = landscape.TerrainTexturesList(); if (terrainTextureList != null) { if (terrainTextureList.Count > 0) { // Add all the non-disabled textures to a list // Previously MegaSplat uses an array of Texture2Ds. Now it has a TextureEntry class // which can hold multiple textures (diffuse, normalmap, heightmap etc) List <JBooth.MegaSplat.TextureArrayConfig.TextureEntry> textureEntryList = new List <JBooth.MegaSplat.TextureArrayConfig.TextureEntry>(); JBooth.MegaSplat.TextureArrayConfig.TextureEntry textureEntry = null; for (int t = 0; t < terrainTextureList.Count; t++) { LBTerrainTexture lbTerrainTexture = terrainTextureList[t]; if (!lbTerrainTexture.isDisabled) { Texture2D texture2D = lbTerrainTexture.texture; if (texture2D != null) { textureEntry = new JBooth.MegaSplat.TextureArrayConfig.TextureEntry(); if (textureEntry != null) { textureEntry.diffuse = texture2D; textureEntry.normal = lbTerrainTexture.normalMap; textureEntry.height = lbTerrainTexture.heightMap; textureEntryList.Add(textureEntry); } } } } try { if (textureEntryList.Count > 0) { cfgEditorType = System.Type.GetType("JBooth.MegaSplat.TextureArrayConfigEditor, Assembly-CSharp-Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", true, true); TerrainPainterWindowType = System.Type.GetType("JBooth.TerrainPainter.TerrainPainterWindow, Assembly-CSharp-Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", true, true); ITerrainPainterUtilityType = System.Type.GetType("JBooth.TerrainPainter.ITerrainPainterUtility, Assembly-CSharp-Editor, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null", true, true); TerrainToMegaSplatConfigType = objTerrainToMegaSplatConfig.GetType(); var cfgEditorWindow = UnityEditor.EditorWindow.GetWindow <UnityEditor.EditorWindow>("Inspector", false); if (cfgEditorType == null) { if (showErrors) { Debug.LogWarning(methodName + " - could not find TextureArrayConfigEditor editor class. Please Report."); } } else if (TerrainPainterWindowType == null) { if (showErrors) { Debug.LogWarning(methodName + " - could not find TerrainPainterWindowType editor class. Please Report."); } } else if (ITerrainPainterUtilityType == null) { if (showErrors) { Debug.LogWarning(methodName + " - could not find ITerrainPainterUtilityType editor class. Please Report."); } } else if (TerrainToMegaSplatConfigType == null) { if (showErrors) { Debug.LogWarning(methodName + " - could not find TerrainToMegaSplatConfigType editor class. Please Report."); } } else { // LB 2.0.6 Beta 7j add compile step back in (was previously broken and had to be done manually in the editor) //string[] shaderFeatures = { "_TERRAIN" }; //LBIntegration.MegaSplatCompileShader(landscape, shaderFeatures, false, true); // Previously MegaSplat uses an array of Texture2Ds. Now it has a TextureEntry class cfgType.GetField("sourceTextures").SetValue(obj, textureEntryList); if (cfgEditorWindow != null) { cfgEditorType.InvokeMember("CompileConfig", System.Reflection.BindingFlags.InvokeMethod, null, null, new object[] { obj }); // Select the landscape in the Hierarchy and open the Terrain Painter window UnityEditor.Selection.activeGameObject = landscape.gameObject; var windowTerrainPainter = UnityEditor.EditorWindow.GetWindow(TerrainPainterWindowType, false); if (windowTerrainPainter == null) { Debug.LogWarning("LBIntegration.MegaSplatCopyTextures - Could not open TerrainPainter window. Please Report."); } else { // Add the TextureArrayConfig to the TerrainToMegaSplatConfig file TerrainToMegaSplatConfigType.InvokeMember("config", System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.Public, null, objTerrainToMegaSplatConfig, new object[] { obj }); // Updates the Paint tab in Terrain Painter TerrainPainterWindowType.InvokeMember("config", System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public, null, windowTerrainPainter, new object[] { obj }); // Initialise Utilities (else results in a timing issue where Utilities not found first time) TerrainPainterWindowType.InvokeMember("InitPluginUtilities", System.Reflection.BindingFlags.InvokeMethod | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public, null, windowTerrainPainter, new object[] { }); // We need to give time for MegaSplat to configure the Texture Array Debug.Log("INFO: Setting up MegaSplat Texture Array..."); // Update "config" field of the Terrain Converter on the Utilities tab IList utilitiesList = (IList)TerrainPainterWindowType.InvokeMember("utilities", System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public, null, windowTerrainPainter, new object[] { }); if (utilitiesList == null) { if (showErrors) { Debug.LogWarning("LBIntegration.MegaSplatCopyTextures - Could not find Utilities. Please Report."); } } else if (utilitiesList != null) { if (utilitiesList.Count == 0) { if (showErrors) { Debug.LogWarning("LBIntegration.MegaSplatCopyTextures - No Utilities found. Please Report."); } } // Located the Terrain To Splat Converter utility foreach (var tPainterInterface in utilitiesList) { if (tPainterInterface.ToString() == "JBooth.MegaSplat.TerrainToSplatConverter") { //Debug.Log("Interface: " + tPainterInterface.GetType().Name); tPainterInterface.GetType().InvokeMember("config", System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic, null, tPainterInterface, new object[] { objTerrainToMegaSplatConfig }); int tabIndex = LBIntegration.MegaSplatGetTerrainPainterTabIndex("Utility", true); // Show the Utilities tab TerrainPainterWindowType.InvokeMember("tab", System.Reflection.BindingFlags.SetField | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public, null, windowTerrainPainter, new object[] { tabIndex }); //var terrainJobs = TerrainPainterWindowType.InvokeMember("terrains", System.Reflection.BindingFlags.GetField | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Public, null, windowTerrainPainter, new object[] { }); ////Debug.Log("Calling OnGUI"); //tPainterInterface.GetType().InvokeMember("OnGUI", System.Reflection.BindingFlags.InvokeMethod, null, tPainterInterface, new object[] { terrainJobs }); break; } } } LBIntegration.MegaSplatUpdateShaderSplat(landscape, "Albedo", false, obj, true); } } else { Debug.LogWarning(methodName + " - Could not open TextureArrayConfigEditor window. Please Report."); } } } } catch (System.Exception ex) { if (showErrors) { Debug.LogWarning(methodName + " something has gone wrong (MegaSplat 1.73+ required). Please report. " + ex.Message); } } } } } else { Debug.LogWarning("MegaSplatCopyTextures - Please select the Texture Array Config in the Project window and try again."); } } else { Debug.LogWarning("MegaSplatCopyTextures - Please select the Texture Array Config in the Project window and try again."); } } }