Рецепты Houdini. Работа с уровнем Details

В отличии от обычных редакторов в Houdini каждой точке или полигону можно присвоить любые атрибуты (переменные) на этом строится вся философия редактора. Но кроме точек и полигонов, есть еще один уровень - Details - самый верхний. В нем обычно хранятся параметры всего объекта. Но также в нем можно хранить глобальные переменные для работы на нижних уровнях.

В отличии от обычных редакторов в Houdini каждой точке или полигону можно присвоить любые атрибуты (переменные) на этом строится вся философия редактора.

Чтобы было интереснее решим задачу: Необходимо заданный прямоугольник заполнить плитками 2х2, 1х2 и 1х1.
Алгоритм:

  • Выберем случайную точку на поле.
  • Разместим квадрат 2х2 в точке и покрутим его по 90°. Если в одной из позиции можно разместить, то помещаем.
  • Если квадрат 2х2 не получилось поместить, пробуем также с палкой 1х2.
  • Если палка 1х2 не поместилась, то пихаем квадрат 1х1.
  • Повторяем пока не заполнится всё поле.

Эту задачу можно сделать в одном Attribute Wrangle. Но мы вспомним правило рефакторинга: одна функция - одно действие.

Поместим в Details переменные.

В отличии от обычных редакторов в Houdini каждой точке или полигону можно присвоить любые атрибуты (переменные) на этом строится вся философия редактора.-2
setdetailattrib(0,"blocktype","block2x2","set");
setdetailattrib(0,"maxx",chi("MaxX"),"set");
setdetailattrib(0,"maxy",chi("MaxY"),"set");
setdetailattrib(0,"seed",chf("Seed"),"set");
setdetailattrib(0,"status","init","set");

В отличии от обычных редакторов в Houdini каждой точке или полигону можно присвоить любые атрибуты (переменные) на этом строится вся философия редактора.-3

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

В отличии от обычных редакторов в Houdini каждой точке или полигону можно присвоить любые атрибуты (переменные) на этом строится вся философия редактора.-4
setdetailattrib(0,"status","init","set");
int maxx = detail(0,"maxx",0);
int maxy = detail(0,"maxy",0);
float seed = detail(0,"seed",0);
int rx = 1 + fit01(rand(seed),0,maxx-2);
int ry = 1 + fit01(rand(seed+78),0,maxy-2);
setdetailattrib(0,"rx",rx,"set");
setdetailattrib(0,"ry",ry,"set");
int pn = ry * maxx + rx;
setdetailattrib(0,"pn",pn,"set");

Размещаем квадрат 2х2.

В отличии от обычных редакторов в Houdini каждой точке или полигону можно присвоить любые атрибуты (переменные) на этом строится вся философия редактора.-5
if (detail(0,"blocktype",0)=="block2x2"){
string status = "setting";
setdetailattrib(0,"status",status,"set");
int id = chi("id");
int maxx = detail(0,"maxx",0);
int maxy = detail(0,"maxy",0);
float seed = detail(0,"seed",0);
int rx = detail(0,"rx",0);
int ry = detail(0,"ry",0);
int pn = detail(0,"pn",0);
vector2 dir[] = {{-1,-1},{-1,1},{1,-1},{1,1}};
int d = 0;
//printf (itoa(rx1)+":"+itoa(ry1)+"\n");
if ( prim(0,"blockid",pn) == 0)
{
for (d=0;d<4;d++)
if (status == "setting"){
int pn1 = (ry + dir[d].y) * maxx + rx;
int pn2 = (ry) * maxx + (rx + dir[d].x);
int pn3 = (ry + dir[d].y) * maxx + (rx + dir[d].x);

if ( prim(0,"blockid",pn1) == 0
&& prim(0, "blockid", pn2) == 0
&& prim(0, "blockid", pn3) == 0 ){

setprimattrib(0,"blockid",pn, id, "set");
setprimattrib(0,"blockid",pn1, id, "set");
setprimattrib(0,"blockid",pn2, id, "set");
setprimattrib(0,"blockid",pn3, id, "set");
status = "set ok";
}
}
}
setdetailattrib(0,"status",status,"set");
}

Здесь самое главное - в результате функции мы отправляем в Details результат разместили квадрат или нет.

Еще в этой ноде используется обращение к Details цикла, а именно берем номер итерации

detail("../foreach_count1/","iteration",0)

Нода set_1x2 это копипаст с set_2x2, с минимальными правками

if (detail(0,"blocktype",0)=="block2x2"){
string status = "setting";
setdetailattrib(0,"status",status,"set");

int id = chi("id");
int maxx = detail(0,"maxx",0);
int maxy = detail(0,"maxy",0);
float seed = detail(0,"seed",0);
int rx = detail(0,"rx",0);
int ry = detail(0,"ry",0);
int pn = detail(0,"pn",0);
vector2 dir[] = {{-1,-1},{-1,1},{1,-1},{1,1}};
int d = 0;
if ( prim(0,"blockid",pn) == 0)
{
for (d=0;d<4;d++)
if (status == "setting"){
int pn1 = (ry + dir[d].y) * maxx + rx;
int pn2 = (ry) * maxx + (rx + dir[d].x);

if ( prim(0,"blockid",pn1) == 0){
setprimattrib(0,"blockid",pn, id, "set");
setprimattrib(0,"blockid",pn1, id, "set");
status = "set ok";
}
else if ( prim(0,"blockid",pn2) == 0){
setprimattrib(0,"blockid",pn, id, "set");
setprimattrib(0,"blockid",pn2, id, "set");
status = "set ok";
}
}
}
setdetailattrib(0,"status",status,"set");
}

Перед переходом на новую итерацию мы меняем сид

В отличии от обычных редакторов в Houdini каждой точке или полигону можно присвоить любые атрибуты (переменные) на этом строится вся философия редактора.-6
int pn = detail(0,"pn",0);
float seed = detail(0,"seed",0);
setdetailattrib(0,"seed",seed+pn,"set");

После цикла удалим граничные плитки, так как там не было проверки

В отличии от обычных редакторов в Houdini каждой точке или полигону можно присвоить любые атрибуты (переменные) на этом строится вся философия редактора.-7
int maxx = detail(0,"maxx",0);
int maxy = detail(0,"maxy",0);
int pn = 0;
for (int x = 0; x<maxx; x++){
pn = x;
setprimattrib(0,"blockid",pn, -1, "set");
pn = (maxy-1) * maxx + x;
setprimattrib(0,"blockid",pn, -1, "set");
}
for (int y = 0; y<maxy; y++){
pn = (y) * maxx + 0;
setprimattrib(0,"blockid",pn, -1, "set");
pn = (y) * maxy + (maxx-1);
setprimattrib(0,"blockid",pn, -1, "set");
}