【Houdini】VEX – 基础篇(捷佳的教程笔记)

说明

教学视频

笔记参考

数据类型

常用数据类型

//常用数据类型
int     a_ = 1; //变量名可以用字母和下划线。一些整数类型:21, -3, 0x31(16进制), 0b1001(2进制), 0212(8进制), 1_000_000(长数字可以用下划线分隔)
float   _b1= 2.1; //变量名可以用数字,但数字不能放在最前面,字母下划线随意
vector2 c  = {1.1,2.0}; //向量(和矩阵)的每个分量都是浮点类型
vector  d  = {2.0,3.3,4.1}; //vector代表三维向量,(在向量中使用最频繁,故作简写处理)
vector4 e  = {3,5,7,9}; //不必刻意写成{3.0,5.0,7.0,9.0},这点与C不同
matrix2 f  = {2,4,6,8}; //vector4(四维向量)和matrix2(2*2矩阵)结构相似,都是四个元素,所以为了区分二者,不建议用这种方式写2*2矩阵,应当采用下面的形式
matrix3 g  = {{1,2,3},{4,5,6},{7,8,9}}; //括起来的表示一行,或者采用下面的形式更方便阅读
matrix  h  = {{1,1,1,1},
              {2,2,2,2},
              {3,3,3,3},
              {4,4,4,4}}; //matrix代表四维矩阵,四维矩阵和三维向量一样,(在矩阵中使用最频繁,故也作简写处理)
matrix  h  = {1,2,3,4...} //中间的大括号可以省略,只不过为了方便阅读,你还是加上吧。             
string  i  ="hello world"; //也可以用单引号'hello world'

类型转换

有的会自动转换,比如点位置,最后都会变成浮点

 

变量类型(要转化的变量)
如float(100)-> 100.0

 

变量类型(函数( ))
如float( rand(@ptnum))

示例1
@P.x = int(@P.x);//int()会将x坐标从浮点转为整数,
//重新赋予给@P.x后又会自动转成浮点

//printf('%s\n',int(@P.x));
print_once(sprintf('%s\n',int(@P.y)));

//sprintf('%s\n',变量数据)  将变量转换成字符串并返回
//print_once(字符串,....)  相同的字符串只打印一次(这里官方的API都没看懂)
//print_once(sprintf('%s\n',变量数据)));干脆就按照就这个用得了

示例2
//@P +=noise(@P)*chf('amp');
//这里'+='后面的代码求出的是浮点,在加法运算时自动被转成向量了

@P += vector(noise(@P))*chf('amp');

//noise()可以返回浮点也可以返回向量,
//vector(noise())明确让它返回向量

示例3
//@Cd = length(point(1,'P',@ptnum) );
@Cd = 0.3*length(vector(point(1,'P',@ptnum) ) );

//length()返回浮点,但参数可以有多种类型,如vector2 vector vector4
//point()返回点属性,点属性有多种类型
//length()不知道point()会返回什么类型,所以报错Ambiguous call

 运算符

printf('>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n'); 
//重点*****重点*****重点*****重点*****重点*****重点*****重点*****重点*****重点*****
int iii = 5; int ii = 2; float ff = 5.2;
printf('0 %s\n',iii*ii ); //整数之间运算结果还是整数
printf('1 %s\n',ii*ff );  //只要有浮点,结果就是浮点,不论在运算符左边右边
//重点*****重点*****重点*****重点*****重点*****重点*****重点*****重点*****重点*****

//重点*****重点*****重点*****重点*****重点*****重点*****重点*****重点*****重点*****
vector4 a = {5,8,2,4};
printf('2 %s\n', a.a );//向量的每个分量可以用 xyzw 或rgba 或0123 获取
printf('3 %s\n', a[1]);

vector2 b = {6,7};
printf('4 %s\n', b.v );//二维向量可用uv xy获取

matrix d = {3,6,8,7,  1,5,4,2,  2.2,1.9,5.6,8,  77,32,17,32};
printf('5 %s\n', d.rx);//矩阵也可用xyzw rgba获取
                       //例如xy(第一行第二列)wb(第四行第三列)rx(第一行第一列)
//重点*****重点*****重点*****重点*****重点*****重点*****重点*****重点*****重点*****

//向量(包括矩阵)与标量(浮点或整数)相加咸乘除还是向量,每个分量都会进行运算
printf('6 %s\n',{1,2,3}*5 );//不论正反
printf('7 %s\n',6/{1,2,3} );
matrix c = 2;
printf('8 %s\n', 5*c );
printf('9 %s\n', 5-c ) ;
//printf('9.5 %s\n',2.0/c );//不能用 标量除以矩阵

//切换向量的元素顺序,相当于set
vector e = {3,2,4};
printf('10 %s\n', e.zyz );printf('11 %s\n', e.xzy );//不会改变vector e
printf('12 %s\n', set(e[2],e.r,e.y) );//会改变vector e
vector4 gg = {5,8,7,2}; vector kk = {8,7,9}; vector2 jj={1,7};
printf('13 %s\n',jj+kk);//不同维度的向量相加减乘除,取元素最多的作结果
printf('14 %s\n',gg+kk);
//注意四维向量和2维3维向量运算2维3维缺少的元素会用{0,0,0,1}填充

//比较操作符== != > < >= <=,得到结果是整数,只能用于对比字符串,整数和浮点
string name = 'piece0' ; int in = 20; float ffr = 20.0;
printf('15 %s\n', name == 'piece0');
printf('16 %s\n', in != 20);
printf('17 %s\n', in >= ffr) ;
//逻辑操作符 || && ! 只能用于整数(或 真和假) 得到结果是1或0,
printf('18 %s\n', 1 && 0);
printf('19 %s\n', true || false);
printf('20 %s\n', 1>0 && 1!=0);

 格式化输出

打印变量的格式:
%[flags][width][.precision][format]

flags :- + 0
format : g p c[通用] f e E[浮点] s[字符串] d i[整数]

 

The format string is a simpler version of the C printf format string. When a % symbol is found in the string, an argument will be printed out in a format specified by the characters following the % symbol. The conversion of the argument is specified by a single letter: g, f, s, d, x, c, p.
格式化字符串是一个简单的版本的C printf格式字符串。当字符串中有一个%符号时,一个参数将以字符的形式在%符号后面以指定的格式输出。参数的转换由一个字母指定:g,f,s,d,x,c,p。
You can prefix the format option with an optional prefix characters to control the formatting of the output. The general form of a prefix is [flags][width][.precision][format], where Flags can be:
你可以使用可选前缀字符对格式选项进行前缀,以控制输出格式。前缀的一般形式是[flags][width][.precision][format],可用标志有:
[Flags]
-: The result will be left justified in the field
-: 结果会被左对齐。
+: A numeric value will be prefixed with either + for positive values. A non- standard behavior of this flag is that string arguments will be quoted when the + flag is set.
+:如果是数值并且为正,将前缀+。如果是字符串,会加上双引号。
0: For numeric values, leading zeros are used to pad the field.
0:对于数值,最前面的零用于填充字段。
Width
[width]宽度
The width can be specified by one or more decimal digits. Alternately, if an asterisk () is given, the width will be taken from the next value in the printf argument list.
宽度 即打印出多少个字符 不够的话用空格或0补(flag为0则补0 否则补空格)
宽度可以用一个或多个十进制数字来指定。另外,如果一个星号()是给定的,宽度将从在printf函数的参数列表中的下一个值。

