Viz Artist User Guide

Version 5.0 | Published December 20, 2022 ©

Viz Engine Shader

This page contains information on the following topics:

Viz Engine Shaders are a novel way to create custom materials for the Viz Engine Renderer. Only basic knowledge of how to write OpenGL shaders is necessary to be able to integrate the material of your needs. Viz Engine provides multiple template shaders, so that only the most important parts of a material need to be implemented. The common and repetitive steps are taken care of the by the template itself.

With the use of Viz Engine shaders, designers can achieve outstanding effects. Viz Engine Shaders are executed purely on the GPU. They can be used to create photo realistic effects or you can use them as a backdrop on Videowall instead of utilizing Ultra HD clips.

Viz Engine Shaders can be developed either by using the Viz plug-in or within Viz Artist using the Shader Design Environment.

The following chapters shall give you a starting point on how to work with Viz Engine Shaders and inspire your creativity.

Introduction to Viz Engine Shaders

There are two types of Shaders available, Fragment shaders and Fragment and Vertex shaders. While fragment shaders modify pixel data only, Vertex shaders can additionally modify vertex (geometry) data. A typical Vertex shader is for example a bump mapping effect.

The following example will explain how to create a simple fragment shader with some exposed parameters:

Let's say you've found some nice twirl shader on sites like shadertoy.com. We will now explain step by step how to create a Viz Engine Shader out of it.

images/download/attachments/105105015/image2020-3-25_11-53-16.png

The original code for this shader looks like this:

Minimal Fragment Shader
#define PI 3.14159
 
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
float effectRadius = .5;
float effectAngle = 1. * PI;
vec2 center = iMouse.xy / iResolution.xy;
center = center == vec2(0., 0.) ? vec2(.5, .5) : center;
vec2 uv = fragCoord.xy / iResolution.xy - center;
float len = length(uv * vec2(iResolution.x / iResolution.y, 1.));
float angle = atan(uv.y, uv.x) + effectAngle * smoothstep(effectRadius, 0., len);
float radius = length(uv);
 
fragColor = texture(iChannel0, vec2(radius * cos(angle), radius * sin(angle)) + center);
}

Create a new scene and add a rectangle to it.

Next step is to switch to the Scripting Workspace. In the workspace, select +Add and Fragment Viz Engine Shader. A new Shader appears as Fragment Shader.

images/download/attachments/105105015/image2022-11-29_10-15-29.png

Drag the Shader to the container. the Shader Design Environment is activated. As we are creating a Fragment Shader only, only this tab gets activated. A Vertex Fragment Viz Engine Shader would activate both tabs, Fragment and Vertex Shader.

Now copy and paste the shader code into the Script Editor. As we need to link some properties between the Shader and Viz Engine, some adjustments are needed for our code. Viz Engine calls fragmentMain() on a Fragment shader, therefore we call the existing mainImage code from within this function.

Fragment Shader
#define iResolution vec2(1920,1080)
#define PI 3.14159265359
 
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
float effectRadius = .5;
float effectAngle = 1. * PI;
vec2 center = iMouse.xy / iResolution.xy;
center = center == vec2(0., 0.) ? vec2(.5, .5) : center;
vec2 uv = fragCoord.xy / iResolution.xy - center;
float len = length(uv * vec2(iResolution.x / iResolution.y, 1.));
float angle = atan(uv.y, uv.x) + effectAngle * smoothstep(effectRadius, 0., len);
float radius = length(uv);
 
fragColor = texture(iChannel0, vec2(radius * cos(angle), radius * sin(angle)) + center);
}
 
void fragmentMain()
{
vec4 fragColor = vec4(0);
vec2 fragCoord = viz_getTexCoord() * iResolution;
mainImage(fragColor, fragCoord);
vec3 col = fragColor.xyz;
viz_setFragment(vec4(col, 1.0));
}

Hitting the Compile and Run function still gives some errors. We need to replace the iMouse variable with a static variable. vec2(0.0,0.0) as we do not want to interact with the user.

Finally the texture, defined in the original code iChannel0, needs to be replaced by a function that provides a Viz Engine texture. Expose this as a property the user can change:

Fragment Shader
@registerParametersBegin
@registerParameterSampler2D(iChannel0, "Texture0")
@registerParametersEnd

This will override the iChannel0 with a userParameter. After a Compile and Run, we now have a property available to the user. Drag and drop a texture on it and you'll already see some effects:

