Как создать трехмерную линейку 3D.js с шириной и толщиной?

Есть ли способ создать трехмерную линейку Three.js с шириной и толщиной?

Несмотря на то, что объект линии Three.js поддерживает ширину линии, этот атрибут пока не поддерживается во всех браузерах на всех платформах в WebGL.

Здесь, где вы задаете ширину линии в Three.js:

    var material = new THREE.LineBasicMaterial({
        color: 0xff0000,
        linewidth: 5
    });

Недавно был удален ленточный объект Three.js, который имел ширину.

Объект трубки Three.js генерирует 3D-экструзии, но - будучи основанными на Безье - линии не проходят через контрольные точки.

Может ли кто-нибудь подумать о методе рисования линейного ряда (полилиний, сюжетных линий) в файле Three.js, который имеет определенную определяемую пользователем "массу", такую ​​как ширина, толщина или радиус?

Этот вопрос может быть повторением этого вопроса: Экстремирование графика в файле three.js.

Учитывая, что я не думаю, что есть доступный метод, я был бы рад принять участие в попытке создать простую функцию, отвечающую на этот вопрос.

Но ответ, который указывает на существующий работоспособный метод, будет классным...

Как предполагает WestLangley, одно из возможных решений включает в себя полилинию, имеющую постоянную ширину пикселя, - как это доступно в настоящее время с помощью средства рендеринга холста Three.js.

Сравнение двух визуализаторов показано здесь:

Линии Canvas и WebGL по сравнению с страницами GitHub

Линии Canvas и WebGL По сравнению с jsFiddle

enter image description here

Решение, в котором вы могли бы указать ширину линии и аналогичные результаты на обоих рендерах, было бы очень круто.

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

Вот ссылки на страницы GitHub с двумя демонстрационными линиями, состоящими из нескольких ячеек:

Spheres and Cubes Polyline

Сфера и цилиндры Полилинии

"дорогое решение. Каждое соединение состоит из полной сферы.

Cubes Polylines

Cubes Polylines

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

Трехмерная строка в jsFiddle

3d box lines

Цель состоит в том, чтобы кодировать "с низким уровнем сложности", другими словами - для "чайников". Таким образом, 3D-линия должна быть такой же простой и знакомой, как добавление сферы или куба. Геометрия + материал = сеткa > сцена. Геометрия должна быть довольно экономичной с точки зрения создания вершин и граней.

Строки должны иметь ширину и высоту. Вверх всегда находится в направлении Y. Демонстрация показывает это. То, что демо не показывает, - это углы, которые приятно мигрируют...

Ответ 1

Я приготовил возможное решение, которое, как мне кажется, отвечает большинству ваших требований:

http://codepen.io/garciahurtado/pen/AGEsf?editors=001

enter image description here

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

Шейдер вдохновлен размытыми шейдерами в дистрибутиве ThreeJS, которые по существу копируют изображение по нескольку раз вдоль горизонтальной и вертикальной оси. Я автоматизировал этот процесс и сделал количество копий определяемым пользователем параметром, гарантируя, что копии были смещены на 1 пиксель.

Я использовал трехмерную кубическую сетку в своей демонстрационной версии (с орто-камерой), но это должно быть тривиально, чтобы преобразовать ее в поли линию.

Реальное мясо и картофель этой вещи находится в пользовательском шейдере (фрагмент шейдерной части):

    uniform sampler2D tDiffuse;
    uniform int edgeWidth;
    uniform int diagOffset;
    uniform float totalWidth;
    uniform float totalHeight;
    const int MAX_LINE_WIDTH = 30; // Needed due to weird limitations in GLSL around for loops
    varying vec2 vUv;

    void main() {
        int offset = int( floor(float(edgeWidth) / float(2) + 0.5) );
        vec4 color = vec4( 0.0, 0.0, 0.0, 0.0);

        // Horizontal copies of the wireframe first
        for (int i = 0; i < MAX_LINE_WIDTH; i++) {
            float uvFactor = (float(1) / totalWidth);
            float newUvX = vUv.x + float(i - offset) * uvFactor;
            float newUvY = vUv.y + (float(i - offset) * float(diagOffset) ) * uvFactor;  // only modifies vUv.y if diagOffset > 0
            color = max(color, texture2D( tDiffuse, vec2( newUvX,  newUvY  ) ));    
            // GLSL does not allow loop comparisons against dynamic variables. Workaround below
            if(i == edgeWidth) break; 
        }

        // Now we create the vertical copies
        for (int i = 0; i < MAX_LINE_WIDTH; i++) {
            float uvFactor = (float(1) / totalHeight);
            float newUvX = vUv.x + (float(i - offset) * float(-diagOffset) ) * uvFactor; // only modifies vUv.x if diagOffset > 0
            float newUvY = vUv.y + float(i - offset) * uvFactor;
            color = max(color, texture2D( tDiffuse, vec2( newUvX, newUvY ) ));  
            if(i == edgeWidth) break;
        }

        gl_FragColor = color;
    }

Плюсы:

  • Нет необходимости в дополнительной геометрии за пределами вершин строки
  • Толщина линии определяется пользователем.
  • Полноэкранный шейдер должен быть относительно нежным на графическом процессоре
  • Может быть полностью реализована в холсте WebGL

Минусы:

  • Толщина линии близко к пикселю, идеальному по горизонтали и по вертикали, но слегка по диагонали. Это связано с используемым алгоритмом и является ограничением решения. Сказав это, для низкой толщины линии и сложных геометрий это едва заметно невооруженным глазом.
  • Суставы между линиями будут показывать зазоры при достаточно большой толщине линии. Вы можете играть с демо-версией Codepen, чтобы понять, что я имею в виду. Я начал реализовывать это решение, добавив второй "диагональный проход", но получился немного волосатым, и я думаю, что это будет проблемой только для более высоких толщин линий (+8 пикселей) или крайних линий. Если вы заинтересованы в этом решении, вы можете посмотреть исходный источник, чтобы узнать, куда я иду.
  • Поскольку для этого используется полноэкранный фильтр, вы можете использовать только контекст WebGL для отображения объектов этой толщины. Отображение различной ширины линий потребует дополнительных проходов рендеринга.

Ответ 2

Как потенциальное решение. Вы можете взять свои 3D-очки, а затем использовать метод THREE.Vector3.project для определения координат экрана. Затем просто используйте холст и операции lineTo и moveTo. Контекст Canvas 2d поддерживает толщину переменной строки.

var w = renderer.domElement.innerWidth;
var h = renderer.domElement.innerHeight;
vector.project(camera);
context2d.lineWidth = 3;
var x = (vector.x+1)*(w/2);
var y = h - (vector.y+1)*(h/2);
context2d.lineTo(x,y);

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

Если у вас есть редкие изменения камеры, также возможно построить линию из полигонов и обновить ее вершинные позиции на основе преобразования камеры. Для орфографической камеры это будет работать лучше всего, поскольку только вращение потребует манипуляции с вершинами.

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

Строки причины не работают, как вы ожидали, из-за того, что ANGLE работает, он используется в Chrome и Firefox, насколько мне известно, он эмулирует OpenGL через DirectX. Ребята из ANGLE заявляют, что спецификация WebGL требует только поддержки толщины линии до 1, поэтому они не видят ее как ошибку и не намерены ее "исправлять". Толщина линии должна работать на не-ОС Windows, хотя, где ANGLE не используется.