Precision
[.precision]精度
The precision can be specified by one or more decimal digits. Alternately, if an asterisk () is given, the width will be taken from the next value in the printf argument list.
精度可以用一个或多个十进制数字来指定。另外,如果一个星号()是给定的,宽度将从在printf函数的参数列表中的下一个值。

The different format characters supported are
所支持的不同格式字符如下

%g, %p, %c
Print an integer float, vector, vector4, matrix3, matrix or string in "general" form.
用一般形式打印一个整数,浮点,矢量,Vector4,matrix3,矩阵或字符串

%f, %e, %E
Print a float, vector, vector4, matrix3 or matrix in floating point form.
用浮点形式打印一个浮点数,矢量,Vector4,matrix3或矩阵。

%s
Print a string.
打印字符串。

%d, %i
Print an integer variable in decimal.
用十进制打印整型变量。

%x, %X
Print an integer variable in hexidecimal. The value will be prefixed with "0x" (i.e. 0×42).
用十六进制打印一个整数变量。该值将以“0x”作前缀。

%o
Print an integer variable in octal.
用八进制打印整型变量。

%%
Print a percent sign (%).
打印百分号(%)。

作者:Joe_Game
链接:https://www.jianshu.com/p/d20798c2ae15
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

string var_string = "abcdef";
float var_float = 1.23456789;
int var_int = 256;

printf("string: %+1s, float: %10.3f, integer: %-6d \n", var_string, var_float, var_int);
// string = abcdef
// %[+-][length]s 

//____表示空格,占位符
// %10s   -> ____abcdef         //字符串,占位10个字符位
// %-10s  -> abcdef____         //字符串,占位10个字符位,左对齐
// %+10s  -> __"abcdef"         //字符串,占位10个字符位,字符串被双引号引起来
// %+-10s -> "abcdef"__         //字符串,占位10个字符位,字符串被双引号引起来,左对齐

// float = 1.23456789
// %[+-][0][length][precision]f

// %8.3f  -> ___1.235                 //3位小数浮点,占位8个字符位
// %-8.3f -> 1.235___                 //3位小数浮点,占位8个字符位,左对齐
// %08.3f -> 0001.235                 //3位小数浮点,占位8个字符位,左补全3个0
// %+8.3f -> __+1.235 (+ shows sign)  //3位小数浮点,占位8个字符位,数字前缀+

// integer = 256
// %[+-][0][length]d

// %6d  -> ___256            //整数,占位6个字符位
// %+6d -> __+256            //整数,占位6个字符位,数字前缀+
// %-6d -> 256___            //整数,占位6个字符位,左对齐
// %06d -> 000256            //整数,占位6个字符位,左补全3个0

printf("\n");

// escaping characters in string                                                   //字符串中的转义字符
// from my testing it requires 4 more backslashes to escape \n                     //从我的测试来看,它还需要4个反斜杠才能转义\n
// when using raw strings, they are automatically escaped, but @ symbol still      //当使用原始字符串时,它们会自动转义,但@符号仍然
// needs to be escaped                                                             //需要转义。
// following lines will output the same thing                                      //下面的行将输出相同的内容
// 4 backslashes are needed probably because hscript is parsing this text field    //之所以需要4反斜杠,可能是因为hscript正在解析这个文本字段
// and sending to vop's field, see the node bellow                                 //并发送到vop的字段,请参见下面的节点
string a = 'abc \\\\\n \\\\\t v\@P, %04.2f';   //想要打印类似\n \t这样的特殊符号,需要前缀四个\.  打印@,需要前缀\.   简单理解:  \\\\\n = \n   \\\\\t = \t  \@ = @
string b = "abc \\\\\n \\\\\t v\@P, %04.2f";   //单引号和双引号没有区别
string c = r"abc \n \t v\@P, %04.2f";          //在引号前缀r,会屏蔽掉字符串中的\n \t
string d = R"(abc \n \t v\@P, %04.2f)";        //R也一样,但多了个括号

printf(a + "\n");
printf(b + "\n");
printf(c + "\n");
printf(d + "\n"); 

string multiLine = 
R"(It is possible to easily create multi
line strings with this syntax.
In some cases it might
be useful to do it this way,
rather then using \n
However as you have noticed it has weird
4 characters offset starting on the second line,
not sure if it is a bug or feature)";//打印多行可以用 R"(多行内容)" 括起来,会有四格的缩进

printf(multiLine + '\n');

// sprintf() 类似printf()
//而且起到 将输入值转化为字符串,并且返回该字符串的作用
string ss = sprintf('%010d', 20180412);
printf('%s',ss);

 

数组

数组创建

//array  数组
int     j[]={}; //数组可以为空
float   k[]={0.1,0.2,0.3};
vector2 l[]={{1,2},{3,4},{5,6}};
vector  m[]={{1,2,3},{4,5,6}};
vector4 n[]={{1,2,3,4}}; //数组中可以只有一个元素(这里指一个四维向量)
matrix2 o[]={{1,2,3,4},{5,6,7,8}}; //该数组包含两个2*2的矩阵元素
matrix3 p[]=array(g);//可以引用已存在的变量,但一定要加上array,而不能直接写成matrix3 p[]=g。引用多个变量则是 array(g1,g2,g3...)

//可以用纯数字创建数组
vector color[]= { {1,0,0},{0,1,0},{0,0,1},{1,1,0}};
@Cd = color[@primnum];

//使用变量或表达式创建时,要用array()
float alpha[]= array(chf('a0'),chf('a1'),chf('a2'),chf('a3'));
@Alpha = alpha[@primnum];

/*以下是官方解释:
 数组是在编译时构造的,因此它们不能包含变量。
 例如,这是一个错误:
 int arr[] = { my_var, other_var + 2 }; // Error
 为了避免这个错误,请使用 array ()函数,该函数在运行时用任意数量的参数构造数组:
 int arr[] = array( my_var, other_var + 2 );*/
matrix  q[]=array(h);
string  r[]={"hello world","abcd"};

数组写入

vector pos[];//创建空的向量数组
float pos_float[];//空的浮点数组