images/download/attachments/105105015/image2022-11-29_10-18-7.png

Now if you change some parameters like the effectRadius or effectAngle and click on the Compile and Run button, the shader behaves differently.

float effectRadius = .5;
float effectAngle = 1. * PI;

It would be nice, if we can also expose those settings to the user. We extend our code so that we use more paramters to set our variables. Finally, to access the values of this parameters, the lines where those variables are used need to be slightly changed to read the actual values.

Our final code looks like this:

Fragment Shader
@registerParametersBegin
@registerParameterSampler2D(iChannel0, "Texture0")
@registerParameterFloat(effectAngle, "Angle", 0.5f, -5.f, 15.f)
@registerParameterFloat(effectRadius, "Radius", 0.5f, -5.f, 15.f)
@registerParameterVec2(myCenter, "Center", 0.0, 0.0)
@registerParametersEnd
 
#define iResolution vec2(1920,1080)
#define PI 3.14159265359
 
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
vec2 center = vec2(0.0,0.0) / iResolution.xy;
center = center == vec2(0., 0.) ? vec2(.5, .5) : center;
vec2 uv = fragCoord.xy / iResolution.xy - center;
float len = length(uv * vec2(iResolution.x / iResolution.y, 1.));
float angle = atan(uv.y, uv.x) + userParametersFS.effectAngle* PI * smoothstep(userParametersFS.effectRadius, 0., len);
float radius = length(uv);
 
fragColor = texture(iChannel0, vec2(radius * cos(angle), radius * sin(angle)) + center);
}
 
void fragmentMain()
{
vec4 fragColor = vec4(0);
vec2 fragCoord = viz_getTexCoord() * iResolution;
mainImage(fragColor, fragCoord);
vec3 col = fragColor.xyz;
viz_setFragment(vec4(col, 1.0));
}

The UI now has been extended to show these values:

images/download/thumbnails/105105015/image2020-4-3_8-28-22.png


Changing these values immediately changes the way how the shader affects our image. Instead of an image, you can also apply this effect to any Media Asset like Live Sources or Clip Surfaces. These values are also fully animatable.

images/download/attachments/105105015/image2020-3-25_12-39-28.png

Tip: Viz Engine Shaders can be saved into Graphic Hub. Drag and drop them from the Workspace window into the Graphic Hub Server view.

Properties for Viz Engine Shaders

images/download/attachments/105105015/image2020-4-3_8-33-57.png

Viz Engine Shaders can integrate into Viz Engine design workflows by exposing some parameters to the user. This enables certain built-in render features inside the Viz Engine Shader. These properties can be found in the Options tab.

Transparency is part of the Viz Engine Shaders User Interface:

images/download/thumbnails/105105015/image2020-4-3_8-35-26.png

Viz Engine Fragment Shader

The Viz Engine Fragment Shader allows it to write a fragment shader only, without the need to write a vertex shader. The vertex shader is provided by Viz Engine and provides the fragment shader API with all standard information available.

The main function for the Viz Engine Fragment Shader needs to be called fragmentMain. To set the color of a fragment, viz_setFragment needs to be called.

Minimal Fragment Shader
void fragmentMain()
{
viz_setFragment(vec4(1,0,0,1));
}

Fragment Shader API

The template shader provides an additional API to get access to the properties of Viz Engine, lights, geometry etc.

Geometry API Functions

Function Name

Description

viz_getPosition

Returns the current worldspace position as vec3.

viz_getPositionCS

Returns the current clipspace position as vec4.

viz_getNormal

Returns the current worldspace normal as vec3.

viz_getTangent

Returns the current worldspace tangent as vec3.

viz_getBinormal

Returns the current worldspace binormal as vec3.

viz_getTexCoord

Returns the texture coordinates as vec2.

viz_getColor

Returns the color as vec4.

viz_getGlyphAlpha

Returns the glyph alpha for razor text as float.

Environment Map API Functions

Function Name

Description

viz_getEnvironmentMapRotation

Returns the scenes environment map rotation as float.

viz_getEnvironmentMapIntensity

Returns the scenes environment map intensity as float.

Rendering Globals API Functions

Function Name

Description

viz_getAlpha

Returns the current alpha value as float.

viz_getRetraceCounter

Returns the current retrace counter value as uint.

viz_getTime

Returns the current time in seconds as double.

viz_getCameraPosition

Returns the worldspace position of the current camera as vec3.

viz_getViewDirection

Returns the normalized view vector as vec3.

Container Lights API Functions

Function Name

Description

Supported Lights

viz_getPointLightCount

Returns the number of pointlights as int.


viz_getPointLightIndex

Returns the global light index of a pointlight as int.


viz_getDirectionalLightCount

Returns the number of directional lights as int.


viz_getDirectionalLightIndex

Returns the global light index of a directional light as int.


viz_getSpotLightCount

Returns the number of spot lights as int.


viz_getSpotLightIndex

Returns the global light index of a spotlight as int.


viz_getAreaLightCount

Returns the number of area lights as int.


viz_getAreaLightIndex

Returns the global light index of an area light as int.


viz_getLightPosition

Returns the worldspace position of a light as vec3.

Point, Spot, Area

viz_getLightDirection

Returns the normalized worldspace direction of a light as vec3.

Directional, Spot, Area

viz_getLightUp

Returns the normalized worlspace up-vector of a light as vec3.

Area

viz_getLightRight

Returns the normalized right vector of a light as vec3.

Area

viz_getLightColor

Returns the color of a light as vec3.

All

viz_getLightIntensity

Returns the intensity scale factor of a light as float.

All

viz_getLightDiffuseIntensity

Returns the diffuse intensity scale factor of a light as float.

All

viz_getLightSpecularIntensity

Returns the specular intensity scale factor of a light as float.

All

viz_getLightRadius

Returns the radius of a light as float.

Point, Spot

viz_getLightInnerConeAngle

Returns the inner cone angle in radians of a light as float.

Spot

viz_getLightOuterConeAngle

Returns the outer cone angle in radians of a light as float.

Spot

viz_getLightWidth

Returns the width of a light as float.

Area

viz_getLightHeight

Returns the height of a light as float.

Area


To access light properties, a global light index is needed. So a loop over all available point lights would look like:

Light iteration example
int pointLightCount = viz_getPointLightCount();
for (int i=0; i<pointLightCount; ++i)
{
int lightIndex = viz_getPointLightIndex(i);
vec3 lightColor = viz_getLightColor(lightIndex);
}

Global Illumination FX API Functions

Function Name

Description

viz_getGlobalIlluminationIrradiance

Returns the irradiance color as vec3.

viz_getGlobalIlluminationAmbientOcclusion

Returns the ambient occlusion factor as float.

viz_getGlobalIlluminationBakeLight

Returns the color of the baked lights as vec3.

Viz Engine Vertex and Fragment Shader

The Viz Engine Vertex/Fragment Shader allows it to write both the vertex and the fragment shader. In addition to the fragment shader API from above, the vertex shader template gives access to geometry vertex data and allows to override vertex positions, normals, etc.

The main function for the Vertex Shader needs to be called vertexMain. Multiple vertex attributes are available to be set by the vertex shader via API functions, the most important one is viz_setVertex.

Minimal Vertex Shader
void vertexMain()
{
vec3 pos = viz_getVertex();
 viz_setVertex(pos);
}

Vertex Shader API

Geometry API Functions

Function Name

Description

viz_getVertex

Returns the current vertex as vec3.

viz_getNormal

Returns the current normal as vec3.

viz_getTangent

Returns the current tangent as vec3.

viz_getBinormal

Returns the current binormal as vec3.

viz_getTexCoord

Returns the current texture coordinate as vec2.

viz_getColor

Returns the current color as vec4.

viz_setVertex

Sets the current vertex as vec3.

viz_setNormal

Sets the current normal as vec3.

viz_setNormals

Sets the three normals (normal, tangent, binormal) as vec3's.

viz_setNormals

Sets the normal and tangent, binormal is calculated automatically as vec3's.

viz_setTexCoord

Sets the texture coordinates as vec2.

viz_setColor

Sets the color as vec4.

All viz_get functions return their values as they are provided by the geometry, they are not altered. All viz_set functions assume the values are passed in the same space, too. Afterwards, the values are multiplied by the geometry's world space matrix and passed to the fragment shader. The vertex position itself gets multiplied by the model-view-projection matrix and passed as gl_Position.

In the case of vertex skinning, the vertex and normals get the skinning transformation applied before being passed to the fragment shader and gl_Position.

Rendering Globals API Functions

Function Name

Description

viz_getAlpha

Returns the current alpha value as float.

viz_getRetraceCounter

Returns the current retrace counter value as uint.

viz_getTime

Returns the current time in seconds as double.

