PerPixelLighting using NV_vertex_program & NV_register_combiners

I’m stuck.
I’ve got diffuse working, but specular is giving me a real headache.

My main question is this:
Is the H vector (half angle) mentioned in various documents calculated in this way:-
H=normalise(vertextolightvec + vertextoviewpointvec)
???
If it is, then I will have some more questions, because it’s not working for me.

Thanks.

IIRC

half angle = (L + E) / 2.

Where L is normalized surface to light, and E is normalized surface to eye.

You then dot this with the normal, and raise to the power of something. 16 for example. If you dont raise to the power, then you wont get very specular looking specular. i.e. it’ll be rather non shiny.

Nutty

Thanks Nutty - just as I thought.
Anything wrong with this register combiner nvparse script? :::

!!RC1.0
const0 = (0.5, 0.5, 0.5, 0);

// INPUTS OF INTEREST:
// col0 = interpolated pixel-to-light vector (compressed into unsigned RGB)
// col1 = interpolated half angle vector (compressed into unsigned RGB)
// tex0 = decal texture
// tex1 = normal map texture (bump map) (compressed into unsigned RGB)

//////////////////////////////////////////////////////
// Normalise col0 and col1
{
rgb
{
spare0 = expand(col0) . expand(col0);
spare1 = expand(col1) . expand(col1);
}
}
{
rgb
{
discard = expand(col0);
discard = half_bias(col0) * unsigned_invert(spare0);
spare0 = sum();
}
}
{
rgb
{
discard = expand(col1);
discard = half_bias(col1) * unsigned_invert(spare1);
spare1 = sum();
}
}
////////////////////////////////////////////////////

// dot L and H with normal map
{
rgb
{
spare0 = spare0 . expand(tex1);
spare1 = spare1 . expand(tex1);
}
}

{
rgb
{
spare0 = tex0 * spare0;
spare1 = unsigned(spare1) . unsigned(spare1);
}
}

final_product = spare1 * spare1;
out.rgb = const0 * final_product + spare0;
out.a = unsigned_invert(zero);

Ah, no matter. I’ve just discovered a fundemental flaw in the way the modelview matrix was being constructed from the viewpoint object in the application itself - what I thought was the absolute position of the viewpoint, turned out to be some mad weird position. It was written by one of our junior programmers…little sh*t. He’s gonna get some earache on monday, you can be damned sure!

Glad you seem to have found the problem.

Never used nvparse scripts, and I dont intend to either.

Nutty

Yes, they do seem a bit redundant, considering the vastly limited options you’ve got with register combiners. It’s actually easier to use the function calls than it is to write the scripts, because so many combinations of ops are illegal that you might as well stick to the stage input/output function calls. The texture shader nvparse scripts are laughable…just a tiny selection of pedantically named, parameterless function calls.
But that contradicts my pixel shader script methodology - pixel shaders in my renderer are defined by scripts, there’s no point me changing it just for the geforce1/2 path.

i don’t see any problems in nvparse here, it’s much more readable than the function calls, and the biggest faults that can happen in the function calls are wrong mappings and all that because of copypasting (come on, dudes, who actually writes out all the parameters by hand? ) and with such a script such bugs are much less dangerous and much more easy to find.

the only problem with nvparse is… uhm… nvparse… getting it to work, with the crappy fancy dlls and all that. dunno… i got it one time working, and that was it…

anyways, /me moves over to ARB_vertex_program and ARB_fragment_program, hehe

But arb_vertex_program and (especially) arb_fragment_program aren’t widely supported, are they? (to put it mildly).

He’s gonna get some earache on monday, you can be damned sure!

I’d give the ear-ache to the guy reviewing his check-in, instead. Or perhaps the guy writing the unit test, unless that’s the same guy as wrote the code.

Or, if all three are yourselves, I suggest a pub round. The morning after will teach you :slight_smile:

Originally posted by inept:
But arb_vertex_program and (especially) arb_fragment_program aren’t widely supported, are they? (to put it mildly).

arb_vertex_program runs in hw on gf3, gf4, radeon8500, radeon9700, radeon9500, radeon9000 (damn there are much numbers out yet ), and of course on the nv30…

arb_fragment_program only runs for now on the radeon9700, yes… and it will on the nv30.

no one needs to use nv_vertex_program anymore, it’s just for backwards compatibility… or does it have any feature arb_vertex_program doesn’t have? i don’t know of any. but arb_vertex_programs run on my pc as well.

if i ever would have gotten nvparse to run simple by including #include “nvparse.h”, then i would have never moved back… the scripting languages primitive? yes, and? it’s still easier to edit and much more easy to read and error check espencially…

Originally posted by davepermen:
arb_vertex_program runs in hw on gf3, gf4, radeon8500, radeon9700, radeon9500, radeon9000 (damn there are much numbers out yet ), and of course on the nv30…

And are there any platforms, where ARB runs in software (like NV on gforce2)?

Edit: Excepth of course NV30.

[This message has been edited by MichaelK (edited 11-18-2002).]

Well, no it isn’t much easier to read than the api calls, in my opinion. As I said, register combiners are just a way of mapping inputs to outputs through selecting which (out of a very narrow choice) maths operation you want it to perform on those inputs. The nvparse scripts seem to give users the idea that they can use something as simple as the + symbol to add two input registers together, when really they can’t. So code like this (below) looks incredibly confusing:-

rgb{
discard = spare0;
discard = spare1;
spare = sum();
}

rgb{
spare0 = spare1 * spare0;
}

Does that look readable to you? Being able to use the * operator, but not the +?
Someone new will look at that code and think, mmm…why are sums expressed differently than products? And then, bam! - they are then hit by the limitations of register combiners, so why express their operations as a language?
(I only do it to keep it consistant with everything else).

BTW, I’m using nv_vertex_program and register_combiners because I haven’t the time to read through the arb_vertex_program spec…it’s just too damn huge, and there simply isn’t the same volume of examples/tutorials on them as there are for NV ones. I also believe that the nv_vertex_program emulation on gf2< will be much faster than anything I can do in my own code, while keeping the interfaces in my own code cleaner.

I agree that the functions are easier to understand than the nvparse programs. But the main advantage to the nvparse programs is that you can change/compile them again and again at runtime. I wrote myself a parser for the actual function calls themselves (glCombinerInputNV… etc. actually in a text file), so I could change them at runtime, and this has worked very well for my applications. It is also a pain in the arse that you need to use nvidia’s own opengl sdk to link to nvparse - but that can actually be sorted out by commenting out all the nvidia init_extention calls in the nvparse source code - it will then link to your own entry points when you statically link it. Just be sure they’ve been correctly initialised at your end!

Originally posted by MichaelK:
And are there any platforms, where ARB runs in software (like NV on gforce2)?

sure, runs on all nvidia hw at least in software, as far as i know. not sure about the radeons older than 8500… anyone with an old radeon can check if the new drivers expose ARB_vertex_program?..

but on all more or less new hw, gf1+,radeon8500+,pathelia,p10, you get it, eighter hw or software. the rest, i don’t know…

but hey, every driver wich can do dx8 vertexshaders can do ARB_vertex_program as well…

does mesa yet have it? dunno…

but there is NO need to use NV_vertex_program anymore. it was just there because no standard was there yet. now, drop it.

for pixelshading thats another topic… if you want to be compliant for all hw of the current generation, use ARB_texture_env_XXX extensions only, like _dot3 and others…

if you want to support modern hw, nv30, >radeon9000 (9500 and 9700 for now), use ARB_fragment_program…

and, i hope soon, we get ARB_float_something, and ARB_fragment_program_multitarget or something like that… we’ll see…

Originally posted by inept:
[b]Well, no it isn’t much easier to read than the api calls, in my opinion. As I said, register combiners are just a way of mapping inputs to outputs through selecting which (out of a very narrow choice) maths operation you want it to perform on those inputs. The nvparse scripts seem to give users the idea that they can use something as simple as the + symbol to add two input registers together, when really they can’t. So code like this (below) looks incredibly confusing:-

[quote]

rgb{
discard = spare0;
discard = spare1;
spare = sum();
}

