private void UpdateTexture() { // create preview RT here and keep until the next Repaint if (m_previewRT != null) { RenderTexture.ReleaseTemporary(m_previewRT); } NoiseSettings noiseSettings = m_serializedNoise.targetObject as NoiseSettings; m_previewRT = RenderTexture.GetTemporary(512, 512, 0, RenderTextureFormat.ARGB32); RenderTexture tempRT = RenderTexture.GetTemporary(512, 512, 0, RenderTextureFormat.RFloat); RenderTexture prevActive = RenderTexture.active; NoiseUtils.Blit2D(noiseSettings, tempRT); NoiseUtils.BlitPreview2D(tempRT, m_previewRT); RenderTexture.active = prevActive; RenderTexture.ReleaseTemporary(tempRT); m_image.image = m_previewRT; }
private void Export2D() { Texture2D texture = null; try { string path = EditorUtility.SaveFilePanel("Export Noise To Texture2D", Application.dataPath, "New Noise Texture2D.png", "png"); if (!path.StartsWith(Application.dataPath)) { Debug.LogError("You must specificy a path in your project's Assets folder to export a Noise Texture"); } if (!string.IsNullOrEmpty(path)) { EditorUtility.DisplayProgressBar("Exporting Noise to Texture2D", "Making some noise...", 0.1f); texture = NoiseUtils.BakeToTexture2D(m_noise, dims2D.x, dims2D.y, m_format, TextureCreationFlags.None); byte[] bytes = ImageConversion.EncodeToPNG(texture); System.IO.File.WriteAllBytes(path, bytes); Texture2D.DestroyImmediate(texture); texture = null; string assetPath = path.Remove(0, Application.dataPath.Length - "Assets".Length); AssetDatabase.Refresh(); EditorUtility.ClearProgressBar(); texture = AssetDatabase.LoadAssetAtPath <Texture2D>(assetPath); EditorGUIUtility.PingObject(texture); } } catch (Exception e) { Debug.LogError(e); if (texture != null) { Texture2D.DestroyImmediate(texture); } Debug.Log("Exception caught"); EditorUtility.ClearProgressBar(); } }
private void Export3D() { Texture3D texture = null; var textureDims = m_exportDims3D.value; var textureFormat = m_exportFormat.value; try { string path = EditorUtility.SaveFilePanel("Export Noise To Texture3D", Application.dataPath, "New Noise Texture3D.asset", "asset"); if (string.IsNullOrEmpty(path)) { return; } if (!path.StartsWith(Application.dataPath)) { Debug.LogError("You must specificy a path in your project's Assets folder to export a Noise Texture"); } if (!string.IsNullOrEmpty(path) && path.StartsWith(Application.dataPath)) { EditorUtility.DisplayProgressBar("Exporting Noise to Texture3D", "Making some noise...", 0.1f); texture = NoiseUtils.BakeToTexture3D(m_noiseUpdateTarget, textureDims.x, textureDims.y, textureDims.z, textureFormat, TextureCreationFlags.None); AssetDatabase.CreateAsset(texture, path.Remove(0, Application.dataPath.Length - "Assets".Length)); AssetDatabase.Refresh(); EditorUtility.ClearProgressBar(); EditorGUIUtility.PingObject(texture); } } catch (Exception e) { Debug.LogError(e); if (texture != null) { Texture2D.DestroyImmediate(texture); } EditorUtility.ClearProgressBar(); } }
/// <summary> /// Renders an interactive Noise Preview along with tooltip icons and an optional Export button that opens a new ExportNoiseWindow. /// A background image is also rendered behind the preview that takes up the entire width of the EditorWindow currently being drawn. /// </summary> /// <param name = "minSize"> Minimum size for the Preview </param> /// <param name = "showExportButton"> Whether or not to render the Export button </param> public void DrawPreviewTexture(float minSize, bool showExportButton = true) { // Draw label with tooltip GUILayout.Label(Styles.noisePreview); float padding = 4f; float iconWidth = 40f; int size = (int)Mathf.Min(minSize, EditorGUIUtility.currentViewWidth); Rect totalRect = GUILayoutUtility.GetRect(EditorGUIUtility.currentViewWidth, size + padding * 2); // extra pixels for highlight border Color prev = GUI.color; GUI.color = new Color(.1f, .1f, .1f, 1f); GUI.DrawTexture(totalRect, Texture2D.whiteTexture, ScaleMode.StretchToFill, false); GUI.color = Color.white; // draw info icon // if(totalRect.Contains(Event.current.mousePosition)) { Rect infoIconRect = new Rect(totalRect.x + padding, totalRect.y + padding, iconWidth, iconWidth); GUI.Label(infoIconRect, Styles.infoIcon); // GUI.Label( infoIconRect, Styles.noiseTooltip ); } // draw export button float buttonWidth = GUI.skin.button.CalcSize(Styles.export).x; float buttonHeight = EditorGUIUtility.singleLineHeight; Rect exportRect = new Rect(totalRect.xMax - buttonWidth - padding, totalRect.yMax - buttonHeight - padding, buttonWidth, buttonHeight); if (GUI.Button(exportRect, Styles.export)) { serializedNoise.ApplyModifiedProperties(); serializedNoise.Update(); ExportNoiseWindow.ShowWindow(serializedNoise.targetObject as NoiseSettings); } float safeSpace = Mathf.Max(iconWidth * 2, buttonWidth * 2) + padding * 4; float minWidth = Mathf.Min(size, totalRect.width - safeSpace); Rect previewRect = new Rect(totalRect.x + totalRect.width / 2 - minWidth / 2, totalRect.y + totalRect.height / 2 - minWidth / 2, minWidth, minWidth); EditorGUIUtility.AddCursorRect(previewRect, MouseCursor.Pan); if (previewRect.Contains(Event.current.mousePosition)) { serializedNoise.Update(); HandlePreviewTextureInput(previewRect); serializedNoise.ApplyModifiedProperties(); } if (Event.current.type == EventType.Repaint) { // create preview RT here and keep until the next Repaint if (m_previewRT != null) { RenderTexture.ReleaseTemporary(m_previewRT); } NoiseSettings noiseSettings = serializedNoise.targetObject as NoiseSettings; m_previewRT = RenderTexture.GetTemporary(512, 512, 0, RenderTextureFormat.ARGB32); RenderTexture tempRT = RenderTexture.GetTemporary(512, 512, 0, RenderTextureFormat.RFloat); RenderTexture prevActive = RenderTexture.active; NoiseUtils.Blit2D(noiseSettings, tempRT); NoiseUtils.BlitPreview2D(tempRT, m_previewRT); RenderTexture.active = prevActive; GUI.DrawTexture(previewRect, m_previewRT, ScaleMode.ScaleToFit, false); RenderTexture.ReleaseTemporary(tempRT); } GUI.color = prev; }
public override void Eval(FilterContext fc) { if (m_noiseSettings == null) { m_noiseSettings = ScriptableObject.CreateInstance <NoiseSettings>(); } m_noiseSettings.useTextureForPositions = m_useHeightmap; if (m_useHeightmap) { m_noiseSettings.positionTexture = fc.renderTextureCollection[FilterContext.Keywords.Heightmap]; } Vector3 brushPosWS = fc.brushPos; float brushSize = fc.brushSize; float brushRotation = fc.brushRotation; // TODO(wyatt): remove magic number and tie it into NoiseSettingsGUI preview size somehow float previewSize = 1 / 512f; // get proper noise material from current noise settings NoiseSettings noiseSettings = m_noiseSettings; Material mat = NoiseUtils.GetDefaultBlitMaterial(noiseSettings); // setup the noise material with values in noise settings noiseSettings.SetupMaterial(mat); // convert brushRotation to radians brushRotation *= Mathf.PI / 180; // change pos and scale so they match the noiseSettings preview bool isWorldSpace = false == m_isLocalSpace; brushSize = isWorldSpace ? brushSize * previewSize : 1; brushPosWS = isWorldSpace ? brushPosWS * previewSize : Vector3.zero; // // override noise transform Quaternion rotQ = Quaternion.AngleAxis(-brushRotation, Vector3.up); Matrix4x4 translation = Matrix4x4.Translate(brushPosWS); Matrix4x4 rotation = Matrix4x4.Rotate(rotQ); Matrix4x4 scale = Matrix4x4.Scale(Vector3.one * brushSize); Matrix4x4 noiseToWorld = translation * scale; mat.SetMatrix(NoiseSettings.ShaderStrings.transform, noiseSettings.trs * noiseToWorld); int pass = NoiseUtils.kNumBlitPasses * NoiseLib.GetNoiseIndex(noiseSettings.domainSettings.noiseTypeName); RenderTextureDescriptor desc = new RenderTextureDescriptor(fc.destinationRenderTexture.width, fc.destinationRenderTexture.height, RenderTextureFormat.RFloat); RenderTexture rt = RenderTexture.GetTemporary(desc); Graphics.Blit(fc.sourceRenderTexture, rt, mat, pass); Material blendMat = FilterUtility.blendModesMaterial; blendMat.SetTexture("_MainTex", fc.sourceRenderTexture); blendMat.SetTexture("_BlendTex", rt); Graphics.Blit(fc.sourceRenderTexture, fc.destinationRenderTexture, blendMat, 1); RenderTexture.ReleaseTemporary(rt); }
//=================================================================================================== // // APPLY BRUSH // //=================================================================================================== private void ApplyBrushInternal(PaintContext ctx, BrushTransform brushXform, Vector3 brushPosWS, float brushRotation, float brushStrength, float brushSize, Texture brushTexture) { brushPosWS.y = 0; /* * blit steps * 1. blit noise to intermediate RT, this includes all the noise transformations and filters, * using the appropriate noise material. do this with NoiseUtils.Blit2D? * 2. use that noise texture and mult it with brushmask to paint height on terrain */ // TODO(wyatt): remove magic number and tie it into NoiseSettingsGUI preview size somehow float previewSize = 1 / 512f; // get proper noise material from current noise settings NoiseSettings noiseSettings = this.noiseSettings; Material matNoise = NoiseUtils.GetDefaultBlitMaterial(noiseSettings); // setup the noise material with values in noise settings noiseSettings.SetupMaterial(matNoise); // convert brushRotation to radians brushRotation *= Mathf.PI / 180; // change pos and scale so they match the noiseSettings preview bool isWorldSpace = (m_toolSettings.coordSpace == CoordinateSpace.World); brushSize = isWorldSpace ? brushSize * previewSize : 1; brushPosWS = isWorldSpace ? brushPosWS * previewSize : Vector3.zero; // // override noise transform Quaternion rotQ = Quaternion.AngleAxis(-brushRotation, Vector3.up); Matrix4x4 translation = Matrix4x4.Translate(brushPosWS); Matrix4x4 rotation = Matrix4x4.Rotate(rotQ); Matrix4x4 scale = Matrix4x4.Scale(Vector3.one * brushSize); Matrix4x4 noiseToWorld = translation * scale; matNoise.SetMatrix(NoiseSettings.ShaderStrings.transform, noiseSettings.trs * noiseToWorld); // render the noise field to a texture // TODO(wyatt): Handle the 3D case. Would need to blit to Volume Texture int rtW = ctx.destinationRenderTexture.width; int rtH = ctx.destinationRenderTexture.height; RenderTextureFormat rtF = RenderTextureFormat.RFloat; RenderTextureDescriptor rtDesc = new RenderTextureDescriptor(rtW, rtH, rtF); RenderTexture noiseRT = RenderTexture.GetTemporary(rtDesc); RenderTexture tempRT = RenderTexture.GetTemporary(noiseRT.descriptor); RenderTexture prev = RenderTexture.active; RenderTexture.active = tempRT; int noisePass = NoiseUtils.kNumBlitPasses * NoiseLib.GetNoiseIndex(noiseSettings.domainSettings.noiseTypeName); Graphics.Blit(tempRT, matNoise, noisePass); RenderTexture.active = noiseRT; // if(noiseSettings.filterSettings.filterStack != null) // { // noiseSettings.filterSettings.filterStack.Eval(tempRT, noiseRT); // } // else { Graphics.Blit(tempRT, noiseRT); } RenderTexture.active = prev; RenderTexture.ReleaseTemporary(tempRT); // then add the result to the heightmap using the noise height tool shader Material matFinal = paintMaterial; TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushXform, matFinal); // set brush params Vector4 brushParams = new Vector4(0.01f * brushStrength, 0.0f, brushSize, 1 / brushSize); matFinal.SetVector("_BrushParams", brushParams); matFinal.SetTexture("_BrushTex", brushTexture); matFinal.SetTexture("_NoiseTex", noiseRT); matFinal.SetVector("_WorldHeightRemap", m_toolSettings.worldHeightRemap); Graphics.Blit(ctx.sourceRenderTexture, ctx.destinationRenderTexture, matFinal, 0); RenderTexture.ReleaseTemporary(noiseRT); }
//=================================================================================================== // // APPLY BRUSH // //=================================================================================================== private void ApplyBrushInternal(Terrain terrain, PaintContext ctx, BrushTransform brushXform, Vector3 brushPosWS, float brushRotation, float brushStrength, float brushSize, Texture brushTexture) { var prevRT = RenderTexture.active; brushPosWS.y = 0; /* * blit steps * 1. blit noise to intermediate RT, this includes all the noise transformations and filters, * using the appropriate noise material. do this with NoiseUtils.Blit2D? * 2. use that noise texture and mult it with brushmask to paint height on terrain */ // TODO(wyatt): remove magic number and tie it into NoiseSettingsGUI preview size somehow float previewSize = 1 / 512f; // get proper noise material from current noise settings NoiseSettings noiseSettings = this.noiseSettings; Material matNoise = NoiseUtils.GetDefaultBlitMaterial(noiseSettings); // setup the noise material with values in noise settings noiseSettings.SetupMaterial(matNoise); // convert brushRotation to radians brushRotation *= Mathf.PI / 180; // change pos and scale so they match the noiseSettings preview bool isWorldSpace = (m_toolSettings.coordSpace == CoordinateSpace.World); brushSize = isWorldSpace ? brushSize * previewSize : 1; brushPosWS = isWorldSpace ? brushPosWS * previewSize : Vector3.zero; // // override noise transform var rotQ = Quaternion.AngleAxis(-brushRotation, Vector3.up); var translation = Matrix4x4.Translate(brushPosWS); var rotation = Matrix4x4.Rotate(rotQ); var scale = Matrix4x4.Scale(Vector3.one * brushSize); var noiseToWorld = translation * scale; matNoise.SetMatrix(NoiseSettings.ShaderStrings.transform, noiseSettings.trs * noiseToWorld); var noisePass = NoiseUtils.kNumBlitPasses * NoiseLib.GetNoiseIndex(noiseSettings.domainSettings.noiseTypeName); // render the noise field to a texture // TODO(wyatt): Handle the 3D case. Would need to blit to Volume Texture var rtDesc = ctx.destinationRenderTexture.descriptor; rtDesc.graphicsFormat = NoiseUtils.singleChannelFormat; rtDesc.sRGB = false; var noiseRT = RTUtils.GetTempHandle(rtDesc); RenderTexture.active = noiseRT; // keep this Graphics.Blit(noiseRT, matNoise, noisePass); // then add the result to the heightmap using the noise height tool shader Material matFinal = paintMaterial; var brushMask = RTUtils.GetTempHandle(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height, 0, FilterUtility.defaultFormat); Utility.SetFilterRT(commonUI, ctx.sourceRenderTexture, brushMask, matFinal); TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushXform, matFinal); // set brush params Vector4 brushParams = new Vector4(0.01f * brushStrength, 0.0f, brushSize, 1 / brushSize); matFinal.SetVector("_BrushParams", brushParams); matFinal.SetTexture("_BrushTex", brushTexture); matFinal.SetTexture("_NoiseTex", noiseRT); matFinal.SetVector("_WorldHeightRemap", m_toolSettings.worldHeightRemap); Graphics.Blit(ctx.sourceRenderTexture, ctx.destinationRenderTexture, matFinal, 0); RTUtils.Release(noiseRT); RTUtils.Release(brushMask); RenderTexture.active = prevRT; }
private void ApplyBrushInternal(Terrain terrain, PaintContext ctx, BrushTransform brushTransform) { Init(); Vector3 brushPos = new Vector3(commonUI.raycastHitUnderCursor.point.x, 0, commonUI.raycastHitUnderCursor.point.z); FilterContext fc = new FilterContext(terrain, brushPos, commonUI.brushSize, commonUI.brushRotation); fc.renderTextureCollection.GatherRenderTextures(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height); RenderTexture filterMaskRT = commonUI.GetBrushMask(fc, ctx.sourceRenderTexture); m_rtCollection.ReleaseRenderTextures(); m_rtCollection.GatherRenderTextures(ctx.sourceRenderTexture.width, ctx.sourceRenderTexture.height, 16); Graphics.Blit(ctx.sourceRenderTexture, m_rtCollection[RenderTextureIDs.sourceHeight]); Material mat = GetMaterial(); Matrix4x4 toolMatrix = Matrix4x4.TRS(Vector3.zero, toolSettings.rotation, toolSettings.scale); Bounds modelBounds = activeMesh.bounds; float maxModelScale = Mathf.Max(Mathf.Max(modelBounds.size.x, modelBounds.size.y), modelBounds.size.z); // maxModelScale *= Mathf.Sqrt( 2 + maxModelScale * maxModelScale / 4 ) * .5f; // mult so the mesh fits a little better within the camera / stamp texture bounds // maxModelScale /= 1.414f; float x = .5f; float y = .5f; float xy = Mathf.Sqrt(x * x + y * y); float z = .5f; float xyz = Mathf.Sqrt(xy * xy + z * z); maxModelScale *= xyz; // build the model matrix to transform the mesh with. we want to scale it to fit in the brush bounds and also center it in the brush bounds Matrix4x4 model = toolMatrix * Matrix4x4.Scale(Vector3.one / maxModelScale) * Matrix4x4.Translate(-modelBounds.center); // get the world bounds here so we can calculate the needed offset along the up axis // Bounds worldBounds = MeshUtility.TransformBounds( model, activeMesh.bounds ); // float localHeightOffset = Mathf.Min( worldBounds.extents.y, toolSettings.stampHeight / brushUI.terrainUnderCursor.terrainData.size.y * .5f ); // Matrix4x4 localHeightOffsetMatrix = Matrix4x4.Translate( Vector3.up * localHeightOffset ); // apply the local height offset // model = localHeightOffsetMatrix * model; Vector3 translate = Vector3.up * (toolSettings.stampHeight) / commonUI.terrainUnderCursor.terrainData.size.y; // translate = translate / brushUI.brushStrength * .5f; model = Matrix4x4.Translate(translate) * model; // actually render the mesh to texture to be used with the tool shader TerrainTools.MeshUtility.RenderTopdownProjection(activeMesh, model, m_rtCollection[RenderTextureIDs.meshStamp], TerrainTools.MeshUtility.defaultProjectionMaterial, TerrainTools.MeshUtility.ShaderPass.Height); NoiseUtils.BlitPreview2D(m_rtCollection[RenderTextureIDs.meshStamp], m_rtCollection[RenderTextureIDs.meshStampPreview]); // generate a mask for the mesh to be used in the compositing shader TerrainTools.MeshUtility.RenderTopdownProjection(activeMesh, model, m_rtCollection[RenderTextureIDs.meshStampMask], TerrainTools.MeshUtility.defaultProjectionMaterial, TerrainTools.MeshUtility.ShaderPass.Mask); // perform actual composite of mesh stamp and terrain source heightmap float brushStrength = Event.current.control ? -commonUI.brushStrength : commonUI.brushStrength; Vector4 brushParams = new Vector4(brushStrength, toolSettings.blendAmount, (commonUI.raycastHitUnderCursor.point.y - commonUI.terrainUnderCursor.GetPosition().y) / commonUI.terrainUnderCursor.terrainData.size.y * .5f, toolSettings.stampHeight / commonUI.terrainUnderCursor.terrainData.size.y * .5f); mat.SetVector("_BrushParams", brushParams); mat.SetTexture("_MeshStampTex", m_rtCollection[RenderTextureIDs.meshStamp]); mat.SetTexture("_FilterTex", filterMaskRT); mat.SetTexture("_MeshMaskTex", m_rtCollection[RenderTextureIDs.meshStampMask]); mat.SetFloat("_TerrainHeight", commonUI.terrainUnderCursor.terrainData.size.y); TerrainPaintUtility.SetupTerrainToolMaterialProperties(ctx, brushTransform, mat); Graphics.Blit(ctx.sourceRenderTexture, ctx.destinationRenderTexture, mat, 0); Graphics.Blit(ctx.destinationRenderTexture, m_rtCollection[RenderTextureIDs.combinedHeight]); // restore old render target RenderTexture.active = ctx.oldRenderTexture; }