Well, I think this is the first time I've posted anything under the Programmer Discussion forum, but hey, it really doesn't belong elsewhere!
Ok, starting to dabble in the .fx High Level Shader Language, since I think it's a really good skill for an artist to have; if not to make 100% of their own shaders, then to be able to calibarate on more advanced ones with programmers more directly and understand what numbers to plug to make things look good in an artists eye.
So where I'm up to is I'm picking apart basic blinn and lambert shaders, reverse engineering a few more advanced effects, and starting to slowly get a grasp on everything. I can write a basic light and texturing shader, and playing around with per pixel specular component at the moment.
My question is, does anyone else have shader experiance, and if so how have you found it? what have you done so far?
My current aim is to make myself 3 pluggable shaders:
1)A base shader supporting diffuse, normal, specular, opacity, gloss, offset mapping (read: virtual displacement) and hopefully attenuation
2)A skin shader as above, but also a faked translucency with colour component, intensity, and falloff, plus an added fresnal specular.
3)A hair shader, anisotropic highlights, normal, and light transmission (eg, another spin on a fake translucency for backlighting).
Well I've been working with shaders for a little while now. Like you're probably finding, initially the hard part was getting my head around the myriad coordinate spaces (model-space, view-space, texture-space, etc.) that you have to deal with. After that, it was getting a grasp on what you can and can't do with shaders. I mean, you can probably do anything but it might take 17 render passes in which case there's no way it's going to happen in real time. This is where I think HLSL is just too high-level. It's nice that you're shaders are much more human readable than assembly code, but it's too powerful: there's support for if-statements but everyone will tell you not to use them because they can badly affect performance.
I've really enjoyed taking the time to work it all out because you can see the results of your work almost immediately, and coming up with a cool effect ("Hey those clouds look almost real!") is really satisfying. On the other hand the limitations can be really frustrating. I've managed a pretty good looking water effect but I've not been able to get it to reflect the environment properly yet simply because I'm constrained to doing everything in one pass.
If you are able to work out you're base shader and fully understand everything that's going on, then I think you're probably about 80% of the way to doing just about anything you want.
Quick update before I run off home; so far:
ambient controller (base light multiplier)
diffuse tint
diffuse multiplier
translucent colour (due to be a texture)
translucent falloff
diffuse texture
specular texture
[img]http://server2.uploadit.org/files/jistyles-hlslskinwip01.jpg[/img]
very pleased with the progression so far.
My barely passable coding abilities however mean I've been stuck up on a few basic code structure problems. I've found passing data through different states is a pain in the butt though [:(] took me way too long to figure out how to pass the uv's into the shared segment... anyways:
[img]http://server2.uploadit.org/files/jistyles-hlslskinwip03.jpg[/img]
edit: Pretty bad head shot there of my test asset - it only has a very quick translucency mask and ramp off texture, so I really should spend a little time seeing how far I can push the visuals before going too far on. Just an update on specs:
inputs:
light
ambient
diffuse colour (tints texture)
diffuse texture
diffuse power
translucency colour
translucency power
translucency ramp in
translucency ramp out
translucency mask texture
translucency ramp bias texture
basic specular is broken since I borked the shader structure and it got way too messy... hopefully have something a bit more elegant sometime this decade.
soooo... now I have full per pixel texture masked ramping controls, so I can bleed the light around into the shadow per area. What that means in a practical sense is I can effectively make the difference between the thin minimal light occlusion of the ear and the thick near total occlusion forehead skin being so close to the skull.
One thing that seems rather cool is that it's pretty cheap even in this unoptomised state... you can even bump the translucency maps down to half or even quarter resolution of your diffuse since since the sampling is hardly noticeable and it's a very smooth gradient effect.
anyways, more to come soon I suppose, and I should also be posting something done with this in the exhibition soon enough.
enough blab!
ok, quick update - required a new test asset, so I made what I'm calling a "Squishy". They go BOING if you drop them.
Work in progress, also showing the UI:
[url]http://www.jistyles.com/content/resources/hlsl/hlsl-skin_wip03.jpg[/url]
I've also set up a mini diary/log, documenting my progress on my website, so check that out for more info :)
[url]http://www.jistyles.com/main.php?id=doc&page=hlsl[/url]
(man... I need to put in a lighter backing for those text boxes huh?)
I don't know if this will be of any use, but there
is a free plugin for 3DSMAX5+ exporting .x files
that also generates .fx shader files; it's called
"Panda". I found it on the web as "PandaExporter.dle",
but can't remember where I got it [}:)].
There is also apparently one in the DirectX SDK but
it was missing in my copy. I should probably look
for a better one.
wifflecube: I don't really need to export anything since it's written directly in .fx form :) good to know there's a replacement to the standard ms .x exporter though - I needed to export some assets for a client recently and didn't like the ms exporter very much.
redwyre: Heh, you'll probably laugh... I'm writing it in notepad (couldn't stand fx composer or rendermonkey... felt like a loss of control) and using 3dsmax 6 and 7's direct x 9 viewport as a test bed. The shader itself is a .fx file, so you can just plug it straight into the max viewport, as well as any engine that supports .fx / .hlsl shaders. I think I'll start posting source once I've got fresnal specular component in there and the lighting model debugged; I've got a seam error on my normal map which I can't figure out for the life of me.
I doubt any programmer will laugh if you tell them you're coding in a plain text editor with a compiler to do your learning. It might not be pretty, or quick, but actually knowing things from the bottom up gives you an insight you just can't get with yer fancy IDEs.
Of course, they'll laugh if you *stay* using it for long after your first few months [:)]
A bit off-topic, but I disagree mcdrewski. I do most of my coding with a text editor and commandline. The text edotor is SciTE http://scintilla.org/SciTE.html and I've got my own build system written in ruby. IDEs slow me down because I work across many platforms and compilers and I have no desire to maintain a project file for each IDE/platform.
I used to use IDEs, and they can be nice. I just refuse to use text editors with UIs designed by a dyslexic gibbon (I'm talking about VI and Emacs).
JI, you will get far more out of SciTE if you spend 1/2 an hour or so going through the global config file and set it up the way you like. I turn on multiple tabs (10 files open at once), line numbers, default to monospace font, and have it check if it is already open before launching another instance. It's way cooler than what you see from the basic setup you get from a fresh download.
Also if you edit the config file in SciTE itself, as soon as you save it the changes take effect i.e. no need to restart it.
Ok, been going pretty steady, but I've got a quick question:
is there any cleaner way to invert a 0-1 range to 1-0? As in, white/black inverse? Currently, my fresnel masking code looks something like this:
...
fresnel = dot(lightvector,normals);
return saturate(fresnel - 1) * -1;
...
I think that's it... don't have it here to directly copy/paste though [:)] anyways, you get the drift... clamping to 0-1 - 1 * -1 ; that seems really bulky and crap to me, and it seems like I should just be able to saturate -fresnel or something along those lines, but that obviously doesn't work [:D]
anyways, if any programming types can point me in the right direction there, it'd be much appreciated :)
Erm...that code doesn't look like it even does what you are wanting it to, unless I'm reading it wrong.
Anyways, as long as you can guarantee that your range is [0,1] (which "saturate" does nicely), then inverting the range is just "1 - n". So, if I'm guessing the intent of your code correctly:
[code]fresnel = dot( lightvector, normal );
return 1 - saturate( fresnel );
[/code]
huh, odd... sorry, I didn't think I explained it very clearly, but trying out the 1-n seems to work even if the numbers aren't the same... what I need to do is invert the range 0-1, to effectively change 1 to 0 and 0 to 1.
so what I'm doing is - 1 * -1, so:
0 - 1 * -1 = 1
1 - 1 * -1 = 0
the 1-n I thought would just put 0 to -1 and 1 to 0, but it doesn't seem to have any visible difference and is computationally lighter. since I'm using it as a mask to ramp in glancing glare on the on specular, I thought the -1 would make a negative addition (burning the specular instead of additively pushing up the value). Well... that's my crappy maths for ya! cheers :)
Hey nice goal Joel. You dabble into something I've been meaning to do for quite some time! You might help kick me into action [:D]