Как нарисовать контур в Unity3d?


13

Я пытаюсь выделить прямоугольник произвольной высоты. Я подумал, что самый простой способ сделать это - создать отдельный игровой объект «прямоугольник», который очерчивает прямоугольник.

Я попытался с помощью MeshRenderer + Transparent Texture и LineRenderer обвести четыре точки прямоугольника. Ни один из них не очень удовлетворителен.

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

(Линия рендерера включена в середине, масштабированный куб справа)

Как правильно это сделать? Я пытаюсь получить что-то вроде левого прямоугольника - простой периметр фиксированной ширины через четыре точки по моему выбору.

Ответы:


8

Использование GUI.Box().

Если вам нужен только двухмерный прямоугольник, лучше всего использовать GUI. Создайте новый GUIStyle, используя простой прямоугольник в качестве текстуры (конечно, внутренняя часть прямоугольника должна быть прозрачной), установите его Borderзначение так, чтобы оно не растягивалось, и вызовите GUI.Box(new Rect(...),"",myGuiStyle);.

Вы можете использовать Camera.WorldToScreenPointметод, если хотите нарисовать что-то в мировых координатах (например, в 3D), просто помните, что в мировых координатах Unity 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 всегда рисуется после других объектов. Есть хак, который вы можете использовать, чтобы визуализировать отдельную камеру поверх графического интерфейса, но это довольно громоздко.
— Nevermind

Этот ответ дал мне то, что мне было нужно, но я пока держу его открытым в надежде, что в общем случае есть лучший способ сделать это.
— Raven Dreamer

Я принял ваш пример добавления кода редактирования и исправил в нем ошибку GUI-y-up-down.
— Nevermind

1

Ниже приведен не шейдерный подход.

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

Имея это в виду, вы можете разработать, скажем BoxBuilder, Компонент, который при подключении к GameObject создает и управляет четырьмя дочерними объектами GameObject. Каждый дочерний игровой объект является одним из ребер вашего бокса и может быть просто трехмерным кубом, растянутым только в одном измерении. С widthи heightопределенном BoxBuilderуровне, можно рассчитать необходимое позиционирование и неравномерную шкалу четырех детей края. Это будет много pos.x=w/2, pos.y=h/2, ..., scale.x=h,scale.y=w и т.д. вид кода.

Хотя я полагаю, что вы запрашиваете только BoxBuilderдвумерные изображения , обратите внимание, что эту же идею можно применить к трехмерным блокам, если это необходимо, где теперь необходимо создать и управлять 12 дочерними ребрами, но опять же только масштабировать каждое ребро в одном локальном измерении.


Работоспособный, но Слишком сложный.
— Nevermind

Если бы мне пришлось делать это таким образом, я бы просто использовал 4 линейных рендера ...
— Raven Dreamer

Однако это правильно обрабатывает глубину.
— DuckMaestro

1

Простой способ - использовать шейдер с двумя проходами: первый проход использует вершинный шейдер, чтобы немного увеличить масштаб объекта, и использует пиксельный шейдер, чтобы закрасить его до сплошного цвета, соответствующего цвету, который должен иметь контур, и затем второй проход делает обычный рендеринг.


Не могли бы вы привести пример кода, чтобы лучше объяснить, что вы имеете в виду?
— Raven Dreamer

Это будет работать только для выпуклых объектов (например, прямоугольника), источник которых находится в его геометрическом центре.
— rootlocus

1

У меня была такая же проблема при создании контура, за исключением того, что мне нужно было создать «обводку» для 3d-куба, и я нашел новый способ сделать это, чего я не видел нигде в Интернете.

На изображении ниже есть две фигуры с очертаниями. Правый - это куб, построенный с помощью LineRenderer, который строит плоские грани, которые всегда обращены к пользователю. Я нашел этот метод супер глючным, со случайными «штрихами», которые имитируют треугольники, составляющие лицо.

Слева - мое «новшество» с 12-ю отдельными тощими кубиками, создающими то, что выглядит как контур. Чтобы изменить размер «обводки» в контуре, мне нужно увеличить / уменьшить размеры двух сторон каждого из 12 тощих кубов. Это также будет работать для двухмерных контуров. Просто примените материал, чтобы изменить цвет и вуаля!

два разных контура

На этом изображении вы можете увидеть детали структуры этого куба. Все это может быть создано во время выполнения, но я сделал это вручную и использовал его в качестве сборного.

подробно


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.