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.
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.
Is it any skill to export the color from Houdini to AI?
The SVG color property also supports RGB hex colors (#RRGGBB).
Read the color from the polyline/polygon using p.attribValue(‘Cd’), convert it to hex format and use it instead of black in write_path().
https://www.sidefx.com/docs/houdini/hom/hou/Polygon.html#attribValue
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(”)
Entagmazing!!!
please delete my comment , it’s not working in any case
🙂
done 🙂
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);
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.
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
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,”)”);
////////////////////////////////////////////////////////////////////////////////////////////////////////////////
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!