BS Contact Shader Support

Screenshot

Contact 6.2 supports programmable shaders. The node implementation follows the X3D Programmable Shaders Proposal.

Shaders are supported with the Contact Direct X9 renderer. The supported shader protocol is hlsl:, the cg: protocol is treated as hlsl. Supported shader file extensions are : vhl phl and hlsl.

Shaders are tiny programs written in a javascript / c like language, which are running natively on the graphics card.
Vertex Shaders are called for each vertex data tuple (position, normal, vertexColor, texture coord 0 .. n). They are outputting per vertex parameters which are linear interpolated across each pixel of each triangle of a mesh.
Likewise a Fragment Shader (or Pixel Shader in Direct X speak) gets executed on each pixel, the input is the interpolated set of parameters, the output is the final color to be passed on to the frame buffer.

Minimally the Vertex Shader needs to output the right screen position for a vertex, and the fragment shader a color value.

In addition to the proposal, Contact also supports the Direct X 9 FX file format. The fx script is specified in a VertexShader using the fx: protocol or the fx file extension. FX files may contain vertex and/or pixel shaders.

Example:

Shape {
			appearance ShaderAppearance {
				vertexShader  VertexShader 
				{
					url "HLSL/BumpReflectHLSL.fx"
					exposedField SFNode normalMap ImageTexture { url "HLSL_textures/Default_bump_normal.dds" }
					exposedField SFNode cubeMap ImageTexture { url "HLSL_textures/Default_reflection.dds" }
				}

				# fallback 
				material Material {
					ambientIntensity 0.416667
					diffuseColor 0.6 0.6 0.6
					specularColor 0.4 0.4 0.4
					shininess 0.2
				}}
				geometry  IndexedFaceSet {
				....
				}

Some benefit of FX files are : vertex and pixel shader can be combined in one file, parameters can be annotated with semantic meanings. Also FX allows to create procedural textures on shader creation time.

Contact parses the semantic string associated with shader parameters and automatically fills in known parameters semantic with state runtime parameters. Most of the parameters of the NVidia FX-Composer / Direct X9 Effectedit example are supported. Here is the list of parameters.

The major drawback of FX files is that they are currently Direct X 9 only, and no emulation for Open GL is currently provided. Some tools like Discreet 3D Studio Max 6 are supporting FX files.

Required hardware

The latest Direct X 9 class hardware supports more advanced shader models, older hardware (Direct X 8 Level) much simpler profiles named vs_1_1 ps_1_3 / ps_1_4 with more limitations in the amount of instructions and capabilities. Contact tries to compile the shader script against the supported hardware level, but this compilation may fail. The author can give fallback less complex shader scripts. In FX fallback techniques can be provided.

 

Nodes

The following nodes are providing the programmable Shader support

ShaderAppearance - replacement for the Appearance node

VertexShader - for setting the per vertex shader script

FragmentShader - for setting the per fragment (pixel) shader script

For the Node specification see the proposal:

Example: the VertexShader computes the basic lighting model, the FragmentShader applies a 2D texture:
ShaderAppearance {
				vertexShader  DEF VertexShader1 VertexShader 
				{
					field SFVec3f  lightDir	 0.577 -0.577 0.577
					# any needed parameters can be mapped to fields here 
					url "hlsl:	

					// light intensity
					float4 I_a : LIGHTAMBIENT  = { 0.1f, 0.1f, 0.1f, 1.0f };    // ambient
					float4 I_d : LIGHTDIFFUSE  = { 1.0f, 1.0f, 1.0f, 1.0f };    // diffuse
					float4 I_s : LIGHTSPECULAR = { 1.0f, 1.0f, 1.0f, 1.0f };    // specular

					float3 lightDir : LIGHTDIRECTION = {0.577, -0.577, 0.577};

					// material reflectivity
					float4 k_a : MATERIALAMBIENT = { 1.0f, 1.0f, 1.0f, 1.0f };    // ambient
					float4 k_d : MATERIALDIFFUSE = { 1.0f, 1.0f, 1.0f, 1.0f };    // diffuse
					float4 k_s : MATERIALSPECULAR= { 0.0f, 0.0f, 1.0f, 1.0f };    // specular
					float  n   : MATERIALPOWER = 32.0f;                           // power

					// transformations

					// Contact built-ins					 
					float4x4 modelViewProjectionT :WORLDVIEWPROJECTION;
					float4x4 modelViewT :WORLDVIEW;
					float4x4 modelT :WORLD;

					struct VS_OUTPUT
					{
    					float4 Pos  : POSITION;
    					float4 Diff : COLOR0;
    					float4 Spec : COLOR1;
    					float2 Tex  : TEXCOORD0;
					};

					VS_OUTPUT main (
    					float3 Pos  : POSITION, 
	    				float3 Norm : NORMAL, 
    					float2 Tex  : TEXCOORD0
					)
					{
    				VS_OUTPUT Out = (VS_OUTPUT)0;

    				Out.Pos  = mul(float4(Pos, 1),modelViewProjectionT);   // position (projected)

    				float3 L = -lightDir;
    				float3 P = mul(float4(Pos, 1), (float4x3)modelViewT);  // position (view space)
    				float3 N = normalize(mul(Norm, (float3x3)modelViewT)); // normal (view space)

    				float3 R = normalize(2 * dot(N, L) * N - L);          // reflection vector (view space)
    				float3 V = -normalize(P);                             // view direction (view space)

    				Out.Diff = I_a * k_a + I_d * k_d * max(0.0f, dot(N, L)); // diffuse + ambient
    				Out.Spec = I_s * k_s * pow(max(0, dot(R, V)), n/4);   // specular
    				Out.Tex  = Tex;                          
	                
    				return Out;
					}
					"
				}
				fragmentShader DEF FragmentShader1 FragmentShader 
				{
					field SFNode texture0 ImageTexture {
                    	url [
                        	"../textures/maps/chromic.jpg"
                    	]
                	}
					url "hlsl:
					const sampler2D texture0; 

					float4  main(
					float4 Position : POSITION,
					float4 Diffuse  : COLOR0,
    				float4 Specular : COLOR1,
    				float2 Tex  : TEXCOORD0
					) : COLOR
					{
					return Diffuse*(0.5+0.5*tex2D(texture0,Tex))+Specular;
					}
					"
				}

				# fallback 
                texture ImageTexture {
                    url [
                        "../textures/maps/chromic.jpg"
                    ]
                }
			
                material Material {
                    ambientIntensity 0.416667
                    diffuseColor 0.6 0.6 0.6
                    specularColor 0.8 0.8 1
                    shininess 0.4
                }
			}

Examples:

If not done yet Please activate the Contact Direct X 9 Renderer using RightMouse Click->Settings->Renderer->DirectX9

Venus Simple basic lighting model computed in vertex shader with one directional light, fragment shader sets color.

Venus per pixel lighting model computed in fragment shader with one directional light and a texture (requires ps_2_0)

Venus glow an animated offset model is computed, transparency depends on glow

Venus_shader_marble marble procedural texture (based on a big 3D noise texture) and per pixel lighting. (Adapted from ATI Rendermonkey)

FX Examples:

The following examples are using the Direct X 9 effect file format in the VertexShader.

Adapted NVIDIA FX Composer examples:

Venus_fx_plastic per pixel lighting. See the FX file for different per pixel lightning effects PlasticDX9.fx

Venus_fx_bumpplastic per pixel bump mapping. Tangents and Binormals computed via TextureCoordGen node. FX file BumpPlastic.fx

Venus_fx_bumpreflect per pixel bump mapping with cubic environment cube map. Tangents and Binormals computed via TextureCoordGen node. FX file BumpReflect.fx

moscow_lava procedural lava texture. FX file moscow_lava.fx

ocean procedural ocean, waves computed in VertexShader, bump mapping. FX file ocean.fx

venus_shader_noise perlin noise computed in vertex shader and used for offset.

glass environment mapping. FX file glass.fx

BumpReflect environment bump with reflection. FX file BumpReflectHLSL.fx

BumpReflectNOPS environment bump mapping using fixed function pipeline and DOTPRODUCT3. FX file BumpReflectHLSL-NOPS.fx

Only minimal changes need to be done to fx files, the vertex format has been changed to use TEXCOORD channels for Tangents and Binormals, in Plastic the sign of the normal has been changed. It is important to specify the used textures as SFNode ImageTexture parameters in the shader interface.

Examples adapted from the DX9 SDK:

Venus_fx basic example using an FX effect file in the VertexShader. The DX9 Example default.fx computes basic lighting. (Works with older ps_1_1 cards)

Venus_fx_wood FX shader example using a procedural wood texture. A 2D Ring and a 3D Noise textures are created procedurally in the fx file, from the DX9 SDK wood.fx example.

Other examples:

Venus_fx_fur multipath fur effect. fur.fx computes 15 layers of transparent offsets using a VertexShader. (Works with ps_1_X cards)

Fur fur on a sphere

venus_shader_multi several shaders in once scene

Video Effects

video-laplace laplace filter on video trailer. (Normal video)

video-blur 4 tap blurring filter and negative interpolated over time.

video-fur similar to venus-fur layers of movie with transparency for black parts computed from the movie in a pixelshader. (Works with ps_1_3 cards)

Other tips

Some techniques like Per pixel Bump mapping are using Tangents and Binormals per Vertex vectors.

This can be generated using

MultiTextureCoordinate {
		coord  [
			TextureCoordinate {point [ ... ] }
			TextureCoordGen	{ mode "TANGENT" parameter [ 0 2 ] }
			]
		}	

This will compute Tangent vectors based on Texture coordinate channel 0, binormal vectors will be placed in texture coordinate channel 2 of the IFS. Another way is to directly set a VRML Normal node with pre computed Tangent vectors as a TextureCoordinate. Likewise using a Coordinate node to specify 3 component texture coordinates is supported.

Contact 6.2 also implements the SFVec4f field type for match with float4/half4 texture parameters and the SFMatrix field type.

The supported shader profiles can be queried from vrmlscript via:

print('vertexShaderProfile:'+Browser.getOption('vertexShaderProfile')); 
print('fragmentShaderProfile:'+Browser.getOption('fragmentShaderProfile'));  
There is currently no cross language standard for associating per shader parameters with a specific meaning. The proposal defines some strings. In hlsl a semantic value can be associated with parameters.

 

Writing Shaders for non DX9 hardware is possible but very tricky, usually Texture lookups are used instead computations like normalize. See papers / examples on the ATI and NVidia developer sites for tips and examples. (Often in Shader assembly language).

If using the same or similar procedural textures across several shaders resources it could be better to DEF & USE the texture resources. Examples could be normalization cube maps, noise volume maps. The fx file may generate large 3D noise textures, which can be slow. A common 3D noise DDS volume could be shared accross shaders.

If a Shader parameter need not to be tweaked from VRML it can be omitted from the Shader field interface, which should results in less run-time overhead. Even further the preprocessor can be used (DEFINE ) or parameters can be made const, for possible Compiler optimizations.

A good debugging technique is to early exit from a pixel shader using a partly evaluated result or some (normal) vectors for visual debugging.

The Direct X Shader compiler optimizes scripts, ie. the Contact Warning : "Shader parameter field 'XXX' not found in shader : might occur also if the compiler has optimized way parameters because not used in a shader.

Converting (FX) Composer Files:

If the Vertex shader requires Tangent / Binormal vertex attributes replace the declaration with TEXCOORD1 TEXCOORD 2 and add MultiTextureCoordinate { coord [ TextureCoordinate { ** existing ones *** } TextureCoordGen { mode "TANGENT" parameter [ 0 2 ] } ] } to the IndexedFaceSet.

All filename texture references need to be added as SFNode parameters to the Shader interface.

For compatibility with ATI cards the shader profiles in the FX file can be lowerd if applicable from the Geforce FX supported ps_2_a and vs_2_a to ps_2_0 and vs_2_0.

 

 

Parameter mapping:

There is currently no cross language standard for associating per shader parameters with a specific meaning. The proposal defines some strings. In FX hlsl a semantic value can be associated with parameters as a string, but unfortunately this string is not avaible from the D3DX Shader runtime. Therefore in extension to the X3D proposed Shader parameter keywords strings Contact uses the following state parameter values :

Variable name Data type Description Comments
model

float4x4

the matrix transforming from local to global coordinates (named WORLDMATRIX in the DX world, modelMatrix in the Open GL world) transforms vertices from their model position to their position in world space (i.e. after effect of all Transform nodes has beed applied).
view   the viewing matrix transforming from global (world) to view relative coordinates  
projection   the projection matrix transforming from viewing relative to clip space and includes the projective part.  
modelView   concatenation of model and view transforms vertices from their model position to their position in view space (i.e. after effect of all Transform nodes and current viewpoint has beed applied).
modelViewProjection   concatenation of model, view and projection transforms vertices from their model position to their final position in clip space
Suffixes :      
***I   Inverse of Matrix  
***T   Transpose of Matrix  
***IT   Inverse transpose of matrix  
       
Vectors float3
float4
   
viewPosition   Position of the viewer in world coordinates
viewPositionLocal   Position of the viewer in local coordinates
viewTarget   Target position of camera  
viewUp   up direction vector (normalized vector)
viewDirection   view direction vector  
viewRight   right pointing vector  
       
viewFovY float field of view in Radians  
viewZRange float2 / float4 znear, zfar clipping plane  
CURRENTPASS float the current pass index of an FX effect 0 for first pass
       

 

Matrices are normally passed in the transposed form because that fits the layout of the intrinsic mul(vector,matrix) multiplication macros. In the examples the parameter name modelViewProjectionT is used to transform a vertex from model space to clip space ("screen"). The transposed modelViewProjection matrix is passed by Contact. In the cg examples using the intrinsic mul(matrix,vector) the standard non-transposed matrix is passed.

The paramName paramType in the Shader Node can be used to remap the semantic of parameters

E.g.

VertexShader
				{

					paramName
					[
						"view_proj_matrix",
						"view_position",
					]
					paramType
					[
						"WVPMATRIX",
						"VIEWPOSITION",
					]
}

 This associates the meaning WVPMATRIX with the shader parameter view_proj_matrix.

 

Caveats:

Using VertexShaders means the author is responsible for doing Lighting (Lights & Material, vertex colors ), Transform, TextureTransform and TextureCoordGen.
Using FragmentShaders means the author is responsible for Coloring, Texturing and MultiTexture. Even worse on some type of typical hardware shaders might run slower than the fixed function pipeline.

The ShaderApperance node is allowing fallback implementation using the material, texture and textureTransform fields if a shader fails or is not present.

Parameters not really needed to be tweakable at runtime can be omitted from the Shader nodes field declaration list. In addition they can be replaced inline or made const static in-order to minimize runtime shader parameter setup. For NVidia Geforce FX class hardware study NVidia whitepapers and example to optimize shaders (e.g. using the half data type instead of float) to tweak performance.

Resources:

More Info

HLSL Shader Reference in the Microsoft Direct X 9 SDK
Online

Web3d X3D Shaders Group

 

Books

Shader X2, Wolfgang Engel

Useful tools

 

ATI Rendermonkey - a GUI tool for editing, previewing effects ( recommended)

Goncalo Nuno M. de Carvalho has written a C++ tool and an xslt transform transforming RenderMonkey rfx XML files to X3D.

NVidia FX Composer Shader tool using FX files directly ( recommended). Contact supports most of the FX parameter semantic convention. Porting of FX files to Contact requires minimum effort.

Shaderworks - a great nice GUI tool for creating DX FX effects, but currently in early alpha state (anyway recommended!)

Maya

NVidia tools for Maya

cg Shaders org - Experts exchange on CG shaders, example shaders

ATI Ahsli (Advanced Shading Language Interface ) - a tool for converting Renderman shaders to FX / HLSL/ASM, good for studying shader examples.

Microsoft Direct X 9 SDK - SDK Documentation contains HLSL/ASM references and related information

Discreet 3D Studio Max 6 has some FX support.

RT/Zen RT/shader a new Shader editor based on wiring building blocks writing fx files.

 

 

Shader parameter semantics used by different Tools

NVidia FX Composer

List of parameters

RT/Shader

float4x4 projTM : WorldViewProjection;
float4x4 worldTM : World;
float4 eyePos : WorldEyePosition;

 

ATI Render Monkey:

Render Monkey is using the following predefined variables:

See RmPredefinedVariables.txt in the RenderMonkey installation directory

"time_0_X" "RmFloatVariable"
"cos_time_0_X" "RmFloatVariable"
"sin_time_0_X" "RmFloatVariable"
"tan_time_0_X" "RmFloatVariable"
"time_cycle_period" "RmFloatVariable"
"time_0_1" "RmFloatVariable"
"time_0_2PI" "RmFloatVariable"
"cos_time_0_2PI" "RmFloatVariable"
"sin_time_0_2PI" "RmFloatVariable"
"tan_time_0_2PI" "RmFloatVariable"
"viewport_width" "RmFloatVariable"
"viewport_height" "RmFloatVariable"
"viewport_inv_width" "RmFloatVariable"
"viewport_inv_height" "RmFloatVariable"
"random_fraction_1" "RmFloatVariable"
"random_fraction_2" "RmFloatVariable"
"random_fraction_3" "RmFloatVariable"
"random_fraction_4" "RmFloatVariable"

"view_direction" "RmVectorVariable"
"view_position" "RmVectorVariable"

"view_proj_matrix" "RmMatrixVariable"
"view_matrix" "RmMatrixVariable"
"inv_view_matrix" "RmMatrixVariable"
"proj_matrix" "RmMatrixVariable"
"world_view_proj_matrix" "RmMatrixVariable"

 

Microsoft Direct X 9 SDK Sample EffectEdit

The following semantics are supported in fx files, semantics in red are not supported. Matrices are passed transposed.

Matrix parameters:

Parameters with the WORLD semantic will contain the world matrix
Parameters with the VIEW semantic will contain the view matrix
Parameters with the PROJECTION semantic will contain the projection matrix
Parameters with the WORLDVIEW semantic will contain the world*view matrix
Parameters with the VIEWPROJECTION semantic will contain the view*projection
matrix

Parameters with the WORLDVIEWPROJECTION semantic will contain the
world*view*projection matrix

For sampler parameters:
Parameters with the NAME annotation will cause a texture with the given
name to be loaded - not recommeded, an absolute path is used, no HTTP download.
Parameters with the FUNCTION annotation will cause a procedural texture
with the given name to be loaded and used to initialize the texture
Parameters with the TARGET annotation will cause the procedural texture
to use the specified instruction set (Default is "tx_1_0")
Parameters with the WIDTH annotation will cause the texture to have the
specified width
Parameters with the HEIGHT annotation will cause the texture to have the
specified height


An integer parameter named "BCLR" will be used to define the background
color of the scene
A string parameter named "BIMG" will be used to define a background image
for the scene
A string parameter named "XFile" will be used to load an XFile containing
the object to be rendered
A float parameter with the TIME semantic will contain the app time, in seconds

A vector parameter with the CAMERAPOSITION semantic will contain the
camera position, in world space

For example, loading an .fx file with:
float4x4 MyWorld : WORLD;
would tell that the "MyWorld" parameter is the world matrix.

Vector parameters:

materialambient materialdiffuse materialspecular meshradius

Scalar parameters:

materialpower time

 


© 2003 - 2004 Bitmanagement Software - All rights reserved.