for(int i=0; i<@numpt; ++i)           //有多少点,循环多少次(4个点)
{
    pos[i]= point(0,'P',i);           //将数据写入数组元素
    pos_float[i*3+0] = pos[i].x;      //[id]读取元素值  .x读取向量的第一个分量(xyz)
    pos_float[i*3+1] = pos[i].g;      //·g读取向量的第二个分量(rgb)
    pos_float[i*3+2] = pos[i][2];     //[2]读取向量的第三个分量(012)
    /*
    for(int j=0; j<3;++j)         //每个点再循环3次
    pos_float[i*3+j]= pos[i][j];  //每次都把向量的每个分量填入数组
    */                            //pos[i][j],获取pos数组中的第i个元素
                                  //这个元素是向量,[j]获取这个向量的第j个
}

v[]@pos = pos;  //创建属性,类型为向量数组,然后将变量pos的值赋予给属性
f[]@pos_float = pos_float; //浮点数组属性

 数组读取

float not_exist = f[]@pos_float[12];//读取数组属性要写清楚类型,如v[],f[]...
printf('%s\n',not_exist); //不存在的元素,返回0;如果是字符串数组则返回""
printf('%s\n',len(f[]@pos_float) );

f[]@pos_float[12]= 120;//写入原本不存在的12号元素,如果跨位写入,比如跳过12直接写13,那么12会变0
float new =f[]@pos_float[12];
printf('%s\n',len(f[]@pos_float) );
printf('%s\n',new);   //没问题

f[]@pos_float[16]= 140;//跳过13.14.15号元素写入16号元素,那么13.14.15号元素会变0
printf('%s\n',f[]@pos_float[13]);

 数组切割

int nums[]= { 0, 1, 2, 3, 4, 5 };
//           -6 -5 -4 -3 -2 -1

//value[start:end:step]开始结束步幅
int start[]= nums[0:2];  //{ 0, 1 }0号开始,2号之前结束(取不到2号)
int end[]  = nums[-2:];  //{ 4, 5 }倒数第2个开始,没有结束(意味着直到尽头)

int rev[] = nums[::-1];      // { 5, 4, 3, 2, 1, 0}反着数 1每次加一
int rev2[]= nums[-1:-4:-1];  // { 5, 4, 3 }倒数第1个开始反着数,
                                         //倒数第4个之前结束(取不到倒数第4个)
int odd[] = nums[1::2];           // { 1,3,5 }从1号开始,步幅为2,隔一个取一个,直到结尾
int odd2[]= nums[1:len(nums):2];  // { 1,3,5 }同上,len()数组元素数量

printf('start %s\n',start);
printf('end %s\n',end);
printf('rev %s\n',rev);
printf('rev2 %s\n',rev2);
printf('odd %s\n',odd);
printf('odd2 %s\n',odd2);

 数组与其他类型转换

//数组与其他数据类型互相拷贝
vector pos = {1,2,3};
vector cd  = 0;
float x[];

//float x[]= pos; *wrong*
x = set(pos);  //x =[1,2,3]向量赋予给数组
cd = set(x);   //cd={1,2,3}数组拷贝给向量

x = {1,9};       //对数组重新赋值
cd = set(x);     //将 一个只有两个元素的数组 赋值给一个 三维向量,不够的元素会用0补上.所以cd={1,9,0}数组拷贝给向量,不够的在后面补上0.
vector mycd = 1; //将 单个数据             赋值给一个 三维向量,该数据会同时填补三个分量的位置.比如会得到mycd={1,1,1}
                 //注意两者的区别

printf('%s\n',x);
printf('%s\n',cd);

数组的for each

//对于体积,并非只能用Volume Wrangle,也可以用Attribute Wrangle
//正如Attribute Wrangle其名,有属性就能用它;有point prim vertex就能用
//  aw可以读取和修改属性,vw可以读取和修改体积(体素)

float density[]= primintrinsic(0,'voxeldata',0);//获取intrinsic属性,
                                //voxeldata:体素值的浮点数组

float maxValue = 0;//该变量用来存放最大值

foreach(float value; density)            //遍历density数组中的每一个浮点value
         maxValue = max(maxValue,value); // 上次的值 与 这次的值 对比,取最大的

setprimattrib(0,'name',0,sprintf('%s',maxValue) ); //sprintf()函数可以将maxValue变成字符串
//转成字符串赋予给name属性(也就是体积的名字)
//中键按住即可方便地观察体素的最大值

float density[] = primintrinsic(0,'voxeldata',0);

float maxValue = 0;//存放最大值
float minValue = 0;//存放最小值
float rangeMax = chf( 'range_max');//最大范围
float rangeMin = chf( 'range_min');//最小范围
int sampleRate = int( rint( 1/chf('sample_rate') ) );//采样率(跳过的体素个数):用户输入'sample_rate'在0.0001~1之间; 
                    //rint()取最近整数返回浮点,如 2.5=3.0, 2.49=2.0, -0.6= -1; int()强制转整数
//例如 用户输入   0.0001  0.01  0.3  0.5   1 恰好0和1意味着完全采样
//sampleRate =  10000   100    3    2    1
int count = 0; //计数器

foreach(int id; float value; density)//遍历density数组中的每一个浮点value,
                                     //每循环一次. id+1
{
    if( id % sampleRate == 0 )//如sampleRate = 5,则每隔5个体素运行下列代码一次
    {
        maxValue = max (maxValue,value) ;
        minValue = min (minValue,value) ;
        if( value < rangeMax && value > rangeMin )//如果体素值符合范围
            ++count;//计数器+1
     }           

}
printf( '===========================================================\n') ;
printf( 'max        = %s\n',maxValue) ;
printf( 'min        = %s\n',minValue) ;
printf( 'sampleRate = %s\n',sampleRate) ;
printf( 'percent    = %s\n',float(count*sampleRate)/len(density));//百分比=计数结果*跳过体素个数/体素总数量

 数组常用函数

int num[10] = {5,2,3,3,4,8,1};//绿色波浪线是警告,因为用户设置的数组初始长度会被忽略,所以没必要声明长度(10会被忽略)
printf('%s\n',num);

// resize(数组名,新长度-整型):重置数组的长度,长了用0补全;短了,直接截断
resize(num,10);    //设置数组的长度,变长,新值为0或''
printf('%s\n',num);//注意这类function不返回数据,而直接修改所传入的数组变量
resize(num,6);//设置数组的长度,变短,当然会删去已有元素
printf('%s\n',num);

// len(对象):获取对象长度
string word[]= {'$','HIP','/'};//创建字符串数组
printf('%s\n',word         );
printf('%s\n',len(word)    ); //len(array)  返回数组的长度(元素数量)
printf('%s\n',len(word[2]) ); //len(string) 返回元素的字符数量

// pop(数组,[索引]):抽取元素,默认抽取最后一个
string last = pop(word); //pop() 将数组最后一个元素抽取出来返回,并且数组长度会减一
int  numm[] = {5,2,3,3,4,8,1};

pop(word,0);            //依据id将指定元素抽离
pop(numm,-2);            //删去倒数第二个

//removeindex(&array[], value) :根据值删除,返回1/0(是否成功删除)
int ture = removevalue(numm,3);//删除数组中发现的第一个数值为3的元素,册除成功返回1,否则返回0
printf('%s\n',ture );
printf('%s\n',numm );

