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.
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.
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 } }
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)
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)
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.
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.
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.
More Info
HLSL Shader Reference in the Microsoft Direct X 9 SDK
Online
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!)
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.
NVidia FX Composer
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