// кастомный криптомат из атрибута (points, primitive)
s@`chs("name_crypto")` = sprintf('`chs("name_crypto")`%d', @`chs("attrib_name")`+chi("number"));

// нойз в вексе (points)
float noise = fit(snoise(@P * chf('scale'), chi('turbulence'), chf('rough'), chf('attenuation')), chf('min_noise'), chf('max_noise'), 0, 1);
@Cd=noise;

// выравнивание по двум точкам и оси (point)
int pt1 = chi('pt_num1');
int pt2 = chi('pt_num2');
vector v_pts = point(0, 'P', pt2) - point(0, 'P', pt1);
vector axis = {0, 0, 1};
@orient = dihedral(axis, v_pts);

// выравнивание через функцию intersect (points)
// input 0 - geo to, input 1 - geo from
vector hitdir = {0,10000,0};
vector uvw, hitPoint_high, hitPoint_low;

int prims_low = intersect(1, @P, hitdir, hitPoint_high, uvw);
int prims_high = intersect(1, @P, -hitdir, hitPoint_low, uvw);

if (prims_high >=0) @P = hitPoint_low;
if (prims_low >=0) @P = hitPoint_high;

// выравнивание по uv (points)
// input 0 - geo to, input 1 - geo from
int prim;
vector uv;

xyzdist(1, @P, prim, uv);
@P = primuv(1, 'P', prim, uv);

// нахождение минимального и максимального значения в атрибуте (points)
float values[];
float value;
int array_value = @numpt;

for (int i=0; i<array_value; i++) {
    value = point(geoself(), 'P', i);
    append(values, value);
}
@min_value = min(values);
@max_value = max(values);

// создание целочисленного атрибута из всех групп объекта (points)
string groups[] = detailintrinsic(0, 'pointgroups');
int x = 0;
foreach(string i; groups) {
    if(inpointgroup(0, i, @ptnum)==1) i@id_groups = x;
    x++;
}

// дистанция от камеры на геометрии (points)
matrix camxform = optransform(chs('camera_path'));
vector pos_cam = set(0,0,0) * camxform;
vector pos_ground = point(0, 'P', @ptnum);
float far = chf('far');
float d = distance(pos_cam, pos_ground);

if (d<far) @mask_obj = 1;
@mask_dist = chramp('ramp_distance', fit(d, 0, far, 1, 0));
@Cd = @mask_dist;

// забрать world трансформацию с объекта на obj уровне (detail)
string path = chs('path_node');
matrix m = optransform(opfullpath(path));
vector null_pos = set(m.ax, m.ay, m.az);

v@pos = set(m.ax, m.ay, m.az);
v@scale = cracktransform(0, 0, 2, @P, m);
v@rot = cracktransform(0, 0, 1, @P, m);
@orient = quaternion(matrix3(m));
addpoint(geoself(), null_pos);

// добавить эту трансформацию на точки (points)
v@pos = detailattrib(0, 'pos', 0, 1);
@orient = detailattrib(0, 'orient', 0, 1);
@scale = detailattrib(0, 'scale', 0, 1);

// создать группу по path атрибуту (glob) (primitive)
if (s@path ~= '*name*') setprimgroup(0, 'gr_name', @primnum, 1);

// случайные цвета точек по рампе (points)
int type_attrib = @ptnum;
float rnd_value = fit01(rand(type_attrib + chf('seed')), 0, 1) * 2;
vector ramp = chramp('ramp_color', rnd_value);

@Cd=ramp;

// случайные значения масштаба и поворота на точках (points)
float angle;
vector axis;
//random scale
@pscale=fit01(rand(@ptnum) * rand(ch('seed') * @ptnum), ch('min_scale'), ch('max_scale'));
//random rotation
axis = {0,1,0};
angle = fit((rand(@ptnum)) * chf('rotation'), 0, 1, 0, 10);
@orient = quaternion(angle, axis);

