Як я можу намалювати контур у Unity3d?


13

Я намагаюся виділити прямокутник довільної висоти. Я подумав, що найпростішим способом це буде створити окремий «коробковий» ігровий об’єкт, який окреслює прямокутник.

Я намагався і з MeshRenderer + прозорою текстурою, і з LineRenderer окреслити чотири точки прямокутника. Жоден із них не є дуже задовільним.

введіть тут опис зображення

(Лінійний рендерінг посередині, масштабний куб праворуч)

Який правильний шлях для цього? Я намагаюся отримати щось на зразок лівого прямокутника - простий периметр фіксованої ширини через чотири точки, що я вибираю.

Відповіді:


8

Використовуйте GUI.Box().

Якщо вам потрібен лише 2D прямокутник, GUI - це шлях. Створіть новий GUIStyle, використовуючи простий прямокутник як текстуру (внутрішня частина прямокутника, звичайно, повинна бути прозорою), встановіть його Borderзначення, щоб він не розтягувався, і зателефонуйте GUI.Box(new Rect(...),"",myGuiStyle);.

Ви можете використовувати Camera.WorldToScreenPointметод, якщо ви хочете окреслити щось у світових координатах (тобто 3D), просто пам’ятайте, що у світових координатах Unity y переходить y знизу вгору, а в GUI y іде зверху вниз.

Приклад коду:

void OnGUI()
{
    //top left point of rectangle
    Vector3 boxPosHiLeftWorld = new Vector3(0.5f, 12, 0);
    //bottom right point of rectangle
    Vector3 boxPosLowRightWorld = new Vector3(1.5f, 0, 0);

    Vector3 boxPosHiLeftCamera = Camera.main.WorldToScreenPoint(boxPosHiLeftWorld);
    Vector3 boxPosLowRightCamera = Camera.main.WorldToScreenPoint(boxPosLowRightWorld);

    float width = boxPosHiLeftCamera.x - boxPosLowRightCamera.x;
    float height = boxPosHiLeftCamera.y - boxPosLowRightCamera.y;


     GUI.Box(new Rect(boxPosHiLeftCamera.x, Screen.Height - boxPosHiLeftCamera.y, width, height),"", highlightBox);
}

Якщо я не помиляюся, GUI.Box () завжди буде намальований поверх будь-яких об'єктів на сцені? Чи можливо мати елемент GUI позаду або частково позаду ігрового об’єкта?
Сонник ворон

Так, GUI завжди малюється після інших об'єктів. Існує хак, який можна використовувати для візуалізації окремої камери поверх GUI, але це начебто грозно.
Nevermind

Ця відповідь дала мені те, що мені потрібно, але я залишаю її відкритою поки що, сподіваючись, що є кращий спосіб зробити це в загальному випадку.
Сонник ворон

Я прийняв ваш зразок редагування, додавши код, і виправив помилку GUI-y-догори дном.
Nevermind

1

Нижче наводиться не-шейдерний підхід.

Подумайте про своє 2d вікно як не більше ніж про чотири лінії, де кожна лінія розтягнута лише на один вимір (інші два виміри - це поперечний переріз краю). Це дуже схоже на те, якби ви побудували коробку в реальному житті, де ви збираєте деревину різної довжини, яка має однаковий розмір поперечного перерізу.

Зважаючи на це, ви можете розробити компонент, скажімо BoxBuilder, який, приєднавшись до GameObject, створює та керує чотирма дочірніми GameObjects. Кожен об’єкт дитячої гри є одним із ваших країв коробки, і може просто бути кубиком 3d, який розтягується лише на один вимір. За допомогою widthта heightвизначеного BoxBuilderрівня можна обчислити необхідне розміщення та нерівномірну шкалу чотирьох дочірніх країв. Це буде багато pos.x=w/2, pos.y=h/2..., scale.x=h, scale.y=wі т.д. вид коду.

Хоча я вважаю, що ви просите лише 2-d, зауважте, що ця сама ідея може бути застосована до 3d-ящиків, якщо BoxBuilderзараз потрібно створити та керувати 12 дочірніми краями, але знову лише масштабування кожного краю в одному локальному вимірі.