Environment Map API

Function Name

Description

viz_getEnvironmentMapRotation

Returns the scenes environment map rotation as float.

viz_getEnvironmentMapIntensity

Returns the scenes environment map intensity as float

Passing Values from Vertex to Fragment Shader

Passing data between different shader stages is also supported. In GLSL, out and in need to be used, but to ensure that the data passed by the user does not conflict with the data passed by the template shader, new keywords were added: varying_out and varying_in.

Viz GLSL Extension

Viz Keyword

Description

@varying_out(location)

Declares an out value at the given location. location must be a number starting from 0.

@varying_in(location)

Declares an in value at the given location. location must be a number starting from 0.

Example

Vertex Shader
@varying_out(0) vec4 vColor;
 
void vertexMain()
{
vColor = vec4(1,1,0,0);
}
Fragment Shader
@varying_in(0) vec4 vColor;
 
void fragmentMain()
{
viz_setFragment(vColor);
}

User Parameters

In GLSL, shader parameters are usually passed using uniforms or uniform buffers, textures most of the time as sampler2d. For a better Command Map and Artist integration and forward compatibility, new keywords were added, though. Each shader can have its own, but only one set of user parameters. All parameters need to be declared within a block that starts with @registerParametersBegin and end with @registerParametersEnd.

Viz GLSL Extensions

Viz Keyword

Description

Arguments

@registerParametersBegin

Marks the start of the user parameters block.


@registerParametersEnd

Marks the end of the user parameters block.


@registerParameterInt(paramInt, "Int Label", 1, -1, 1)

Register an int parameter.

name, label, default, min value, max value

@registerParameterFloat(paramFloat, "Float Label", 1.0, -1.0, 1.0)

Register a float parameter.

name, label, default, min value, max value

@registerParameterVec2(paramVec2, "Vec2 Label", -1.2, 2.2)

Register a vec2 parameter.

name, label, default x, default y

@registerParameterVec3(paramVec3, "Vec3 Label", 1.3, -2.3, 3.3)

Register a vec3 parameter.

name, label, default x, default y, default z

@registerParameterVec4(paramVec4, "Vec4 Label", 1.4, 2.4, -2.4, 3.4)

Register a vec4 parameter.

name, label, default x, default y, default z, default w

@registerParameterColor(paramColor, "Color Label", 0, 0, 0, 255)

Register a vec4 parameter exposed as a color.

name, label, default r, default g, default b, default a

@registerParameterSampler2D(textureA, "Color Texture")

Register a sampler2d parameter.

name, label

All parameters except sampler2d are managed by a single uniform buffer for each shader stage. To access them, the uniform buffer name inside the vertex shader is userParametersVS and in the fragment shader userParametersFS.

Examples

Vertex Shader with parameter block
@registerParametersBegin
@registerParameterInt(paramInt, "Int Label", 1, -1, 1)
@registerParameterFloat(paramFloat, "Float Label", 1.0, -1.0, 1.0)
@registerParameterVec2(paramVec2, "Vec2 Label", -1.2, 2.2)
@registerParameterVec3(paramVec3, "Vec3 Label", 1.3, -2.3, 3.3)
@registerParameterVec4(paramVec4, "Vec4 Label", 1.4, 2.4, -2.4, 3.4)
@registerParameterColor(paramColor, "Color Label", 0, 0, 0, 255)
@registerParametersEnd
 
void vertexMain()
{
int intValue = userParametersVS.paramInt;
float floatValue = userParametersVS.paramFloat;
vec2 vec2Value = userParametersVS.paramVec2;
vec3 vec3Value = userParametersVS.paramVec3;
vec4 vec4Value = userParametersVS.paramVec4;
vec4 colorValue = userParametersVS.paramColor;
 
viz_setColor(colorValue);
}
Fragment Shader with parameter block
@registerParametersBegin
@registerParameterFloat(intensity, "Intensity", 1.0, 0.0, 1.0)
@registerParameterSampler2D(inputTexture,"Texture Label")
@registerParametersEnd
 
void fragmentMain()
{
vec4 textureColor = texture(inputTexture, viz_getTexCoord());
vec4 vertexColor = viz_getColor();
vec4 finalColor = textureColor * vertexColor * userParametersFS.intensity;
viz_setFragment(finalColor);
}

Environment Map

It's possible to gain automatic access to a scenes global environment map by declaring a two dimensional texture sampler named EnvironmentMap or environmentMap.