rgb{
spare0 = spare1 * spare0;
}

Does that look readable to you? Being able to use the * operator, but not the +?
Someone new will look at that code and think, mmm…why are sums expressed differently than products? And then, bam! - they are then hit by the limitations of register combiners, so why express their operations as a language?
(I only do it to keep it consistant with everything else).

BTW, I’m using nv_vertex_program and register_combiners because I haven’t the time to read through the arb_vertex_program spec…it’s just too damn huge, and there simply isn’t the same volume of examples/tutorials on them as there are for NV ones. I also believe that the nv_vertex_program emulation on gf2< will be much faster than anything I can do in my own code, while keeping the interfaces in my own code cleaner.[/b][/QUOTE]

you got me wrong. it’s not a scriptlanguage, nothing against cg or something like that. but once you know registercombiners, you can set them up much faster and more easy with the nvparse language for them (and runtime change them even, hehe… who ever needs that)…

and yes, it’s more readable than 5 nearly fullscreen lines of GL_XX_NV capslockconstants…

but you have to know register combiners. they are never easy… but typing all that functioncalls is just… hm… do you set them up that way? dunno, but once i wanted to do perpixellighting with smooth selfshadowing, specular with glossmap and exponentmap, all on the gf2 in one pass, hehe. and power16 for the specular as max… so i had to do a lot of cheating, of course… that was simplest on a paper with some math formulae. then i rewrote it so that it fit into the combiners. you really think it’s more easy with the functions then? i had no nvparse then yet to use, so i had to use functions… and it took quite some time…

btw, for all the dudes that think register combiner setup with functions is readable, i just want to let you one time read the nvidia demo wich does high precision shadow mapping (16bit) on <gf3 hw…

now tell me those screens over screens of different combiner settings are readable

and the rest is just training…

There certainly is a good reason to use NV_vertex_program, at least in the world of real shipping software: plenty (likely millions!) of end users probably have drivers old enough that ARB_vertex_program isn’t supported. A second reason might be that it is a very, very close match to DX8, and so converting DX8->NV_vp or NV_vp->DX8 is pretty darn easy.

Excluding that, though, I’d probably stick to ARB_vertex_program, though I’d stay away from some of its features.

Of course, NV_fragment_program and NV_vertex_program2 are another story entirely. Both are very substantial supersets of what the ARB extensions can do.

  • Matt

arb_vertex_program is only supported in the beta drivers, as far as I know…or is there a new release version that I don’t know about?

Which features of ARB_vertex_program should we stay away from Matt, and why?

I dont suppose you can probably answer that tho… IF not a little confidential email would be nice. Would be nice to know about any problems this spec has on certain hardware.

Thanks,
Nutty

Originally posted by mcraighead:
[b]There certainly is a good reason to use NV_vertex_program, at least in the world of real shipping software: plenty (likely millions!) of end users probably have drivers old enough that ARB_vertex_program isn’t supported. A second reason might be that it is a very, very close match to DX8, and so converting DX8->NV_vp or NV_vp->DX8 is pretty darn easy.

Excluding that, though, I’d probably stick to ARB_vertex_program, though I’d stay away from some of its features.

Of course, NV_fragment_program and NV_vertex_program2 are another story entirely. Both are very substantial supersets of what the ARB extensions can do.

  • Matt[/b]

how about simply providing proper minimum drivers with your software? most games i know ship for example dx with, why not drivers for the known supporting gpu’s?

and in realworld, there is not only nvidia, matt. so please don’t try to get people using your proprietary extensions in situations the arb provides a just as good tool for most situations. and mapping to arb_vertex_program from dx vertexshaders is just as easy.

the arb_vertex_program is superior in usage as well.

and nvidia should finally provide a fragment_program profile for cg. as they want cg to be a real standart, its their job to get it working on real platforms…

i know at least that my code runs on your platforms as well. can you tell this from your “realworld apps using nvidia proprietarity?”

Originally posted by davepermen:
sure, runs on all nvidia hw at least in software, as far as i know.

Don’t forget do put a “on Windows” at the end of such statements: it will prevent me to rush on the Linux drivers page at nvidia.com :’(

Julien.