// собрал здесь функции для работы со строковыми атрибутами
s[]@path_split = split(s@path, '/'); // разбить массив символом
resize(s[]@path_split, 1); // изменить размер массива
push(s[]@path_split, 'preview'); // добавить объект в массив
i@len_path = len(s[]@pathSplit); // вычислить длину массива
s@name_attrib = pop(s[]@pathSplit, 1); // забрать строку из массива
s@name_join = join(s[]@pathSplit, '.'); // объединить массив символом в строку
s[]@slice = slice(s[]@test, 1, 5); // разрезать строку, начало строки/конец строки
i@nums = opdigits(string); // найти последние цифры в строке
f@nums = atof(re_replace(r'[^.0-9]+', '', s@path)); // вернуть цифры из строки
i@num = re_match ('word', s@path) // вернуть 1 если слово в строке
# arnold
# открыть параметр shdowmask на arnold light (по умолчанию он скрыт)
sel = hou.selectedNodes()
for light in sel:
    null_tg = light.parmTemplateGroup()
    copy_parm_template = null_tg.find("shadowmask")
    null_tg.hide(copy_parm_template, False)
    light.setParmTemplateGroup(null_tg)

# arnold
# добавить фильтр light decay на arnold light с вынесенным параметром far decay в папку Light
import re
sel = hou.selectedNodes()

for light in sel:
    g = light.parmTemplateGroup()
    folder = g.findFolder(' Light ')
    t = hou.ToggleParmTemplate('decay_far', 'decay far')
    p = hou.FloatParmTemplate("decay", "decay light", 1, default_value=[10])
    g.appendToFolder(folder, t)
    g.appendToFolder(' Light ', p)
    light.setParmTemplateGroup(g)
    light.allowEditingOfContents()
    childs = light.allSubChildren()
    for shader in childs:
        match  = re.search('arnold_vopnet', str(shader))
        if match:
            path_shader = shader.path()
            path_out = path_shader + '/OUT_light'
            out = hou.node(path_out)
            decay=shader.createNode('arnold::light_decay')
            decay.moveToGoodPosition()
            decay.parm('use_far_atten').setExpression('ch("../../../decay_far")')
            decay.parm('far_end').setExpression('ch("../../../decay")')
            out.setInput(2, decay)

# arnold
# скрипт создает референсную ноду arnold triplanar в материале
select_node = hou.selectedNodes()[0]
select_node_name = select_node.name()
network_path = '/'.join(select_node.path().split('/')[:-1])
network = hou.node(network_path)
sel_pos = select_node.position()
triplanar=network.createNode('arnold::triplanar')
triplanar.setPosition(sel_pos)
triplanar.move([0, -2])
script = 'ch("../' + select_node_name
triplanar.parm('scalex').setExpression(script+'/scalex")')
triplanar.parm('scaley').setExpression(script+'/scaley")')
triplanar.parm('scalez').setExpression(script+'/scalez")')
triplanar.parm('rotatex').setExpression(script+'/rotatex")')
triplanar.parm('rotatey').setExpression(script+'/rotatey")')
triplanar.parm('rotatez').setExpression(script+'/rotatez")')
triplanar.parm('offsetx').setExpression(script+'/offsetx")')
triplanar.parm('offsety').setExpression(script+'/offsety")')
triplanar.parm('offsetz').setExpression(script+'/offsetz")')
triplanar.parm('coord_space').setExpression('chs("../'+ select_node_name +'/coord_space")')
triplanar.parm('blend').setExpression(script+'/blend")')
triplanar.parm('cell').setExpression(script+'/cell")')
triplanar.parm('cell_rotate').setExpression(script+'/cell_rotate")')
triplanar.parm('cell_blend').setExpression(script+'/cell_blend")')

# arnold
# скрипт создает arnold light по позициям точек (также при наличии добавляет атрибут 'rotation')
import re
root = hou.node('/obj/')
name_light = 'name_light'
path_pt = '/obj/sphere1/OUT'
pt_node = hou.node(path_pt)
pts = pt_node.geometry().points()
list_num=[]

