HowTo:IntroToShaders

From VsWiki
Jump to: navigation, search

Requirements Overview

  • A diffuse texture is the color of a surface.
  • A spec texture determines what color a certain place on the model reflects, and how much. Not the diffuse colour - the specularity!. Usually and in rough terms, the brighter the specularity, the dimmer the diffuse, and vice versa, since energy must be conserved.
  • A shininess map (which we locate in the alpha channel of the specular texture) determines how coarse or glossy the surface is; --that is, how sharp or blurry reflections look on it. This is UNRELATED to the material's specularity. For example, glossy paint has low specularity (Fresnel specularity) but the reflections are sharp, making the material look glossy. A sheet of stainless steel, for an opposite example, is highly specular, but reflections on it are blurry, because the surface is rough (non-glossy). A value of 1.0 in spec alpha makes the surface mirror-like; a value of 0.0 in spec alpha makes the surface completely rough, almost fully diffuse. Real materials lie somewhere in between the two.
  • A normal map is quite difficult to make, it is a purple texture that changes the normal of a surface, so that it looks like the surface is bumped (Used for making details like armor plates). Normal maps should be baked with tools designed to do that.
  • A damage texture is basically a diffuse texture but with scratches and holes in it. Gets faded-in when the ship is damaged.
  • A glow texture is that one that glows by itself without any light shining on it. It specifies emissive parts of the model, like lit windows, baked static lights, etc...


Introduction to Shaders, and what they mean to the modelling and texturing pipeline

I'm going to expand on this and write a whole bunch of wiki how-to's; this is a first overview. As of this writing, the default shaders aren't finalized yet, and the changes that are coming affect the way the textures need to be packed.

However, you CAN start working on bumpmaps and normalmaps (and shininess maps) right now, if you want. There will be off-line tools provided to convert texture packs from the current set, namely...

* Diffuse texture
* Specular texture
* Glow texture
* Damage texture,  plus the new
* Normal map
* Shininess map (the current shader expecting it in the alpha channel of the specular texture)

...to the most likely new packing arrangement of:

* Texture 0: Diffuse texture (may have 0, 1, or 8 bits of alpha)
* Texture 1: Specular texture (plus shininess in alpha)
* Texture 2: Glow texture(plus normalmap dU in alpha)
* Texture 3: Damage texture (plus normalmap dV in alpha)
* Texture 4: Auxiliary texture (Bump, concavities, plus ambient occlusion in alpha)

Even this rapidly evolving "standard" is only temporary, in the sense that with Klauss' GI (Global Illumination) techniques, we'll need to have two textures called "PRT-N" and "PRT-P"; but won't need ambient occlusion; and probably the "concavities" will move to the alpha channels of the PRT-N and PRT-P textures. In any case, the "concavities" are an untested idea, explained below in italics. Feel free to skip it if it sounds like Aera slang...

This is very technical; read at your peril:

In more detail, Texture 4 would have the height map (bump map) in the green channel, and two "concavities" in the red and blue channels. Well, not concavities, at all, but I didn't know a better term... This is what I mean:

Suppose you plant a normal at a point on a ship's surface, normalmap considered. Now, suppose this normal is a solid pole with two sticks that pivot at the base and can open up at the top, like a V, symmetrically, like the handles of a wine bottle cork extractor. So, open the sticks like a V until one stick or the other touches any other part of the ship. Write down the angle. Now turn the pole 90 degrees and take another measurement. The two planes of rotation should align with the texture's x and y axes (i.e.: in "tangent space"). These two angle measurements get recorded to red and blue, by an off-line tool yet to be programmed.

