Isocontours: Importing & Exporting Vectors to/from Houdini

comments 13
Free Tutorials

Niklas Rosenstein is with us again! And if Niklas is in the house, chances for some Python code are pretty high. This time we’ll import vectors from Illustrator into Houdini, create an isocontour-effect and export the result back to illustrator.

Apart from the bread-and-butter standard way of using DXF files for interchange, Niklas will go over implementing an SVG exporter using Python to be able to export into another format that is a bit more common amongst designers than DXF.

Download Project File (.zip)

Liked it? Take a second to support Moritz on Patreon!
Become a patron at Patreon!

13 Comments

  1. Thanks for the very helpful Python script. I just wanted to say that it’s possible to do this with a slightly different method, albeit not in a pure Houdini environment. If you have access to Rhino, then you can export from Houdini as an ‘IGES’ file, and import that into Rhino. From there, Rhino can export to Illustrator.

  2. Is it any skill to export the color from Houdini to AI?

      • I am not familiar with Python but it seems I managed to export color
        (rgb to hex code is from https://github.com/Aeoll/Aelib)
        Here is the tweaked python code if someone needs

        import struct

        node = hou.pwd()
        geo = node.geometry()

        # Add code to modify contents of geo.
        # Use drop down menu to select examples.

        filename = node.evalParm(‘filename’)
        maxsize = node.evalParm(‘maxsize’)
        stroke_width = node.evalParm(‘stroke_width’)

        def RGBtoHex(rgbarray):
        a = [x * 255.0 for x in rgbarray]
        #print(a)
        s = struct.pack(‘BBB’, int(a[0]), int(a[1]), int(a[2]))
        #print(s.hex())
        #hex = “#” + codecs.encode(s.decode(), ‘hex’)
        return “#” + s.hex()

        box = geo.boundingBox()
        minv = box.minvec()
        size = box.sizevec()

        if size.x() > size.y():
        width = maxsize
        height = maxsize * size.y() / size.x()
        else:
        height = maxsize
        width = maxsize * size.x() / size.y()

        def write_path(fp, points, col):
        if not points:
        return
        data = ‘M{} {} ‘.format(points[0].x(), points[0].y())
        for cd in col[1:]:
        color = [1, 1, 1]
        color = cd
        hex = RGBtoHex(color)
        for p in points[1:]:
        data += ‘L{} {} ‘.format(p.x(), p.y())
        fp.write(‘\n’.format(data,hex,stroke_width))

        def getCd():
        color = [1, 1, 1]
        color = p.attribValue(“Cd”)
        hex = RGBtoHex(color)
        return hex

        def transform_points(points):
        for p in points:
        p = hou.Vector2(
        (p.x() – minv.x()) / size.x() * width,
        (1.0 – (p.y() – minv.y()) / size.y()) * height
        )
        yield p

        with open(filename, ‘w’) as fp:
        fp.write(‘\n’)
        fp.write(‘\n’)
        fp.write(‘\n’.format(width, height))
        for prim in geo.iterPrims():
        if prim.type() != hou.primType.Polygon:
        continue
        points = [v.point().position() for v in prim.vertices()]
        points = list(transform_points(points))
        col = [v.point().attribValue(“Cd”) for v in prim.vertices()]
        write_path(fp, points, col)
        fp.write(”)

  3. benjamin

    please delete my comment , it’s not working in any case
    🙂

  4. Carl Fairweather

    Thanks for the tutorial guys. That SVG export is just what I’ve been after, thank you.

    I have an alternative approach for flattening the geometry into the XY plane. Just needs two wrangle nodes so you can keep it vex based:

    wrangle1_removeCamTransform:

    matrix camM = optransform(chs(“cam”)); // create parameter and pick the camera
    @P *= invert(camM);

    wrangle2_flattenToXYPlane:

    vector bboxMax = getbbox_max(0); // getbbox has _min and _max in H16+
    float zDiff = bboxMax.z – @P.z;
    vector dir = -normalize(@P);
    float cos = dot({0,0,1},dir);
    @P += ((zDiff/cos)*dir) + set(0,0,-bboxMax.z);

  5. Found japan webpage, “How to use Wren ROP and pipe with external application by SOHO”, where he dealing with same problem, how to export nurbs from Houdini to Illustrator as SVG. Not really understand what exactly he is doing, but may be you, Entagma guys, can make it more clear.
    Take a look, use google translate:
    https://qiita.com/kit2cuz/items/0acc5b6352129db587cb

    • It’s too bad Wren node only works for Houdini FX, not Indie…
      Was hoping to find a way to write out an SVG sequence with Python instead. But have not found a way yet.

  6. Really helpfull tuto, i learned so much.
    But i don’t see the imprementation of Z = closepath
    in my case all my circle miss a part.
    So it miss a Fuse to close the path primitives.
    then How can we check if the primitive/path is closed ?
    the hou.Face class have function isClosed (but not what i expect)
    Thx

  7. I found it useful to convert Houdini native colors to RGB in VEX and write the fill value in the Python node at the end.
    It’s really messy and doesn’t work for out of range colors (>1) but this seemed to work for me most of the time, hope it helps someone who wants to use Houdini colors in SVG!
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    ////CONVERT COLOR RANGE TO 255
    vector color = @Cd;
    s@fill = “”;

    int new_red = (int)rint(ceil(fit(@Cd.r, 0, 1, 0, 255)));
    int new_green = (int)rint(ceil(fit(@Cd.g, 0, 1, 0, 255)));
    int new_blue = (int)rint(ceil(fit(@Cd.b, 0, 1, 0, 255)));

    string s_red = itoa(new_red);
    string s_green = itoa(new_green);
    string s_blue = itoa(new_blue);

    @fill = concat(“rgb(“,s_red,”, “,s_green,”, “,s_blue,”)”);
    ////////////////////////////////////////////////////////////////////////////////////////////////////////////////

  8. Erik Spellerberg

    Thank you very much for this tutorial!
    I just want to add that I think it might not be best practice in the python section to call file.write() for every line, as you are writing the file to the for every new line in the svg file!

    Better to store each new line in a variable and call file.write(data) just once at the very end!

Leave a Reply