Topic: A new way to capture terrains ?

Hi Alex,

The anchor you added in 4.4.0.1 is a great feature. You could add a checkbox “center anchor” and then calculate the center coordinates.

I would like to suggest another way to capture a terrain than selecting its boundaries, which is not always, to me, the most convenient.

The main problem is that if you want to get a nice horizon aspect (as if the terrain would be limitless) you need to capture a very large terrain.

I am using terrains within oculus Quest, so memory optimisation is very important.

My actual process is as follow (tell me what you think, maybe I am wrong…) :

I capture the terrain that I need with a high resolution. I prefer to capture large tiles (8192x8192) to avoid the meshes junction issues that may happen between the tiles.
I capture a larger terrain (5x the 1st terrain size) with a lower resolution.
I place the 1st terrain above the second one

As I use invisible fences around the high res terrain, the result is correct, but this process could be easier : it would be great if the resolution of the surrounding tiles could be automatically adjusted.

When I want to capture a terrain, I know 2 things :
the center of this terrain
the (approximative) area that I need in high resolution that could be adjusted to match the tiles.

The rest of the process could be automated, capturing all the needed tiles automatically, in the desired resolution, as shown on the picture below.

https://i.ibb.co/cwYK3YY/terrain-resolution.png

Another idea to improve the “infinite” horizon aspect could be to raise the mesh boudaries of the “external” terrains in order that they match the horizon line, I don’t know if this is possible.
Best regards,

Philippe

Re: A new way to capture terrains ?

Hello.

Thanks for the suggestions.

The suggestion for unique settings for each tile I marked in work.
But it will not be implemented in RWT 4x. Only in RWT 5.
Currently, this can be automated using RWT API.
Please give me 3-5 days and I will give you an example of how to do this.

The infinite horizon suggestion cannot be implemented, simply because there can be nothing infinite in Unity.
In addition, Unity has many bugs, when something have a large sizes or positions in the scene.

Kind Regards,
Infinity Code Team.

Do not know the best way to thank the developer? Rate the asset in Asset Store!

Re: A new way to capture terrains ?

Thanks Alex, keep me informed ! Best regards !

Re: A new way to capture terrains ?

Something like that:
https://i.ibb.co/TKDsWDr/img1.png

Place the script in the Editor folder, and run Menu / RWT / Automator.

using System;
using System.Collections.Generic;
using InfinityCode.RealWorldTerrain;
using InfinityCode.RealWorldTerrain.Windows;
using UnityEditor;
using UnityEngine;

public class AutomatorExample : EditorWindow
{
    private RealWorldTerrainContainer container;
    private List<Rule> rules = new List<Rule>();
    private Vector2 scrollPosition;
    private int status = 0; // 0 - idle, 1 - execute, 2 - finalize
    private int executeIndex = -1;
    private bool finished = false;

    private void Execute()
    {
        if (container == null) return;
        if (container.terrains == null) return;
        if (rules.Count == 0) return;

        status = 1;
        executeIndex = -1;
        ExecuteNextTerrain();
    }

    private void ExecuteNextTerrain()
    {
        int ruleIndex = -1;
        Rule activeRule = null;
        RealWorldTerrainItem item = null;

        do
        {
            executeIndex++;
            if (executeIndex == container.terrainCount)
            {
                status = 2;
                Repaint();
                return;
            }

            item = container.terrains[executeIndex];

            for (int i = 0; i < rules.Count; i++)
            {
                Rule rule = rules[i];
                if (rule.Contains(item) && rule.textureResolution != item.prefs.textureSize.x)
                {
                    activeRule = rule;
                    ruleIndex = i;
                    break;
                }
            }
        } while (activeRule == null);

        finished = false;

        Debug.Log(item + ", Rule - " + ruleIndex);

        RealWorldTerrainWindow.OpenWindow(RealWorldTerrainGenerateType.texture, item);

        RealWorldTerrainWindow.prefs.textureSize = new RealWorldTerrainVector2i(activeRule.textureResolution, activeRule.textureResolution);
        RealWorldTerrainWindow.OnCaptureCompleted += OnCaptureCompleted;
        RealWorldTerrainWindow.OnCaptureCanceled += OnCaptureCanceled;

        RealWorldTerrainWindow.StartCapture();
    }

    private void OnCaptureCanceled()
    {
        UnsubscribeFromEvents();

        status = 2;
    }

    private void OnCaptureCompleted()
    {
        UnsubscribeFromEvents();

        finished = true;
        Repaint();
    }

