Pull to refresh
41
0
Евгений Никитенко @Jeka8

Программист

Send message
Рисовать траву с помощью пятистадийного пайплайна — это, пожалуй, наиболее неоптимальный способ рисовать траву. Я даже молчу про то, что геометрические шейдеры не всегда оптимальны, в данном случае это будут мелочи.
Nvidia во времена dx11 баловалась с HairWorks, где был пятистадийный пайплайн, но потом внезапно выяснилось, что это работает очень медленно.

Намного более правильно было бы использовать только тесселяцию для травы.
Хотелось бы больше услышать про графику. А именно как были сделаны эффекты: полупрозрачная стенка с двигающимся шумом, анимация отскока от стенки, как был реализован ray tracing. Было бы хорошо, если бы автор написал отдельную статью про это. И мне кажется, что это было бы намного лучшим пиаром, чем рассказ про какие-то основы OpenGL.
А Opengl ES 3.2 так и не войдет в финальный API? Конечно, есть aep, но лучше сразу добавить поддержку OpenGL ES 3.2, чем использовать такой костыль.
А почему 1 кг нельзя описать, как N молекул/атомов какого-то вещества в данном состоянии и с данной температурой? Или же описать, как N ядер какого-то атома?
И все-таки если разрабатывать приложение под андроид 2.3 и выше, то появляются проблемы. В старом андроиде нету action bar, фрагментов и еще некоторых вещей, которые активно используются в приложениях. Из-за этого приходится использовать android support library, что не очень удобно.
Это не будет работать, так как условие внутри static_assert не гарантировано будет известно на этапе компиляции, из-за чего будет ошибка компиляции в любом случае, даже если ассерт не должен сработать.
Цитата из статьи:
Когда пишешь какую-то constexpr-функцию, которую потом будут часто использовать, хорошо бы возвращать читабельную ошибку. Тут можно ошибочно предположить, что static_assert как раз для этого подходит. Но static_assert использовать не получится, так как параметры функций не могут быть constexpr, из-за чего значения параметров не гарантированно будут известны на этапе компиляции.
constexpr int foo(int i); // Здесь foo() может быть вычислена и в рантайме и в
const int j  = foo(2); // компайлтайме, несмотря, что её аргументом является constexpr

constexpr int foo(int i);  // А здесь foo() обязаны быть вызвана в
constexpr int j  = foo(2); // компайлтайме

В первом случае функция обязана быть вызвана в compile-time, несмотря на то, что ее значение приравнивается не constexpr-переменной, так как функция обязана вызвана в compile-time, если ее параметры можно посчитать на этапе компиляции.
Бывают такие случаи, когда сложно уследить за тем, чтобы все параметры могли посчитаться на этапе компиляции, и как раз приравнивание значение гарантирует то, что функция будет вызвана в compile-time (в противном случае будет выведена ошибка).

Так что время вычисления функции зависит только от параметров.
В случае запуска этой функции в runtime (это возможно сделать, передав в функцию параметр, который нельзя посчитать на этапе компиляции), будет выброшено исключение.

Вообще GCC выполняет код по мере необходимости (по стандарту он может проверять весь constexpr-код сразу, но он этого не делает). Так что если y не будет равняться нулю, то кусок кода после '?' будет проигнорирован. Но чтобы вопросов не было, можно это переписать таким образом:
return (y == 0)? (throw std::logic_error («x can't be zero»), 0): (y / x);
Спасибо за конструктивный отзыв!

constexpr int b = inc (a); // ошибка: преобразование int -> constexpr int
Это неверно. Ошибка в данном случае заключается не в том, что происходит попытка преобразования int в constexpr int, а в том, что a не является constexpr выражением, а такого типа, как constexpr int вообще не существует, так как constexpr не является частью типа, поэтому никаких попыток преобразования не делается.

Тут вы правы, поправил статью.

То есть не получится создать исключительно constexpr-функцию, которая может работать только на этапе компиляции.

Вот это тоже непонятно.

Любую constexpr-функцию можно запустить в runtime, для этого достаточно передать аргумент, который нельзя посчитать на этапе компиляции. Напомню, что компилятор может посчитать на этапе компиляции выражения, которые содержат только литералы или constexpr-переменные и constexpr-функции.

Также constexpr-функции могут работать с объектами, это будет рассмотрено позже.

Непонятная фраза. Могут работать с объектами? А обычные не могут?

Возможно, я не очень понятно это написал. Имелось ввиду, что constexpr-функции могут работать не только с базовыми типами, но и с классами.
Я имел ввиду, что разработчики компиляторов могут ее переписать (если это будет соотчествовать стандарту), тем самым увеличив производительность.
Я бы не назвал это ошибкой.
Если вы хотите получить гарантию того, что результат будет посчитан на этапе компиляции, достаточно приравнять результат функции constexpr-переменной.
constexpr int n = get_n(); // теперь в случае невозможности использовать constexpr-функцию будет выведена ошибка
constexpr как раз это и позволяет сделать (в C++11 не очень удачно). Но преимущество constexpr-функций в том, что в случае невозможности вызова функции на этапе компиляции, она запуститься в runtime, из-за чего не надо будет делать два экземпляра каждой функции.
Будем надеяться, что в C++14 или в C++17 добавят constexpr regex. Вообще после С++14 из-за того, что уберут много ограничений на constexpr-функции и классы, можно будет почти всю стандартную библиотеку переписать, используя constexpr.
Компилятор тщательно следит за тем, что делают constexpr-функции. В случае деления на ноль, компилятор выдаст ошибку, показывая при этом стек вызовов.
Еще в constexpr-функциях все переменные должны быть инициализированы, из-за чего не получится использовать неинициализированную переменную.
Также компилятор ловит переполнение стека. В GCC по умолчанию глубина стека равна 512. В случае переполнения можно получить красивую ошибку из 512 строчек. С помощью флага можно расширить глубину стека.

А дебажить constexpr затрудительно. Но это можно сделать, запустив функцию в runtime (например, передав в качестве параметра не constexpr-переменную).
Ссылка не рабочая.
Не помню в каком возрасте собрал из лего дом, который был больше меня по высоте. В доме был лифт, мотор лифта был не «леговский», а вытащен из чего-то. Нередко этот дом рушился, и я собирал его заново.
Также собрал аналогично из лего и стороннего мотора троллейбус.
После этого записался на курсы робототехники, где потом начал писать маленькие программы для робота/машины из лего.
Ну а дальше уже понятно.
Пожалуй добавлю ссылку на его статью. Я и не уверяю то, что именно я нашел эту уязвимость.
Очень интересно все это читать. На самом деле, меня никогда раньше еще не называли шпионом Microsoft :)
Я бы с радостью поработал бы там.
Такой, к сожалению, нету. Есть только функция, которая принимает 32-битные числа.
1

Information

Rating
Does not participate
Location
Москва, Москва и Московская обл., Россия
Date of birth
Registered
Activity