//append(数组名,新数组/新元素)  在数组的末尾拼接新数组或新元素。
string word1[]= {'HIP'};
append(word1,'/geo');                 //在数组的末尾添加一个元素,相同功能的还有push()
word1[5] = '/agents';                 //跳过2 3 4号索引的元素,直接在5号索引位置赋值'/agents'
append(word1, {'/zombie','/clip'});   //在数组的末尾拼接另一个数组(literal)
string test[]= {'/walk'};
append(word1,test);                   //在数组的末尾拼接另一个数组(variable)
printf('%s\n',word1 );

int pts[] = array(1, 2.5, 'k', {-4.9,4,-5.3});//用各种数据和变量创建一个数组
printf('%s\n',pts );                          //都会被转成指定类型,这里是整型
//Founction   array(元素,元素,.....) 按照指定的数组类型,将元素强转后返回成数组

// 展平:serialize(向量/矩阵/各种数据...) 将 输入的数据 展平成 浮点 ,并返回成 浮点数组
vector  pos[]= { {1,2,3}, {4,5,6} };
matrix3 rot[]= { { {1,0,0},{0,1,0},{0,0,1} },   { {0,0,2},{2,0,0},{0,2,0} } };
float posfloat[]= serialize(pos);   //将向量数组 展平  成浮点数组
float rotfloat[]= serialize(rot);   //将矩阵数组 展平,每个分量都是一个浮点元素

// 组合:unserialize(数组名) 将 浮点数组 组合成 指定类型的数组 并返回
vector vel[];
matrix3 scale[];
float flt[]= {1, 1, 0, 1, 2, 0, 3, 1, 3 };
vel = unserialize(flt);    //将浮点数组组合成向量数组,3个浮点一个向量
scale = unserialize(flt);  //将浮点数组组合成矩阵数组

// 其他常用函数
// 看文档,带&的是修改原数组,不带是返回新的
//Founction   min(数组名)                     返回数组中的最小值
//Founction   max(数组名)                     返回数组中的最大值
//Founction   avg(数组名)                     返回数组的平均值
//Founction   sort(数组名)                    将数组从小到大排列,并返回
//Founction   argsort(数组名)                 将数组从小到大排列,并返回 排序后的各元素 在 原数组中的索引
//Founction   reorder(数组名,argsort(数组名))  实际就是利用两个函数的配合实现了sort()的功能
//Founction   reverse(数组名)                 将数组反转顺序,并返回新的数组,原数组不变
//Founction   reverse(sort(数组名))           利用两个函数实现从大到小排列
int number[]={ 5, 2, 3, 1, 4, 6, 7, 9, 0 };
printf('min     = %s\n',min (number) );
printf('max     = %s\n',max (number) );
printf('avg     = %s\n',avg (number) );
printf('sort    = %s\n',sort(number) );    //返回新的排好序的数组,排序方式从小到大,原数组不变
printf('argsort = %s\n',argsort(number) ); //将数组从小到大排列,并返回 排序后的各元素 在 原数组中的索引
int sorted[];
for(int i=0; i<len( number); ++i)
{
    int temp[] = argsort(number);
    sorted[i]  = number [temp[i]];
}
printf('sorted  = %s\n',sorted );
float re[]= reorder(flt,argsort(flt)); //fit在第8部分定义的
printf('re      = %s\n',re );
reverse(sorted); //返回新的数组,反转顺序,原数组不变,还可以用来反转字符串"hello" -> "olleh
printf('reverse = %s\n',reverse(sorted) );

//insert(数组名,索引,元素/数组...)  在索引前面插入元素或数组等,直接改变原数组,无返回值
int digit[]= { 5, 2, 3, 1, 4, 6, 7, 9, 0 };
insert(digit,1,23);   //在 第n号元素    前面插入元素
insert(digit,-1,43);  //在 倒数第n个元素 前面插入元素
printf('%s\n',digit );
int a[]= {8,8,8};
insert(digit,3,a);    //插入数组变量

//isvalidindex(数组名,索引) 判断该数组是否拥有该索引,返回1或0
int data[]= { 5, 2, 3, 1, 4, 6, 7, 9, 0 };
printf('%s\n',isvalidindex(data,-10));
//该数组序号范围0~8或-1 ~ -9(倒数第一个~倒数第九个)
//如果序号在这数组中有,isvalidindex()返回真,否则返回假
//等价于index < len(array) && index >= -len( array)isvalidindex (
//         这个例子中id<9 && id>=-9

//find(数组,某个元素)
//若该元素存在于该数组,则返回该元素在数组中的索引序号
//若该元素不存在于该数组,则返回负值

 自定义函数

更多参考

https://github.com/jtomori/vex_tutorial#functions

https://github.com/jtomori/vex_tutorial#functions-overloading

 

vex的函数,修改形参会影响实参!类似c的地址传递。可以加const 禁止修改。(见例1)

例1

/*
function 关键词 可加可不加
float是该函数的返回类型,如果返回类型是void,代码中不需要return
mydot是函数名字
a,b是函数参数(由用户提供)
vector是参数类型,相同类型可用逗号隔开;
                不同类型必须用分号,比如(vector a;float b)
const意味着只读 不可写
*/
function float mydot(const vector a,b)
{
    float c = a.x*b.x +a.y*b.y +a.z*b.z;
    return c;//必须有return关键词,返回浮点c
             //如果返回类型是void,不需要return
}
//函数重载,相同函数名下,可以有不同的参数类型和不同的返回类型
function float mydot(const vector2 a,b)
{
    float c = a.x*b.x +a.y*b.y;
    return c;//也可以直接写 return  a.x*b.x +a.y*b.y; 返回一个式子的值
}
//@Cd = mydot({0,1,0},@N);//我们自定义的点乘函数mydot()
//@Cd = dot({0,1,0},@N);//系统自带的点乘函数dot()

vector2 pos = set(@P);
@Cd = mydot({1,0},pos);

 例2 可以有多个return

//可以有多个return关键词
function int mymax ( const int a,b)
{
    //b*=2;这样做会报错,因为const int b只能读不能写.这里const的作用和C++里指针的作用差不多
    if(a>=b)
        return a;
    else
        return b;
}
printf('%s\n',mymax(1,2));

自定义叉乘

//参数always passed by reference,总是引用,不是拷贝
//意味着如果在函数中修改了参数变量,这个变量就改变了
//为了避免意外地改变参数,可以加上const关键词
function void acrossb(vector a;const vector b)
{
    //自定义函数里面可以使用vex自带函数
    //a = set(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
    //自定义函数里面还可以再次自定义函数[nested function]
    function vector myset(const float a,b,c)
    {
        vector result = 0;
        result.x = a;
        result.y = b;
        result.z = c;
        return result;
    }
    a = myset(a.y*b.z-a.z*b.y,a.z*b.x-a.x*b.z,a.x*b.y-a.y*b.x);
}
@N = @P;
//@N = cross({0,1,0},@N);//自带的叉乘函数
//acrossb({0,1,0},@N);
acrossb(@N,{0,1,0});

 

