User Tools

Site Tools


Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
matsys:cmat_manual [2005-10-22 15:08]
Carsten Revised the Keywords Reference section
matsys:cmat_manual [2013-01-07 12:07] (current)
Line 1: Line 1:
 ====== The Materials (cmat files) Manual ====== ====== The Materials (cmat files) Manual ======
  
-Ca3DE materials are defined in //material script files//, which in turn are simple ASCII text files with file name suffix ''​.cmat''​. This page describes how such "cmat scripts"​ can be written, their syntax and semantics.+Cafu materials are defined in //material script files//, which in turn are simple ASCII text files with file name suffix ''​.cmat''​. This page describes how such "cmat scripts"​ can be written, their syntax and semantics.
  
  
 ====== Overview ====== ====== Overview ======
  
-First of all, here is a simple example for a material definition script. It was taken from the ''​Ca3D-Engine/​Games/​DeathMatch/​Materials/​Kai.cmat''​ file, which also contains several other, very similar material definitions:​+First of all, here is a simple example for a material definition script. It was taken from the ''​Cafu-9.06/​Games/​DeathMatch/​Materials/​Kai.cmat''​ file, which also contains several other, very similar material definitions:​
 <​code>​ <​code>​
     Textures/​Kai/​3r_metpan01 ​       // Material definitions start with the material name.     Textures/​Kai/​3r_metpan01 ​       // Material definitions start with the material name.
Line 21: Line 21:
   * All statements in such files are //​case-sensitive//​. That means that ''​text''​ and ''​Text''​ are //not// the same. This is also true for filenames, like the ''​Textures/​Kai/​3r_metpan01_diff.png''​ filename above, because some operating systems like Linux have a case-sensitive file-system.   * All statements in such files are //​case-sensitive//​. That means that ''​text''​ and ''​Text''​ are //not// the same. This is also true for filenames, like the ''​Textures/​Kai/​3r_metpan01_diff.png''​ filename above, because some operating systems like Linux have a case-sensitive file-system.
   * C++ style comments are allowed in material scripts: ​ ''​%%//​%% This is a comment.''​   * C++ style comments are allowed in material scripts: ​ ''​%%//​%% This is a comment.''​
-  * The cmat files for MOD "​MyMOD"​ are all stored in the ''​Ca3D-Engine/​Games/​MyMOD/​Materials/''​ directory and its subdirectories. This is necessary because the Ca3D-Engine ​automatically scans this directory for material scripts whenever MOD "​MyMOD"​ is run.+  * The cmat files for MOD "​MyMOD"​ are all stored in the ''​Cafu-9.06/​Games/​MyMOD/​Materials/''​ directory and its subdirectories. This is necessary because the Cafu engine ​automatically scans this directory for material scripts whenever MOD "​MyMOD"​ is run.
   * Tokens in cmat files are separated by white-space and these individual characters: ''​( { [ ] } ) ,''​   * Tokens in cmat files are separated by white-space and these individual characters: ''​( { [ ] } ) ,''​
   * Quoted tokens are recognized. That is, everything between two ''​%%"​..."​%%''​ is considered as one statement, even if white-space or one of the above characters is inside it. That means, if for example you //really// want to have a material name like ''​my(new and cool)material'',​ then you have to enclose it in quotation marks like this: ''​%%"​my(new and cool)material"​%%''​ in order to account for both the white-space and the brackets. Using quotation marks is not recommended,​ though! They'​re mostly useful if somebody created textures with weird file names like for example ''​%%"​{_SomeFile.bmp"​%%''​. Write ''​MyNewAndCoolMaterial''​ or ''​My/​New/​And/​Cool/​Material''​ or something similar for your material names instead.   * Quoted tokens are recognized. That is, everything between two ''​%%"​..."​%%''​ is considered as one statement, even if white-space or one of the above characters is inside it. That means, if for example you //really// want to have a material name like ''​my(new and cool)material'',​ then you have to enclose it in quotation marks like this: ''​%%"​my(new and cool)material"​%%''​ in order to account for both the white-space and the brackets. Using quotation marks is not recommended,​ though! They'​re mostly useful if somebody created textures with weird file names like for example ''​%%"​{_SomeFile.bmp"​%%''​. Write ''​MyNewAndCoolMaterial''​ or ''​My/​New/​And/​Cool/​Material''​ or something similar for your material names instead.
  
 Material definitions always start with the **material name**. In the example above, that's ''​Textures/​Kai/​3r_metpan01''​. You can name materials almost anything you like. If you want to use white-space,​ commas or brackets in their name, you'll have to put the name into quotation marks as mentioned above. However, it is important that the name is //unique//. If the same material name appears again in any other cmat file of the same MOD, the engine will use only the first occurance, so the chances are 50:50 that your material wins over the other. Material definitions always start with the **material name**. In the example above, that's ''​Textures/​Kai/​3r_metpan01''​. You can name materials almost anything you like. If you want to use white-space,​ commas or brackets in their name, you'll have to put the name into quotation marks as mentioned above. However, it is important that the name is //unique//. If the same material name appears again in any other cmat file of the same MOD, the engine will use only the first occurance, so the chances are 50:50 that your material wins over the other.
-Most materials that come with Ca3DE have a filename that roughly resembles the name of its texture image files. That is often a helpful hint for conveniently working with the material, but by no means a requirement.+Most materials that come with Cafu have a filename that roughly resembles the name of its texture image files. That is often a helpful hint for conveniently working with the material, but by no means a requirement.
  
 The **body** of the material definition is enclosed in a pair of ''​{ ... }''​. The **body** of the material definition is enclosed in a pair of ''​{ ... }''​.
 In many cases, it will only contain a few texture map specification statements like in the example above. In many cases, it will only contain a few texture map specification statements like in the example above.
  
