Jump to content


  • Content count

  • Donations

    0.00 CAD 
  • Joined

  • Last visited

  • Days Won


Everything posted by f1480187

  1. Orient noise pattern along vectors

    Hi. How about computing local space per primitive instead, and then get noise position from point position in the local space? Some sort of edge based UV unwrap. // Primitive wrangle. int pts[] = primpoints(0, @primnum); // Compute averaged primitive normal from point normals computed from their neighbours. vector normals[]; foreach (int pt; pts) { vector normalized_edges[]; vector pt_pos = point(0, "P", pt); foreach (int nb; neighbours(0, pt)) { vector nb_pos = point(0, "P", nb); append(normalized_edges, normalize(pt_pos - nb_pos)); } append(normals, normalize(avg(normalized_edges))); } vector normal = normalize(avg(normals)); // Compute edge tangent. vector pt0 = point(0, "P", pts[0]); vector pt1 = point(0, "P", pts[1]); vector edge = normalize(pt0 - pt1); // Compute bitangent and orthonormalize matrix. vector perp = normalize(cross(normal, edge)); normal = normalize(cross(edge, perp)); 3@tangent_space = set(perp, normal, edge); Final deformation code: // Point wrangle. int prim; xyzdist(1, @P, prim, set(0)); matrix3 tangent_space = prim(1, "tangent_space", prim); vector pos = @P * invert(tangent_space); float deform = noise(pos * {10,1,100}) * 0.05; v@P += v@N * deform; Some image sampling could work too: tangent_space_noise.hipnc
  2. Hi. Here is the crappy function I could think of. It returns list of lists with questions answered by each kid. First question is answered by one kid, last question is answered by everyone. Kids will get some kind of brain penalty for answers, so they won't know the answer next time. I found if I force this strictly, I get visible switching between two "teams" in the middle. So, randomized sampling is taking precedence after a few questions: Function returns after everyone answered about X times, 5 for your case. from random import seed, shuffle, randint from numpy import median seed(hou.ch('seed')) def quiz(num_kids, median_answers, randomness=0.8): # Empty lists accumulating answered questions per kid. kids = [[] for _ in range(num_kids)] # Ask until median amount of answers per kid is met. i = 0 while True: # Randomize pending kids to avoid halves switching pattern. slice = int(len(kids) * randomness) a = kids[:slice] b = kids[slice:] shuffle(a) kids = a + b # Comment this to see problem. # Score approximately i answers. pick = randint(max(1, i), min(i + 1, num_kids)) clever = kids[:pick] dumb = kids[pick:] clever = [scores + [i] for scores in clever] # Extra shuffle for cases where randomness is near 0. shuffle(clever) kids = dumb + clever # Finish if kids answered enough questions. if median([len(s) for s in kids]) >= median_answers: # Complete last row. kids = [s + [i] if i not in s else s for s in kids] return kids, i i += 1 Close neighbors can still answer simultaneously, though. random_kids.hipnc
  3. reset to origin.

    @bonassus that will take an arbitrary perpendicular to y. Using random constant usually enough, except it may break with vectors collinear to the constant. rot is an orthonormal matrix with y pointing at dir and arbitrary rotation around y axis.
  4. Best way is to deal with it upstream than post-process collapsed geometry. How about grouping unshared points and counting them using npointsgroup() expression function? Grid will have plenty of points in that group, while piece missing a quad will have only 4. Condition_problem_fix.hipnc
  5. dealing with ramp using python

    # Initialize new ramp. node = hou.pwd() ramp_parm = node.parm('ramp') bases = [hou.rampBasis.Linear] * 5 keys = [0.0, 0.125, 0.25, 0.375, 0.5] values = [0.0, 0.25, 0.5, 0.75, 1.0] ramp = hou.Ramp(bases, keys, values) ramp_parm.set(ramp) # Add multiple points to existing ramp. node = hou.pwd() ramp_parm = node.parm('ramp') ramp = ramp_parm.eval() bases = list(ramp.basis()) + [hou.rampBasis.Constant] * 4 keys = list(ramp.keys()) + [.5, 0.625, 0.75, 0.875] values = list(ramp.values()) + [0.25, 0.5, 0.75, 1.0] ramp = hou.Ramp(bases, keys, values) ramp_parm.set(ramp) # Change first point value from 0.0 to 1.0. node = hou.pwd() point1_val = node.parm('ramp1value') # Point indexing starts from 1. point1_val.set(1.0) python_ramp.hipnc
  6. Need two decimals

    Using Python: 'Time: %.1f' % hou.time() Using VEX sprintf(): // Detail wrangle. s@num = sprintf("%.1f", @Time); in Font node: Time: `details("../attribwrangle1", "num")` format_font.hipnc
  7. Filter node children's output with python

    This is the proper way, I think. It is commonly used in $HH/python2.7libs to filter nodes by type: https://pastebin.com/EnmhzJKj You can use list comprehensions to make it one-liner: vops = [c for c in node.children() if c.type().name() == 'vopsurface']
  8. python - node calls itself

    In the Operator Type Properties → Scripts tab select "On Created" event handler, change "Edit as" to Python. Here is basic code: node = kwargs['node'] node.setName('some_special_name') For default operators you need to make a shelf tool and create node and change it's name manually in the tool script. Custom assets also use tool script. In Operator Type Properties → Tools tab and the tool script looking like this: import soptoolutils soptoolutils.genericTool(kwargs, '$HDA_NAME') The function call at the last line returns fully created node instance. After On Created event was executed. You can use it too: import soptoolutils node = soptoolutils.genericTool(kwargs, '$HDA_NAME') node.setName('some_special_name') It's more logical to use On Created, but sometimes it doesn't work. For example, if I remember correctly, you can't set node position in it, it will be overridden.
  9. Extract nodes from OTL

    asset_node = hou.node('/obj/geo1/my_asset') file_nodes = [c for c in asset_node.allSubChildren() if c.type().name() == 'file'] hou.copyNodesTo(file_nodes, asset_node.parent())
  10. Shortcut - run script in network view

    Create a shelf tool from the script. You will find Hotkeys tab here:
  11. Python Question

    Does it cause problems? It is for display. There is no relative or absolute nodes in HOM, as far as I know.
  12. Measure Curvature

    Curvature usually works nice on dense and smooth meshes. There is no general method to measure curvature on all kinds of inputs. The one on Measure node probably has to do something with averaged point normals on the neighbours. It also scale-dependent, so, if you scale box by number of divisions (hence maintaining size of quads) it will stay at 1.41421. It is a square root of 2, which has nothing to with the problem, but I still want to point it out. I recommend @petz uploads on curvature. Various mesh curvature algorithms, including mean and gaussian curvatures, also principal curvature directions: Same but using VDBs:
  13. UV Flatten distorted plane

    Smoothing geometry may help a bit. It will leave UVs straightened and tileable and reduce interpolation zigzags. It will also help UV Flatten to output proper geometry without such big distortion. Also you may try Delta Mush, it may simulate results you need. Swap UV with P, then apply DM on straightened UVs using UV Flatten output as a second input: delta_mush_uv.hipnc
  14. VEX on Copy To Points

    Named constant defined in $HH/vex/include/math.h: #define XFORM_XYZ 0 // Rotate order X, Y, Z If you apply rotation in different order, like, pitch→yaw→roll or roll→yaw→pitch, resulting orientation will be different. It is not same as swapping axes (using Z angle as X and X angle as Z) because changing order doesn't change axes (X will work like pitch with XYZ and ZYX). You will see difference if you set non-zero angles for all axes and try different constants.
  15. VEX on Copy To Points

    Need all 4 components to have meaningful values to define orientation. You can convert from Euler (in radians) like this: @orient = eulertoquaternion(set(rotate_X, rotate_Y, rotate_Z), XFORM_XYZ); It is equivalent of this (for XYZ order): float cos_x = cos(rotate_X/2); float sin_x = sin(rotate_X/2); float cos_y = cos(rotate_Y/2); float sin_y = sin(rotate_Y/2); float cos_z = cos(rotate_Z/2); float sin_z = sin(rotate_Z/2); @orient = set(cos_z * sin_x * cos_y - sin_z * cos_x * sin_y, cos_z * cos_x * sin_y + sin_z * sin_x * cos_y, sin_z * cos_x * cos_y - cos_z * sin_x * sin_y, cos_z * cos_x * cos_y + sin_z * sin_x * sin_y);
  16. Building Corners Auto Groups

    Not sure if VEX would be handy there. Here is same thing without bevel and transfer: vu_AutoGroups_.hipnc
  17. Connect Adjacent Peices to Polygons

    Triangulate 2D?
  18. Simple noise expression on float value

    1. After you add noise to the parameter (example expression: "noise($T, 0, 0)"), Shift+Click on the parameter field to open Animation Editor. It will show the graph you are looking for: 2. Noise in 1D/2D/3D can be visualized in many ways using SOPs: visualize_noise.hipnc
  19. General way is to use Python as Menu script: from itertools import chain node = hou.pwd() geo = node.geometry() attribs = [a.name() for a in geo.pointAttribs()] return list(chain(*zip(attribs, attribs))) attributes_menu.hipnc It is possible to avoid it in many cases. When you promote parameter it will usually pick the menu script (if it exist) from the node. It is not necessary to have such menu on the target node, as you may promote parameter from a different node (example).
  20. [SOLVED] VEX in Volume Wrangle

    That should work if you will use "A" as volume name (not "@A").
  21. VEX:: User-defined functions calls problems

    I think the problem is "a + 0.1" expression used as argument of custom function called inside different custom function, and when both functions defined inside third function (wrangle). Intermediate "float a_ = a + 0.1;" solves it.
  22. op_path = '/obj/geo1/null1' preset_name = 'Some Preset' cmd = 'oppresetload %s "%s"' % (op_path, preset_name) hou.hscript(cmd)
  23. [SOLVED] VEX in Volume Wrangle

    Never used it, but it seems that volumeindex() function already returns actual value from ix, iy, iz: volumeindex Use "A" as volume name. To access different neighbours, increment voxel indices. Current voxel's indices stored in i@ix, i@iy, i@iz variables.
  24. VEX:: User-defined functions calls problems

    Submit a bug. Compute intermediate variables explicitly, as a workaround.
  25. set and get persistant attibute

    Shorter version ("trigger_grp" renamed to "trigger"): i@count = i@opinput1_count + (i@group_trigger && !i@opinput1_group_trigger); Solver is a cleanest way to do something over time, I think. Everything after animated Group node will be time dependent and cook every frame.