Pull to refresh

Comments 64

Пару лет назад пытался найти библиотеку для отображения и взаимодействия с молекулами в 3D, что бы можно было использовать как виджет в своих программах. GLmol позволяет отображать молекулы, но не позволяет выделять атомы. Может с тех пор что-то готовое появилось?
А почему glut, а не freeglut, glfw или тому подобные вещи? Мне казалось, он уже мертв.
Я использую freeglut, конечно же. Хотя он тоже мёртв. Но мне просто контекст создать и он у меня установлен уже. Можно было бы какой-нибудь sfml, но мне удобно было использовать чайник и полигональную сферу из glut'a.
Вообще, для обучения програмированию шейдеров, куда лучше подходят интерактивные glslsandbox.com или shadertoy.com чем платформозависимые полумёртвые фреймворки. К тому же эти сервисы вполне нормально работают на планшетах.
Не очень понимаю, как мне это поможет нарисовать настоящую молекулу.
А причёт тут молекулы?
Ваш пост называется «Краткий курс компьютерной графики, аддендум: GLSL»
а вовсе не «Изображение молекулы средствами компьютерной графики».
Для тех, кто хочет понять, как рисовать сферы при помощи шейдеров, но с перспективой, а не с glOrtho, есть прекрасная статья.

Правильно ли я понял, что там используют Point Sprites вместо того чтобы топтаться в экранных координатах? Я слабо представляю как эта цепь магических констант будет выглядеть в случае перспективы:

vec2 ndc_current_pixel = ((2.0 * gl_FragCoord.xy) - (2.0 * viewport.xy)) / (viewport.zw) - 1;

Или это возможно даже без расширений ARB? И есть ли какая-то разница между PointSprite и просто Point?

В общем, самое таинственное осталось за кадром.
Мой код в случае перспективы работает без спрайтов, ровно так же в экранных координатах. И я не понял про таинственность, там же всё крайне примитивно, не сильно сложнее случая glOrtho…
А насколько сложно дергать какой-нибудь egl вместо всего этого дела?
Возможно, я пропустил какой-то дисклеймер при чтении статьи, но замечу — для обучения лучше подходят статьи с использованием нового API, где нет матричных стеков и прочих старых функций. Интернет запружен примерами для новичков со старым API, что приводит к результату, когда начинающие в openGL вынуждены переучиваться на новый лад (сам в своё время попался на эту удочку).

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

В любом случаи, автору спасибо. Статья достаточно интересная.
Мне API не сильно интересен в принципе, см. мой предыдущий цикл статей, я там вообще всё писал руками с нуля без использования библиотек.

Мне интересно показать, что возможно делать этими инструментами и как оно внутри устроено. О чём я и говорил раньше, я не учу как писать что-то под OpenGL, я показываю кишки.
Я просто посмотрел на данную статью с точки зрения человека, который мог бы найти её при обучении openGL и воспринять как учебную конкретно по этому API.
Это понятно и ваш комментарий вполне уместен, спасибо. Действительно, я не очень был чёток в моём позиционировании.
Лично мне при чтении чужих статей интересны идеи, а не синтаксис, который нужно смотреть в справочнике. С точки зрения хороших практик программирования я отнюдь не являюсь эталоном.
Как у вас с производительностью на рендеринге 3-х миллионов сфер? Рисовать такое в immediate mode, это жесть.
Следующим шагом должен быть переход на VBO, а дальше, чтобы не ограничивать себя непрозрачными сферами, можно пробовать визуализировать объемы, заданные, например, явным образом через 3D-текстуры, с рейкастингом в фрагментном шейдере.
Я не собирался говорить про выжимание всех соков, я собирался показать, что шейдеры используются не только для отрисовки затенения, что было не совсем очевидно из моего предыдущего (краткого) курса. Моей целью было иметь как можно более простой и короткий код.

Чтобы ответить на ваш вопрос, я спокойно отрисовываю десятки миллионов атомов без малейших тормозов вообще, FPS не считал, но отрисовка (и редактирование молекул) идёт в интерактивном режиме. Проблемы подобного подхода в том, что первая же запись в gl_FragDepth полностью отключает early-z culling.