- 
-====== Texture Map Specifications ====== 
- 
-The simplest form of a material definition is to only specify the texture map images that compose the material. 
-The previous example was an example for such a simple definition. 
- 
-A texture map specification starts with a keyword (e.g. ''​diffusemap''​) and is followed by a "map composition"​. 
- 
-Map compositions are normally just the path plus file name of a texture image relative to the MOD directory, like for example ''​Textures/​Kai/​3r_metpan01_diff.png''​. However, map compositions can also be more complex constructs as explained in the next section [[matsys::​cmat_manual#​map_compositions|Map Compositions]]. 
- 
-The initial keyword (''​diffusemap''​ etc.) defines how the texture image is used in dynamic lighting computations during rendering. This is very similar to Doom3 materials, and both Ca3DE and Doom3 implement in this regard a form of the //Phong lighting model//. 
- 
-Here comes a list of all available keywords for texture map specifications,​ along with a short description of their default meaning. (The default is dynamic Phong lighting, which however can be overridden, as explained at [[matsys::​cmat_Manual#​Shader_Specifications|Shader Specifications]].) 
- 
-  * **''​diffusemap''​** The texture map image that defines the diffuse color (or diffuse reflectivity) of the material. The alpha channel of the diffuse-map specifies the translucency of the material. 
- 
-  * **''​normalmap''​** The texture map image that specifies the color-encoded normal-map of the materials surface. The normal vectors must be specified in tangent space, range compressed (-1 to 1 maps to 0 to 1), and the y-axis points top-down. Note that heightmaps can be converted into normal-maps as described in section [[matsys::​cmat_Manual#​Map_Compositions|Map Compositions]] below. 
- 
-  * **''​specularmap''​** The image for the materials specular highlights. 
- 
-  * **''​lumamap''​** This texture map image defines the luminance for this material. Note that the light emittance that is defined here is local only (as is a general property of the Phong lighting model). It is not cast onto other surfaces. 
- 
-  * **''​lightmap''​** This materials lightmap image. This image is normally computed and provided by the 3D engine or the program with which you use the material. Although you can provide texture map file names as for the above keyword, that rarely ever makes sense. Normally, simply specify the special lightmap ''​$lightmap''​ in combination with the ''​lightmap''​ keyword in order to use whatever lightmap the 3D engine provides for this material. This is demonstrated in the preceding example. 
- 
-  * **''​shlmap''​** The image that contains color-encoded coefficients for //Spherical Harmonic Lighting// for this material. As for lightmaps, you may specify arbitrary texture map file names with this keyword, but normally just use ''​$shlmap''​ in order to let the engine supply the proper SHL map. 
- 
-  * **''​cubeMap''​** A six-sided cube-map image that is used e.g. for environmental mapping. Normally, cube-map specifications are per default //​ignored//,​ because they are not regularly used with Phong lighting. Instead, they are specially activated as described in section [[matsys::​cmat_Manual#​Shader_Specifications|Shader Specifications]]. As a single cube-map is actually composed of six individual images, a special convention for its file name is employed: A ''​%%'#'​%%''​ character in the file name is automatically replaced with the six possible cube-map suffixes _px, _nx, _py, _ny, _pz and _nz. For example, consider this material definition from the ''​Ca3D-Engine/​Games/​DeathMatch/​Materials/​SkyDomes.cmat''​ file: <​code>​ 
-    Textures/​SkyDomes/​PK_BrightDay2 
-    { 
-        AmbientShader A_SkyDome 
-        LightShader ​  ​none ​     // == noDynLight 
- 
-        // The '#'​ in the next line is auto-replaced with the relevant suffixes (_px, _ny, ...). 
-        cubeMap Textures/​SkyDomes/​PK_BrightDay2#​.png,​ wrapS clampToEdge,​ wrapT clampToEdge 
- 
-        // ... 
-    } 
-</​code>​ This example has keywords and elements that will be explained further below, but for now observe that the file name that is assigned to the cube-map is ''​Textures/​SkyDomes/​PK_BrightDay2#​.png''​. When the Material System loads the six individual images from disk, it will therefore load them from the files ''​Textures/​SkyDomes/​PK_BrightDay2_px.png'',​ ''​Textures/​SkyDomes/​PK_BrightDay2_nx.png'',​ ''​Textures/​SkyDomes/​PK_BrightDay2_py.png'',​ and so on. 
- 
-  * **''​cubeMap2''​** This is like the above ''​cubeMap''​ keyword. It allows you to specify a second cube-map for special-purpose shaders that require two cube-maps. This keyword too is normally ignored unless a shader is specified that makes use of it. See [[matsys::​cmat_Manual#​Shader_Specifications|Shader Specifications]] for more details. 
- 
-You can specify arbitrary combinations of these keywords in one material, as only the ''​diffusemap''​ keyword is mandatory. 
-However, if you use the same keyword more than once, only the last occurrence is considered. The order of the keywords occurrences is not relevant. 
- 
-===== Map Compositions ===== 
- 
-Texture map image specifications with the above keywords can not only be simple file names, but also by more powerful **Map Compositions**. A map composition is a description of how a //single// texture map image is composited from several source images on disk. 
-Here is an example for a simple material whose normal-map is defined by a complex map composition:​ 
-<​code>​ 
-    Textures/​Kai/​barrel_rst 
-    { 
-        diffusemap Textures/​Kai/​barrel_rst_diff.png 
-        normalmap ​ combineNMs(MyNm1.png,​ hm2nm(add(MyHm2.jpg,​ MyHm3.tga))) 
-        lightmap ​  ​$lightmap 
-    } 
-</​code>​ 
-(This example is overly complex for demonstration purposes, and not really meaningful. Real-life examples are normally much simpler.) 
- 
-The expressions that are valid to define a map composition are defined as follows. 
-Please note that the //arbitrary nesting// of expressions is expressly permitted, yielding great freedom for artists. 
- 
-  * **''​filename''​** This is the most simple expression: a path plus a filename, as e.g. ''​Textures/​Kai/​barrel_rst_diff.png''​ in the above example for the ''​diffusemap''​. The path is relative to the directory of the MOD for which this material script was written. Supported file extensions include png, tga, jpg and bmp. 
- 
-  * **''​add(e1,​ e2)''​** This expression adds the colors of ''​e1''​ and ''​e2'',​ where ''​e1''​ and ''​e2''​ can be arbitrary sub-expressions. The resulting RGBA values are clamped to 1.0. 
- 
-  * **''​mul(e1,​ e2)''​** This expression multiplies/​modulates/​filters the colors of ''​e1''​ and ''​e2''​. 
- 
-  * **''​combineNMs(e1,​ e2)''​** Treats the colors of ''​e1''​ and ''​e2''​ as color-compressed normal vectors, and combines or "​adds"​ them in a mathematically correct fashion. (This it //not// the same as the ''​add(...)''​ operation.) 
- 
-  * **''​hm2nm(e1,​ scale)''​** Assumes that ''​e1''​ is a gray-scale heightmap and converts it into a normal-map. The relative height of the heightmap is scaled by factor ''​scale''​ in order to weaken or pronounce the resulting effect. Values between 1.0 and 10.0 are normal use, but numbers greater then 10.0, less then 1.0, or even negative numbers are allowed, too. 
- 
-  * **''​flipNMyAxis(e1)''​** Considers the colors of ''​e1''​ as color compressed normal-vectors,​ and flips their y-component. This is useful for normal-maps that have their y-component pointing into the wrong direction. Such normal-maps occurred in the early days of dynamic lighting or were created for other programs than Ca3DE. This function is for fixing such cases, and should rarely be needed. 
- 
-  * **''​renormalize(e1)''​** Considers the colors of ''​e1''​ as color compressed normal-vectors,​ and renormalizes them (scales them to unit length). This is mostly useful for testing and debugging. 
- 
-  * **''​blue2alpha(e1)''​** This function is for use with old diffuse-maps. It replaces the alpha channel of ''​e1''​ with value 0.0 (transparent) if the RGB color at this pixel is pure blue (0.0, 0.0, 1.0), and 1.0 (opaque) otherwise. Moreover, pure blue pixels are replaced with the average pixel color of the non-blue pixels in order to account for texture filtering. 
- 
-  * **''​(automatic scaling)''​** Whenever you employ one of the above expressions to combine the results of two expressions ''​e1''​ and ''​e2''​ that have different lateral dimensions, ''​e2''​ is automatically scaled to match the size of ''​e1''​. 
- 
-You can apply map composition expressions to //all// above mentioned texture map specification keywords, 
-i.e. they work with ''​diffusemap'',​ ''​normalmap'',​ ''​specularmap'',​ ''​cubemap'',​ etc. 
- 
-Technically,​ a map composition is completed before the Ca3D-Engine or the graphics board see them. 
-In other words, the engine or the 3D hardware never see the individual images, only the composite result. 
-//​Everything that is done by these composition steps could also be pre-worked by the artist in an image processing software. There would be **no** difference for the engine, the hardware, or in the resource (memory) consumption.//​ 
-Note that this feature has nothing to do with dynamic lighting or how a texture map image is combined 
-with images of other texture map specification keywords! 
- 
-Finally, you can specify several comma-separated options for the map composition:​ 
-  * **''​minFilter''​** This controls MipMap usage and the filter that is used for texture minification. While the default setting usually looks best and also yields the best performance on modern graphics hardware, sometimes it is desireable to turn filtering off and accept some aliasing, as for example for font textures. The ''​minFilter''​ keyword must be followed by one of the filter methods 
-    * **''​nearest''​** or **''​point''​** 
-    * **''​linear''​** or **''​bilinear''​** 
-    * **''​nearest_mipmap_nearest''​** 
-    * **''​nearest_mipmap_linear''​** 
-    * **''​linear_mipmap_nearest''​** 
-    * **''​linear_mipmap_linear''​** or **''​trilinear''​** (This is the default.) 
- 
-  * **''​magFilter''​** This controls the filter that is used for texture magnification and must be followed by one of 
-    * **''​nearest''​** or **''​point''​** (There is almost never a reason to use this, except for very rare and special purposes, like some kinds of debugging.) 
-    * **''​linear''​** or **''​bilinear''​** (This is the default and gives best results.) 
- 
-  * **''​wrapS''​** This controls horizontal texture coordinate wrapping and must be followed by one of 
-    * **''​repeat''​** for repeating the texture in horizontal direction. This is the default. 
-    * **''​clamp''​** for clamping the texture in horizontal direction, taking the border color into account. As the Ca3DE MatSys never uses or sets the border color, using ''​clamp''​ is rarely ever useful. 
-    * **''​clampToEdge''​** for clamping the texture in horizontal direction to its edge color. Often useful with cube-map images. 
- 
-  * **''​wrapT''​** This controls vertical texture coordinate wrapping and must be followed by one of 
-    * **''​repeat''​** for repeating the texture in vertical direction. This is the default. 
-    * **''​clamp''​** for clamping the texture in vertical direction, taking the border color into account. As the Ca3DE MatSys never uses or sets the border color, using ''​clamp''​ is rarely ever useful. 
-    * **''​clampToEdge''​** for clamping the texture in vertical direction to its edge color. Often useful with cube-map images. 
- 
-  * **''​noScaleDown''​** specifies that the texture image is never scaled down, not even if the user selects a medium or low texture detail setting for tuning the graphics performance. Used e.g. for the Ca3DE splash screen logo, which would get blurred otherwise. (Look into ''​Games/​DeathMatch/​Materials/​Splash.cmat''​ if you want to toy around with it  a little :-) ). 
- 
-The meaning of the ''​minFilter'',​ ''​magFilter'',​ ''​wrapS''​ and ''​wrapT''​ options is analogous to their respective meanings in the OpenGL and DirectX APIs. The OpenGL Programming Guide (the "Red Book") about OpenGL version 1.2 and higher has a good explanation about these options. Although the text is specific to OpenGL, the same concepts apply to the above mentioned options. The "Red Book" for version 1.1 does not address the ''​clampToEdge''​ option, but its text is available online at [[http://​www.rush3d.com/​reference/​opengl-redbook-1.1/​chapter09.html]]. 
- 
-Here is an example from ''​Games/​DeathMatch/​Materials/​Fonts.cmat''​ that demonstrates how the options are used: 
-<​code>​ 
-    Fonts/Arial 
-    { 
-        diffusemap ../​../​Fonts/​Arial.png,​ minFilter nearest, magFilter nearest, noScaleDown 
-        // ... 
-    } 
-</​code>​ 
- 
-====== Shader Specifications ====== 
- 
-The examples of material definitions that we have seen so far were only composed of texture map specifications. In the [[MatSys::​Introduction|MatSys Introduction]] we have learned that internally, "​shaders"​ take materials to finally implement how they are rendered and how they look. In cases like our example materials above, the MatSys selects shaders from a built-in library automatically,​ picking the one that best fits the material. 
- 
-But what if you want to change the way how your materials are rendered, either just in the details or radically from ground up? What if you don't want regular Phong lighting? Or you want an entirely different method to render diffuse-maps or a different way to combine them with normal-maps?​ What if the built-in shaders don't cover a way of rendering that you prefer? It also happens that the built-in shaders do not take cube-maps into account at all, so what if you want to have a material with cube-map environment reflections?​ 
- 
-The answer to these questions is two-fold: You have to override the automatic shader selection by assigning a shader manually. But you also have to "​know"​ that shader: You have to know its name, or you cannot assign it to your material. You have to know wether it needs a diffuse-map or a cube-map or both, or any other combination of texture map images, so that you can specify them in your material definition. Sometimes you have to know even more details about it. 
- 
-The good news is that the MatSys renderers have more shaders built-in than just those that are considered during the automatical selection. They are documented below, inclusive sample material definitions,​ and you can use them to override the auto-selection. Alternatively,​ if you know or are a programmer, you can also make your own shaders. By making own shaders you gain the greatest flexibility that you can get, because only shaders eventually define how materials look, and shaders can do everything that the underlying hardware can do! Creating own shaders is documented at [[matsys::​Writing_Shaders]]. 
- 
-There is another issue that you should know about shaders: Each material gets not only one shader assigned, but //two//. This is because the Ca3DE Material System renders materials in two steps: First, the //ambient// part of a material is rendered, that is, everything that is rendered even if no light source is present. The //ambient shader// of a material is responsible for how this part is rendered. Then, the parts of the material looks that are contributed by each light source are rendered separately, as for example diffuse reflections,​ specular highlights and other effetcs. The per-light-source contributions are controlled by the //light shader// of a material. 
- 
-You set the ambient and light shader of a material (and thereby override the automatic selection) with the following keywords in the material definitions body: 
- 
-  * **''​AmbientShader MyAmbientShader''​** assigns the shader with name ''​MyAmbientShader''​ as the ambient shader to this material. 
- 
-  * **''​LightShader MyLightShader''​** assigns the shader with name ''​MyLightShader''​ as the per-light-source shader to this material. 
- 
-Here is an example for how these statements could be used in a material definition: 
-<​code>​ 
-    Textures/​Kai/​barrel_rst 
-    { 
-        AmbientShader myCarMetallicBlue_ambient 
-        LightShader ​  ​myCarMetallicBlue_light 
- 
-        diffusemap ​   Textures/​Kai/​barrel_rst_diff.png 
-        normalmap ​    ​flipNMyAxis(Textures/​Kai/​barrel_rst_norm.png) 
-        cubeMap ​      ​Textures/​SkyDomes/​ReflectiveCubeMap#​.jpg 
-    } 
-</​code>​ 
- 
- 
-===== Built-in special-purpose Shaders ===== 
- 
-Currently, all MatSys renderers come with several special-purpose shaders built-in (special-purpose means that they are never taken into account for automatic assignment). In most cases, they are actually pairs of shaders, one shader for the ambient and one shader for the per-light contribution of the same effect, but you will find that the exception to this rule is more often true than not. 
-More built-in shaders are currently in preparation,​ for example for special effects like cube-map environment reflections,​ realistic water surfaces, etc. Note that any programmer can also write his own shaders, allowing him to implement //any// rendering effect that he wants! This makes the MatSys highly flexible, extensible and future-proof,​ and was one of its primary design goals. Writing own shaders is documented at [[matsys::​Writing_Shaders]]. 
- 
-The following special-purpose shaders are currently built into all renderers of the MatSys. Please note these shaders and their related examples are pretty advanced, and you might want to skip them until later. It may be convenient to first finish reading the rest of this documentation,​ which will help to fully understand the special-purpose shader examples. 
- 
- 
-==== The SkyDome Shader ==== 
- 
-In order to create surfaces that are invisible like fully transparent glass and instead only show the far sky dome beyond them, the ambient shader **''​A_SkyDome''​** exists. It basically only requires a cube-map for the sky to be specified. In fact, it ignores the specification of any other (i.e. diffuse-, normal-, etc.) maps. However, in most cases you'll want to specify additional keywords that further describe the properties of the sky surfaces. Here is an example: 
- 
-<​code>​ 
-    Textures/​SkyDomes/​PK_BrightDay2 
-    { 
-        // Activate the A_SkyDome shader as the ambient shader 
-        AmbientShader A_SkyDome 
- 
-        // Have no dynamic light affect surfaces with this material. 
-        LightShader ​  none 
-        noDynLight 
- 
-        // The '#'​ in the next line is auto-replaced with the relevant suffixes (_px, _ny, ...). 
-        cubeMap Textures/​SkyDomes/​PK_BrightDay2#​.png,​ wrapS clampToEdge,​ wrapT clampToEdge 
- 
- 
-        // Don't write into the z-Buffer, so that entities (like missiles) outside of the map can still be drawn. 
-        ambientMask d 
- 
-        // This material does not cast dynamic shadows. 
-        noShadows 
- 
-        // Don't create or keep lightmaps for this material, don't participate in Radiosity computations. 
-        meta_noLightMap 
- 
-        // This keyword states that this material casts sunlight. 
-        meta_sunlight 
-            // The irradiance of the sunlight in Watt/m^2 that comes (or shines) through this material. 
-            // Values like (100  90  80) might work, too. 
-            (220  180  100) 
-            // The direction of the incoming sunlight rays. The z-component should be negative. 
-            // (These values match the actual position of the sun in the cube-maps.) 
-            (-17 -699 -715) 
-    } 
-</​code>​ 
- 
-The **''​AmbientShader A_SkyDome''​** line activates the ambient sky dome shader. Note that the far away sky dome is //not// affected by light of any dynamic light source, and therefore we assign the **''​none''​** shader as the per-lightsource shader in order to make sure that no dynamic light is applied to sky surfaces. The **''​noDynLight''​** keyword does essentially the same as **''​LightShader none''​** and will soon be obsoleted. Until then, please use it together with each occurrence of **''​LightShader none''​**. 
- 
-The **''​cubeMap ...''​** statement specifies the cube-map that is to be used for this sky. If you also specified other texture maps like diffuse-maps or specular-maps,​ they would simply be ignored, as the **''​A_SkyDome''​** shader has no use for them. 
- 
-The remaining keywords further specify important properties of this material. Please refer to section [[#​Keyword_Reference|Keyword Reference]] for a detailed description. Short explanations of their meanings are given in the comments in the above example. 
- 
-==== The Terrain Shader ==== 
- 
-The terrain shader exists in order to render the Ca3DE outdoor terrains, which work a bit different than regular, Phong-lit surfaces. You activate the ambient terrain shader by writing 
-<​code>​ 
-    AmbientShader A_Terrain 
-</​code>​ 
-in the materials body. Normally, you would now to expect to also assign a terrain-specific shader for the per-lightsource contribution to the terrain, as in 
-<​code>​ 
-    LightShader L_Terrain 
-</​code>​ 
-However, I have not yet written the **''​L_Terrain''​** shader, and so we have to turn off dynamic lighting for terrains: 
-<​code>​ 
-    LightShader none 
-    noDynLight 
-</​code>​ 
-:?: Why do terrains not account for light by dynamic light sources? Well, there are several reasons: 
-  - Terrain is typically employed by mappers in outdoor areas that are in bright sunlight. The effect of dynamic light sources would barely be visible, if at all (but cost //a lot// of performance instead). 
-  - Dynamic light sources are normally very "​small"​ when being compared to the extends of terrains, and mappers tend to place them inside buildings rather than in the open area. This further limits the per-lightsource contribution on terrain surfaces. 
-  - I simply have not yet had the time to write the **''​L_Terrain''​** shader. 
-:!: But if for example somebody wanted to model an indoor cave with the Ca3DE terrain technique, having a shader that accounts for the light of dynamic light sources even on terrains would make a lot of sense. Good news is that, as indicated above, it is //easy// to write such a shader -- I'll probably do so as soon as I need one. 
- 
-Next, the **''​A_Terrain''​** (and the future **''​L_Terrain''​**) shader requires a diffuse-map to be specified. This diffuse-map will be scaled to match the physical size of the terrain, that is, it will cover the terrain completely. In order to get the edges of the terrain properly textured, it makes sense to also specify **''​clampToEdge''​** border wrapping for the diffuse texture: 
-<​code>​ 
-    diffusemap Textures/​Terrains/​BPRockB_tx1.png,​ wrapS clampToEdge,​ wrapT clampToEdge 
-    lightmap $lightmap 
-</​code>​ 
-As the Ca3D-Engine map compile tools will also generate a lightmap for the terrain in order to e.g. take sunlight or other radiosity light sources into account, we specify the **''​lightmap''​** keyword with the engine-supplied lightmap. Note that while the lighting of dynamic light-sources is //not// taken into account, the light of radiosity light sources //is//! 
- 
-Next, the **''​A_Terrain''​** shader employs the texture-map that is specified with the **''​lumamap''​** keyword as a //​detail-map//​ for the terrain. This is a good example for how the specification of a custom shader (here **''​A_Terrain''​**) can entirely alter the meaning of a material keyword. We will see below how the coarseness (the repetition-count) of the detail-map is set. 
-<​code>​ 
-    lumamap ​   Textures/​Terrains/​CommonDetail2.png ​     // "​A_Terrain"​ takes the Luma-map as Detail-map (optional). 
-</​code>​ 
-The detail-map is optional, and may be omitted. However, terrains look a lot better with them, and so their use is recommended. 
- 
-:?: You may be wondering wether multiple detail-maps can be handled, as for example in FarCry, where they have a detail-map for beach sand, one for rocks, one for grass and one for pavement. \\ 
-:!: The answer is: The **''​A_Terrain''​** shader can indeed //not// handle such detail maps. But as before, it would actually be easy to write such a shader as soon as one is needed! 
- 
-Finally, you need this block of statements in the body of your material definition: 
-<​code>​ 
-    shaderParamExpr fParam4 ​   // The first eight shader parameters are taken from fParam4 to fParam11 
-    shaderParamExpr fParam5 ​   // and specify the coefficients of two planes for automatic tex-coord generation. 
-    shaderParamExpr fParam6 
-    shaderParamExpr fParam7 
-    shaderParamExpr fParam8 
-    shaderParamExpr fParam9 
-    shaderParamExpr fParam10 
-    shaderParamExpr fParam11 
-    shaderParamExpr 21.3       // Scale / repetitions of the Detail-map. 
-</​code>​ 
-The only thing that you may change here is the number of repetitions of the detail-map, 21.3 in the above example. The lines above that are required in order to get the terrain properly rendered and cannot reasonbly be altered. 
- 
-For more information on what all the **''​shaderParamExpr fParam*''​** lines do, please refer to section FIXME (TODO). 
- 
-Here is a complete example for a terrain shader: 
-<​code>​ 
-    Terrains/​BPRockB_tx1 
-    { 
-        AmbientShader A_Terrain 
-        LightShader ​  none 
-        noDynLight 
- 
-        diffusemap Textures/​Terrains/​BPRockB_tx1.png,​ wrapS clampToEdge,​ wrapT clampToEdge 
-        lightmap ​  ​$lightmap 
-        lumamap ​   Textures/​Terrains/​CommonDetail2.png 
- 
-        shaderParamExpr fParam4 ​    // The first eight shader parameters are taken from fParam4 to fParam11 
-        shaderParamExpr fParam5 ​    // and specify the coefficients of two planes for automatic tex-coord generation. 
-        shaderParamExpr fParam6 
-        shaderParamExpr fParam7 
-        shaderParamExpr fParam8 
-        shaderParamExpr fParam9 
-        shaderParamExpr fParam10 
-        shaderParamExpr fParam11 
-        shaderParamExpr 21.3        // Scale / Repetitions of the Detail-map. 
- 
-        twoSided ​                   // "​twoSided"​ is required for the SOAR terrain algorithm. 
-    } 
-</​code>​ 
- 
- 
-==== The WaterCubeReflect Shader ==== 
- 
-In order to turn a polygon into a translucent water surface with moving waves and reflected environment with Fresnel effect, employ the **''​A_WaterCubeReflect''​** shader: 
-FIXME (This section is not complete!) 
- 
- 
-==== The "​none"​ Shaders ==== 
- 
-You can use the special **''​none''​** shader both as an ambient or a per-lightsource shader in order to have no shader for ambient or per-lightsource contributions at all. 
- 
-As you have seen in the examples above, this makes sense in several situations. Especially materials that are not affected by local, dynamic light sources often have the **''​LightShader none''​** statement, as for example for sky dome. Note that currently, you still have to combine any **''​LightShader none''​** statement with the **''​noDynLight''​** statement in order to take proper effect. The **''​noDynLight''​** will however become obsolete in future releases of the Ca3DE Material System. 
- 
-Using **''​AmbientShader none''​** is much less frequently useful, and almost only ever employed for "​invisible"​ materials. Note that **''​AmbientShader none''​** also implies **''​LightShader none''​**. Also, in order to take proper effect, the **''​noDraw''​** keyword is required with each occurrence of **''​AmbientShader none''​**,​ but that requirement will be removed and **''​noDraw''​** be obsoleted in future versions of the MatSys. 
- 
-====== Keyword Reference ====== 
- 
-This section lists all keywords that are allowed in the body of a materials definition. 
- 
-Some of the keywords influence the automatic selection of the shader for the material, others just give more control over the shader that is eventually used for the material, for making better use of the features of that shader, increasing its usefulness. 
- 
-Note that the built-in shaders of all MatSys renderers were written to comply to the documentation of the keywords below, or rather, the documentation was written to reflect the implementation of the built-in shaders. 
-If you employ a custom shader (e.g. a self-written one) instead, there is no guarantee that this shader interpretes and implements the keywords in an identical manner, because the shader is flexible and free to do anything that its author made it to. This is where you need a documentation that is specific to that shader, see [[matsys::​cmat_manual#​Built-in_special-purpose_Shaders]] for the built-in ones. 
- 
-In general, most keywords should occur only once per material definition. If such a keyword is stated several times, only its last occurrance is taken into account, overriding its previous statements. The order in which such keywords are specified in the body of the material definition is irrelevant, you may state the keywords in any order. 
- 
-However, some keywords are allowed to occur several times, for example for enumerating textures or numbers. For such keywords, the order in which they appear //is// important. Keywords with this feature are explicitly mentioned below. \\ FIXME We should get rid of this exception by changing the syntax to e.g. **''​shaderParamExpr ($expr1, $expr2, ..., $exprN)''​**. 
- 
- 
-===== Texture Map Specifications ===== 
- 
-  * **''​diffusemap $mc''​** 
-  * **''​normalmap $mc''​** 
-  * **''​specularmap $mc''​** 
-  * **''​lumamap $mc''​** 
-  * **''​lightmap $mc''​** 
-  * **''​shlmap $mc''​** 
-  * **''​cubeMap $mc''​** 
-  * **''​cubeMap2 $mc''​** 
-  * **''​shaderParamMapC $mc''​** 
- 
-With these keywords you specify texture map compositions **''​$mc''​** for use with this material. The keywords and texture map compositions are explained in detail in section [[matsys:​cmat_manual#​texture_map_specifications]]. 
- 
-The **''​shaderParamMapC''​** keyword is special, as it can occur arbitrarily often! You can use it to pass an arbitrary number of texture-maps to the shader. Materials that employ a custom shader that for example combines several diffuse-maps and several normal-maps might use this keyword in order to list all the textures that the shader employs. 
- 
- 
-===== Shader Specifications ===== 
- 
-  * **''​AmbientShader''​** 
-  * **''​LightShader''​** 
- 
-These keywords are used to override the automatic shader selection. 
-They are explained in detail in section [[matsys:​cmat_manual#​shader_specifications]]. 
- 
- 
-===== Custom Data ===== 
- 
-  * **''​shaderParamExpr $expr''​** 
-  * **''​shaderParamMapC $mc''​** 
- 
-These two expressions are used to pass additional information to custom shaders. 
-They can occur arbitrarily often in a material definition, so their order is important. \\ 
-FIXME: This should be **''​shaderParamExpr ($expr1, ...)''​** etc. in order to get rid of the order requirement. 
- 
-The meaning of the expressions and map compositions that you pass to the shader with these keywords entirely depends on how the shader interprets them! The [[matsys:​cmat_manual#​the_terrain_shader|Terrain]] shader is a good example that employs these keywords. \\ 
-FIXME: Provide more details here. \\ 
-FIXME: The terrain shader should employ **''​shaderParamMapC''​** rather than **''​lumamap''​** for its detail-map... \\ 
- 
- 
-===== Rendering Options ===== 
- 
-The following material parameters are //global rendering parameters//​. 
-They affect the entire material, but only how it is rendered, that is, its "​looks"​. 
-These parameters are never looked at or taken into account by the map compile tools. 
- 
-  * **''​noDraw''​** If specified, this material does not render at all, it becomes invisible. This is probably mostly useful for debugging. (For mappers: ''​noDraw''​ does //not// cause CaBSP to remove any faces from the world. If you want faces to be actually removed, you should rather use the ''​meta_XXX_TODO''​ keyword in order to make CaBSP remove them right from the start.) 
- 
-  * **''​noDynLight''​** If specified, this material does not receive any light from dynamic light sources, only the ambient contribution is rendered. (Technically,​ the material does not even get a per-light-source shader assigned.) Useful e.g. for sky domes, additive effects like particles, translucent surfaces like water and glass etc. 
- 
-  * **''​twoSided''​** Normally, the back or "​inside"​ faces of materials are not rendered. This renders both sides of the material. Useful for "​indefinitely"​ thin objects like metal grates and fences, spider webs, ... Note that two-sided faces are currently not properly lit by dynamic light when seen from the back side. 
- 
- 
-==== Ambient-Only Rendering Options ==== 
- 
-The following parameters do only affect the ambient contribution of a material (as implemented by the Material Systems ambient default shaders). 
-The map compile tools never look at these parameters. 
-Some of these parameters take expressions as their arguments, which are denoted by ''​$expr''​. 
-Expressions can be simple numbers or more complex constructs, they are discussed in greater detail in subsection [[matsys::​cmat_Manual#​Expressions]] 
- 
-  * **''​alphaTest $expr''​** Activates the alpha test with the result of ''​$expr''​ as the reference value. The alpha test passes if and only if the alpha value of the ambient contribution (which normally comes from the diffuse-map) is greater than the reference value. Note that the reference value can be specified as an expression, that is, it can be //varying over time//. This can produce interesting effects (i.e. materials that appear to grow or shrink) if the diffuse-map comes with an appropriate alpha channel. Negative values turn the alpha test off. The test is off by default. 
- 
-  * **''​blendFunc $src_factor $dst_factor''​** This parameter determines the blend function for the ambient contribution of the material. ''​$src_factor''​ and ''​$dst_factor''​ must be one of ''​zero'',​ ''​one'',​ ''​dst_color'',​ ''​src_color'',​ ''​one_minus_dst_color'',​ ''​one_minus_src_color'',​ ''​dst_alpha'',​ ''​src_alpha'',​ ''​one_minus_dst_alpha'',​ or ''​one_minus_src_alpha''​. Note that not all combinations make sense. Using ''​blendFunc''​ will be documented in greater detail in future releases of this text. Per default, blending is turned off. 
- 
-  * **''​red $expr''​** 
-  * **''​green $expr''​** 
-  * **''​blue $expr''​** 
-  * **''​alpha $expr''​** 
-  * **''​rgb $expr''​** 
-  * **''​rgba $expr''​** These parameters all define expressions for (channels of) the color with which the ambient contribution is modulated. I have defined the default ambient shaders such that for materials that have luma-maps, only the luma-map is modulated. Materials that have no luma-map get the entire ambient contribution modulated. This allows to create effects such as panels that have flickering LEDs, glowing lights etc. Note that you can specify different expressions for different color channels. That is, if you have a luma-map for a computer panel that has both red and green LEDs, you can for example have the red LEDs morse SOS, while the green LEDs change gradually by a sinus function. The default expression for all color channels is 1.0 (identity). 
- 
-  * **''​useMeshColors''​** Additionally to the above color definitions,​ this will modulate the materials color with the colors that are specified with the vertices of the mesh that is to be rendered. This option does currently only work in a very limited set of shaders, and is mostly useful internally in CaWE, the Ca3DE World Editor, e.g. for rendering wire-frame stuff. You will rarely ever need this in a real-world material script. 
- 
- 
-===== Meta Keywords ===== 
- 
-Finally, here are the meta-parameters that are taken into account by the Ca3DE map compile tools. 
-These parameters are not directly related to the rendering of the material. 
- 
-  * **''​meta_RadiantExitance_Values[4]''​** Radiant Exitance RGB values plus intensity (scale). Used by CaLight. 
- 
-  * **''​meta_RadiantExitance_ByImage_FileName''​** Radiant Exitance RGB values from image file. Used by CaLight. 
- 
-  * **''​meta_RadiantExitance_ByImage_Scale''​** Radiant Exitance intensity (scale) for the RGB values from image file. Used by CaLight. 
- 
-  * **''​meta_AlphaModulatesRadiosityLight''​** Makes CaLight handle the DiffMapComps alpha channel and the RGBAGens properly. For fences, grates, glass, water, etc. 
- 
-  * **''​meta_NoLightMap''​** Makes the compile tools not cover this material with a lightmap. 
- 
- 
-===== Expressions ===== 
- 
-Some of the above keywords cannot only take numbers as their arguments, but entire mathematical **expressions**. 
-An expression is a combination of numbers, mathematical operations, symbols, and table look-ups. 
-Here is an example for such an expression: 
-<​code>​ 
-    (1 + sinTable[ time*0.25 + 3 ]) / 2 
-</​code>​ 
-Unfortunately,​ there are also bad news: The current parser of the Ca3DE MatSys is not yet powerful enough to 
-parse expressions that use operator infix notation like the one above. 
-Instead of ''​+'',​ ''​-'',​ ''​*'',​ ... we therefore have to use explicit prefix notation, 
-which is much easier to parse. The prefix notation is explained below. 
-Here is the above example in prefix notation that we have to use until I can improve the parser to support infix notation: 
-<​code>​ 
-    div(add(1, sinTable[ add(mul(time,​ 0.25), 3) ]), 2) 
-</​code>​ 
- 
-Expressions are defined recursively as follows: 
- 
-  * **''​$num''​** A number. 
- 
-  * **''​$var''​** A variable. Please see below for a list of all valid variables. 
- 
-  * **''​$table[ $expr ]''​** A table look-up. The value of the table at position ''​$expr''​ is returned. The details of the look-up depend on the tables definition. The default tables ''​sinTable''​ and ''​cosTable''​ are always predefined. Custom tables can be defined as described in subsection [[matsys::​cmat_Manual#​Tables]]. Note that table look-ups are normalized. That is, all table elements are accessed by indices between 0.0 and 1.0, that is, the fractional part of ''​$expr''​. 
- 
-  * **''​add($expr1,​ $expr2)''​** Adds the results of ''​$expr1''​ and ''​$expr2''​. 
- 
-  * **''​sub($expr1,​ $expr2)''​** Subtracts the results of ''​$expr1''​ and ''​$expr2''​. 
- 
-  * **''​mul($expr1,​ $expr2)''​** Multiplies the results of ''​$expr1''​ and ''​$expr2''​. 
- 
-  * **''​div($expr1,​ $expr2)''​** Divides the results of ''​$expr1''​ and ''​$expr2''​ if ''​$expr2''​ is not 0. Otherwise, this evaluates to 0. 
- 
- 
-The following variables are defined: 
- 
-  * **''​time''​** The current system time in seconds, starting from zero. 
- 
-Tables and table look-ups are described in subsection [[matsys::​cmat_Manual#​Tables]]. 
- 
- 
-===== Tables ===== 
- 
-Another type of object that you can define in material scripts are **tables**. 
-Tables are a very powerful means to express arbitrary functions for use in expressions. 
-Expressions are explained in detail above in subsection [[matsys::​cmat_Manual#​Expressions]]. 
- 
-Table definitions start with the keyword ''​table'',​ followed by the name of the table. 
-Then come two ''​{''​s,​ the table data values separated by commas, and then the closing two ''​}''​s. 
-Here is an example of a table definition: 
-<​code>​ 
-    table myFlickerTable { { 0.5, 1, 0, 0.2, 0.0, 0.8, 0.1, 0.7 } } 
-</​code>​ 
- 
-The elements of tables can be accessed from expressions as explained in subsection [[matsys::​cmat_Manual#​Expressions]]. 
-It is important to note that the indices for table access are treated as //​normalized//​ indices. 
-That means that all values of a table are accessed with numbers that are greater or equal to 0.0 and less than 1.0. 
-In the above table, which has eight elements, you'd get 0.5 for ''​myFlickerTable[0.0]'',​ 1 for ''​myFlickerTable[0.125]'',​ 
-0.2 for ''​myFlickerTable[0.375]''​ and so on. 
- 
-As tables normally wrap, that is, start over when you read over their end, you will get 0.5 also for ''​myFlickerTable[1.0]''​ 
-(but 0.7 for ''​myFlickerTable[0.9999]''​). 
-You may want to think of this as only the fractional part of the index being taken for the look-up, while the integer part is ignored. 
-That means that for example the expression 
-<​code>​ 
-    rgb myFlickerTable[time] 
-</​code>​ 
-runs through the entire table exactly once per second, //no matter how many elements the table actually has//. 
- 
-Between the two opening ''​{'',​ one or both of the keywords ''​snap''​ and ''​clamp''​ are allowed. 
-''​snap''​ defines that there is no linear interpolation between the table values. 
-For example, we just said that ''​myFlickerTable[0.0]''​ yields 0.5 and ''​myFlickerTable[0.125]''​ yields 1.0. 
-But what does ''​myFlickerTable[0.0625]''​ (the middle between 0.0 and 0.125) yield? 
-If ''​snap''​ has not been specified, the value will automatically be interpolated between the table elements, 
-and the result would be 0.75. If however ''​snap''​ has been defined, the result would be "​snapped"​ to the next lower table element, 
-and the result would be 0.5. 
-Figure TODO demonstrates plots of two tables that differ in the use of the ''​snap''​ keyword but are identical otherwise. 
-Interpolation is useful whenever you want to have a table to encode functions that have "​smooth transitions"​. 
-Snapping is useful whenever you want to have a table to encode functions that have "hard transitions"​. 
-For example, in order to have LEDs flicker the SOS morse code, you'd use this table: 
-<​code>​ 
-    table sosTable { snap { 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 
-                            1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0 } } 
-</​code>​ 
- 
-The ''​clamp''​ keywords defines what happens if a table is accessed at indices outside of the normalized range 0.0 to 1.0. 
-Without ''​clamp'',​ the default behaviour is to wrap. 
-With clamping enabled, the indices are clamped to yield the smallest or greatest table element. 
-Figure FIXME TODO demonstrates plots of two tables that differ in the use of the ''​clamp''​ keyword but are identical otherwise. 
- 
-Tables must be defined before their first use. 
-As an exception, the two tables ''​sinTable''​ and ''​cosTable''​ are implicitly predefined and can always be used without 
-prior declaration. 
-The scope of a table begins at its definition and ends at the end of the material script. 
-Note that although in the above examples only table element values between 0.0 and 1.0 occur, arbitrary numbers are allowed. 
matsys/cmat_manual.txt ยท Last modified: 2013-01-07 12:07 (external edit)