@registerParameterSampler2D(EnvironmentMap, "Environment Map")

Built-in Features

All Viz Engine Shader templates have built-in features that can be enabled separately. Enabling a feature generates multiple variants of the shader and the best fitting one is selected to render. Keep in mind that the more features enabled, the more combinations of shaders need to be generated and compiled. This can drastically increase the load time of a scene and the performance impact of a material. Only the features that are really necessary should be enabled.

Clipping

Enables support for the scenes Clipper objects. The template shader takes care of discarding the elements that are clipped.

Note: This feature makes use of the discard keyword, which can have a negative impact on performance.

Global Illumination FX

Enables support for Global Illumination FX. The Global Illumination FX API functions should be used to retrieve the computed GI values.

Parameters and Samplers Naming Convention

The Global Illumination system needs material colors and textures to be able to generate realistic indirect lighting. Therefor parameters should be named according the following convention:

Name

Example

Description

AlbedoMap

@registerParameterSampler2D(AlbedoMap, "Albedo Texture")

GI takes the albedo color from this texture. Also called base color sometimes.

If no AlbedoMap is defined, it's assumed to be full white as in vec4(1,1,1,1)

AlbedoColor

@registerParameterColor(AlbedoColor, "Albedo Color", 255, 255, 255, 255)

GI takes the albedo color as a plain color. It's multiplied with the color from the texture.

If no AlbedoColor is defined, it's assumed to be full white as in vec4(1,1,1,1)

EmissiveMap

@registerParameterSampler2D(EmissiveMap, "Emissive Texture")

GI takes the emissive color from this texture, alpha value is ignored.

If no EmissiveMap is defined, it's assumed to be full black as in vec4(0,0,0,0)

EmissiveColor

@registerParameterColor(EmissiveColor, "Emissive Color", 0, 0, 0, 0)

GI takes the emissive color as a plain color and adds it to the color from the texture, alpha value is ignored.

If no EmissiveColor is defined, it's assumed to be full black as in vec4(0,0,0,0)

EmissiveIntensity

@registerParameterFloat(EmissiveIntensity, "Emissive Intensity", 1.f, 0.f, 100.f)

Scale factor on the sum of both emissive texture and color values.

If no EmissiveIntensity is defined, it's assumed to be 1.0

Example

Fragment shader with GI support
@registerParametersBegin
@registerParameterColor(AlbedoColor, "Albedo Color", 255, 255, 255, 255)
@registerParameterSampler2D(AlbedoMap, "Albedo Texture")
@registerParameterColor(EmissiveColor, "Emissive Color", 0, 0, 0, 0)
@registerParameterFloat(EmissiveIntensity, "Emissive Intensity", 1.f, 1.f, 100.f)
@registerParameterSampler2D(EmissiveMap, "Emissive Texture")
@registerParametersEnd
 
void fragmentMain()
{
vec4 albedoColor = texture(AlbedoMap, viz_getTexCoord()) * userParametersFS.AlbedoColor;
vec3 emissiveColor = (texture(EmissiveMap, viz_getTexCoord()).rgb + userParametersFS.EmissiveColor.rgb) * userParametersFS.EmissiveIntensity;
 
vec3 color = albedoColor.rgb + emissiveColor;
float alpha = albedoColor.a * viz_getAlpha();
 
color += viz_getGlobalIlluminationIrradiance(viz_getNormal(), albedoColor.rgb);
color *= viz_getGlobalIlluminationAmbientOcclusion();
 
viz_setFragment(vec4(color, alpha));
}

Razor Font Rendering

Enables support for Razor Font rendering. Use viz_getGlyphAlpha to get the alpha channel value for the font.

Example

Fragment Shader with Razor Font support
@registerParametersBegin
@registerParameterColor(textColor,"Text Color", 255, 255, 255, 255)
@registerParametersEnd
 
void fragmentMain()
{
float glyphAlpha = viz_getGlyphAlpha();
float alpha = viz_getAlpha();
 
vec4 textColor = userParametersFS.textColor;
textColor.a *= alpha;
textColor.a *= glyphAlpha;
 
viz_setFragment(textColor);
}

Skinning

Enables support for Vertex Skinning. There's nothing that needs to be done, the vertex shader template takes care of transforming the necessary vertex attributes.

Vertex Colors

Enables support for Vertex Colors. If Vertex Colors are enabled viz_getColor returns the vertex color, full white otherwise.