    private void OnGUI()
    {
        if (status == 0) OnIdleGUI();
        else if (status == 1) OnWaitGUI();
        else if (Event.current.type == EventType.Repaint)
        {
            status = 0;
            Repaint();
        }
    }

    private void OnIdleGUI()
    {
        int rulesCount = rules.Count;
        int moveUp = -1;
        int moveDown = -1;

        container = EditorGUILayout.ObjectField("RWT Container", container, typeof(RealWorldTerrainContainer), true) as RealWorldTerrainContainer;

        try
        {
            scrollPosition = EditorGUILayout.BeginScrollView(scrollPosition);
        }
        catch (Exception e)
        {
            Debug.Log(Event.current.type);
        }
        

        for (int i = 0; i < rulesCount; i++)
        {
            Rule rule = rules[i];

            EditorGUILayout.BeginHorizontal();

            EditorGUILayout.LabelField("From X", GUILayout.Width(50));
            rule.fromX = EditorGUILayout.IntField(rule.fromX);
            EditorGUILayout.LabelField("Y", GUILayout.Width(20));
            rule.fromY = EditorGUILayout.IntField(rule.fromY);

            EditorGUILayout.LabelField(" To X", GUILayout.Width(40));
            rule.toX = EditorGUILayout.IntField(rule.toX);
            EditorGUILayout.LabelField("Y", GUILayout.Width(20));
            rule.toY = EditorGUILayout.IntField(rule.toY);

            EditorGUILayout.LabelField(" Resolution", GUILayout.Width(80));
            rule.textureResolution = EditorGUILayout.IntField(rule.textureResolution);

            if (GUILayout.Button("Up", GUILayout.ExpandWidth(false))) moveUp = i;
            if (GUILayout.Button("Down", GUILayout.ExpandWidth(false))) moveDown = i;
            if (GUILayout.Button("X", GUILayout.ExpandWidth(false)))
            {
                rules.RemoveAt(i);
                rulesCount--;
            }

            EditorGUILayout.EndHorizontal();
        }

        EditorGUILayout.EndScrollView();

        if (moveUp > 0)
        {
            Rule t = rules[moveUp - 1];
            rules[moveUp - 1] = rules[moveUp];
            rules[moveUp] = t;
        }

        if (moveDown != -1 && moveDown < rulesCount - 1)
        {
            Rule t = rules[moveDown + 1];
            rules[moveDown + 1] = rules[moveDown];
            rules[moveDown] = t;
        }

        if (GUILayout.Button("Add")) rules.Add(new Rule());
        if (GUILayout.Button("Execute")) Execute();
    }

    private void OnWaitGUI()
    {
        if (finished) ExecuteNextTerrain();

        Rect rect = GUILayoutUtility.GetRect(GUIContent.none, GUI.skin.box, GUILayout.Height(20), GUILayout.ExpandWidth(true));
        float progress = (float)executeIndex / (container.terrainCount - 1);
        EditorGUI.ProgressBar(rect, progress, Mathf.FloorToInt(progress * 100) + " %");

        if (GUILayout.Button("Cancel"))
        {
            status = 2;
            RealWorldTerrainWindow.CancelCapture();
        }
    }

    [MenuItem("RWT/Automator")]
    private static void OpenWindow()
    {
        GetWindow<AutomatorExample>();
    }

    private void UnsubscribeFromEvents()
    {
        RealWorldTerrainWindow.OnCaptureCompleted -= OnCaptureCompleted;
        RealWorldTerrainWindow.OnCaptureCanceled -= OnCaptureCanceled;
    }

    internal class Rule
    {
        public int fromX;
        public int fromY;
        public int toX;
        public int toY;
        public int textureResolution = 256;

        public bool Contains(RealWorldTerrainItem item)
        {
            return fromX <= item.x && toX >= item.x && fromY <= item.y && toY >= item.y;
        }
    }
}
Kind Regards,
Infinity Code Team.

Do not know the best way to thank the developer? Rate the asset in Asset Store!

Re: A new way to capture terrains ?

Excellent ! Great improvement ! But I have an issue : it works fine with 1 tile, but if I have several tiles in 1 line or several lines each with several (or only one) tile, it seems that only 1 tile is downloaded ?
I can send a video if you want.
Thanks a lot !

Re: A new way to capture terrains ?

I tested this with the settings above for several terrains.
Yes, please send a video.

Kind Regards,
Infinity Code Team.

Do not know the best way to thank the developer? Rate the asset in Asset Store!

Re: A new way to capture terrains ?

You are right, I tested in another project and it works fine ! Awesome !
Thanks Alex !