I am working on translating a series of light and surface shaders from 3Delight to PRMan, and I have discovered a difference between the two that I cannot work out. It seems that when a surface shader is being evaluated for transmission opacity due to a trace in a light shader, the incident vector I
in PRMan is being set to the surface's normal.
In my example scene, there is a hemisphere floating above a disc. A distant light from above is projecting traced transmission values onto the surfaces behind them (a little backwards for a light, but this is a demo). The surface on the hemisphere is rendering as a solid coloured by its normals when viewed by the camera, but with the opacity of the incident direction when queried for transmission.
This is what I expect it to look like, and what I receive from 3Delight:
Note that the floor is solid nearly pure green; the colour we would expect if the incident angle is vertical. However, this is what I receive when I render the exact same scene with PRMan:
It appears to be projecting the normals.
I have attempted fetching values via rayinfo
and calculating a new I
, but those values all match with what I
is actually set to. I have also noticed discrepancies with E
, but I have not been able to nail down what it is being set to in PRMan.
Q: How can I get the incident vector `I that I am expecting?
Contents of scene.rib
:
Display "falloff.tiff" "framebuffer" "rgba"
Projection "perspective" "fov" [17]
Format 400 400 1
ShadingRate 0.25
PixelSamples 3 3
# Move the camera
Translate 0 -0.65 10
Rotate 30 -1 0 0
Option "searchpath" "string shader" ".:&"
WorldBegin
LightSource "projector" "projector_light"
"point to" [0 -1 0]
Surface "matte"
TransformBegin
Rotate 90 1 0 0
Disk 0 1.25 360
TransformEnd
Surface "inspect_incident"
Attribute "visibility" "integer transmission" [1]
Attribute "shade" "string transmissionhitmode" "shader"
TransformBegin
Translate 0 1 0
Rotate -90 1 0 0
Sphere 1 0 1 360
TransformEnd
WorldEnd
Contents of projector.sl
:
light projector(
float intensity = 1;
color lightcolor = 1;
point from = point "shader" (0,0,0);
point to = point "shader" (0,0,1);
float maxdist = 1e12;
) {
uniform vector dir = normalize(to - from);
solar(dir, 0.0) {
Cl = intensity * lightcolor * (1 - transmission(Ps, Ps - dir * maxdist));
}
}
Contents of inspect_incident.sl
:
class inspect_incident() {
public void opacity(output color Oi) {
vector In = normalize(I);
Oi = color((In + 1) / 2);
}
public void surface(output color Ci, Oi) {
vector Nn = normalize(N);
Ci = color((Nn + 1) / 2);
Oi = 1;
}
}
Quoting the documentation for the special
__computesOpacity
parameter of surface shaders:And quoting Brian from Pixar: