Рисовать траву с помощью пятистадийного пайплайна — это, пожалуй, наиболее неоптимальный способ рисовать траву. Я даже молчу про то, что геометрические шейдеры не всегда оптимальны, в данном случае это будут мелочи.
Nvidia во времена dx11 баловалась с HairWorks, где был пятистадийный пайплайн, но потом внезапно выяснилось, что это работает очень медленно.
Намного более правильно было бы использовать только тесселяцию для травы.
Хотелось бы больше услышать про графику. А именно как были сделаны эффекты: полупрозрачная стенка с двигающимся шумом, анимация отскока от стенки, как был реализован ray tracing. Было бы хорошо, если бы автор написал отдельную статью про это. И мне кажется, что это было бы намного лучшим пиаром, чем рассказ про какие-то основы OpenGL.
А почему 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 не будет равняться нулю, то кусок кода после '?' будет проигнорирован. Но чтобы вопросов не было, можно это переписать таким образом:
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-переменную).
Не помню в каком возрасте собрал из лего дом, который был больше меня по высоте. В доме был лифт, мотор лифта был не «леговский», а вытащен из чего-то. Нередко этот дом рушился, и я собирал его заново.
Также собрал аналогично из лего и стороннего мотора троллейбус.
После этого записался на курсы робототехники, где потом начал писать маленькие программы для робота/машины из лего.
Ну а дальше уже понятно.
А зачем в браузере каждый раз писать, какой это браузер? По мне это просто бесполезное использование места
Nvidia во времена dx11 баловалась с HairWorks, где был пятистадийный пайплайн, но потом внезапно выяснилось, что это работает очень медленно.
Намного более правильно было бы использовать только тесселяцию для травы.
В первом случае функция обязана быть вызвана в compile-time, несмотря на то, что ее значение приравнивается не
constexpr
-переменной, так как функция обязана вызвана в compile-time, если ее параметры можно посчитать на этапе компиляции.Бывают такие случаи, когда сложно уследить за тем, чтобы все параметры могли посчитаться на этапе компиляции, и как раз приравнивание значение гарантирует то, что функция будет вызвана в compile-time (в противном случае будет выведена ошибка).
Так что время вычисления функции зависит только от параметров.
Вообще GCC выполняет код по мере необходимости (по стандарту он может проверять весь constexpr-код сразу, но он этого не делает). Так что если
y
не будет равняться нулю, то кусок кода после'?'
будет проигнорирован. Но чтобы вопросов не было, можно это переписать таким образом:Тут вы правы, поправил статью.
Любую constexpr-функцию можно запустить в runtime, для этого достаточно передать аргумент, который нельзя посчитать на этапе компиляции. Напомню, что компилятор может посчитать на этапе компиляции выражения, которые содержат только литералы или constexpr-переменные и constexpr-функции.
Возможно, я не очень понятно это написал. Имелось ввиду, что constexpr-функции могут работать не только с базовыми типами, но и с классами.
Если вы хотите получить гарантию того, что результат будет посчитан на этапе компиляции, достаточно приравнять результат функции
constexpr
-переменной.constexpr
как раз это и позволяет сделать (в C++11 не очень удачно). Но преимуществоconstexpr
-функций в том, что в случае невозможности вызова функции на этапе компиляции, она запуститься в runtime, из-за чего не надо будет делать два экземпляра каждой функции.constexpr regex
. Вообще после С++14 из-за того, что уберут много ограничений наconstexpr
-функции и классы, можно будет почти всю стандартную библиотеку переписать, используяconstexpr
.constexpr
-функции. В случае деления на ноль, компилятор выдаст ошибку, показывая при этом стек вызовов.Еще в
constexpr
-функциях все переменные должны быть инициализированы, из-за чего не получится использовать неинициализированную переменную.Также компилятор ловит переполнение стека. В GCC по умолчанию глубина стека равна 512. В случае переполнения можно получить красивую ошибку из 512 строчек. С помощью флага можно расширить глубину стека.
А дебажить
constexpr
затрудительно. Но это можно сделать, запустив функцию в runtime (например, передав в качестве параметра неconstexpr
-переменную).Также собрал аналогично из лего и стороннего мотора троллейбус.
После этого записался на курсы робототехники, где потом начал писать маленькие программы для робота/машины из лего.
Ну а дальше уже понятно.
Я бы с радостью поработал бы там.