Поэтому я вдобавок к тому пользуюсь ещё hierarchical occlusion culling.
Понимаю, что статья обучающая, но все же предупрежу новичков, что использование discard существенно замедляет работу фрагментного шейдера, как и ветвление ( if ). Это не значит, что нужно отказаться от discard и if, но следует быть осторожным.
Ну, чтобы замечание было полнее, то нужно сказать, что это естественно для параллелизма данных. К слову, тут на ресурсе очень мало рассказано об opencl/cuda, наверное, имеет смысл об этом поговорить отдельно.
Ну, смотря как используется discard/clip, где-то можно заменить BS, а где-то без них не обойтись. Но да, больше всего страдают SGX-девайсы.

Ну и ветвление, если condition — статический (например параметр для шейдера) — ничего страшного. Ну и если еще используется branch-«режим» if-ов (не знаю, если ли в GLSL такое, я про HLSL) — тоже особо не теряется на производительности.

Ну а так да, все верно, к этим штукам осторожно нужно подходить :)
Погоди, разве дискард не просто-напросто прерывает работу текущего шейдера, а следовательно невидимые фрагменты выполняются только до проверки if(d2>r2), далее никаких вычислений и пиксель просто не перекрашивается и всё? Следовательно, фрагмент с discard заканчивает свою работу быстрее, чем фрагмент не попадающий в блок с дискардом.
Это многопоточное программирование, в рамках одной рабочей группы потоки, которые сделали дискард, обязаны дождаться тех, кто дискард не сделал. И часть GPU просто простаивает.
тогда То на ТО и выходит по-лбасе, но никак не медленней))
Погоди, а разве невозможно запустить следующие еще неотработанные фрагменты?
Например у меня 1000 ядер и около 500000 фрагментов, зачем GPU будет простаивать если все фрагменты могут работать независимо друг от друга? Фрагменты то эти соответствуют пикселям на экране. Все они — видимые — уже прошли Z-Test. Это вся рабочая группа с фрагментами должна ждать выполнения всей рабочей группы с вершинами, а затем должна ждать растеризацию и Z-Test и всю промежутоную хрень. Количества ядер на все пиксели ни в одной суперкрутой видюхе по-любасе не хватает, их всего то от силы 1000-5000. А пикселей — 1920x1080, а бывает и больше.
Фрагменты можно рассматривать как очередь задач, которую мы скармливаем пулу потоков.
Тысяча ядер не является независимой. Она разбивается на группы ядер, которые работают параллельно, но синхронно. Если внутри одной такой группы половина ядер зашла в if () {}, а половина не зашла — то эта самая вторая половина простаивает, покуда первая не выйдет из блока if.
Зачем так делать?
Значит, особенности архитектуры?
Инженерам из NVidia и AMD конечно виднее.

Но по-любому discard скорости не уменьшит, просто будет простой части вычислительной мощности и всё.
Не уменьшит скорости по сравнению с чем?
Только «такой же, но без discard» не нарисует нужную картинку, поэтому некорректно об этом говорить…
Вы же сами начали говорить, что использование discard замедляет работу фрагментного шейдера. А теперь вы говорите про некорректность.
Я не говорил нигде про замедление работы, я говорил про простаивающие потоки. Мы имеем право говорить про замедление работы кода, если один код по сравнению с другим работает дольше, выдавая такой же результат. Иначе мы сравниваем компилятор с тетрисом.
я то говорил про замедление работы.

"
perfectdaemon25 марта 2015 в 05:51#
Понимаю, что статья обучающая, но все же предупрежу новичков, что использование discard существенно замедляет работу фрагментного шейдера, как и ветвление ( if ). Это не значит, что нужно отказаться от discard и if, но следует быть осторожным.
kovalexius25 марта 2015 в 21:38#↵↑
Погоди, разве дискард не просто-напросто прерывает работу текущего шейдера, а следовательно
невидимые фрагменты выполняются только до проверки if(d2>r2), далее никаких вычислений и пиксель
просто не перекрашивается и всё? Следовательно, фрагмент с discard заканчивает свою работу быстрее,
чем фрагмент не попадающий в блок с дискардом.
"