Працездатний, але ШЛЯХ занадто складний.
Nevermind

Якби мені довелося це зробити так, я просто використав би 4-ма рядкові рендери ...
Ворон Мрійника

Однак це все правильно справляється з глибиною.
DuckMaestro

1

Простим способом є використання шейдера з двома проходами: перший прохід використовує шейдер вершини, щоб трохи масштабувати об’єкт, і використовує піксельний шейдер, щоб пофарбувати його до суцільного кольору, відповідного кольору, який ви хочете мати контур, і то другий прохід робить регулярну рендерінг.


Чи можете ви навести приклад коду, щоб краще пояснити, що ви маєте на увазі?
Ворон Сонник

Це буде працювати лише для опуклих об'єктів (як прямокутник), походження яких знаходиться в його геометричному центрі.
rootlocus

1

У мене була ця сама проблема створення контуру, за винятком того, що мені потрібно було створити "штрих" для 3d-куба, і я знайшов новий спосіб зробити це, якого я ще ніде в Інтернеті не бачив.

На зображенні внизу є дві форми з контурами. Справа - куб, створений за допомогою LineRenderer, який створює плоскі грані, які завжди повертаються до користувача. Я виявив, що цей метод є надзвичайно глючним, із випадковими "штрихами", які імітують трикутники, що складають обличчя.

Ліворуч - це моє «нововведення» з 12 окремих кубиків, що створюють те, що схоже на контур. Щоб змінити розмір "штриха" у контуру, мені потрібно збільшити / зменшити розміри двох сторін кожного з 12 худих кубів. Це також буде працювати для 2d контури. Просто нанесіть матеріал, щоб змінити колір і вуаля!

два різні контури

На цьому зображенні ви можете побачити деталі будови цього куба. Це все можна створити під час виконання, але я зробив це вручну і використав його як збірний засіб.

докладно


0

В даний час я стикаюся з тією самою проблемою, і моє рішення полягає саме в тому, що запропонували DuckMaestro і Raven Dreamer - Скрипт, який створює 4 дочірні об’єкти під час виконання, кожен з яких представляє сторону кордону і приєднувати рендери ліній до кожного.

У моєму випадку мені потрібно було постійно змінювати розмір кордону, щоб зберегти його навколо мого об'єкта (Текстова сітка [для якої використовується мережевий візуалізатор] для користувацького текстового поля), тому кожне оновлення я робив так:


float width = Mathf.Max(renderer.bounds.size.x + paddingX * 2, minWidth);      
float x = renderer.bounds.center.x - width / 2;
float height = renderer.bounds.size.y + paddingY * 2;
float y = renderer.bounds.center.y - height / 2;

AlterBorder(0, new Vector3(x - thickness / 2, y, 0), new Vector3(x + width + thickness / 2, y, 0)); //Bottom edge going left to right
AlterBorder(1, new Vector3(x + width, y + thickness / 2, 0), new Vector3(x + width, y + height - thickness / 2, 0)); //Right edge going bottom to top
AlterBorder(2, new Vector3(x + width + thickness / 2, y + height, 0), new Vector3(x - thickness / 2, y + height, 0)); //Top edge going right to left
AlterBorder(3, new Vector3(x, y + height - thickness / 2, 0), new Vector3(x, y + thickness / 2, 0)); //Left edge going top to bottom

AlterBorder() просто отримує доступ до відповідного рендерінга рядка (вказаний першим параметром) і встановлює його початок і кінець відповідно на перший і другий вектор.

Зауважте, що я використовував rendererяк орієнтир розмір, але очевидно, що ви можете використовувати будь-який прямокутник, якщо х, у - верхній лівий кут.

З того, що я можу сказати, це працює дуже добре, чудово виглядає в грі, тому що я можу легко переміщати мій облямований об'єкт на всіх 3-х осях (Навіть обертати його, а оскільки рендери завжди стикаються з камерою, це не виглядає дивно), і це не важко здійснити.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.