创建属性

Houdini自带常用属性

//Houdini有许多浮点类型的常用属性,如@pscale,以下时除浮点以外的其它类型:
/*
vector               @P, @accel, @Cd, @N, @scale, @force, @rest, @torque, @up, @uv, @v,@center, @dPdx, @dPdy, @dPdz (see Volume Wrangle).

vector4              @backtrack, @orient, @rot

int                  @id, @nextid, @pstate,@elemnum, @ptnum, @primnum, @vtxnum, @numelem, @numpt, @numprim, @numvtx (see indexing variables below).
                     @group_* (see accessing group membership below).
                     @ix, @iy, @iz, @resx, @resy, @resz (see Volume Wrangle).

string               @name, @instance
*/
//以上所有属性在创建时可以不申明类型

直接创建

@N;@v;@up;//Houdini自带属性不必申明类型
@foo;//自定义属性时,默认类型为float

// 非简写形式
int      @num_of_pt  = 8;
float    @pscale     = 0.5;
vector2  @uv         = {0.3,0.9};
vector   @v          = {0.2,0.3,0.4};
vector4  @orient     = {0,1,2,3};
matrix2  @rot_2d     = {{1,0},{0,1}};
matrix3  @rot        = {{1,0,0},{0,1,0},{0,0,1}};
matrix   @transform  = {{1,0,0,2},{0,1,0,3},{0,0,1,4},{0,0,0,1}};
string   @name       = "box";

// 非简写特性: 
/*
1.不能在等号(=)的右边做计算。错误示例:
float    @myfoo   = 1+10;

2.不能在等号(=)的右边引用函数。错误示例:
vector   @myup    = set(0, 1, 0);

3.大括号内不能包含变量(和函数)
vector   @mycolor = {@pscale,0.3,0.4};
vector   @mycolor = {COS($PI),0.3,0.4};

4.使用非简写形式创建数组属性,可以赋空值,但不能赋初值。以下是错误语法:
int      @neighbours[] = {0,1,2};//只能写成如下形式:

int      @neighbours[];
matrix3  @rotate[];//使用非简写形式创建矩阵数组亦是如此
string   @words[] = {};//但是可以赋空值
*/

//简写形式
i@id         = 8;
f@width      = 1.0+2.3;
u@xy         = {1.0,0.8};  //二维向量
v@w          = set(@width,$PI,0.5); //三维向量
p@point      = {0,0,0,1}; //四维向量
2@scale_2d   = {{2,0},{0,2}};
3@scale      = {{3,0,0},{0,3,0},{0,0,3}};
4@tranf      = {{1,0,0,2},{0,1,0,3},{0,0,1,4},{0,0,0,1}};
s@path       = "op:/obj/Create_Attributes/box1/";

i[]@pointcloud = {0,1,2};
f[]@len        = array(1,@Time,@width);
3[]@rotation; //
4[]@transform2 = {}; 
s[]@letters    = {"Hello","World"};

/* 简写特性
1.可以在等号(=)右边作运算
2.可以在等号(=)右边引用函数
3.简写形式下,大括号内也不能包含变量(和函数)
4.使用简写形式创建数组属性,可以赋初值。也可以不赋初值或赋空值
*/

// 简写与非简写区别
f@myfoo       = 3.14;//使用简写时,无论该属性存在与否,都将创建并赋值
vector @myvec = {2,2,2};//使用非简写:1.若该属性已存在,不会覆盖掉原属性值。若该属性不存在,创建并赋值

//结论:一般用简写形式创建属性,除非需要上述功能
//可能想到的用处:在不知道预创建属性名是否被占用时,可以使用非简写来创建,这样可以避免属性值改变带来的项目问题

用函数创建

//添加属性:add...层级...attrib(节点端口,属性名,属性值);
addpointattrib(0,"myvalue1",1);
addvertexattrib(0,"myvalue2",{1,2});
addprimattrib(0,"myvalue3",{1,2,3});
adddetailattrib(0,"myvalue4",{1,2,3,4});

//修改属性:set...层级...attrib(节点端口,要修改的属性名,具体对象(点/顶点/面),要修改的属性值);
setpointattrib(0,"myvalue1",1,3);       //修改   0号input端口   点层级      1号点         myvalue1属性的值为3
setvertexattrib(0,"myvalue2",2,3,{3,4});//修改   0号input端口   顶点层级    2号面3号顶点   myvalue2属性的值为{3,4}
setprimattrib(0,"myvalue3",1,{4,5,6});  //修改   0号input端口   面层级      2号面         myvalue3属性的值为{4,5,6}
setdetailattrib(0,"myvalue4",{5,6,7,8});//修改   0号input端口   整体层级                 myvalue4属性的值为{5,6,7,8}

读取属性

可以使用attribvop来查看Geometry VOP Global Parameters

使用@获取

float y = @P.y;//使用 .x .y .z 或 .r .g .b 或 [0] [1] [2]来引用多维向量的分量
@Cd.r = @opinput1_Cd.g;//读取第二个输入端口 相同点序号的Cd属性。将第二输入端口的颜色绿通道 赋值给 第一输入端口相同序号点的颜色红通道
                       //自带属性不用声明属性类型
float f =v@opinput1_foo.y; // 调用,前面要加v

vector @c = {0,1,0};
@P.y = @c.y;// 现创现用,前面可以不加v

//读取体积属性 @+属性名 
//如果体素的y值大于0,则将其密度值减1
if(@P.y > 0)
--@density;//相当于@density -=1

使用函数获取与修改

// 获取属性 :层级(输入端口,属性名,点/顶点/面序号)
v@mypoint_color = point(1,"point_Cd",1);     //将第二输入端口1号点的Cd属性值    赋值给  第一输入端口每个点新创建的属性mypoint_color
v@mypoint_color = point(1,"point_Cd",2);     //将第二输入端口2号点的Cd属性值    赋值给  第一输入端口每个点新创建的属性mypoint_color(这里特意修改了2号点的值,以区别1号点)
v@mypoint_color = point(1,"point_Cd",@ptnum);//将第二输入端口所有点的Cd属性值   赋值给  第一输入端口每个相同序号点新创建的属性mypoint_color

v@myprim_color   = prim(2,'prim_Cd',3);//用法和上面一样,只是这里获取的是prim层级的属性(这里特意修改了3号面的值)

v@myvertex_color = vertex(3,'vertex_Cd',2,3);//获取顶点属性时,可以用几号面几号顶点引用到具体的顶点序号(这里特意修改了2号面3号顶点的值)

v@mydetail_color = detail(1,'detail_Cd');//用法差不多,只是detail不需要具体指定(不作演示,所以这里并没有在一号端口输入对象的detail上创建detail_Cd)