Но даже несмотря на то что вы меня убедили насчет простаивания кода, всё равно discard может даже слегка увеличить скорость окрашивания всех фрагментов в пределах статистической погрешности выполнения одного и того же куска кода (тот что под else). Ибо один и тот же кусок кода запускаемый многократно слегка колеблется по времени выполнения. Например, у нас было N одновременно выполняющихся потоков с «кодом под else». Время выполнения всех потоков равно max времени выполнения из всех N. Если мы уменьшим N, возьмем M < N, то возникает вероятность что и max из всех M будет меньше чем max из N
Опять же, я не говорил, что использовать if и discard нельзя. Например, в этой статье я использую и то, и то. Надо только их использовать, имея в виду простой ресурсов. Если есть выигрыш в простоте и, как следствие, быстрой работе шейдеров, то можно пожертвовать частью вычислительных ресурсов. Универсального рецепта нет.
Понятно.
Ну может быть инженеры GPU в будущем выкинут рабочие группы или изобретут способ перераспределения рабочих групп на разных этапах конвейера, если в настоящее время этого еще нет.
Шейдер, использующий discard, обычно отключает механизмы типа EarlyZ на всех чипах.
Z-Test в 3D конвеере выполняется после выполнения шейдера. EarlyZ позволяет определить видимость пикселя заранее, не вызывая шейдер если не нужно.
Если я не ошибаюсь, то discard не отключает earlyz. А вот запись в gl_FragDepth отключает.
Альфатест, Discard и экспорт Z отключают
Не везде и далеко не всегда. Только троганье z отключает его всегда.
Эти операции концептуально идентичны. От вычислений в шейдере зависит будет пиксель записан или нет, поэтому шейдер нельзя не выполнить.
В общем, хотите верьте, а хотите нет =)
Нет, не идентичны.

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

Я не отрицаю существование архитектур, где использование дискарда отключаёт раннее отсечение по z, но это далеко не все архитектуры.
Z можно тоже консервативный выдавать. Аналогично описанному вами случаю.
www.opengl.org/registry/specs/ARB/conservative_depth.txt

В моём посте не случайно использовано слово «обычно».
Есть нюансы, но они зависят от конкретного железа.

amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/05/GCNPerformanceTweets.pdf

GCN Performance Tip 18: clip, discard, alpha-to-mask and writing to oMask or
oDepth disable Early-Z when depth writes are on.
Notes: Early-Z is the per-pixel depth rejection test that occurs before the pixel shader
stage in the GPU. For performance reasons it should be enabled as often as possible. If
depth writes are disabled then doing clip, discard, alpha-to-mask and writing to oMask
will not disable Early-Z.

GCN Performance Tip 19: Writing to a UAV or oDepth disables both Early-Z and
Hi-Z unless conservative oDepth is used.
Notes: Declaring [earlydepthstencil] in front of a pixel shader guarantees the depth test
happens early even if the shader writes to a UAV.
Ипануться можно.
Читаешь спецификацию OpenGL — действительно depth test выполняется после fragment shader И управляется glEnable/glDisable (GL_DEPTH_TEST)
А Early вроде как автоматический и действительно не произойдет, если писать в gl_FragDepth или дискард.

Всё через жопу короче и ломает мне шаблоны напрочь. Абсолютное отсутствие логики, ппц.
Может, потому, что спецификация OpenGL очень древняя.

www.opengl.org/wiki/Early_Fragment_Test

www.opengl.org/wiki/Depth_Test
Нашел красивые картинки.

openglinsights.com/pipeline.html
Блин, чувак, респект. Забрал себе в топ-ссылки. Действительно очень круто!.. Сам такое когда-то рисовать хотел — а тут вон как, готовое уже есть.
Маркетинговых «тысяч ядер» на самом деле не существует.
Есть просто пачка SIMD ALU, которые выполняют одну операцию над группами из 16-64 элементов параллельно.
Вот этих АЛУ и есть около тысячи
Но никак не «ядер», которыми оперируют маркетологи.

Собственно вот, крайне рекомендуется к просмотру:
www.slideshare.net/DevCentralAMD/gs4106-the-amd-gcn-architecture-a-crash-course-by-layla-mah
Ну ясно)
А какая разница что называть ядрами.
16 pixel pipes написано.
также написано 16 SIMDS для одной модели 4 SIMDS для другой
Также — 2560 threads как 64 threads x 10 waves x 4 SIMDs на один CU (компьют юнит наверно)
Короче — тоже вынос мозга)) Маркетинговые картинки, а на самом деле у них всего 4 процессора стоят и все, хаха))

