Comments 26
PS: Острые углы я срезал немного по-другому:

Мне такой вариант показался более симпатичным.
Плюс, его можно прокачать до аккуратных скруглённых углов, если добавить немного «магии» в пиксельный шейдер.
Я делал через круглые точки для SolveSpace: https://github.com/solvespace/solvespace/blob/master/src/render/gl3shader.cpp
А еще там есть прикольная система для пунктира и шейдерный фейковый антиалиазинг.
П.С.
У меня есть идея, сделать через текстурную маску, и с помощью маски задавать любой стиль штрихования.
Да, идея именно такая. Только там создается не маска, а distance-map, которая позволяет получить потрясающую точность. Еще там есть хак, чтобы запаковать float в цвет. Про distance map можно почитать здесь http://www.valvesoftware.com/publications/2007/SIGGRAPH2007_AlphaTestedMagnification.pdf
Пока что ещё пришла немного сумасшедшая мысль нарисовать обычный прямоугольник, а линию рисовать во фрагментном шейдере.

SVG (который ИМХО в данной задаче можно считать своего рода ground truth) не накапливает прозрачность на самопересечениях, что, кажется правильнее. Но как решить это без стенсила, я пока не знаю.
Вы правильно указали на ошибку с обрезанным треугольником внутри сложенных отрезков, я не решил эту проблему. Этот момент легко находится в шейдере, но я посчитал, что такие случаи бывают редко и решил оставить до поры до времени…
мб alpha-to-coverage?
ну здесь ручное управление масками… плохо совместимо с антиалиазингом.
glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE)
не возымеет никакого эффекта если для буфера не включен MSAA. Кроме того, я все равно не очень понял, даже если он у нас включен, как alpha-to-coverage поможет решить проблему на самопересечениях. Судя по спеке, результат интерпретации такой маски, вообще говоря, непредсказуем (а точнее, зависит от оборудования, на котором работает программа). Или я чего-то не понимаю?Да, наверное я зря здесь написал про alpha-to-coverage, опыта разработки чего-то подобного у меня нет. Но я предположил, что есть вручную задавать маски для пикселя, для одинаковых масок наложение будет давать тот же результат, т.е. цвет не будет удваиваться. Если использовать разные маски для разных материалов, можно создать такой эффект, который требуется. Но это слишком сложно и все равно, что из пушки по воробьям. Тут важно понять, говорим ли мы о 2d или о 3d. С 2d очень просто все разруливается, про 3d надо что-то изобретать.
хотя тут достаточно элементарного depth-test режима LESS вместо LEQUAL
// clip line begin
if (position_1.z > -z_near) {
float t = (position_1.z + z_near) / abs(position_2.z - position_1.z);
position_1 = lerp(position_1, position_2, t);
width_1 = lerp(width_1, width_2, t);
texcoord_0_1 = lerp(texcoord_0_1, texcoord_0_2, t);
texcoord_2_1 = lerp(texcoord_2_1, texcoord_2_2, t);
texcoord_3_1 = lerp(texcoord_3_1, texcoord_3_2, t);
}
// clip line end
if (position_2.z > -z_near) {
float t = 1.0f - (position_2.z + z_near) / abs(position_2.z - position_1.z);
position_2 = lerp(position_1, position_2, t);
width_2 = lerp(width_1, width_2, t);
texcoord_0_2 = lerp(texcoord_0_1, texcoord_0_2, t);
texcoord_2_2 = lerp(texcoord_2_1, texcoord_2_2, t);
texcoord_3_2 = lerp(texcoord_3_1, texcoord_3_2, t);
}
Рисование толстых линий в WebGL