Всех приветствую!
Пробую перенести простенький шейдер в свою программу.
Тут появились вопросы:
1) В shadertoy только фрагментный шейдер (?) используется, поэтому
в своей программе вершинный не нужен? Или же все таки нужен такой простой квадрат-холст на все окно приложения, на который уже растеризует фрагментный.
2) В shadertoy есть uniform переменные, в частности оч. важная iResolution.
Как увидеть ee значения?, где она задается в shadertoy?
Еще, не понятно, например, что делают следующие строки:
vec2 uv = fragCoord/iResolution.xy;
vec2 myuv = vec2(uv-vec2(0.5,0.5));
PS. Мой шейдер такой: просто круг
#version 430 core
out vec4 FragColor;
uniform vec2 resolution;
float sdCircle( vec2 p, float r )
{
return length(p) - r;
}
void main()
{
vec2 p = gl_FragCoord.xy/resolution.xy;
float d = sdCircle(p, 1.0);
vec3 col = (d>0.0) ? vec3(0.9,0.6,0.3) : vec3(0.65,0.85,1.0);
FragColor = vec4(col, 1.0);
}
Gyros
Нажимаешь в контекстном меню страницы "Просмотр кода страницы" и читаешь что там делается.
Если интересует iResolution, в просмотре кода нажимаешь поиск по странице и ищешь где оно упоминается
header += "uniform vec3 iResolution;\n" +
...
this.mRenderer.SetShaderConstant3F( "iResolution", xres, yres, 1.0);1) Да, в shtoy работает фрагментный шейдер , на полноэкранном кваде. Нужен тебе вертексный или нет - решать тебе , если нужно во фрагментный прокидывать какие-то кастомные аттрибуты через вершины, делать дисплейсмент и т.п.
2) Юниформы прокидываются в шейдер из вне. Как правило полезно иметь доступ к текущему времени , размеру экрана ( особенно для экранных эффектов )и т.п. iResolution соотв-но хранит размер окна в пикселях. Где задаётся ответили выше.
vec2 uv = fragCoord/iResolution.xy;
обычная нормализация координат пикселей : fragCoord хранит индекс текущего пикселя , iResolution размер окна. Соотв-но поделив первое на последнее получишь положение текущего пикселя в диапазоне [0,1] что на порядок удобнее чем использовать фактические значение ширины и высоты.
vec2 myuv = vec2(uv-vec2(0.5,0.5));
ну тут для удобства центр uv сделали в точке [0,0]. Т.е сначала uv получили в диапазоне [0,1] , а этим действием всё сместили до[-0.5,0.5]. Обычно еще умножают на 2 чтоб было [-1,1] , но видимо не было нужды. Это обычно делают для радиальных эффектов : использовать центр в 0 удобнее чем считать всё относительно [0.5,0.5] и т.п.
Спасибо, CD, RandomStroke!
С пунктом 2) я разобрался, спасибо, но появился новый вопрос:
на сайте glslsandbox.com для шейдеров есть, как бы zoom (x1, x2, x4, x8) - чем выше, тем больше пикселизация получаемого изображения. Чтобы реализовать этот zoom, нужно сделать uniform float zoom, и как-то домножать к fragCoord/iResolution.xy?
По поводу 1)-го пункта: у меня в обычной программе на С+OpenGL+GLSL4, если нет vbo (т.е. вершин - в данном случае квадрата, а значит и вершинный шейдер есть ), то ничего выводиться из фрагментного не будет (фрагментному как бы не на чем "рисовать"). Будет черный экран и все, никакого круга не будет. Круг появляется только когда я добавляю вначале вершинный шейдер в который я передаю координаты квадрата. Тогда на квадрате я вижу круг.
Ваши слова " на полноэкранном кваде", как трактовать?: т.е. в shadertoy определенно ЕСТЬ вершинный шейдер с квадратом в полный экран? (а значит там устанавливаются и матрицы модельно-видового и проекционного преобразования).
UPDATE
Посмотрел Page Source страницы с типичным шейдером glslsandbox.com
Там действительно есть вершинный шейдер.
создание буфера:
surface.width = surface.height * parameters.screenWidth / parameters.screenHeight;
var halfWidth = surface.width * 0.5, halfHeight = surface.height * 0.5;
gl.bindBuffer( gl.ARRAY_BUFFER, surface.buffer );
gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( [
surface.centerX - halfWidth, surface.centerY - halfHeight,
surface.centerX + halfWidth, surface.centerY - halfHeight,
surface.centerX - halfWidth, surface.centerY + halfHeight,
surface.centerX + halfWidth, surface.centerY - halfHeight,
surface.centerX + halfWidth, surface.centerY + halfHeight,
surface.centerX - halfWidth, surface.centerY + halfHeight ] ), gl.STATIC_DRAW );создание вершинного шейдера:
var vertex = document.getElementById( 'surfaceVertexShader' ).textContent; var vs = createShader( vertex, gl.VERTEX_SHADER );
вывод двух треугольников:
gl.bindFramebuffer( gl.FRAMEBUFFER, frontTarget.framebuffer ); gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT ); gl.drawArrays( gl.TRIANGLES, 0, 6 );
Ну да , создаётся квад ( в простейшем случае) размер которого равен размеру окна вывода. Пикселизацию я лично делал вот так :
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/iResolution.xy;
vec2 zoom_2 = iResolution.xy * 0.5 ;
vec2 zoom_4 = iResolution.xy * 0.25 ;
vec2 zoom_8 = iResolution.xy * 0.125 ;
uv = floor( uv * zoom_2 ) / zoom_2 ;
//uv = floor( uv * zoom_4 ) / zoom_4 ;
//uv = floor( uv * zoom_8 ) / zoom_8 ;
vec4 tx = texture(iChannel0,uv);
Соотв-но делаешь дискретизацию через floor оператор с последующей нормализацией.
Тема в архиве.