:bookmark_tabs: 包含代码片段和示例的集合,展示了 SideFX Houdini 中 VEX 语言的语法和功能
:bookmark_tabs: 包含代码片段和示例的集合,展示了 SideFX Houdini 中 VEX 语言的语法和功能
A collection of code snippets and examples showing syntax and capabilities of VEX language inside SideFX Houdini
by Juraj Tomori
You can clone, or directly download this repository.
It contains examples.hipnc and vex/include/myLib.h files which are full of various examples with explanations in comments.
It is the best to check all the nodes with open Geometry Spreadsheet and Console Output windows to see values of attributes and output text. Alternatively you can use this page for quick looking at the topics covered and most of the code that I include here as well. I am not including here all of the code since sometimes it might not make a lot of sense outside of Houdini. Where necessary I include related functions from myLib.h or attach screenshots.
/*
multi-line comments can be typed
using this syntax
*/
// in vex you can evaluate values from parameters on this node
// by calling ch*() function, with * representing a signature, check the docs
// for the full list, some of them: chv() - vector, chu() - vector2, chs() - string
// chramp() - ramp, chp() - vector4, chi() - int, chf() - float, ch4() - matrix, ch3() - matrix3 ...
// you can also use optioinal argument for time which will enable you to evaluate
// the channel at different frame
//
// once you type ch*() in your code, you can press a button on the right, to
// generate a UI parameter for it automatically, you can do the same by hand as well
float y = chf("y_position");
vector col = chv("color");
matrix3 xform = ch3("xform");
// you can also reference parameters from external nodes
// if there is an expression (Python/hscript) in the parameter,
// it will be evaluated
float up = chf("../params_1/move_up");
// apply variables to attributes
[email protected] += y*5;
v@Cd = col;
v@P *= xform;
[email protected] += up;
v@myVec = 1.456;
v@myVec += [email protected];
float blend = chf("blend");
float blendPig = chf("blend_pig");
vector P1, P2, P3, P_new;
// this is one way of reading attributes, this is only valid, when
// point count is exactly the same in both inputs, then attribute from
// point from second input with the same @ptnum is retrieved
// v@P can also be replaced with @P, since its signature can be guessed as it is
// commonly used attribute, however I prefer explicit declaration :)
// v@ - vector, i@ - integer, f@ - float, 3@ - matrix3, p@ - vector4
// 4@ - matrix4, 2@ - matrix2, u@ - vector2, s@ - string,
//P1 = v@P;
//P2 = v@opinput1_P; // inputs numbering starts at 0, therefore 1 refers to the second input
// this approach is useful for querying attributes from different points (other from the currently processed one)
// node input numbering starts from 0 (first input), 1 (second input) ...
P1 = point(0, "P", @ptnum);
P2 = point(1, "P", @ptnum);
// note that you can also read attributes from node, which is not connected
// to the current node using the "op:" syntax
// this is valid for any function which is expecting geo handle (sampling from other volumes...)
// note that Houdini network UI will not detect this dependency when Show -> Dependency links display is enabled
P3 = point("op:../pig_shape", "P", @ptnum);
// blend positions
P_new = lerp(P1, P2, blend);
P_new = lerp(P_new, P3, blendPig);
v@P = P_new;
// create a new attribute simply by typing *@attrib_name with
// * representing its signature
// v@ - vector, i@ - integer, f@ - float, 3@ - matrix3, p@ - vector4
// 4@ - matrix4, 2@ - matrix2, u@ - vector2, s@ - string
v@myVector = {1,2,3};
// vectors with functions/variables in them need to be created with set()
u@myVectorFunc = set(@Frame, [email protected]);
u@myVector2 = {4,5};
f@myFloat = 400.0;
i@myInteger = 727;
3@myMatrix3x3 = matrix3( ident() ); // this line contains function casting, which is explained in functions_casting section
4@myMatrix4x4 = matrix( ident() );
s@myString = "abc";
// attributes can be set to different point from the currently processed one
// and if they do not exist, they need to be added first
// setpointattrib() is also the only way of setting an attribute on newly
// created points
addpointattrib(0, "Cd", {0,0,0});
setpointattrib(0, "Cd", 559, {1,0,0});
// arrays can be exported as well
v[]@myVectorArray = { {1,2,3}, {4,5,6}, {7,8,9} };
u[]@myVector2Array = { {4,5}, {6,7} };
f[]@myFloatArray = { 4.0, 2.7, 1.3};
i[]@myIntegerArray = {132, 456, 789};
// arrays containing functions/variables need to be initialized with array() function
3[]@myMatrix3x3Array = array( matrix3( ident() ), matrix3( ident() ) * 5 );
4[]@myMatrix4x4Array = array( matrix( ident() ), matrix( ident() ) * 9 );
s[]@myStringArray = { "abc", "def", "efg" };
// this is how you can create local array variables and load array attributes into them
vector myVectorArray[] = v[]@myVectorArray;
matrix3 a = ident() * 5;
[email protected] *= a.yy; // you can access matrix components using this syntax
// x -> 1st element, y -> 2nd, z -> 3rd, w -> 4th
[email protected] = 4[]@myMatrix4x4Array[1].ww; // second array matrix, last element
[email protected] = u[]@myVector2Array[1][0]; // this is how you can access array of vectors - second array, first element
int numbers[] = array(1,2,3,4);
// arrays can be handled in Pythonic way
numbers = numbers[::-1]; // array reverse
// rading from arrays
i@firstItem = numbers[0];
// writing into arrays
numbers[0] += 1;
// indexing can also go backwards
i@secondLastItem = numbers[-2];
// slicing
i[]@firstHalf = numbers[:2];
i[]@secondHalf = numbers[2:];
// some useful functions
i@returnedPopVal = pop(numbers); // removes the last element and returns it
push(numbers, i@returnedPopVal); // appends element to the array
i@lenghtOfArray = len(numbers);
// export into integer array attribute
i[]@numbers = numbers;
// flattening an array of vectors and reverting it
vector vectors[] = { {1,2,3}, {4,5,6}, {7,8,9} };
f[]@serializedVectors = serialize(vectors);
v[]@unserializedFloats = unserialize(f[]@serializedVectors);
// simple example of manipulating strings and arrays
// it will convert /path/to/the/project/file/project_v3.hipnc
// into /path/to/the/project/file/preview/project_v3_img_0001.jpg
// with 0001 being current frame number
string path = chs("path"); // get string from path parameter of the current hipfile
s@pathOrig = path; // store into attribute original value
string pathSplit[] = split(path, "/"); // split path into array of strings based on "/" character
string fileName = pop(pathSplit); // remove last value of the array and assign it into a variable
string fileNameSplit[] = split(fileName, "."); // split string into an array based on "." character
fileNameSplit[0] = fileNameSplit[0] + sprintf("_img_%04d", @Frame); // append into the string _img_0001 (current frame number)
fileNameSplit[-1] = "jpg"; // change file extension
fileName = join(fileNameSplit, "."); // convert array of strings into a one string with "." between original array elements
push(pathSplit, "preview"); // append "preview" string into the array of strings
push(pathSplit, fileName); // append file name into the array of strings
path = "/" + join(pathSplit, "/"); // convert array of strings into one string, starting with "/" for root, because it is not added before the first element, only to in-betweens
s@path = path; // output into the attribute
// To intilize a vector or a matrix with a variable/attribute we have to use the set method
float f = 0;
vector v = set(f,f,f);
matrix3 m = set(f,f,f,f,f,f,f,f,f);
m = set(v,v,v);
// We can then read the value back by
float f = getcomp(m,0,0);
// However we can not read back a vector directly instead we have to use:
f = set(getcomp(m,0,0));
v = set(getcomp(m,0,0),
getcomp(m,0,1),
getcomp(m,0,2));
// Likewise the setcomp can be used
setcomp(m,f,0,0);
// it is also possible to determine if incoming geometry has an attribute
i@hasCd = hasattrib(0, "point", "Cd");
i@hasN = hasattrib(0, "point", "N");
i@hasOrient = hasattrib(0, "point", "orient");
i@hasPscale = hasattrib(0, "point", "pscale");
// if you use @attribute and it does not exist,
// then it will be automatically created
// this might lead to problems, when you have a typo and a
// new attribute is created
f@foo = 4;
f@boo = [email protected];
//v@CD = {1,1,0}; // this line does not work here, otherwise it would crete new v@CD attribute
// if you remove * chracter from "Attributes to Create" parameter
// bellow, then you need to manually specify new attributes
// to be created, if you then have a typo and use v@CD instead
// of v@Cd, node will report an error
// VEX is well integrated into Houdini, it can for example fetch
// world space transformation matrix from an OBJ node, let it be a null OBJ
// or part from a rig, camera or whatever object there which has a transformation
// optransform() will contain also all parent transformations
string nodePath = chs("node_path"); // parameter is a string, but I went into "Edit Parameter Interface" and specified it to be a Node Path
matrix xform = optransform(nodePath);
v@P *= invert(xform);
// a lot of information and functionality is stored in
// "intrinsic" attributes, they might be hidden to many users
// because they do not show up in primitive attributes list
// by default
// they are however very useful and important for manipulating
// and controlling those primitives from VEX
// you can display intrinsics in Geometry Spreadsheet, in primitive attributes
// and Show All Intrinsics in Intrin
暂无开放 Issues,或尚未同步最近议题。