Как написать шейдер повторения текстуры без обрезок на GLSL

В этом уроке напишем собственный шейдер для WebGL на языке GLSL. Он будет накладывать текстуру на 3D-объект таким образом, чтобы она повторялась нужное число раз по горизонтали.

58 открытий2К показов
Как написать шейдер повторения текстуры без обрезок на GLSL

В этом уроке напишем собственный шейдер для WebGL на языке GLSL. Он будет накладывать текстуру на 3D-объект таким образом, чтобы она повторялась нужное число раз по горизонтали. При этом будем учитывать, что часть текстуры может выйти за границы объекта. В этом случае мы хотели бы не показывать данный кусочек изображения.

Текстуру я сгенерировал с помощью рисования текста на Canvas (если хотите, чтобы я сделал урок по этой теме, то напишите, пожалуйста, в комментарии).

Как написать шейдер повторения текстуры без обрезок на GLSL 1
Текстура в виде текста в формате JPEG

Создадим простую 3D-сцену с помощью Three.js, добавим плоскость и применим к ней «шейдерный» материал (ShaderMaterial).

Для начала передадим ему стандартный вершинный шейдер:

			varying vec2 vUv;

void main()
{
  vUv = uv;
  gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
}

		

Далее напишем фрагментный шейдер, который просто «натянет» наше текстуру на плоскость:

			varying vec2 vUv;

void main()
{
  vec2 uv = vUv;
  vec4 color = texture2D(map, uv);
  gl_FragColor = color;
}

		

Вот, что мы получим:

Как написать шейдер повторения текстуры без обрезок на GLSL 2
Результат наложения текстуры на плоскость в 3D-пространстве

Наша текстура растянулась на 3D-объект с искажениями. Теперь попробуем размножить текстуру. Для этого нужно вычислить, сколько понадобится повторов нашего изображения для покрытия модели:

			const aspectPlane = widthPlane / heightPlane;
const textureAspect = textureWidth / textureHeight;
const repeat = aspectPlane / textureAspect;

		

Здесь мы делим соотношение сторон нашей плоскости (aspectPlane) на соотношение сторон текстуры (textureAspect). Передадим это число в наш фрагментный шейдер и создадим повторы текстуры с помощью встроенной в GLSL функции mod:

			uniform sampler2D map;
uniform float repeat;
varying vec2 vUv;

void main()
{
  vec2 uv = vUv;

  uv.x = mod(uv.x * repeat, 1.0);
  
  vec4 color = texture2D(map, uv);
  gl_FragColor = color;
}

		

Получаем повтор нашей картинки на протяжении всей плоскости. Однако, есть один недостаток. Последний повтор уходит за границы нашей 3D-модели.

Как написать шейдер повторения текстуры без обрезок на GLSL 3
Результат повтор текстуры с обрезанной частью

Для начала, чтобы исправить данную проблему, нужно вычислить координату от 0 до 1 той части текстуры, которая не влезает. Для этого разделим дробную часть нашего параметра repeat (найдем её с помощью функции fract) на само значение числа повторов. И напишем наш шейдер с нужным условием:

			uniform sampler2D map;
uniform float repeat;
varying vec2 vUv;

void main()
{
  vec2 uv = vUv;
  
  if (uv.x > 1.0 - fract(repeat) / repeat)
  {
    gl_FragColor = vec4(1.0, 0.0, 1.0, 1.0);
    return;
  }
  
  uv.x = mod(uv.x * repeat, 1.0);
  
  vec4 color = texture2D(map, uv);
  gl_FragColor = color;
}

		

В данном примере мы просто закрашиваем не влезающую часть текстуры в произвольный цвет.

Как написать шейдер повторения текстуры без обрезок на GLSL 4
Окончательный результат работы шейдера

Данный пример в работе можно посмотреть по ссылке.

Следите за новыми постами
Следите за новыми постами по любимым темам
58 открытий2К показов