НОВОСТИ [Перевод] Генеративное искусство: создание треугольников после 3 часов изучения p5.js

Alvaros
Онлайн
Регистрация
14.05.16
Сообщения
21.452
Реакции
101
Репутация
204
У меня небольшой опыт использования компьютера для творчества и искусства. Когда я начал изучать p5.js, я вдохновился геометрическими рисунками и решил написать код, чтобы создать что-то крутое.

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

_lwza67asite-gqhwihy4zpsrp4.png

Случайные треугольники

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

Во время долгой поездки я мысленно прокручивал в голове всякие идеи, и решил сделать так, чтобы все эти треугольники были связаны друг с другом и не дублировались. Перед началом проекта мы обсуждали данную концепцию, но пришли к выводу: это слишком сложно сделать, учитывая, что мы всего лишь 3 часа изучаем p5.js. Я посмотрел библиотеки, которые реализовывали эту концепцию, но решил создать свое собственное решение для практики. Во время поездок мне сложно рисовать, но как только я смог остановиться, я набросал это:

okpm6pctw3o1oqogbbtrcz7akwc.jpeg

Набросок, который я сделал после долгой поездки, о том, как я мог бы подойти к выполнению этой концепции

Что если вместо случайных координат для создания треугольников я мог бы:
  • настроить сетку на канвас (плоскость)
  • случайным образом расположить точки в этой сетке
  • сохранить координаты в массиве
  • затем систематически пройти через эти точки и начать использовать их для создания новых треугольников

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

Создание сетки.

Для того, чтобы я мог видеть отображение своих идей, я поместил сетку на канвас (поверхность):


function setup() {
createCanvas( windowWidth, windowHeight )
colorMode( HSB )
noLoop()
noStroke()
}


function draw() {
background( 20, 20, 20)

// Setup a grid so i can figure out the uppper and lower bounds
// of where the points should go

var columns = 5
var rows = 5
var columnWidth = windowWidth / columns
var columnHeight = windowHeight / rows
fill( 30, 30, 30)
stroke( 90, 90, 90 )
rect( 0, 0, columnWidth, columnHeight )

// Create a row

for ( i = 0; i < rows; i++ ){

// Create a column

for ( j = 0; j < columns; j++ ){

rect( j * columnWidth, i * columnHeight, columnWidth, columnHeight )
}
}
}



И в итоге получается вот так. Для начала неплохо.

lggvozfslgztmbdcjhvyq4a1n7g.png

Сетка базовых линий

Генерация случайных точек.

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


for ( j = 0; j < columns + 1 ; j++ ){
rect( j * columnWidth, i * columnHeight, columnWidth, columnHeight )

//create my point

var pointPositionX = random( j * columnWidth - columnWidth, j * columnWidth )
var pointPositionY = random( i * columnHeight - columnHeight, i * columnHeight )
circle( pointPositionX, pointPositionY, 10 )
}


и получил какие-то точки:

jq_0qfdnr4en2n3ys5ubd_r5qiw.png

Визуализация координат

Сохранение координат в массивах.

Чтобы вернуться назад и сформировать треугольники, мне надо где-то хранить все эти координаты.


for ( i = 0; i < rows + 1; i++ ){
var columnData = []
// Create a column
for ( j = 0; j < columns + 1 ; j++ ){
rect( j * columnWidth, i * columnHeight, columnWidth, columnHeight )
//create my point
var pointPositionX = random( j * columnWidth - columnWidth, j * columnWidth )
var pointPositionY = random( i * columnHeight - columnHeight, i * columnHeight )
columnData.push( [pointPositionX, pointPositionY] )
console.log( columnData )
//circle( pointPositionX, pointPositionY, 10 )
}
allCoordinates.push( columnData )
console.log( allCoordinates )
}



С тех пор, как я писал на JavaScript, прошло уже несколько лет, но он, кажется, все еще получается у меня легко. Вот то, что я вывел на консоль. Думаю, что у меня получилось сделать это близко к задуманному… за исключением отрицательных чисел.

f1v8wltxc5jg3wzcsrcf7blrf-4.png

Те цифры, которые почти кажутся правильными

Первый треугольник.

Да, те отрицательные числа были ошибкой. Иногда математика мне кажется странной – зачем я должен был бы вычитать из 0? Кто знает. Полагаю, мне казалось, что i и j были 1? Короче, я исправил это.

Я также не имею понятия, зачем мне понадобились два массива. Мне следовало просто сохранить все координаты в массив allCoordinates[].

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

Вот как закончился этот код:

var allCoordinates = [];
// Create a row
for ( i = 0; i < rows + 1; i++ ){
// Create a column
for ( j = 0; j < columns + 1 ; j++ ){
rect( j * columnWidth, i * columnHeight, columnWidth, columnHeight )
//create my point
var pointPositionX = random( j * columnWidth + columnWidth, j * columnWidth )
var pointPositionY = random( i * columnHeight + columnHeight, i * columnHeight )
allCoordinates.push( [pointPositionX, pointPositionY] )
circle( pointPositionX, pointPositionY, 10 )
console.log(allCoordinates)
}
}
// Create the first triangle
fill( 90, 90, 90 )
var currentPoint = 0
var firstPointX = allCoordinates[0][0]
var firstPointY = allCoordinates[0][1]
var secondPointX = allCoordinates[1][0]
var secondPointY = allCoordinates[1][1]
var thirdPointX = allCoordinates[6][0]
var thirdPointY = allCoordinates[6][1]
triangle( firstPointX, firstPointY, secondPointX, secondPointY, thirdPointX, thirdPointY )



