Первый шейдер
Первый шейдер.
Для начала поставим себе цель – имея все эти данные, написать шейдер, который будет просто и без изысков выводить одним цветом на экран наш меш. То есть, пока даже нет никакой речи о расчёте освещения и чего-либо ещё.
Чтобы уметь писать шейдеры, надо знать, как происходит вывод на экран графики.
Итак, выполним нашу задачу сначала обычными средствами. Что у нас есть? Меш который представлен одним полигоном(треугольником). Предположим, что координаты его вершин равны предположим: А(0,10,10) В(0,0,10) С(5, 0, 0). Ну и само собой у нас есть три матрицы: мировая, вида и проекции. Не будем перечислять данные, хранимые в них. Отметим лишь, что меш и камера в пространстве должны выглядеть так, как на рисунке:
Для удобства, экран, на который будет выводиться изображение, имеет разрешение 300 на 200. В общем, виде без использования шейдера код будет выглядеть:
//ставим матрицу вида pMainDirect3DDevice -> SetTransform (D3DTS_VIEW, &MatrixView); //ставим мировую матрицу pMainDirect3DDevice -> SetTransform( D3DTS_WORLD,&MatrixWorld ); //ставим матрицу проекции pMainDirect3DDevice -> SetTransform( D3DTS_PROJECTION, &MatrixProjection ); //рисуем модель for( k = 0; k < amountSubsets; k++) { pMesh -> DrawSubset(k); } //выводим нарисованное на экран pMainDirect3DDevice -> Present( NULL, NULL, NULL, NULL );На экране результат операции будет выглядеть так:
Настал момент разобраться, как это получилось. Откроем Маткад или подобную программу и посчитаем в ней произведение трёх наших матриц в таком порядке: Мировая*Вида*Проекции. Запомним результат. Возьмём одну из вершин меша, предположим С с координатами (5, 0, 0). Координаты (5, 0, 0) - это вектор. Умножим произведение матриц на этот вектор. Что мы получим? Тоже вектор. Самое интересное чему равны координаты этого вектора. Первые две из них будут равны (забудем пока о третьей) 0 и 50. Если мы сделаем тоже самое над двумя другими вершинами, то мы получим для B: (0 и 0) , для А: (75 и 0). А теперь дружно посмотрели на рисунок. Поняли принцип? Если нет, то поясню. Наш экран это двухмерная система координат с центром в центре(извиняюсь за тафтологию). Поэтому, чтобы получить вершину С по оси Х мы откладываем 0, а по оси Y откладываем 50. И так же для других двух вершин. Компьютер, имея эти три пиксела на экране остальные пикселы между ними достраивает сам.
Примечание: Если у вершин разные цвета, то он строит остальные пикселы с таким цветом, что получается плавный переход между вершинами(интерполируе их):
То, что до этого момента делал компьютер, теперь нам, вручную, нужно будет делать в шейдере. Замечу, что произведение трёх матриц придётся считать перед запуском шейдера:
Вот собственно код шейдера:
// произведение матриц запишется в эту // переменную и будет храниться в константных регистрах float4x4 worldViewProj; struct OUTPUT_DATA { float4 pos : POSITION; }; struct INPUT_DATA { float4 Pos : POSITION; }; OUTPUT_DATA ShaderFunc(INPUT_DATA input) { //обнуляем данные OUTPUT_DATA Out = (OUTPUT_DATA)0; //умножаем произведение матриц на позицию Out.pos = mul(input.Pos, worldViewProj); // возвращаем новую вершину return Out; } //необходимо для работы шейдера technique Transform { pass P0 { VertexShader = compile vs_1_1 ShaderFunc(); } }
Слова POSITION в структурах OUTPUT_DATA и INPUT_DATA обязательны.
Ну, вот и всё. Поздравляю с первым шейдером. В следующий раз мы будем постепенно усложнять его. Я не описываю, как заставить работать этот код в приложении – вы можете сами найти это в интернете.
Успехов!
При полном или частичном копировании необходимо указывать ссылку на данную статью.
Юрий (Дата )
Все вопросы и предложения высылайте на адрес soft_support@list.ru. Необходимо в заголовке указать название статьи.
Оставь свой отзыв
Дата: 03.02.09 |