// 修改属性
setpointattrib(0,"myvalue1",1,3); //修改 0号input端口 点层级 1号点 myvalue1属性的值为3
setvertexattrib(0,"myvalue2",2,3,{3,4});//修改 0号input端口 顶点层级 2号面3号顶点 myvalue2属性的值为{3,4}
setprimattrib(0,"myvalue3",1,{4,5,6}); //修改 0号input端口 面层级 2号面 myvalue3属性的值为{4,5,6}
setdetailattrib(0,"myvalue4",{5,6,7,8});//修改 0号input端口 整体层级 myvalue4属性的值为{5,6,7,8}

读取节点参数

chX

写完以后,按右边三横杆,可以自动生成。

【Houdini】VEX - 基础篇(捷佳的教程笔记)

printf('%s\n', chi('my_integer'));
printf('%s\n', chf('my_float')  );
printf('%s\n', chu('my_vector2'));
printf('%s\n', chv('my_vector') );
printf('%s\n', chp('my_vector4'));
printf('%s\n', ch2('my_matrix2'));
printf('%s\n', ch3('my_matrix3'));
printf('%s\n', ch4('my_matrix4'));
printf('%s\n', chs('my_string') );

 chramp

ramp函数需要自变量的范围在0-1之间,超出的范围会循环。通常使用fit函数重新映射下

【Houdini】VEX - 基础篇(捷佳的教程笔记)

//chramp() 示例

int example = chi('example');
if(example==1)
{
    @P.y = chramp('my_ramp1',@P.x);//ramp函数需要自变量的范围在0-1之间,超出的范围会循环
}
else if(example==2)
{
    vector line_min = getbbox_min(0);
    vector line_max = getbbox_max(0);

    float px = fit(@P.x,line_min.x,line_max.x,0,1);
    @P.y = chramp('my_ramp2',px);
}
else if(example==3)
{
    vector line_bbox = relpointbbox(0,@P);
    @P.y = chramp('my_ramp3',line_bbox.x);
}
else if(example=4)
{
    float line_min = chf("/obj/Reading_Parameter_Value/line1/originx");//绝对路径
    float line_max = line_min + chf( "../line1/dist");//相对路径
    float px =fit(@P.x,line_min,line_max,0,1);
    @P.y = chramp('my_ramp4',px);
}

// 示例2 颜色的ramp
@Cd = vector(chramp('my_color',@P.x));//在ramp前面加上vector修饰,可以生成颜色ramp
@Cd = vector(chramp('my_color',fit(@P.x,-5,5,0,1)));// fit到0~1 

 其他说明

printf('%s\n',chf('float'),0.5);//ch类函数的第二个参数是时间,单位是秒,
                                //如果写明了第几秒,就会返回那一秒的值
                                //如果没写,就返回当前帧的值

printf('%s\n',chsraw('float1'));//不会执行参数中的表达式
                                //会直接以原始字符串的形式返回所写表达式

printf('%s\n',chexpr('float2','5*8'));//忽略原表达式,执行新的表达式,返回浮点值
//chexprf();chexprt();后缀f和t指的是帧和秒

 组

组说明

@+组名自动创建 组(如果没有该组的话)

=1进组,=0出组。

// 进出组
if(@P.y>0)
   @group_up = 1;
if(@ptnum==4)
   @group_up = 0;

// 判断元素是否在组内
if(@group_up == 1)//判断点是否在组内,1则在组内,0不在
@Cd = {0,1,0};
else
@Cd = {1,0,0};

 组函数

// 进出组
if(@P.y>0)
   setpointgroup(0,'up',@ptnum,1); //把第0输入端的 @ptnum 点加入(1加入0退出) “up”组

if(@ptnum==4)
   {
   //setpointgroup(0,'up',@ptnum,0);
   setpointgroup(0,'up',@ptnum,1,'toggle');//toggle切换,反转组的状态
   }                                      

//类似的函数:setprimgroup(),setvertexgroup().主要作用是添加元素到组里,同时也起到了创建组的作用

// 判断
if( inpointgroup(0,'up',@ptnum))//如果点在组里,返回1,否则返回0
@Cd={0,1,0};
else
@Cd={1,0,0};

//类似的函数:inprimgroup(),invertexgroup().主要作用是判断元素是否在组里

// 求元素个数
nt npt = npointsgroup(0,'up');//返回该组中的元素个数
printf('%s\n',npt);

//类似的函数:nprimitivesgroup(),nverticesgroup().主要作用是判断元素是否在组里

// 列出组内元素
int list1[] = expandpointgroup(0,'up');//以数组的形式返回该组中的所有点的序号
int list2[] = expandpointgroup(0,'0-5');//0-5是返回的范围
int list3[] = expandpointgroup(0,'');//空组意味着返回所有的点序号

printf('%s\n',list1);
printf('%s\n',list2);
printf('%s\n',list3);

//类似的函数:expandprimgroup(),expandvertexgroup().主要作用就是以数组的形式列出组内的元素

判断

非0就是真

浮点会被转整数,小心被转0

if(true)//如果真
@P.y++;//往上移1

if(false)//如果假
@P.y++;//不会执行这句话

if(1)//1代表真true
@P.y++;//往上移了

if(0)//0代表假false
@P.y++;//不执行

if(1.15)//浮点会被自动转成整数,结果还是1,但会警告//浮点转整是直接抹去小数部分,不是四舍五入.不建议这样做
@P.y++;//往上移了1

if(2+0.15)//浮点转成整数,结果是2,非0就是真
@P.y++;//往上移了1

if(0.15)//浮点转成整数,结果是0
@P.y++;//不执行

if(0.6)//浮点转成整数,结果是0
@P.y++;//不执行

if(-2.15)//浮点转成整数,结果是-2,非0就是真
@P.y++;//往上移了1

//最终往上移了5
//牢记:非0就是真

 逻辑运算符

//  !  非:不是
if(!1)  @P.y++;//非真,也就意味着假,不执行
if(!0)  @P.y++;//执行

//  &&  且:必须两个都成立
if( 0 && 1 ) @P.y++;//不执行
if( 0 && 0 ) @P.y++;//不执行
if( 1 && 0 ) @P.y++;//不执行
if( 1 && 1 ) @P.y++;//执行

// ||  或:只需其中一个条件成立即可
if( 0 || 1 ) @P.y++;//执行
if( 0 || 0 ) @P.y++;//不执行
if( 1 || 0 ) @P.y++;//执行
if( 1 || 1 ) @P.y++;//执行

if( 1 || 0 && 1) @P.y++;//从左往右运算,1 || 0 = 1,1 && 1 = 1,结果为1,执行

 if简写

超过一句话,第二句话开始已经不归if管

@N;//Houdini会自动计算出法线属性
/*
if(@ptnum % 2 ==0)
   @Cd = 0;
   @P +=@N;//沿法线方向往外移动(if控制不了)
*/
//正确写法
if(@ptnum % 2 ==0)
{
   @Cd = 0;
   @P +=@N;
}

if… else if…

@Cd = 1;

if(@ptnum % 2)//符合条件的有1357;不符合的0246
   @P += @N;