At runtime, the shader establishes the direction of the eye vector in texture coordinates (x,y), or (u,v), ignoring tangent space z; and uses these values to interpolate a value between the red and blue channels (the two angles measured off-line). Presumably that would approach the actual V angle at the plane normal to the surface that intersects the eye, if we were to measure it. Now we simply compare the eye-to-normal angle to 1/2 of the V angle, and, VOILA!: If it is less, we paint the environment map (multiplied by surface specular value); if it's more, then we know that the specular reflection is occluded, so we don't paint (or paint with a dark color, like 0.25 times the ship's average color, multiplied by local specular color). This should achieve specular self-occlusion.

End of very technical.

In fact, there may be several such tools, for variations in types and numbers of input textures. And I have a prototype of one such tool, the "nodulizer":

nodulizer.png

The nodulizer is really a Blender3D .blend file. You throw it into a folder where you want to convert a set of textures, rename the textures to what the nodulizer expects, or else edit the input nodes for them (on the left), adjust the scaling factor with that input node at the bottom left corner, and press the Use Nodes button in the menu bar below. The scaling factor is there in case you have large (2k by 2k or 4k x 4k originals, and want to produce 1k outputs; otherwise make the scaling factor 1.0. Needless to say, you need to have Blender installed, then you can just double- -click on nodulizer.blend.

You can download the nodulizer beta here: nodulizer.7z Just don't use it yet; the shader that uses this packing is still in the works; but you can play with it, see what it does.

There may also be a command line tool to do the same thing; not decided yet, but the advantage of using Blender's "nodes" and "noodles" is that the tool can be easily customized, specialized, tweaked, expanded... So, IF there may be a command line version, it will probably only be provided for a default repacking, for those who can't use Blender due to their religion :D


But, getting back to basics, the question most often asked: what's the difference between bump- and normalmaps?

Bump map

A bump map is a gray scale image where the brightness represents height above the surface, and darkness represents depth. 50% gray means at surface level.

The problem with bumpmaps is they take a lot of processing in the gpu (videocard) to be really good to use; and that they are quintessentially non-mipmap-able. So normalmaps soon took over.


Normalmap

Normal maps encode simply the angle of the surface. At each point on the surface, if you think of a normal vector to it, how much it is moved to left or to right from the straight UP position is called the dU. How much it is moved forwards or back from straight up is the dV. And how high it is, is the z. And the length of the normal vector is normalized to 1. What does that mean? 255, of course. :D Well, the way colors are represented in rgb is 8-bits unsigned, going from 0 to 255. On the other hand, you could think of that as a fractional number i.e.: going from 0/256 to 255/256, which is almost 1. In OpenGl it is customary to work with 0-0.994 representation.

In a tangent space normal map, normals are specified relative to the surface (as opposed to older normal maps where x y and z were specified in global coords). So, since, on average, a surface is flat, z is usually close to 1. z goes in the blue channel, so normal maps, when you open them in Gimp look very blue. Red gets the dU, but transposed, as the dU could be positive or negative. 50% red means zero. Same with green and dV. So where a surface is flat, the normal map color is red = 0.5, green = 0.5, blue = 1.0

And you produce them with xNormal, and/or with the Gimp plugin from nvidia. The plugin takes a grayscale bumpmap and computes a normal map. xNormal takes a fine mesh and a coarse mesh, and makes a normal map that, when applied to the coarse mesh, makes it appear like the fine mesh.

Dual Joe nowadays swears by denormgen; --says it's easier to use than xnormal, runs on Linux, and can stack normalmaps. I haven't tried it yet.

What do they look like?

Bumpmap:

bump.jpg

Normal map:

final_norm.jpg

The above normal map is actually a combination of subtle normal corrections computed using xNormal, from a 100k+ polygon mesh, and the result of making a normal map out of the bumpmap above, using Gimp's normal map plugin from Nvidia. That plugin has a choice in the Conversion drop box, called "Normalize Only". Very useful when you're blending normal maps, because normal maps get corrupted by blending ops, and you need to renormalize them, afterwards. Also, if you want to increase the strength of a normal map, you can dim down a bit the blue channel in Gimp, then renormalize.


Shininess Map

"Shininess" is a bad name for a good thing to model, a fundamental property of materials, which can make a glass cockpit look glossy, and make metal look "shiny" without looking "glossy". (Just goes to show what a bad name "shininess" is... Metal looks "shinier" although less glossy, by having a lower shininess than glass. Why couldn't they call it "gloss", for Pete's sake?)

Here's shininess at work in my current beta shader:

shinycockpit.jpg

shot.jpg

Hard to appreciate with a still picture... The metal does reflect the environment, but the reflections are so blurred you can barely notice them. Don't confuse "shininess" with "specular color". Totally different animals.

Shininess describes how "UN-blurred" reflections are. A high shininess (200 or so) reflects images sharp and clear. With a shininess of 100 you begin to notice blurriness. With a shininess of 20, the reflected environment is so blurred it looks almost like half way between specularity or plain diffuse color.

Unlike specular color, shininess is a monochrome (gray scale) parameter. For the ship in the shader screen-shot above, this is what the specular texture looks like:

specular512.jpg

And this is what the shininess texture looks like:

shininess512.jpg

Notice that specular color of the cockpit is pinkish or purplish. Yes, it looks green, but that's because there's a bit of green light I put in the glow map, to make it look like someone lives there; but the specular reflections are actually tinted purple. But anyhow, what I wanted to call your attention to is that the specular strength of the cockpit is not much greater than that of the metal, and in fact it should be less, or rather, the metal should be brighter in specular. I'll fix that. But the cockpit will still look glossier than the metal --i.e.: won't blur the reflections.

And what makes the cockpit look "glossy" is the white color in the shininess map, versus gray for the metal.

Glossy paints and plastics, for example, as well as glass, and most dielectric materials and coatings, can have very high shininess, but very low specularities. Look at a glossy white fridge, for instance: Reflections are sharp ; not blurred; (i.e. high shininess); and yet hard to see (low specularity). Same with glass...

At the opposite extreme, most metal surfaces are best represented by making them (black in diffuse and...) medium to high brightness in specular, but with low or very low, or ultra-low shininess. Stainless steel, for instance: Black in diffuse, about 60% gray in specular, shininess of like 20 or 10, or even 5.

And it's not necessarily true that one must stay away from white specular. Rough aluminium, for instance, would be best represented as black in diffuse, white in specular, and black again in shininess (shininess of "zero" (the shader limits it to 1 (of 255) at the bottom end)).

For gray car paint, almost the exact opposite: 50% gray in diffuse, say, or whatever shade of gray you want the paint to be, up to 80% or 85% gray for "white" paint (white paint is never perfectly white); but about only 10% to 15% gray (pretty dark gray) in specular --regardless of the shade of the paint--; and yet with shininess you could go as high as 255 ("white" shininess) to represent high gloss.

Shininess and specularity are UN-related; because specularity is a characteristic of the material itself, whereas shininess is a function of how smooth or "polished" the surface finish is; and the two things are *completely* unrelated. I strongly disagree about shininess and specularity being related, even for single-layer materials. Take rough aluminium (like cast aluminium) and polished stainless or nickle (like a baking pan), for instance: Stainless has about 60% specularity regardless of polish. If highly polished, it can have pretty high shininess (low blur in the reflections), and yet its specularity stays the same at 60%. Aluminium is almost white in specular (over 90% reflective, and a tiny bit bluish), regardless of polish; but in most uses of aluminium (except shiny foil), it has pretty low shininess. I stand by my argument: shininess and specularity are UN-related, IN-dependent variables; --regardless of how many layers you have.

Maybe what confuses you is oxides. Aluminium becomes less specular when it oxidizes (yes, aluminium oxidizes, but its oxide is clear --well, semi-transparent gray--, so you don't "see" it), and it is statistically less common to find oxides on polished surfaces. But this is only statistical and circumstantial: Just the fact that the act of polishing tends to scrape off oxides and other "dirts".

The first thing you need to do is decide what your materials are. What's metal, what's plastic, what's ceramic, what's glass, etceteras. You can then, in Gimp, select regions by color and paste them in a new layer, then change the color for specular, and yet another layer for shininess. Then you export the layers to separate xcf's. For metals, you need to decide which metals they are. For paints, what kind of paints. Low gloss paints have specular colors of the same hue and saturation as diffuse, but darker, and dark shininess. Glossy paints have gray-scale (desaturated) specular color, and high shininess. Metals are all mostly black in diffuse, and of varying brightness in specular, but low shininess. Chromes would be white in specular, black in diffuse, high shininess. Gold is black in diffuse, yellow in specular, high shininess. Matte ceramics (and matte materials in general, such as paper or fabrics or rust) are whatever color they are, in diffuse; but black in specular (shininess doesn't matter). Plastics are like high gloss paints (gray-scale, desaturated specular color), but lower gloss.

Texture packing

As of this writing, it goes like I wrote at the beginning of the file:

* Texture 0: Diffuse texture (may have 0, 1, or 8 bits of alpha)
* Texture 1: Specular texture (plus shininess in alpha)
* Texture 2: Glow texture(plus normalmap dU in alpha)
* Texture 3: Damage texture (plus normalmap dV in alpha)
* Texture 4: Auxiliary texture (Bump, concavities, plus ambient occlusion in alpha) 

I overwrote the above several times in the past few hours, so to say that it is in flux would be an understatement. Anyways, stay tuned.

Miscellanea

A new release of the vs engine may automatically initialize the ambient and specular color in the systems' xml files (i.e.: obtain them from averaging the color of their associated background textures). This will be a Good Thing (TM)! Where would you suppose ambient light comes from, if not from the background? So, if we're in a blue nebula, it makes no sense for ambient light to be red. But the chances of it being blue, if left to modders, is about <math>2^(-24)</math>, or one in 65 million. So, with this change, it will be right automatically.

This subject is not complete without discussing ambient occlusion baking and the glow map; but this is too experimental at the moment. Suffice it to say that if I succeed, we'll never use gl ambient light, but will use the glow map to emulate ambient illumination, with self-occlusion baked in, and modulated by the color and intensity of the background. (EDIT: After this writing it was decided to separate ambient occlusion from static illumination and glows, and throw it into the alpha channel. This will a) give ambient occlusion a lot more precision and resolution when compressed to dds with dxt5, and will make the job of the shader a lot easier, and avoid the hassle of forcing artists to use only saturated colors for external lights.)

Also: "detail textures": No need to complicate this post with it too much, but... Detail textures are basically tiling textures, typically 256x256, that map multiple times over the same UV map as the regular textures do, typically 16x16 times, "adding detail" as you get closer to an object (ship or station).

There will be two:

* Texture 5: Diffuse detail (color in rgb, detail normal map dU in alpha)
* Texture 6: Spec detail (luma in red and blue, shininess in green, normal dV in alpha)

(The above is tentative and subject to change.) The reason you don't need to worry about it is that there will be default detail textures that will apply generally to all ships and stations and planets, unless you supply your own detail textures and specify them in the .bfxm. The default ones will simply be some kind of Perlin noise, barely noticeable, just enough to hide "pixelation" artifacts when you get close to a ship or station; --no more.

Step by Step Tutorial

Another way of looking at it is, you can start by painting a texture, if you want, like most texturers do; but instead of misleadingly calling that first texture "diffuse", just call it "albedo". Albedo is the overall color you see off a material. And keep in mind that, for each material...

albedo = diffuse + specular

So then the question is how you divide up that albedo color between diffuse color and specular color. For metals, it all pretty much goes to specular. For matte ceramics and matte paints, it all pretty much goes to diffuse. The in-betweens are sparse and far in-between. For plastics, the gray-scale component of the color goes to specular, and the rest to diffuse.

Or... Even easier; step by step:

You got your first texture; albedo.png. Set up a new texture called "specular.png", fill it with black. Now,

  • 1) Decide what parts of albedo.png are metal, select them using the select-by-color tool, in Gimp. Copy, then paste onto specular.png with 90% or 95% blending. Merge down.
  • 2) Decide what parts of albedo.png are plastic, select them, copy, paste on specular.png; but before merging them, desaturate them. 100% blending. Merge down.
  • 3) Decide what parts of albedo.png are glossy paint. Select, copy, paste on specular.png. Bucket-fill the pasted layer with white. Set blending to 6% to 10% alpha. Merge down.
  • 4) Decide what parts of albedo.png are semi-gloss paints. Select, copy, paste on spec. On the pasted layer, use Colors -> Hue/Saturation, and bring saturation half way down. Blend with 50% alpha. Merge down.
  • 5) Decide what parts are chrome or gold, select, copy, paste, bucket-fill the pasted layer with white or yellow, respectively. 100% blend. Merge down.

Any matte paints or other matte materials stay black. Your specular texture is done, sir. You can add noise scatter to it, but be sure it's invisibly small amounts of it, like 2 or 3, correlated.

Now, for the diffuse texture, make a copy of albedo.png, call it diffuse.png. Open specular.png as-layer on top; change blending mode to Subtract. Merge down. Save. Diffuse done!

Shininess: On a separate texture, starting with black, make very glossy things like chromes and high gloss paints white. Make semi-gloss paints and plastics medium grey. Non-polished metals dark grey. The rest black. Add noise to taste. Save it as shininess.png for future reference. Copy and paste into the specular texture's alpha channel (you may need to Add Alpha Channel to specular.png). Save.

All done!

See Also