for pt in pts:
    list_num.append(pt)
    nums=str(len(list_num)-1)
    nums_int=int(nums)
    ar_light=root.createNode('arnold_light')
    ar_light.setName(name_light, unique_name=True)
    ar_light.move([0, -nums_int])
    attribs_pt = pt_node.geometry().pointAttribs()
    match_rotation = re.search("rotation", str(attribs_pt))     
    position_exp0 ='point("' + path_pt + '", '+ nums +', "P", 0)'
    position_exp1 ='point("' + path_pt + '", '+ nums +', "P", 1)'
    position_exp2 ='point("' + path_pt + '", '+ nums +', "P", 2)'
    rotation_exp0 ='point("' + path_pt + '", '+ nums +', "rotation", 0)'
    rotation_exp1 ='point("' + path_pt + '", '+ nums +', "rotation", 1)'
    rotation_exp2 ='point("' + path_pt + '", '+ nums +', "rotation", 2)'
    ar_light.parm('tx').setExpression(position_exp0)
    ar_light.parm('ty').setExpression(position_exp1)
    ar_light.parm('tz').setExpression(position_exp2)
    if match_rotation:
        ar_light.parm('rx').setExpression(rotation_exp0)
        ar_light.parm('ry').setExpression(rotation_exp1)
        ar_light.parm('rz').setExpression(rotation_exp2)

# добавить параметр lightmask на ноду instance (по умолчанию его нет)
sel = hou.selectedNodes()

for node_instance in sel:
    group = node_instance.parmTemplateGroup()
    folder = group.findFolder('Render')
    lm=hou.StringParmTemplate('lightmask', 'Light Mask', 1, default_value=('*',))
    lm.setStringType(hou.stringParmType.NodeReferenceList)
    tags = lm.tags()
    tags["opexpand"] = '1'
    tags["spare_category"] = 'Shading'
    tags["opfilter"] = '!!OBJ/LIGHT!!'
    tags["oprelative"] = '/obj'
    lm.setTags(tags)
    group.appendToFolder(folder, lm)
    node_instance.setParmTemplateGroup(group)

# перезагрузить текущую сцену
hip_path = str(hou.getenv("HIPFILE")) # get current path scene
hou.hipFile.save() # save scene
hou.hipFile.clear(suppress_save_prompt=True) # clear scene
hou.hipFile.load(hip_path) #load scene

# аналог save selected, скрипт сохраняет выделенные ноды по указанному пути
import hou, re
path_to_save = '/home/users/your_name/Documents/test.hip'
#attribs
hip_path = str(hou.getenv("HIPFILE"))
sel=hou.selectedNodes()
obj = hou.node('/obj/')
mat = hou.node('/mat/')
out = hou.node('/out/')
shop = hou.node('/shop/')
path_to_load = ''

hou.hipFile.save() #save scene
hou.copyNodesToClipboard(sel) #copy to clipboard select nodes

# find network
for nodes in sel:
    match_obj = re.search('/obj/', str(nodes.path()))  
    match_mat = re.search('/mat/', str(nodes.path()))  
    match_out = re.search('/out/', str(nodes.path()))
    #match_matnet = re.search('matnet', str(nodes.path()))
    shopnet_name = nodes.path().split('/')[-2]
    match_shopnet = re.search('shop', str(shopnet_name))
    matnet_name = nodes.path().split('/')[-2]
    match_matnet = re.search('matnet', str(matnet_name))
    if match_obj:
        path_to_load = obj
    if match_mat:
        path_to_load = mat
    if match_out:
        path_to_load = out    
    if match_matnet:
       path_to_load = mat    
    if match_shopnet:
        path_to_load = shop    
hou.hipFile.clear(suppress_save_prompt=True) # clear scene
hou.pasteNodesFromClipboard(path_to_load) # paste nodes from clipboard
hou.hipFile.save(path_to_save) # save scene
hou.hipFile.load(hip_path) # load current scene

# запустить программу через terminal
import os
path = '/home/users/name/local_arnold/5.6.0/18.5.462/scripts/bin/kick -info polymesh' #linux
path = "\"C:/ProgramData/Autodesk/ApplicationPlugins/MAXtoA_2021/kick -info polymesh\"" #windows
os.system(path)

# скрипт создает rivets из точек с группами
import re
obj=hou.node('/obj')
name_set = 'pt_name'
path = '/obj/sphere1/OUT'
pt_node = hou.node(path)
pts = pt_node.geometry().points()
groups = pt_node.geometry().pointGroups()
n_groups = len(groups) 
if n_groups == 1:
    groups_names = str(groups).split(' ')[1]
