ПрограммированиеФорумГрафика

Перенос шейдера с shadertoy в свое приложение

#0
17:54, 22 мая 2023

Всех приветствую!
Пробую перенести простенький шейдер в свою программу.
Тут появились вопросы:
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);
}

#1
18:38, 22 мая 2023

Gyros
Нажимаешь в контекстном меню страницы "Просмотр кода страницы" и читаешь что там делается.
Если интересует iResolution, в просмотре кода нажимаешь поиск по странице и ищешь где оно упоминается

    header += "uniform vec3      iResolution;\n" +
...
    this.mRenderer.SetShaderConstant3F(  "iResolution", xres, yres, 1.0);
#2
0:13, 23 мая 2023

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] и т.п.

#3
10:04, 23 мая 2023

Спасибо, 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 );
#4
19:38, 23 мая 2023

Ну да , создаётся квад ( в простейшем случае) размер которого равен размеру окна вывода. Пикселизацию я лично делал вот так :

    // 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 оператор с последующей нормализацией.

ПрограммированиеФорумГрафика

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