Как стать автором
Обновить

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

Время на прочтение4 мин
Количество просмотров2.5K
image

Это вторая часть проекта, в которой мы накладываем динамический 2d-паттерн на 3d-объект. Вы можете начать с первой части (Часть 1) или просто скопировать итоговый код несколькими абзацами ниже.

Некоторое время назад я создал паттерн, который генерировался при помощи нескольких строк кода в библиотеке p5.js.
p5.js — это библиотека для Javascript, созданная в 2014 году. Ее основная цель — стать окном в мир программирования для дизайнеров, художников, учителей и прочих представителей творческих профессий. Он поддерживает и анимацию, и схемы, легко переводится в веб-формат.

Сейчас я расскажу, как сделать финальную часть — наложить паттерн на 3d-объект (в данном случае — куб).

Для начала работы с нуля надо создать проект в онлайн-редакторе editor.p5js.org Мы продолжаем изменять следующий код:

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.06
  a = a + 0.3
    
}

Чтобы сделать наш холст объемным, нам надо добавить параметр WEBGL в функцию, создающую наш канвас: createCanvas(400,400,WEBGL). Поскольку точка отсчета для такого объекта и так находится в центре, нам можно (и нужно!) удалить translate(200,200), который выполнял корректировку при плоском изображении.

Чтобы разнообразить цветовую гамму и сделать более эффектное изображение, давайте заменим параметры fill() на наши переменные r,a,c — теперь с каждой новой итерацией бесконечного цикла draw() цвет эллипсов будет чуть-чуть меняться. Также давайте добавим немного расстояния между кругами и углы наклона, изменив скорость изменения переменных c и a.

  с = с + 0.06
  a = a + 0.3

В качестве последнего улучшения, давайте добавим push() перед нашим кодом паттерна и pop() после. Обрамление таким способом делает код изолированным — на него не будут влиять другие объекты, которые мы будем создавать.

let r=10
let a=0
let c=20

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

function draw() {
  push()
  let x = r+c*cos(a);
  let y = r+c*sin(a);
  fill(r,a,c);
  ellipse (x,y,10,10);
  c = c + 0.09
  a = a + 0.8
  pop()
}

image

В итоге у нас получится что-то такое. Самое время создать куб.

В той же функции draw(), после pop() добавим код коробки:

  push()
  box(200)
  pop()

Сейчас коробка c размером 200 повернута к нам только одной из сторон и выглядит как просто квадрат. Чтобы оценить объем, нам надо ее развернуть. Для этого в переменные верхнего уровня к уже имеющимся там r, a,c добавим четвертую — angle с дефолтным значением 0. Чтобы этот параметр влиял на наш куб, после второго push(), но до создания коробки. добавим три функции: rotateX(), rotateY(), rotateZ() с параметром angle для каждого.

Логично, что объект с углом поворота в 0 градусов крутиться не будет, поэтому добавляем изменение значения переменной angle на 0.003 (для начала будет достаточно). В итоге мы получаем такой код:

let r=10
let a=0
let c=20
let angle = 0

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

function draw() {
  push()
  let x = r+c*cos(a);
  let y = r+c*sin(a);
  fill(r,a,c);
  ellipse (x,y,10,10);
  c = c + 0.09
  a = a + 0.8
  pop()
  
  push()
  rotateX(angle), 
  rotateY(angle), 
  rotateZ(angle)
  box(200)
  angle = angle + 0.003
  pop()
}

Поскольку наш фон создается только один раз (он находится в setup) — мы ловим первый баг наш куб стирает фон при повороте.

image

Чтобы его пофиксить, можно просто перенести background(200) внутрь функции draw() Однако теперь мы ловим другую проблему — наши круги начинают пропадать, как они это делали в начале, поскольку теперь они затираются с каждым новым циклом и возникают лишь на долю секунды из небытия.

Чтобы решить эту проблему нам необходимо создать новую переменную (например, art) без дефолтного значения в самом начале рядом с другими переменными верхнего уровня.

Внутри функции setup() мы приравниваем ее к функции createGraphics(400,400), чтобы потом использовать ее в других местах.
Убедитесь, что вы задаете те же параметры, что и при создании Canvas, чтобы соблюсти размерность.

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

art.fill(r,a,c);
  art.ellipse (x,y,10,10);

После этого осталось наложить паттерн на куб в качестве текстуры. Для этого уже внутри кода куба-коробки добавляем свойство texture(art). Логика следующая: мы создаем сущность графического изолированного объекта art, который вызывает функции создания паттерна с заданными свойствами, и после мы отдаем art в качестве параметра свойства текстура для куба.

let r=10
let a=0
let c=20
let angle = 0
let art

function setup() {
  createCanvas(400, 400, WEBGL);
  art = createGraphics(400,400);
}

function draw() {
  background(220);
  push()
  let x = r+c*cos(a);
  let y = r+c*sin(a);
  art.fill(r,a,c);
  art.ellipse (x,y,10,10);
  c = c + 0.09
  a = a + 0.8
  pop()
  
  push()
  texture(art)
  rotateX(angle), 
  rotateY(angle), 
  rotateZ(angle)
  box(200)
  angle = angle + 0.003
  pop()
}

image

Осталось решить последнюю проблему: наш паттерн начинает проявляться с углов куба. Чтобы начать с центра, мы можем просто прибавить половину ширины и длины куба к параметру x и y, чтобы сместить центр старта отрисовки паттерна.

art.ellipse (x+200,y+200,10,10);

image

Если вы хотите разнообразить паттерн — можете попробовать просто изменить параметры или даже добавить несколько пересекающихся узоров, например, из другого проекта — Как воссоздать эффект муарового узора в библиотеке p5.js для новичка (быстрый гайд)
→ Идея и часть исходного кода взята из статьи Nazia Fakhruddin: Creating 2D texture on a 3D shape in p5.js

Ссылка на итоги проекта
Теги:
Хабы:
Всего голосов 1: ↑1 и ↓0+1
Комментарии0

Публикации

Истории

Работа

Веб дизайнер
41 вакансия
React разработчик
59 вакансий

Ближайшие события