Форум

Изменение стиля контура объектов

13 ноября 2017 05:22
Добрый день,

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


Пробовал искать возможности управления рёбрами объектов, но ничего не нашел , пробовал Vertex paint, но он красит и плоскости.
Пытался приспособить под это отрисовку линий через m_geom.draw_line, но на каждую линию тут нужен empty object, а копировать их в коде нельзя.

Пробовал применить Wireframe Modifier - в целом, получается похоже, но не совсем то, что нужно. Во-первых, такая обрешётка должна выпирать из объекта (что портит его точные размеры и заметно при приближении), во-вторых, при отдалении (или отртогональной проекции) качество отрисовки тонкой обрешётки очень низко и ее, практически не видно.

Подскажите, пожалуйста, возможно ли такое, в принципе?
Если это нереализуемо на движке, то может существуют какие-то иные способы? (например, разобрать объект до рёбер и контролировать отрисовку, перекрыть закраску плоскостей при vertex paint, научиться плодить много empty object c линиями из кода или получить контекст canvas и рисовать на нем самостоятельно)
13 ноября 2017 16:13
В данный момент есть возможность отображать в wireframe режиме только все объекты сразу(wireframe.zip).

В данный момент также возможен такой вариант симуляции обводки.
Для этого нужно продублировать меш, поменять у него материал на цвет обводки, поскейлить и вывернуть нормали.
Александр (команда Blend4Web)
twitter
17 ноября 2017 21:50
Спасибо, интересный вариант.

К сожалению, он сочетает в себе проблемы всех предыдущих вариантов
  • изменяет реальные размеры объекта как при Wireframe Modifier
  • обводит только "задние" границы объекта (как обычный outline)
  • на большой дистанции практически неразличим

Может быть есть какие-то программные способы обойти ограничения? (вплоть до ручного рисования на канвасе)
22 ноября 2017 15:38
Есть один момент, который в текущем состоянии движка потребует дополнительный анализ геометрии. Момент это заглючается в том, что движок сейчас умеет работать только с полигонами с количеством вершин равным 3, поскольку он заточен под рендеринг, и все данные оптимизированы для видеокарты, которая тоже умеет работать только с треугольниками. Поэтому грани кубика будут порезаны на треугольники без предварительной обработки. Проанализировав геометрию можно убрать лишние ребра например простым сравнение нормалей треугольников делящих ребро (векторное произведение близко или равно нулю).

В текущей ситуации с движком, самым реальным решением является отрисовка сетчатого каркаса, немного смещенного процедурно в направлении к камере (для правильного отсечения по глубине). Хоть этот метод и имеет свои проблемы например в Blender, но все-же сейчас его реализовать проще всего.
Для получения геометрии используйте extract_vertex_array и extract_index_array
Для создания объекта линии, не привязанной к Empty используйте create_line.

Метод хорош тем, что позволяет отрисовать любые ребра, в том числе и висячие.
Александр (команда Blend4Web)
twitter
24 ноября 2017 09:26
Это как раз то, что нужно.
Все получилось.

Спасибо за помощь!
24 ноября 2017 19:35
Это как раз то, что нужно.
Все получилось.

Спасибо за помощь!
Поделитесь решением?
25 ноября 2017 11:09
В общем, все оказалось, действительно, не сложно.
Я делаю так:
// исходный объект
const obj = ...
// получаем геометрию объекта
const vertex = m_geom.extract_vertex_array(obj, 'material', 'a_position');
// разбиваем сплошной массив координат на массив точек (для удобства дальнейшего выбора)
const points = splitPoints(vertex);
// выбираем координаты заданных вершин обратно в сплошной массив
// данная магическая последовательность выбрана эмпирически и символизирует обход всех вершин одной сплошной линией (правда, по некоторым ребрам она проходит несколько раз)
const linepoints = reducePoints(points, [3,9,21,15,3,0,6,9,21,18,6,0,12,15,21,18,12]);

// создаем объект линии
const line = m_obj.create_line('line-name');
// рисуем ломанную линию
m_geom.draw_line(line, linepoints);
// задаем параметры ее отображения
m_mat.set_line_params(line, {
  color: new Float32Array([0.0, 0.0, 0.0, 1.0]), // черный цвет
  width: 5
});

// привязываем линию к исходному объекты (при перемещении и поворотах она будет следовать за объектом)
m_const.append_stiff_trans_rot(line, obj);    

// если обводку надо временно скрыть, то можно убрать ей толщину до нуля
m_mat.set_line_params(line, {
  color: new Float32Array([0.0, 0.0, 0.0, 1.0]), // черный цвет
  width: 0
});

// при удалении объекта
m_scene.remove_object(obj);
// надо удалить и линию
m_scene.remove_object(line);
  

// utils
private splitPoints(coords: Float32Array): Float32Array[] {
  const res = new Array<Float32Array>();
  for (let i = 0; i < (coords.length/3)-1; i++) {
    const j = i*3;
    res.push(new Float32Array([coords[j],coords[j+1],coords[j+2]]));
  }
  return res;
}
private reducePoints(points: Float32Array[], numbers: number[]): Float32Array {
  const res = new Float32Array(numbers.length*3);
  for(let i=0; i<numbers.length; i++) {
    res.set(points[numbers[i]], i*3)
  }
  return res;
}
25 ноября 2017 15:37
как я понимаю, что в сложной сцене это сильно сожрет ресурсы.. (( да?
Денис
26 ноября 2017 12:24
Скорее всего, да.
Лично у меня на сцене с сотней простых объектов, визуально производительность не падает.
 
Пожалуйста, зарегистрируйтесь или войдите под своей учетной записью , чтобы оставлять сообщения.