else if(@ptnum<3)//在不符上述条件的点0246中,选择符合该条件的。即02
   @Cd={1,0,0};
else if(@ptnum>3 && @P.x>0)//46不符合上述所有条件,从中选符合当前条件的
   @Cd={0,1,0};
else  //上述条件全部无法满足的点,即4,最终会执行else指令
   @Cd={0,0,1};

三目运算符

@Cd = @ptnum? 1:0;

//@Cd = @P.y>0 ? (0,1,0}:{1,1,1};

//@Cd = @P.y>0 && @ptnum%2==0 ? {0,1,1}:{1,1,1};

 循环

while

//while (condition) statement1
//如果condition为真,执行statement

// 点的y值小于0.1,则加0.1
int count = 0;
while(@P.y<0.1)
{
    @P.y+=.1;
    count++;
}

printf('%s\n',count);

 do while

//do statement [while ( condition)]
//先执行一次statement,然后如果condition为真,接着循环执行statement

do
{
     @P.y+=.1;
}
while(@P.y<0.1);//别忘了分号

 for

//for (init; condition; change) statement
//首先执行init,然后如果condition为真,执行statement,接着执行change
//               如果condition为假,退出循环

for(int i = 0; i < @numpt ; ++i)//标准for loop
{
    vector pos = point(0,'P',i);  // 这里的pos是从上游获取的
    ++pos.y;
    setpointattrib(0,'P',i,pos);  // 设置p
}
//============================================================
int idx = 0;
for(float foo=1; foo <= 128; foo*=2,idx++)//还有许多可能性
{
    vector pos = point(0,'P',idx);  // 这里的pos也是从上游获取的
    --pos.y ;
    setpointattrib(0,'P',idx,pos);
}
//============================================================
addpointattrib(0,'Cd',{0,0,1});
for(int i = 0; i < @numpt ; ++i)
{
    if(i==5) continue; // continue:继续,跳过本次循环,直接进行下一轮循环
    setpointattrib(0,'Cd',i,{1,0,0});
}

 其他

for(float num: {2,4,6,8})
    @P.y += num;
int num[] = {2,4,6,8};
for(int j: num)
    @P.y -= j;

foreach(int number; num)
    @P.y +=number;
foreach(int id;int number; num)//id用来记录循环次数.一开始是0,随着循环进行,逐次+1
    @P.y -= (id+1)*2;

string names[] = {'pieceo', 'piece1', 'piece2'};
for(string name: names)
    printf('%s\n', name);
foreach(string name; names)
    printf('%s\n', name);

vector cd[] = {{1,0,0},{0,1,0},{0,0,1},{0,1,1},{1,1,0},{1,0,1}};
int idx = 0;
for(vector color: cd)
{
    @Cd = idx == @ptnum ? color:@Cd;
    ++idx;//利用++idx 使for循环 拥有计数的功能
}

//for loop      可以使用初始化列表 for(float num: {2,4,6,8}) 对
//for each loop 不能使用初始化列表 foreach(int number; {2,4,6,8}) 错

 创建几何体

点线面

【Houdini】VEX - 基础篇(捷佳的教程笔记)

//老版本创建时必须要有输入端,即便只是一个Null

vector pos = {4,0,0};

int p0 = addpoint(0,{0,0,0});//在0,0,0位置 创建一个点
int p1 = addpoint(0,pos);// 会返回所创建点的序号(
int p2 = addpoint(0,{0,3,0}); // 该序号不一定是最终序号,但可以用来连线,加属性
int p3 = addpoint(0,{0,-2.5,0});

int prim = addprim(0, 'sphere',   p3);       //sphere 球
           addprim(0, 'polyline', p0,p3);    //polyline 线
           addprim(0, 'poly',     p0,p1,p2); //poly 面

setprimintrinsic(0,'transform',prim,matrix3(ident())*.5 );

 创建

int pt0 = addpoint(0,2);//在0号输入端的2号点的位置创建一个点
int pt1 = addpoint(0,{4,3,0});
int pt2 = addpoint(0,1);

setpointattrib(0,'P',pt2,{4,.25,0});

int pt[]= array(pt0,pt1,pt2);//构建数组

int prim0 = addprim(0,'poly',pt);//用数组构建面
//如果addprim()创建的时候提供了点,不需要我们创建顶点

//下面这个例子,未提供点,需要我们手动加顶点
int pt3 = addpoint(0,{-0.5,-1.5,0});
int pt4 = addpoint(0,{-0.5,3,0});

int prim1 = addprim(0,'polyline');//建的时候未提供点

addvertex(0,prim1,pt3);//创建一个顶点,该顶点属于prim1,根基于pt3
addvertex(0,prim1,pt4);

修改顶点

【Houdini】VEX - 基础篇(捷佳的教程笔记)

//改变顶点的引用
//setvertexpoint(输入端口,prim序号,顶点序号,要引用的点序号)

setvertexpoint(0,2,0,0);//将0号输入端口的,2号面,0号顶点,引用到0号点上去(这里相当于没改变)
setvertexpoint(0,2,1,2);//将0号输入端口的,2号primitive的,1号顶点,引用到2号点上去
setvertexpoint(0,2,2,1);//将0号输入端口的,2号primitive的,2号顶点,引用到1号点上去

删除

if(@P.x<0) removepoint(0,@ptnum);//册除第几个输入端的第几号点

removeprim(0,3,0);//删除笫几个输入端的第几号面(线),是否包括点也一起删

 点线面互相访问

函数列表

/*
A_B_s
由A获取B,带s说明是数组
primvertices()    给出primnum           返回这个prim的所有顶点的'线性序号'[数组]
primvertex()      给出primnum和顶点序号   返回这个顶点的'线性序号'
primvertexcount() 给出primnum           返回这个prim的顶点的数量
primpoints()      给出primnum           返回这个prim的所有点的序号[数组],有序,按连接顺序
primpoint()       给出primnum和顶点序号   返回这个顶点所在的点的序号

pointprims()      给出点序号             返回所有包含这个点的prim的序号[数组]
pointvertices()   给出点序号             返回所有住在这个点上的顶点的'线性序号'[数组]
pointvertex()     给出点序号             返回住在这个点上的'第一个'顶点的'线性序号'

vertexpoint()     给出顶点序号           返回这个顶点所在的点的序号
vertexprev()      给出顶点'线性序号'      返回同在一个点上的上一个顶点的'线性序号'
vertexnext()      给出顶点'线性序号'      返回同在一个点上的下一个顶点的'线性序号'
vertexindex()     给出primnum和顶点序号   返回这个顶点的'线性序号'
vertexprim()      给出顶点'线性序号'      返回包含这个顶点的prim的序号
vertexprimindex() 给出顶点'线性序号'      返回这个顶点的序号
*/

示例

//借助Display options -> Markers -> Vertices -> Markers和Numbers观察顶点