И результат:

xeq8beywu72hrih_sjlllw4yijs.png

Эй, первый треугольник находится в нужном месте!

Отлично! А теперь я должен сделать из этого цикл и пройти через каждую из них.

После 2 часов зависания моего браузера...

Я потратил достаточно времени, работая над тем, как прогнать каждую точку через массив и создать 2 треугольника для каждой точки. Я запутывался и перетасовывал все очень много раз, учитывая также то, что мне надо было знать, где что находится: в первой или последней строке, а может в последнем столбце – все было очень странно.

Наконец-то я добрался до того момента, где меня устраивал результат, и я знал, что, если бы я просто потратил еще один час на работу, я мог бы получить практически идеальный результат, но я был готов двигаться дальше и не заниматься перфекционизмом. Я не буду показывать промежуточный код, только визуальные результаты:

8pmlkleaa1niqbqbyduhpnixztm.png

Да, есть недостающие треугольники, я просто не мог заставить себя исправить их прямо сейчас

Вернемся к художественной стороне всего этого дела.

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

q58yldqzx7hjlxrmvsdu2qsg130.png

Все ближе к результату, который мне нравится

Окончательная визуализация и какой-то довольно неряшливый код.

В конце концов, рендер начал выдавать результаты все лучше и лучше, достаточно хорошие, чтобы я мог остановиться на данный момент.

Это окончательная визуализация:

m9_dwsmytkq9jzjgz5by--zqwpu.png

Финальная визуализация, которую я сделал до того, как назвать ее, завершилась. Думаю, мне нравится!

И сам код на p5.js. Он не дочищен, но отражает процесс творческих мук. Наслаждайтесь!

Итоговый код

function setup() {
var canvas = createCanvas( 1600, 1600 )
canvas.parent("canvasArea");
colorMode( HSB )
noLoop()
noStroke()
}

function draw() {
background( 197, 31, 65 )

// Setup a grid so i can figure out the uppper and lower bounds
// of where the points should go
var columns = 20
var rows = 20

var columnWidth = 1600 / columns
var columnHeight = 1600 / rows

// Show the grid
fill( 18, 11, 18 )
//stroke( 90, 90, 90 )
//rect( 0, 0, columnWidth, columnHeight )

var allCoordinates = [];
// Create a row
for ( i = 0; i < rows; i++ ){
// Create a column
for ( j = 0; j < columns ; j++ ){
rect( j * columnWidth, i * columnHeight, columnWidth, columnHeight )
//create my point
var pointPositionX = random( j * columnWidth + columnWidth, j * columnWidth )
var pointPositionY = random( i * columnHeight + columnHeight, i * columnHeight )

allCoordinates.push( [pointPositionX, pointPositionY] )
circle( pointPositionX, pointPositionY, 10 )
}
}
var whichRow = 1
var l = 1
while ( l < allCoordinates.length ){

//firstTriangle
if (whichRow == 1 || whichRow == rows){
//don't do anything on the first and last row (thse need just one triangle)
}
else{
if ( (l + 1) % rows == 0 || l == 0){
console.log("it's the last item, do nothing")
}
else{
//Triangle 1
var colorChoices = [
[45, 15, 75],
[22, 42, 95],
[5, 55, 75],
[0, 61, 95]
]

var randomColorChoice = Math.floor(random(0,4))
fill( colorChoices[randomColorChoice][0], colorChoices[randomColorChoice][1], Math.floor(random(50,100)) )
//stroke( 200, 90, 90 )

var currentPoint = l
var nextPoint = l + 1
var bottomPoint = l + rows
var firstPointX = allCoordinates[currentPoint][0]
var firstPointY = allCoordinates[currentPoint][1]
var secondPointX = allCoordinates[nextPoint][0]
var secondPointY = allCoordinates[nextPoint][1]
var thirdPointX = allCoordinates[bottomPoint][0]
var thirdPointY = allCoordinates[bottomPoint][1]
triangle(firstPointX, firstPointY, secondPointX, secondPointY, thirdPointX, thirdPointY)

//Triangle 2
randomColorChoice = Math.floor(random(0,4))
fill( colorChoices[randomColorChoice][0], colorChoices[randomColorChoice][1], Math.floor(random(50,100)) )
//stroke( 200, 90, 90 )

var currentPoint = l
var nextPoint = l - rows
var bottomPoint = l + 1
var firstPointX = allCoordinates[currentPoint][0]
var firstPointY = allCoordinates[currentPoint][1]
var secondPointX = allCoordinates[nextPoint][0]
var secondPointY = allCoordinates[nextPoint][1]
var thirdPointX = allCoordinates[bottomPoint][0]
var thirdPointY = allCoordinates[bottomPoint][1]
triangle( firstPointX, firstPointY, secondPointX, secondPointY, thirdPointX, thirdPointY )
}
}
l++
if ( l % rows == 0 ){ whichRow++ }
}
}


Если вы хотите попробовать еще что-то или начать с более простых проектов:

 
Сверху Снизу