Привет.
В шейдерах мало разбираюсь, просмотрел серию уроков, но этого мало..
В общем что я хочу сделать.. Есть текстура чёрнобелая. Допустим ее размер 3х3. Для удобства. она вся чёрная, только пиксель по середине белый. И есть вторая текстура(просто картинка). И я хочу чтобы шейдер увидев белый пиксель заменил его текстурой на поле. Хочу так же добавить что это проективный шейдер. Т.е. всё что получается является проекцией. В Юнити есть проектор, который это делает. Так же там есть парочка примитивных шейдеров.
Я прошёл несколько уроков по CG. Но тех знаний мне мало чтобы это провернуть. Буду признателен за помощь.
Так чтобы было более менее понятно:
Входные данные:
1. Текстура-маска: чернобелая текстура по которой можно определить где будет находиться тот или иной паттерн.
2. Тектсура-паттерн: любая картинка
3. Размер текстуры-паттерна при проекции(допустим я хочу чтобы она была 5х5 метров.
4. [Опционально] Расстояние между паттернами
Выходные данные:
Сформированная картинка из паттернов.
Спасибо.
Если не понятно о чём идёт речь, то вот пример:
т.е. Есть маска, есть паттерн и есть результат.
Допустим, у тебя текстурные координаты на кваде от {0,0} до {1,1}. Во фрагментном шейдере читаешь из текстуры с маской по текстурным координатам, которые имеет данный фрагмент. Также умножаешь эти координаты покомпонентно на размеры маски и читаешь по ним из текстуры с картинкой. Оба прочитанных значения перемножаешь и выводишь в цвет.
Естественно, для маски надо настроить текстуру так, чтобы она повторялась (repeat), а не clamp. Также надо отключить фильтрацию (в OpenGL - nearest, в DX - point) для маски.
Получится для чёрных пикселей маски чёрный цвет, для остальных - текстура. Если нужен не чёрный, а какой-то другой, тогда if\else.
у феи на картинке взгляд как у крестухана смотрящего на дельфина.
gammaker
По порядку:
> Допустим, у тебя текстурные координаты на кваде от {0,0} до {1,1}
Ты имеешь ввиду на место в которое осуществляется проекция ?
> Во фрагментном шейдере читаешь из текстуры с маской по текстурным координатам, которые имеет данный фрагмент.
Читаю. Хотя не совсем понял фразу: "которые имеет данный фрагмент"
> Также умножаешь эти координаты покомпонентно на размеры маски и читаешь по ним из текстуры с картинкой. Оба прочитанных значения перемножаешь и выводишь в цвет.
Вообще не понял фразу..
> Естественно, для маски надо настроить текстуру так, чтобы она повторялась (repeat), а не clamp.
А причём тут это вообще ?
Gladiator
> Ты имеешь ввиду на место в которое осуществляется проекция ?
В принципе да, неважно, прямоугольник это или нет.
Gladiator
> Читаю. Хотя не совсем понял фразу: "которые имеет данный фрагмент"
Проинтерполированное по треугольнику значение текстурной координаты.
Gladiator
> А причём тут это вообще ?
Ну у тебя же на картинке текстура повторяется. Я ведь правильно понял, что если маска MxN пикселей вся белая, то текстура должна повториться плиткой MxN раз?
А-а, я опечатался. Не для маски, а для цветовой текстуры.
Gladiator
> Вообще не понял фразу..
Ну есть у тебя двухмерный вектор TexCoord в пиксельном шейдере, уже интерполированный. Он находится в пределах от {0,0} до {1,1}.
Чтобы текстура повторилась MxN раз, нужно умножить TexCoord.x на M, а TexCoord.y на N. По полученным текстурным координатам читать из текстуры с картинкой.
Если полученные цвета перемножить, то чёрный цвет маски загасит картинку, а белый оставит без изменений.
Короче в OpenGL это будет выглядеть как-то так:
vec4 maskColor=texture(maskSampler, TexCoord); vec4 imageColor=texture( maskSampler, TexCoord*vec2( M, N)); gl_FragColor=maskColor*imageColor;
gammaker
> Ну у тебя же на картинке текстура повторяется. Я ведь правильно понял, что если
> маска MxN пикселей вся белая, то текстура должна повториться плиткой MxN раз?
Ну, не совсем.. В принципе визуально оно может быть и так.. но есть различия.. о них я чуть ниже расскажу.. а пока вопрос:
- Вот ты дал пример кода.. Если честно я не очень понимаю что он делает.. первая строчка вроде ясна, он берет текущую текстурную координату и забирает ее цвет в maskColor. Но вот вторая строчка мне не понятна.. Ты умножаешь текстурную координату на двумерный вектор, в результате вторая компонента у функции texture становится двумерным вектором(если я правильно понимаю ф-ю умножения в данном случае). Оно даже не откомпилится. Т.е. смысл этой строчки не ясен.
по поводу отличий:
1. Я бы хотел чтобы между паттернами был небольшой зазор (в принципе это можно было бы обойти делая соответствующую текстуру, но см. пункт 2).
2. Я бы хотел чтобы маска формировала картинку как я показал постом выше.. т.е. там где есть белый пиксель, там и есть паттерн.
3. Я бы хотел иметь возможность произвольного размещения ячеек (но для простоты можно сказать что я бы хотел задать ячейкам ну или рядам ячеек(если еще проще) смещение. Чтобы у меня была не просто сетка, а что-то состоящее из ячеек, но сеткой не являющееся.
4. Усложнение, но мне надо этого достичь. Абстрагироваться от размера ячейки и иметь возможность задавать ячейку любой величины и формировать совокупность ячеек по своему усмотрению(тут конечно надо придумать соответствующие входные данные, но всё же)
Вот..
P.S. Я прощу прощения если быть может задаю глупые вопросы, но мне очень бы хотелось разобраться и сделать это дело как можно скорей.
Спасибо.
Gladiator
> Ты умножаешь текстурную координату на двумерный вектор, в результате вторая
> компонента у функции texture становится двумерным вектором(если я правильно
> понимаю ф-ю умножения в данном случае). Оно даже не откомпилится. Т.е. смысл
> этой строчки не ясен.
А чем ты компилируешь? Я дал код на GLSL, так как с ним работаю. Там символ '*' между векторами обозначает покомпонентное умножение. Вообще в математике такой операции вообще не выделяют, но в шейдерах она полезна. Можно TexCoord*vec2(M,N) расписать как vec2(TexCoord.x*M, TexCoord.y*N). Она же и в перемножении цветов в третьей строчке находится.
Gladiator
> Я бы хотел чтобы между паттернами был небольшой зазор
Это белые линии сетки, из рисунка #1? Такое можно реализовать, если не тупо умножать цвета, а сначала проверять, в какой части пикселя лежат текстурные координаты.
Gladiator
> 3. Я бы хотел иметь возможность произвольного размещения ячеек (но для простоты
> можно сказать что я бы хотел задать ячейкам ну или рядам ячеек(если еще проще)
> смещение. Чтобы у меня была не просто сетка, а что-то состоящее из ячеек, но
> сеткой не являющееся.
А что мешает сделать маску не 4x4, а большую, например 512x512 и иметь возможность задавать видимость попиксельно? Не будет никаких ограничений, только памяти больше понадобится.
Ещё если это размещение ячеек можно задать функцией, то можно попробовать сделать произвольные смещения. Но это сложно. Я бы предпочёл просто одну большую маску, нарисованную заранее. Хотя я не знаю, какие цели ты преследуешь.
Gladiator
> Если не понятно о чём идёт речь, то вот пример:
Как ты это собираешься делать шейдером?
Gladiator
> И я хочу чтобы шейдер увидев белый пиксель заменил его текстурой на поле.
Фрагментный шейдер работает не с текстурой, он работает с пикселем и текселем. Поэтому встретив белый пиксель маски, ты не сможешь в него засунуть всю текстуру - только один пиксель с текстуры
Нет, не покажу - забыл как в юнити в пиксельный шейдер слать свои данные.
Ладно, идея следующая.
Берешь текстуру (например 100х100 пикселей), ставишь ей тайлинг в твоем случае (2х2 - то есть две текстуры на две)
Создаешь маску (размером 200х200 пикселей - потому что у тебя основная -2х2 (2*100х2*100)
Пишешь шейдер, в него кладешь основную текстуру (не забыв про тайлинг 2х2) и маску (а вот у него тайлинг 1х1)
Потом доходишь до пиксельного (фрагментого) шейдера. Берешь пиксель с маски, и смотришь, если он белый
(if mask.rgb == white)
то пишешь пиксель из основной текстуры.
А как сделать по другому - я не представляю. Можно конечно еще маске изменить размер, и потом математически его приводить к размеру текстуры, но это будет такой-то ад
Если число квадратов MxN заранее известно, то просто натягиваем текстуру и пользуемся плиткой как маской.
Если число квадратов неизвестно, то вместо черно-белой маски тебе надо рисовать текстурные координаты, зашифрованные в цвете.
Gladiator
Тебе вот это что ли нужно:
тут и проекция и маска и паттерны, вроде все как по заказу, единственное различие - нужно знать размер маски.
gammaker
> vec4 imageColor=texture(maskSampler, TexCoord*vec2(M, N));
Это 1 пиксель.
gammaker
> > Я бы хотел чтобы между паттернами был небольшой зазор
> Это белые линии сетки, из рисунка #1?
Нет.. Белые линии чтобы просто понять где пиксели.. один квадратик один пиксель
war_zes
> > И я хочу чтобы шейдер увидев белый пиксель заменил его текстурой на поле.
> Фрагментный шейдер работает не с текстурой, он работает с пикселем и текселем.
> Поэтому встретив белый пиксель маски, ты не сможешь в него засунуть всю
> текстуру - только один пиксель с текстуры
Так я вроде как понимаю.. но мне надо ж не обратно засунуть текстурку, а засунуть текстурку в другое место..
Если абстрагироваться от шейдерного языка, то мог бы выглядеть так:
if (currentPixelColor == "white") { outputColorArray = patternTexture; }
но я понимаю что в один момент времени обрабатывается только один пиксель. Но неужели в шейдерном языке нет велосипедов для решения данной проблемы ?
Ну вот допустим мой вариант решения был бы таким: если я имею маску текстуру размером 16х16, и паттерн картинку 64х64, то алгоритм был бы следующий:
resultPixelColor = maskColor[i/4][j/4] == "white" ? patternColor[i ][j] : transparentColor;
kroonk
А что это ?
Gladiator
Это результат работы шейдера. Он по маске, содержащей белые пиксели(в данном случае 2x2), выводит нужные картинки, проецируя на любую поверхность(в данном случае 2 перекрещенных параллелепипеда).
На вход требуется:
world-матрица объекта, на который проецируется изображение
view-projection-матрица камеры
view-projection-матрица источника проекции
текстура маски
текстура паттерна
размер маски в пикселях
Тема в архиве.