//每个面有4个顶点,六个面一共24,'线性顶点序号'就是0~23
//借助Geometry Spreadsheet的顶点属性Map offset观察

//对于任一面来说,有4个顶点,这些顶点的'顶点序号'是0~3
//借助Geometry spreadsheet的顶点属性最左边一栏观察

int pt = vertexpoint(0,1);//form vertex to point
                          //从顶点访问点 输入'线性顶点序号' 返回点序号
int lvt0 = pointvertex(0,7);//form point to vertex
                          //从点访问顶点 输入点序号 返回第1个顶点的'线性顶点序号'
                                              //因为这个7号点里住着3个顶点
//想知道住在7号点的第2和第3个顶点的'线性顶点序号',可以用
int lvt1 = vertexnext(0,lvt0);//输入'线性顶点序号'
                              //返回住在同一点的下一个顶点的'线性顶点序号'
int lvt2 = vertexnext(0,lvt1);//再下一个如果没有下一个,返回-1
                              //另外,vertexprev()可以返回上一个
setvertexattrib(0,'Cd',-1,lvt0,{1,0,0});
setvertexattrib(0,'Cd',-1,lvt1,{0,1,0});
setvertexattrib(0,'Cd',-1,lvt2,{0,0,1});

int prim = vertexprim(0,lvt2);
int vt0  = vertexprimindex(0,lvt2);

setvertexattrib(0,'Cd',prim,vt0+1,{1,1,0});

printf('%s\n',pt);
printf('%s\n',lvt0);
printf('%s\n',lvt1);
printf('%s\n',lvt2);
printf('%s\n',prim);
printf('%s\n',vt0+1);

 neighbor函数

hou自带

// 自带的
i[]@nb = neighbours(0,@ptnum);
//neighbours(输入端口,查哪个点的邻居),以数组形式返回被查询点的邻居点,无特定顺序

 自构:由面推点再推点

int prims[]= pointprims(0,@ptnum);//以5号点为例,5 1 0号面都包含了5号点

int pts[];
int nb[];
int npt;
int ptprev = -1;
int ptnext = -1;
//解释一下find()函数在这里的用法:
//find(数组,某个元素)
//若该元素存在于该数组,则返回该元素在数组中的索引序号
//若该元素不存在于该数组,则返回负值
foreach(int prim; prims) //遍历5 1 0面
{
    pts = primpoints(0,prim);      //5 1 0面中以5号面为例,有5 6 7 4号点,这个数组是按连接顺序排列的
    npt = len(pts);                //5号面的总点数量是4
    int myIndex = find(pts,@ptnum);//查找5号点自身在这个数组中哪个位置

    if( myIndex == 0 )             //在首位,比如5 6 7 4
    {
        ptprev = pts[npt-1];       //前一个是 该数组最后一个 4
        ptnext = pts[myIndex+1];   //后一个是 自己的下一个 6
    }
    else if( myIndex == npt-1 )    //在尾部,比如6 4 7 5
    {
        ptprev = pts[myIndex-1];   //前一个是 自己的前一个 7
        ptnext = pts[0];           //后一个是 该数组第一个 6
    }
    else                           //在中间,比如6 5 7 4
    {
    ptprev = pts[myIndex-1];       //前一个是 自己的前一个 6
    ptnext = pts[myIndex+1];       //后一个是 自己的下一个 7
    }
     if( find(nb, ptprev) < 0 )    //5号面得出邻居4 6,1号面得出1 6,0得出1 4,有重复
     append(nb,ptprev);            //比如算完5号面已知邻居4 6,存放在数组nb
     if( find(nb,ptnext) < 0 )     //下一步1号面得出邻居1号点,往nb数组附加
     append(nb,ptnext);            //如果找不到点1在nb里面的位置(即nb里面不存在点1),find()返回负值则附加上去,
                                   //再下一步1号面得出邻居6号点,发现6在nb里面的位置是1(即存在点6),find()返回非负值,则不附加
}                                  

i[]@nb = nb;

 自构:由点推面 再推点

int lvtx[]= pointvertices(0,@ptnum);//当前点包含的所有顶点的'线性序号'数组
                                    //box每个点都有3个顶点
int primnum = -1;
int vtx= -1;
int nvtx= 0;
int ptprev = -1;
int ptnext = -1;
int nb[];

foreach(int lvtxnum; lvtx)//对于3个线性序号中的每一个线性序号
{
    primnum = vertexprim(0,lvtxnum);//求面序号
    vtx = vertexprimindex(0,lvtxnum);//求顶点序号
    nvtx = primvertexcount(0,primnum);//求这个面的顶点总数

//特殊情况vtx=0(第一个顶点)或vtx=nvtx-1(最后一个顶点)
    if( vtx == 0 )                        //primpoint()通过面序号和顶点序号来获取点序号
    {                                     //顶点序号为0
        ptprev = primpoint(0,primnum,nvtx-1); //一个prim可能有n个顶点,前一个为n
        ptnext = primpoint(0,primnum,1);      //后一个1
    }
    else if( vtx == nvtx-1 )              //顶点为n
    {
        ptprev = primpoint(0,primnum,vtx-1);  //前一个n-1
        ptnext = primpoint(0,primnum,0);      //后一个0
    }
    else                                  //顶点为任何中间顶点i
    {
        ptprev = primpoint(0,primnum,vtx-1);  //前一个i-1
        ptnext = primpoint(0,primnum,vtx+1);  //后一个1+1
    }
    if( find(nb, ptprev) < 0 )
        append(nb,ptprev);
    if( find(nb, ptnext) < 0 )
        append(nb,ptnext);
}
i[]@nb = nb;

lntrinsic属性

lntrinsic属性和普通属性基本相似,区别在于普通属性存储在几何体上(primitive和detail层级),Intrinsic属性仅在需要的时候计算。

不同类型的primitive,lntrinsic不一样相同

【Houdini】VEX - 基础篇(捷佳的教程笔记)

读取

【Houdini】VEX - 基础篇(捷佳的教程笔记)

1.在group参数栏读取

// 组信息
@intrinsic:measuredperimeter>ch('threshold')

// vex:周长大于阈值,则alpha为0
@Alpha = 0;
/*
measuredarea 测量出来的面积
measuredperimeter 测量出来的周长
measuredvolume 测量出来的体积
*/

【Houdini】VEX - 基础篇(捷佳的教程笔记)

2.用primintrinsic()读取(推荐)

if(primintrinsic(0, 'measuredarea',@primnum)>chf('threshold'))
    removeprim(0,@primnum,1);

3.用prim()读取

if(prim(0, 'intrinsic:measuredvolume',@primnum)>chf('threshold'))
    removeprim(0,@primnum,1);

 写入

晚点补

给TA充电
共{{data.count}}人
人已充电
HoudiniHoudini文章与视频

【Houdini节点】Attribute组

2022-1-26 21:45:24

HoudiniHoudini文章与视频

【Houdini】Vex函数:bbox 边界盒

2022-2-9 23:35:28

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
今日签到
搜索