I am trying to learn how to program the register combiners on my GeForce4 Ti4200 card using nvparse. So far, I’ve found lots of sample code and PPT presentations (in the nvOpenGLSDK), but almost no official documentation of the RC language understood by nvparse.
I was wondering if someone on this forum could help me clarify a few sticky points.
- What does expand(…) do?
In the code below:
// Specular Lighting (N’•H)
// tex0: normal map (N’)
// tex1: normalization cube-map (H)
!!RC1.0
{
rgb {
spare0 = expand(tex0) . expand(tex1); // NdotL
}
}
out.rgb = spare0; // auto clamped to [0,1]
I assume that expand(tex0) means that it will treat the 32-bit entity tex0 as a 4-element entity (a “vector”) for the purposes of computing the dot product. Is this accurate? If so, how is the dot product computed: is it just the sum of the pairwise products of R, G, B and A components of the two “vectors”? Is the resulting value “clamped” in any way?
- When is the output “auto-clamped”?
The comment on the last line in the code above indicates that the output “auto-clamped to [0,1]”. How is this auto-clamping actually computed? Does this happen only for dot-product computation? What does it mean to assign a value in the range [0,1] to out.rgb (which expects a 32-bit entity, composed of R,G,B,A)?
- When should unsigned(…) be used?
In the code below:
// Specular Lighting (N’•H)^4
!!RC1.0
{
rgb {
spare0 = expand(tex0) . expand(tex1); // NdotH
}
}
{
rgb {
spare0 = unsigned(spare0) * unsigned(spare0);
}
}
final_product = spare0 * spare0;
out.rgb = final_product;
In the 2nd combiner stage, why is spare0 squared as unsigned(spare0) * unsigned(spare0) instead of spare0 * spare0? unsigned(…) seems to clamp the value to the range [0,1]; if unsigned(…) is not called, what is the range for spare0?
- How should discard be used?
In the code below:
{ // normalize V (step 1.)
rgb {
spare0 = expand(col0) . expand(col0); // VdotV
}
}
{ // normalize V (step 2.)
rgb {
discard = expand(col0); // V in [-1…1]
discard = half_bias(col0) * unsigned_invert(spare0);
col0 = sum();
}
}
Why is discard assigned twice, in the 2nd combiner? From reading another PPT (on texture blending using combiners), it seems that discard is a write-only register; how is discard actually used?
If there is some detailed nvparse() documentation available somewhere, please point it out.
Thanks in advance!
Razvan.