ПрограммированиеФорумОбщее

Помогите написать шейдер

Страницы: 1 2 Следующая »
#0
17:47, 5 авг 2014

Привет.
В шейдерах мало разбираюсь, просмотрел серию уроков, но этого мало..

В общем что я хочу сделать.. Есть текстура чёрнобелая. Допустим ее размер 3х3. Для удобства. она вся чёрная, только пиксель по середине белый. И есть вторая текстура(просто картинка). И я хочу чтобы шейдер увидев белый пиксель заменил его текстурой на поле. Хочу так же добавить что это проективный шейдер. Т.е. всё что получается является проекцией. В Юнити есть проектор, который это делает. Так же там есть парочка примитивных шейдеров.

Я прошёл несколько уроков по CG. Но тех знаний мне мало чтобы это провернуть. Буду признателен за помощь.

Так чтобы было более менее понятно:
Входные данные:
1. Текстура-маска: чернобелая текстура по которой можно определить где будет находиться тот или иной паттерн.
2. Тектсура-паттерн: любая картинка
3. Размер текстуры-паттерна при проекции(допустим я хочу чтобы она была 5х5 метров.
4. [Опционально] Расстояние между паттернами

Выходные данные:
Сформированная картинка из паттернов.

Спасибо.

#1
21:03, 5 авг 2014

Если не понятно о чём идёт речь, то вот пример:
Изображение

т.е. Есть маска, есть паттерн и есть результат.

#2
21:25, 5 авг 2014

Допустим, у тебя текстурные координаты на кваде от {0,0} до {1,1}. Во фрагментном шейдере читаешь из текстуры с маской по текстурным координатам, которые имеет данный фрагмент. Также умножаешь эти координаты покомпонентно на размеры маски и читаешь по ним из текстуры с картинкой. Оба прочитанных значения перемножаешь и выводишь в цвет.
Естественно, для маски надо настроить текстуру так, чтобы она повторялась (repeat), а не clamp. Также надо отключить фильтрацию (в OpenGL - nearest, в DX - point) для маски.
Получится для чёрных пикселей маски чёрный цвет, для остальных - текстура. Если нужен не чёрный, а какой-то другой, тогда if\else.

#3
22:19, 5 авг 2014

у феи на картинке взгляд как у крестухана смотрящего на дельфина.

#4
22:28, 5 авг 2014

gammaker
По порядку:
> Допустим, у тебя текстурные координаты на кваде от {0,0} до {1,1}
Ты имеешь ввиду на место в которое осуществляется проекция ?

> Во фрагментном шейдере читаешь из текстуры с маской по текстурным координатам, которые имеет данный фрагмент.
Читаю. Хотя не совсем понял фразу: "которые имеет данный фрагмент"

> Также умножаешь эти координаты покомпонентно на размеры маски и читаешь по ним из текстуры с картинкой. Оба прочитанных значения перемножаешь и выводишь в цвет.

Вообще не понял фразу..

> Естественно, для маски надо настроить текстуру так, чтобы она повторялась (repeat), а не clamp.
А причём тут это вообще ?

#5
23:41, 5 авг 2014

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;
#6
0:15, 6 авг 2014

gammaker
> Ну у тебя же на картинке текстура повторяется. Я ведь правильно понял, что если
> маска MxN пикселей вся белая, то текстура должна повториться плиткой MxN раз?
Ну, не совсем.. В принципе визуально оно может быть и так.. но есть различия.. о них я чуть ниже расскажу.. а пока вопрос:
- Вот ты дал пример кода.. Если честно я не очень понимаю что он делает.. первая строчка вроде ясна, он берет текущую текстурную координату и забирает ее цвет в maskColor. Но вот вторая строчка мне не понятна.. Ты умножаешь текстурную координату на двумерный вектор, в результате вторая компонента у функции texture становится двумерным вектором(если я правильно понимаю ф-ю умножения в данном случае). Оно даже не откомпилится. Т.е. смысл этой строчки не ясен.

по поводу отличий:
1. Я бы хотел чтобы между паттернами был небольшой зазор (в принципе это можно было бы обойти делая соответствующую текстуру, но см. пункт 2).
2. Я бы хотел чтобы маска формировала картинку как я показал постом выше.. т.е. там где есть белый пиксель, там и есть паттерн.
3. Я бы хотел иметь возможность произвольного размещения ячеек (но для простоты можно сказать что я бы хотел задать ячейкам ну или рядам ячеек(если еще проще) смещение. Чтобы у меня была не просто сетка, а что-то состоящее из ячеек, но сеткой не являющееся.
4. Усложнение, но мне надо этого достичь. Абстрагироваться от размера ячейки и иметь возможность задавать ячейку любой величины и формировать совокупность ячеек по своему усмотрению(тут конечно надо придумать соответствующие входные данные, но всё же)

Вот..

P.S. Я прощу прощения если быть может задаю глупые вопросы, но мне очень бы хотелось разобраться и сделать это дело как можно скорей.

Спасибо.

#7
0:35, 6 авг 2014

Gladiator
> Ты умножаешь текстурную координату на двумерный вектор, в результате вторая
> компонента у функции texture становится двумерным вектором(если я правильно
> понимаю ф-ю умножения в данном случае). Оно даже не откомпилится. Т.е. смысл
> этой строчки не ясен.
А чем ты компилируешь? Я дал код на GLSL, так как с ним работаю. Там символ '*' между векторами обозначает покомпонентное умножение. Вообще в математике такой операции вообще не выделяют, но в шейдерах она полезна. Можно TexCoord*vec2(M,N) расписать как vec2(TexCoord.x*M, TexCoord.y*N). Она же и в перемножении цветов в третьей строчке находится.

Gladiator
> Я бы хотел чтобы между паттернами был небольшой зазор
Это белые линии сетки, из рисунка #1? Такое можно реализовать, если не тупо умножать цвета, а сначала проверять, в какой части пикселя лежат текстурные координаты.

Gladiator
> 3. Я бы хотел иметь возможность произвольного размещения ячеек (но для простоты
> можно сказать что я бы хотел задать ячейкам ну или рядам ячеек(если еще проще)
> смещение. Чтобы у меня была не просто сетка, а что-то состоящее из ячеек, но
> сеткой не являющееся.
А что мешает сделать маску не 4x4, а большую, например 512x512 и иметь возможность задавать видимость попиксельно? Не будет никаких ограничений, только памяти больше понадобится.
Ещё если это размещение ячеек можно задать функцией, то можно попробовать сделать произвольные смещения. Но это сложно. Я бы предпочёл просто одну большую маску, нарисованную заранее. Хотя я не знаю, какие цели ты преследуешь.

#8
8:03, 6 авг 2014

Gladiator
> Если не понятно о чём идёт речь, то вот пример:
Как ты это собираешься делать шейдером?

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

#9
8:28, 6 авг 2014

Нет, не покажу - забыл как в юнити в пиксельный шейдер слать свои данные.

Ладно, идея следующая.

Берешь текстуру (например 100х100 пикселей), ставишь ей тайлинг в твоем случае (2х2 - то есть две текстуры на две)
Создаешь маску (размером 200х200 пикселей - потому что у тебя основная -2х2 (2*100х2*100)

Пишешь шейдер, в него кладешь основную текстуру (не забыв про тайлинг 2х2) и маску (а вот у него тайлинг 1х1)

Потом доходишь до пиксельного (фрагментого) шейдера. Берешь пиксель с маски, и смотришь, если он белый
(if mask.rgb == white)
то пишешь пиксель из основной текстуры.

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

#10
13:10, 6 авг 2014

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

Если число квадратов неизвестно, то вместо черно-белой маски тебе надо рисовать текстурные координаты, зашифрованные в цвете.

#11
13:22, 6 авг 2014

Gladiator
Тебе вот это что ли нужно:
sh_result | Помогите написать шейдер
тут и проекция и маска и паттерны, вроде все как по заказу, единственное различие - нужно знать размер маски.

#12
14:48, 6 авг 2014

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;

#13
14:48, 6 авг 2014

kroonk
А что это ?

#14
15:14, 6 авг 2014

Gladiator
Это результат работы шейдера. Он по маске, содержащей белые пиксели(в данном случае 2x2), выводит нужные картинки, проецируя на любую поверхность(в данном случае 2 перекрещенных параллелепипеда).
На вход требуется:
world-матрица объекта, на который проецируется изображение
view-projection-матрица камеры
view-projection-матрица источника проекции
текстура маски
текстура паттерна
размер маски в пикселях

Страницы: 1 2 Следующая »
ПрограммированиеФорумОбщее

Тема в архиве.