VEX language reference

Context

VEX 프로그램들은 특정 context에 대해 작성된다. 예를 들어, 오브젝트의  표면 색을 제어하는 쉐이더는 surface context에 대해 작성됐다. 라이트로부터의 빛을 결정하는 쉐이더는 light context에 대해 작성됐다. 채널 데이터를 생성하거나 필터하는 VEX 프로그램은 chop context에 대해 작성되었다.

context는 어떤 함수, 문법, 전역 변수들이 사용 가능한지에 영향을 준다.

Statements

VEX는 C에서 익숙한 문법들을 주로 지원한다. illuminace와 gather 루프와 같은 쉐이딩 특정 문법들 또한 지원한다.

Built-in functions

VEX는 거대한 내장 함수 라이브러리를 갖추고 있다. 몇몇 함수들은 특정 context에서만 사용 가능하다.

User-defined functions

함수들은 C와 유사하게 정의된다 : 리턴 타입, 함수 이름, 괄호 안의 아규먼트 리스트를 정의하고, 코드 블록을 붙인다.

같은 타입의 아규먼트들은 콤마로 구분해서 선언될 수 있다. 다른 타입의 아규먼트들은 세미콜론을 사용해 분리되어 선언되어야 한다.

1
2
3
4
5
int test(int a, b; string c) {
    if (a > b) {
        printf(c);
    }
}
cs

같은 이름으로 함수를 중복할 수 있지만 다른 아규먼트 표시와 다른 리턴 타입을 가져야 한다.

함수 정의를 할때 타입이 애매모호하지 않도록 추가 함수 키워드를 함께 사용할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function int test(int a, b; string c) {
    if (a > b) {
        printf(c);
    }
}
void print(basis b) {
    printf(“basis: { i: %s, j: %s, k: %s }\n”, b.i, b.j, b.k);
}
void print(matrix m) {
    printf(“matrix: %s\n”, m);
}
void print(bases b) {
    printf(“bases <%s> {\n”, b.description);
    printf(”  “); print(b.m);
    printf(”  “); print(b.n);
    printf(”  “); print(b.o);
    printf(“}\n”);
}
basis rotate(basis b; vector axis; float amount) {
    matrix m = 1;
    rotate(m, amount, axis);
    basis result = b;
    result.i *= m;
    result.j *= m;
    result.k *= m;
    return result;
}
void rotate(basis b; vector axis; float amount) {
    b = rotate(b, axis, amount);
}
cs

Notes

  • 사용자 함수들은 레퍼런스되기 전에 선언되어야만 한다.
  • 함수들은 컴파일러에 의해 자동적으로 인-라인된다. 그래서 반복이 되지 않는다. 순환 알고리즘을 작성하기 위해서는 shader calls를 대신 사용해야만 한다.
  • RenderMan Shading Language에서처럼, 사용자 함수로 전달되는 파라미터들은 항상 레퍼런스를 통해 전달된다. 그래서 사용자 함수에서의 조작은 함수와 함께 호출된 변수에까지 영향을 미친다. const 키워드를 접두해서 쉐이더 파라미터가 읽기 전용이 되도록 강제할 수 있다. 사용자 함수가 아웃풋 파라미터로 작성되게 하려면, export 키워드를 접두해야 한다.
  • 사용자 함수의 갯수 제한은 없다.
  • 하나의 함수에 하나 이상의 return 문법을 가질 수 있다.
  • RSL 처럼 extern으로 선언을 하지 않고도 전역 변수에 직접 접근할 수 있다. 그러나, 전역 변수에 접근하는 것을 권장하지 않는다. 왜냐하면 이 전역 변수는 함수가 오직 하나의 context에서 작동하도록 제한하기 때문이다. (전역 변수가 존재하는 전제하에). 대신, 전역 변수를 함수의 파라미터로 전달한다.
  • 함수들은 하나의 함수 안에서 정의될 수 있다. (nested functions).

Main (context) function

VEX 프로그램은 context의 이름이 리턴 타입인 함수를 하나는 포함하고 있어야만 한다. 이 것은 Mantra에 의해 호출되는 프로그램의 main 함수이다. 컴파일러는 파일당 하나의 context 함수가 존재하길 원한다.

이 함수는 요구된 모든 정보를 계산하는 작업과 전역 변수들을 변화하는 작업을 해야한다. context 함수로부터 값을 리턴하는 return 문법을 사용하면 안된다.