list_num=[]

for pt in pts:
    list_num.append(pt)
    iterator=len(list_num)
    nums = str(iterator-1)
    attribs_pt = pt_node.geometry().pointAttribs()
    match_N = re.search("(\'N\')", str(attribs_pt)) 
    match_up = re.search("(\'up\')", str(attribs_pt))
    if n_groups != 1:
        groups_arr = groups[iterator-1]
        groups_names = str(groups_arr).split(' ')[1]
    rivet=obj.createNode('rivet')
    rivet.setName('rivet_'+name_set+nums, unique_name=True)
    rivet.move([0, -1 - int(nums)])
    rivet.parm('rivetsop').set(path)
    rivet.parm('rivetgroup').set(groups_names)
    if match_N and match_up:
        rivet.parm('rivetuseattribs').set('1')

# скрипт есть смысл использовать если к вам пришла геометрия с лейаута, а вам надо вывести ее содержимое в отдельные ноды и зашейдить
# скрипт находит в выделенных нодах все ноды с рендер флагами и на obj уровне создает geo ноду с object merge в которой указан путь на ноду с рендер флагом.
root = hou.node('/obj/')
sel = hou.selectedNodes()

if sel != ():
    for nodes in sel:
        name_node=nodes.name()
        name_node = 'shots_' + name_node
        sub_nodes = nodes.allSubChildren(recurse_in_locked_nodes=False)
        for child_nodes in sub_nodes:
            flag_node = child_nodes.isGenericFlagSet(hou.nodeFlag.Render)
            if flag_node == True:
                geo_path=child_nodes.path()
                geo = root.createNode('geo')
                geo.setName(name_node, unique_name=True)
                geo.moveToGoodPosition()
                obj_merge=geo.createNode('object_merge')
                obj_merge.parm('objpath1').set(geo_path)
                obj_merge.parm('xformtype').set('local')

# вынес сюда некоторые часто используемые функции
# операции с нодами
main = hou.pwd() #  вернуть ноду содержащую параметр
new_node = main.createNode('node_name') # создать ноду
new_node.destroy() # удалить ноду
main_childs = main.children() # вернуть ноды с нижнего уровня текущей ноды
main_sub_childs = main.allSubChildren() # вернуть все ноды ниже текущей
new_name = main.setName('name', unique_name=True) # изменить имя ноды
# внешний вид нод
red = hou.Color((1.0, 0, 0)) # добавить цвет
main.setColor(red) # назначить цвет на ноду
main_pos = main.position() # вернуть позицию ноды
new_node.move([0, -1]) # переместить ноду
new_node.setPosition(main_pos) # переместить в позицию другой ноды
new_node.isGenericFlagSet(hou.nodeFlag.Display) # вернуть флаг
new_node.setGenericFlag(hou.nodeFlag.Display, 1) # установить флаг в положении видимый (1) или невидимый (0)

# операции с параметрами
parm_path = node.parm('parm_name').path() # вернуть путь до параметра
node.parm('parm_name').set('/obj/') # изменить параметр
node.parm('parm_name').setExpression('expression') # добавить экспрешн в параметр
node.parm("parm_name").set(ref_node.parm("parm_name")) # установить ссылку на параметр
parm_value = node.evalParm('update_paths') # вернуть значение параметра
node.parm('parm_name').pressButton() # нажать на кнопку

# связи
node_from.setInput(0, node_to, 1) # соединить ноды по номеру каналов
node_from.setNamedInput('normal', node_to, 'vector')  # соединить ноды по названию каналов
node_from.setNextInput(node_to, output_index=0) # соединить ноду к следующему входу (например нода merge)
nodes_from.outputs() # вернуть все выходы
nodes_from.inputs() # вернуть все входы

# строковые функции
num_to_text = str(100) # сконвертировать в строковую переменную
path_split = text.split('/') # разбить в лист по символу
path_join = '/'.join(list) # объединить лист в строку по символу
rename = re.sub('png', 'tx', path) # regex, изменить текст в строке: png - исходный текст, tx - исправленый, path - строка
match = re.search('text', path) # regex, найти текст в строке
slice = str[0:10] # разрезать строку: 0 - начало строки, 10 - длина строки