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

Alvaros
Онлайн
Регистрация
14.05.16
Сообщения
21.452
Реакции
101
Репутация
204
4s4trfjd_x_iewiw8ectzn3cqva.png


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

Некоторое время назад я создал паттерн, который генерировался при помощи нескольких строк кода в библиотеке p5.js.

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


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

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


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()

}
fodi7nd_wup_avsim2xk4yqcugy.png


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

В той же функции 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) — мы ловим первый баг наш куб стирает фон при повороте.

w5cxdthj4s6tyqx3jea88dnt9ng.png


Чтобы его пофиксить, можно просто перенести 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()
}


enyads2ckbcarldnouacdfmsz8m.png


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


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


gwcfuybz_4rc4eb7xclxv0b7x74.png


Если вы хотите разнообразить паттерн — можете попробовать просто изменить параметры или даже добавить несколько пересекающихся узоров, например, из другого проекта —

→ Идея и часть исходного кода взята из статьи Nazia Fakhruddin:

 
Сверху Снизу