context 함수에 사용되는 아규먼트들은 프로그램의 사용자 인터페이스가 될 것이다. 예를 들어 VEX 프로그램을 레퍼런스하는 쉐이딩 노드의 파라미터가 있다.

만약 geometry attribute가 context 함수의 파라미터로써 같은 이름으로 함께 존재한다면, 그 attribute는 파라미터의 값을 오버라이드 한다. 이는 VEX 코드를 컨트롤 하기 위해 geometry 위에 attribute를 칠할 수 있게 한다.

1
2
3
4
5
6
7
surface
noise_surf(vector clr = {111}; float frequency = 1;
export vector nml = {000})
{
Cf = clr * (float(noise(frequency * P)) + 0.5* diffuse(normalize(N));
nml = normalize(N) * 0.+ 0.5;
}
cs

 

** Note **

parameters to context 함수들은 VEX에서 특별한 방식으로 다루어진다. geometry attribute를 변수와 같은 이름으로 사용해 파라미터의 값을 오버라이드 할 수 있다. 단 쉐이터의 범위내에서 “const”가 고려되는 경우는 제외한다. 즉 파라미터 이 경우에는 파라미터 값을 변경할 수 없다. 만약 시도를 한다면 컴파일러에서 오류가 발생하게 된다.

기존의 geometry를 변경하고자 한다면 flag 파라미터들에 export 키워드를 사용할 수 있다.

User interface pragmas

Houdini로 인해 이 프로그램에서 생성되는 사용자 인터페이스는 기본적으로 변수 이름과 데이터 타입을 기반으로한 일반적인 텍스트 칸으로  최소화 될것이다. 예를 들어, frequency를 일정 범위를 가진 슬라이더를 통해 지정하거나, clr이 색으로 여겨지는 것이 있다. 이를 사용자 인터페이스 컴파일러 프라그마를 통해 할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma opname        noise_surf
#pragma oplabel        “Noisy Surface”
#pragma label    clr            “Color”
#pragma label    frequency    “Frequency”
#pragma hint    clr            color
#pragma range    frequency    0.10
surface noise_surf(vector clr = {1,1,1}; float frequency = 1;
           export vector nml = {0,0,0})
{
    Cf = clr * (float(noise(frequency * P)) + 0.5* diffuse(normalize(N));
    nml = normalize(N)*0.+ 0.5;
}
cs

Operators

VEX는 아래의 차이점을 지닌 C 우선권을 가진 스탠다드 C 연산자들을 가지고 있다.

곱셈은 두 벡터들 혹은 포인트들로 정의된다. 내적 혹은 외적과 달리 곱셈은 요소와 요소간의 곱으로 수행된다.

많은 연산자들은 비 스칼라 데이터 타입들에 대해 정의된다. 예를 들어, 매트릭스를 벡터에 곱하면 벡터는 매트릭스에 의해 트랜스폼된다.

연산자로 서로다른 두 타입을 합치는 애매모호한 상황에서는 두번째 타입을 가진 값의 결과가 나오게 된다. 예를 들면, int + vector = vector

Dot operator

dot (.)  연산자를 사용해 vector, matrix, struct의 개별 요소들을 레퍼런스 할 수 있다.

vector의 경우, 요소 이름들은 정해져 있다.

  • .x 또는 .u는 vector2의 첫 번째 요소를 레퍼런스한다.
  • .x 또는 .r은 vector와 vector4의 첫 번째 요소를 레퍼런스 한다.
  • .y 또는 .v는 vector2의 두 번째 요소를 레퍼런스 한다.
  • .y 또는 .g는 vector와 vector4의 두 번째 요소를 레퍼런스 한다.
  • .z 또는 .b는 vector와 vector4의 세 번째 요소를 레퍼런스 한다.
  • .w 또는 .a는 vector4의 네 번째 요소를 레퍼런스 한다.

u, v / x, y,z / r, g, b 문자들의 선택은 임의적이다; vector가 point 혹은 color를 가지고 있지 않더라도 같은 문자를 적용할 수 있다.

matrix의 경우 문자의 짝을 사용할 수 있다.

  • .xx는 [0] [0] 요소를 레퍼런스 한다.
  • .zz는 [2] [2] 요소를 레퍼런스 한다.
  • .ax는 [3] [0] 요소를 레퍼런스 한다.

Comparisons

비교 연산자들 (==, !=, <, <=, >, >=)은 왼쪽과 오른쪽 데이터가 같은 타입일때, string, float, integer 타입일 때에만 정의된다.

로직 (&&, ||, !)  연산자와 비트 (& |, ^, ~ ) 연산자들은 integer 타입들에만 정의된다.

Precedence table

다음 테이블에서 위에 있는 연산자들이 높은 우선권을 가진다.

Order Operator Associativity Description
15 () L to R Function call, expression grouping, structure member.
13 !
~ One’s complement
+ Unary plus
- Unary minus
++ Increment
-- Decrement
(typename) Type cast
12 * L to R Multiplication
/ Division
% Modulus
11 + L to R Addition
- Subtraction
10 < L to R Less than
> Greater than
<= Less than or equal
>= Greater than or equal
9 == L to R Equal
!= Not equal
8 & L to R Bitwise AND
7 ^ L to R Bitwise exclusive OR
6 | L to R Bitwise OR
5 && L to R Logical AND
4 || L to R Logical OR
3 ? : L to R Ternary conditional
2 = R to L Assign to variable
+= Add and assign
-= Subract and assign
*= Multiply and assign
/= Divide and assign
%= Take modulus and assign
&= Take bitwise AND and assign
|= Take bitwise OR and assign
^= Take bitwise exclusive OR and assign
1 , L to R Argument separator

Data types

VEX는 32 비트 정수를 사용한다. AttribCast SOP을 사용해 geometry attribute가 64비트를 계산하면, attribute를 VEX코드로 변경할 때 VEX는 조용히 추가적인 비트들을 버린다.

long 숫자를 분해하기 위해 언더바를 사용할 수 있다.

Type Definition Example
int Integer values 21, -3, 0x31, 0b1001, 0212, 1_000_000
float Floating point scalar values 21.3, -3.2, 1.0, 0.000_000_1
vector2 Two floating point values. You might use this to represent texture coordinates (though usually Houdini uses vectors) or complex numbers {0,0}, {0.3,0.5}
vector Three floating point values. You can use this to represent positions, directions, normals or colors (RGB or HSV) {0,0,0}, {0.3,0.5,-0.5}
vector4 Four floating point values. You can use this to represent positions in homogeneous coordinates, or color with alpha (RGBA) {0,0,0,1}, {0.3,0.5,-0.5,0.2}
array A list of values. See arrays for more information. { 1, 2, 3, 4, 5, 6, 7, 8 }
struct A fixed set of named values. See structs for more information.
matrix2 Four floating point values representing a 2D rotation matrix { {1,0}, {0,1} }
matrix3 Nine floating point values representing a 3D rotation matrix or a 2D transformation matrix { {1,0,0}, {0,1,0}, {0,0,1} }
matrix Sixteen floating point values representing a 3D transformation matrix { {1,0,0,0}, {0,1,0,0}, {0,0,1,0}, {0,0,0,1} }
string A string of characters. See strings for more information. "hello world"
bsdf A bidirectional scattering distribution function. See writing PBR shaders for information on BSDFs.

Structs

Houdini 12 부터 struct 키워드를 사용해 새로이 구조가 있는 타입들을 정의할 수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include <math.h>
struct basis {
    vector i, j, k;
}
struct bases {
    basis m, n, o;
    string description;
}
basis rotate(basis b; vector axis; float amount) {
    matrix m = 1;
    rotate(m, amount, axis);
    basis result = b;
    result.i *= m;
    result.j *= m;
    result.k *= m;
    return result;
}
basis b = { {1,0,0}, {0,1,0}, {0,0,1} };
= rotate(b, {0,0,1}, M_PI/6);
cs

 

** Note **

소스 파일로 사용하기 전에 structs를 정의해야만 한다.

Struct functions

코드를 정리하고 객체 지향 프로그래밍의 제한된 형식을 허용하기 위해 structs 안에 함수들을 정의할 수 있다.

  • struct 함수 안에, struct 인스턴스에 전달하기 위해 이를 사용 할 수 있다.
  • struct 함수 안에, 이 것의 이름이 만약 변수들이라면 이름을 통해 struct 필드에 전달 할 수 있다. (예를 들어, basis는 this.basis의 줄임말이다).
  • struct 인스턴스에 -> 화살표 연산자를 사용해 struct 함수를 호출 할 수 있다. 예를 들어 sampler -> sample(). struct 함수 안에서 this -> method()를 사용해 다른 메소드들을 struct에 호출할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
struct randsampler {
        // Fields
        int        seed;
        // Methods
    float sample()
    {
                // Struct functions can refer to fields by name
                return random(seed++);
    }
}
cvex shader()
{
    randsampler sampler = randsampler(11);
    for (int i = 0; i < 10; i++)
    {
                // Use -> to call methods on struct instances
                printf(“%f\n”, sampler>sample());
    }
}
cs

Mantra Specific Types

Mantra는 쉐이딩 한정 함수로 사용되는 몇가지 이미 정의된 struct 타입을 가지고 있다.

light Defined in mantra shading contexts only. This is a struct representing a
handle to a light source. The struct has methods:

  • illuminate(…)
    Invokes the VEX surface shader bound to the vm_illumshader property of
    the light source.

In an IFD, you may see lines like ray_property light illumshader diffuselighting
or ray_property light illumshader mislighting misbias 1.000000.

These statements define the shader invoked when the illuminate() method
is called on a light object.

material Defined in mantra shading contexts only. This is opaque struct
representing the material assigned to an object.

Type casting

Variable casting

이는 C++ 또는 Java의 type casting과 유사하다 : 한 타입의 값을 다른 것으로 변환한다. (예를들어 int를 float로).

이는 다음 같은 상황일 때 필요하다 :

1
2
3
int a, b;
float c;
= a / b;
cs

 

이 예제에서, 컴파일러는 정수 분할을 할것이다. 소수점 분할을 하고자 한다면 분명하게 a와 b를 float로 캐스트 해야 한다 :

1
2
3
int a, b;
float c;
= (float)a / (float)b;
cs

 

이는 추가적인 명령들을 생성해 캐스트를 행한다. 이는 실행 관련 부분에서 이슈가 될 수도 있다.

Function casting

VEX는 인수의 타입뿐만 아니라 리턴 타입까지 고려해서 함수를 처리한다.같은 인수 타입이지만 다른 리턴 타입을 가진 함수를 호출하는 것과 차이를 두기 위해,  함수를 캐스트 할 수 있다.

예를 들어, noise 함수는 다른 파라미터 타입들을 가질 수 있지만, 또한 다른 타입들을 리턴할 수도 있다 : noise는 float 또는 vector 타입을 모두 리턴할 수 있다.

1
2
float n;
= noise(noise(P));
cs

VEX는 float noise(vector) 또는 vector noise(vector)를 모두 처리할 수 있다.

함수 호출을 캐스트하기 위해, typename( … )으로 함수를 둘러싼다 :

1
= noise( vector( noise(P) ) );
cs

이는 함수 호출처럼 보이는 반면, 아무것도 하지 않지만 함수 호출 내부와 차이를 보이고 위와 같은 퍼포먼스는 가지고 있지 않다.

함수 캐스팅은 함수 호출을 특정 타입의 변수에 직접 적용할 때 함축적이다. 그래서 다음 expression들은 동일하고, 함수 캐스트는 간결한 코드에 대해서 생략될 수 있다 :

1
2
vector n = vector( noise(P) );        // Unnecessary function cast
vector n = noise(P);
cs

** Note **

VEX가 호출하려는 함수의 특징을 결정하지 못한다면,  모호성 오류를 발생시키고 candidate 함수들을 출력한다. 그러면 적절한 리턴 값을 선택하고 그 것을 선택하기 위해 함수 캐스트를 추가한다.

함수 캐스팅이 모든 타입 변환을 생성하지 않기 때문에(단순히 호출한 함수를 선택한다),  사용하는데 있어 퍼포먼스 패널티가 없다. 좋은 경험의 법칙은 가능한 곳에 함수 캐스팅을 사용해보고 변수 캐스팅은 분명한 타입 변환이 요구될 때만 사용하는 것이다.

Comments

VEX는 C++ 스타일의 주석을 사용한다 :

  • 한줄 주석은 //로 시행된다.
  • 자유 형태 주석은 /*로 시작하고 */로 끝난다.

Reserved Keywords

break, bsdf, char, color, const, continue, do, else, export, false, float, for, forpoints, foreach, gather, hpoint, if, illuminance, import, int, integer, matrix, matrix2, matrix3, normal, point, return, string, struct, true, typedef, union, vector, vector2, vector4, void, while

One thought on “VEX language reference

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s