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

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

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

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

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

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

-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");

-3

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

-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.

-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"); }

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

-6
int pn = detail(0,"pn",0); float seed = detail(0,"seed",0); setdetailattrib(0,"seed",seed+pn,"set");

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

-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"); }

Настольная книга рецептов геймдайвераРецепты Houdini, Maya, UE4 и 5 и другого связанного с геймдевом
19 подписчиков