There's a well-known ambiguity in the SL grammar concerning arrays and
texture channels:
string mapnames[10];
string name = mapnames[2]; // 2 is an array subscript
Ci = texture("map.tex"[3], s, t); // 3 is a texture channel
Ci = texture(mapnames[2], s, t); // ambiguous - what is 2?
The first mention of this ambiguity and how to resolve it came in the
PRMan do***ent "RenderMan Shading Language Extensions":
[T]he existing square bracket notation in the texture call for channel
number identification is syntactically ambiguous with the use of
string array elements for texture names. This will be handled by
defining that if an element of a string array is used as a texture
name, the channel number is *not* optional.
My interpretation of this paragraph is that two sets of square brackets
are required whenever using an array for the texture name:
Ci = texture(mapnames[2][3], s, t); // array element 2, channel 3
Course notes from "Advanced RenderMan - Beyond the Companion" (SIGGRAPH
1998 and 1999) have something different to say:
This is handled by defining that if an element of a string array is
used as a texturename, the string array element dereference must be
contained within parenthesis [sic]. Any square bracket notation
outside
the parenthesis is syntactically defined to be the channel number.
The book "Advanced RenderMan" takes it further with an example:
string filenames[10];
Ci = float texture ((filename[i])[1], s, t);
In this example, we have an array of strings, and we are accessing
channel 1 from the 'i'th filename. To avoid ambiguities, we have
surrounded the filename specifier by parentheses, clearly delineating
the array access (inside the parentheses) from the channel selection
(outside the parentheses).
These really are two different solutions to the same problem. The latter
is strictly syntactic (user must disambiguate with parentheses) whereas
the former suggests some semantic processing by the shader compiler.
I checked a recent version of PRMan and found that it uses the latter
(although the do***entation still describes the former, which does not
compile). One side benefit of the syntactic solution is that you can
use any expression that evaluates to a string as long as you enclose it
in parentheses:
string getname(string s) { return format("map%s.tex", s); }
Ci = float texture ((getname("back"))[1], s, t);
While trying to decide how best to handle this for the next release of
RenderDotC, I realized that you can have it all! My solution handles
the following shader:
surface ambiguous()
{
uniform float x;
uniform string mapname = "map.tex";
uniform string texnames[10];
string getname(string s) { return format("map%s.tex", s); }
Ci = texture("map.tex");
Ci = texture("map.tex"[1]);
Ci = texture(("map.tex")[1]);
Ci = texture(mapname[1]); // mapname not array - that's channel
1
Ci = texture((mapname)[1]);
Ci = texture(texnames[4]); // array element 4 - default to
channel 0
Ci = texture(texnames[4][1]); // array element 4 - channel 1
Ci = texture((texnames[4])[1]); // parentheses are optional
Ci = texture(getname("back"));
Ci = texture(getname("back")[1]);
Ci = texture((getname("back"))[1]);
Ci = texture((texnames[5] = mapname)[1]); // parens required
Ci = texture(x < 0 ? "neg.tex" : "pos.tex"); // default to
channel 0
Ci = texture(x < 0 ? texnames[0] : texnames[5]);
Ci = texture((x < 0 ? "neg.tex" : "pos.tex")[1]); // parens required
Ci = texture((x < 0 ? texnames[0] : texnames[5])[1]);
}
Note that parentheses are rarely required. The trick is to leave the
ambiguity explicit in the syntax and to resolve it during type checking
(hat tip to Andrew Bromage, personal communication, 2000).
Rick LaMont
Dot C Software, Inc.
http://www.dotcsw.com/


|