Год назад мне надо было рисовать много шариков, в итоге пришлось рисовать кубы… Скажите данный метод подойдет для DX?
Спасибо весьма полезная идея, наверняка подобным образом можно рисовать не только шарики.
Лично я также рисую куски торов, а вообще можно рисовать вообще любую неявную функцию, единственное что лучше бы она считалась просто, чтобы не нагружать шейдер слишком.
Очень понятно и отлично описываете. С нетерпением жду еще статтей.
Круть, я пока код шейдеров не посмотрел, не врубился как ты сделал вычисление расстояния от центра.
Спс за подсказку!
А подскажи, как можно на этой же версии шейдеров определять, какой фрагмент либо лежит на ребре треугольника, либо насколько удалён от ребра треугольника? Ведь инфы о соседних вершинах старые шейдеры по имени Верт и Фраг не знают…
Неужели хардкорно передавать в шейдер с помощью uniform координаты остальных двух вершин?
Похоже я сам ответил на свой вопрос…
Это я думаю как может быть реализован toon shader на старом пайплайне просто.
Поясню про toon shader — я имею в виду техника, раскрашивающая ребра и все около этого, можно и углы между треугольником и направлением взора считать и соответственно раскрашивать силуэт для замкнутых мешей.
Добавила тестовый проект в своё репо, исходники тут:
sourceforge.net/p/delphioga/code/ci...ee/TestShaders
Exe + папка /shaders в zip тут:
sourceforge.net/p/delphioga/code/ci....zip?format=raw

Есть доработка в шейдерах, при неквадратном размере окна шарики остаются шариками.
Изображение можно повращать мышкой.

Вопрос к автору: требуется все то же самое, но в перспективной проекции.
Вот, насчет перспективной проекции в шейдерах:
stackoverflow.com/questions/1739772...particle-system

Почему я так волнуюсь насчет проекции: пишу кросс-платформенную граф. библиотеку OGL/GLES (Windows/Android), настало время выбора — рисовать 3D примитивы классически (а-ля OGL 2.0, glDrawArrays <массив вершин>), либо рисовать их в шейдерах. Пример автора хорош, но у меня не получилось пока что перевести его в перспективную проекцию. Написала свой примерчик с тучкой сфер, каждая сфера получена первым дроблением икосаедра, 20*4=80 треугольников. Запустить пример можно на смартфонах/планшетах Android или на PC под Windows, камера там свободно перемещается.
Android mc.apk 3.8 MB yadi.sk/d/UaGYqsu9ff8Dd
Windows mc.zip 1.9 MB yadi.sk/d/tBKQxaV7ff8KW

image
Есть неплохое описание технологии рендеринга шариков спрайтами с перспективой в книге «Learning Modern 3D Graphics Programming» в главе 13 «Lies and Impostors». Код урока на bitbucket.

P.S. К сожалению, у вас ссылка на stackoverflow сломана.
Триангулированные сферы
Скрытый текст


против отрисованных шейдером
Скрытый текст


Сорцы (без комментариев) доступны здесь. Это напрямую закодированный метод, предложенный в пдфе, ссылка на который есть в самом конце статьи.
Здорово, теперь тема раскрыта.
В моём случае, к сожалению, пример сработал в обратную сторону — почитав текст Ваших шейдеров я сожгла все свои книги по glsl как опасную ересь :)) Если серьёзно — до этого надо еще дорасти.
Можно ли подобным способом отрисовать затекстурированный куб?
Да, конечно. Но отрисовать 12 треугольников стандартным методом будет проще и быстрее.
Имеете ввиду производительнее? Необходимые для этого вычисления в шейдере будут работать дольше, чем если просто передать в него информацию о геометрии куба?
Да, производительнее. Растеризаторы треугольников работают быстро, каждый пиксель будет прорисован всего два раза. При отрисовке триангулированных сфер мы упираемся в пропускную способность шины — треугольников надо тысячу минимум на каждую сферу, у куба их всего 12.
Спасибо за разъяснение :)
Видеокарта рисует вейвфронтами: blogs.msdn.microsoft.com/nativeconcurrency/2012/03/26/warp-or-wavefront-of-gpu-threads
И треугольник, который занимает хотя бы один пиксель на экране запросто приводит к тому, что 63 из 64 тредов лопатят воздух.
Хорошая демонстрация того, как даже топология треугольников может влиять на производительность тут:
www.humus.name/index.php?page=News&ID=228
Sign up to leave a comment.

Articles