Наложение 2d-текстуры на 3d-объект с использованием p5.js (часть 1 — создание паттерна)

    image

    Наложение плоского рисунка или узора на объемный объект — это всегда нетрививальная задача, а если при этом хочется сделать это с какой-то анимацией, сложность возрастает в разы.

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

    Проще всего начать с создания нового проекта в онлайн редакторе editor.p5js.org

    По умолчанию новый проект имеет следующий вид:

    function setup() {
      createCanvas(400, 400);
    }
    
    function draw() {
      background(220);
    }

    function setup() — задает функцию, которая выполняется только раз
    function draw() — повторяется в бесконечном цикле

    Начинаем мы с создания 2D радиального узора, который потом наложим на наш куб. При его создании мы сначала будем использовать Полярные координаты, а уже потом переведем их в привычные большинству декартовые координаты вида x,y.

    Что важно понимать: полярная координата точки определяется двумя числами:

    r — расстояние от исходной точки (например, центра холста) до целевой точки.
    a — угол воображаемой линии, относительно исходной точки, на которой находится целевая точка

    Таким образом первый параметр может меняться от 0 до бесконечности, а второй — от 0 до 360.

    Прелесть такого подхода в том, что он позволяет чертить достаточно сложные узоры буквально одной формулой.

    image

    Полярная роза задана уравнением r(φ )=2\sin φ

    Для создания переменных давайте в самом начале проекта добавим две переменные: первая ответственная за расстояние от центра и вторая за угол: let r=10 let a=0

    После чего в функцию draw(), которая выполняется в бесконечном цикле, добавим изменение переменной: a = a + 0.4

    В итоге у вас получится следующий код:

    let r =10
    let a =0
    function setup() {
      createCanvas(400, 400);
    
    }
    
    function draw() {
      background(220);
        a = a + 0.4
    }

    Теперь приступим к переводу координат в привычные нам Декартовые координаты x y. Если хотите понимать, что именно здесь происходит в коде, то лучше почитать учебник по тригонометрии, но поскольку для результата это не так важно, можно просто вставить код в ту же функцию draw():

    let x = r*cos(a)
    let y = r*sin(a)

    Чтобы наконец увидеть итоги наших математических вычислений, нам надо сделать две вещи:

    • закрасить объекты цветом (можно использовать внутренний словарь цветов или указать привычный код формата RGB — три числа)
    • задать форму распределения точек. Например, эллипс.

    function draw() {
      background(220);
      
      
      let x = r*cos(a);
      let y = r*sin(a);
      fill(255,0,0);
      ellipse (x,y,10,10);
      r = r + 0.4
        
    }

    image

    Параметры эллипса (положение по X, положение по Y, диаметр по X, диаметр по Y) мы задаем при помощи переменных по x и y. Поскольку переменная x зависит от переменной r, которая в нашем цикле постоянно увеличивается на 0.4, тот красный кружок, который мы увидим будет постоянно двигаться в левом верхнем углу.

    Чтобы переместить точку отсчета в центр, добавим функцию translate(200,200) перед переменной x. Теперь круг будет появляться по середине нашего холста.

    И давайте решим еще одну проблему — сейчас все круги, которые появляются, стираются с каждым новым циклом. Чтобы выйти из этого замкнутого круга, нам нужно вынести создание нашего canvas() за пределы функции draw() и перенести ее в функцию setup(), которая отвечает за создание окружения.
    image
    После этого изменения мы увидим что-то похожее на кружок загрузки. Главная проблема — что сейчас они расположены очень тесно к друг другу. Давайте добавим немного пространства, задав переменную верхнего порядка С со значением 20 и добавив ее изменение с каждым циклом на 0.6 (рядом с a). Ну и внедрим ее в наши тригонометрические формулы: x=r+c*cos(a) and y=r+c*sin(a)

    let r=10
    let a=0
    let с=20
    
    function setup() {
      background(220);
      createCanvas(400, 400);
      
    }
    
    function draw() {
    translate(200,200)
      let x = r+с*cos(a);
      let y = r+с*sin(a);
      fill(255,0,0);
      ellipse (x,y,10,10);
      с = с + 0.6
      a = a + 0.4
        
    }

    image

    Кажется, что-то начинает вырисовываться. Финально давайте уменьшим значение a до 0.3, с до 0.06

    с = с + 0.06
    a = a + 0.3

    image

    Заготовка для паттерна готова, время добавлять его на объем. О том, как это делать, я напишу в следующей части.

    Ссылка на часть 2

    Если вам понравилось, ссылки на материалы по p5.js:


    Идея и часть исходного кода взята из статьи Nazia Fakhruddin:Creating 2D texture on a 3D shape in p5.js

    Ссылка на итоги проекта
    AdBlock похитил этот баннер, но баннеры не зубы — отрастут

    Подробнее
    Реклама

    Комментарии 4

      +1
      А возможно ли на p5.js вот такое: https://jsfiddle.net/customizer/s3uzcqL1/.
        0
        Красивая штука) В целом, конечно, да. Вот пример крутящегося шара p5js.org/examples/3d-textures.html

        Сходу решение: добавить стрелку с изменением точки отрисовки в loop()

        Не факт, что будет проще текущего решения — все же three.js для этой цели лучше подходит, хотя, возможно, ресурс получится сэкономить через псевдо-3d.
          0
          Извините, но имелось в виду не просто вращение сферы, а вращение сферы, у которой полусферы вращаются в разные стороны относительно друг друга. При этом относительно внешнего наблюдателя вращение полусфер одинаковое.
          Собственно к чему все это, мне хочется пояснить как устроен электрический заряд и как заряды взаимодействуют друг с другом, с моей точки зрения, а для этого нужен инструмент визуализации. Мне показалось, что таким инструментом будет three.js, и даже взялся за перевод документации three.js. Но вот увидел p5.js и думаю, может будет проще применить эту библиотеку.
          Но похоже, у three.js возможностей все-же побольше.
            0
            Я не супере эксперт с three.js, но да. Я бы все же остался в нем. А про полусферы — да, понял. Наверное, если бы была сетка, было бы очевиднее, как он крутится.

      Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

      Самое читаемое