RenderMan incident vector inconsistencies

276 views Asked by At

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:

3Delight Render

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:

enter image description here

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;
    }

}
1

There are 1 answers

0
Mike Boers On BEST ANSWER

Quoting the documentation for the special __computesOpacity parameter of surface shaders:

A value of 0 means that the shader does not compute opacity (i.e Oi == Os). This can be used to override a transmission hit mode of shader. For such shaders, the opacity() method will be skipped for transmission rays.

A value of 1 means that the shader does indeed compute opacity. Such shaders will be run to evaluate their opacity for transmission rays. That result may be cached by the renderer, and thus must be view-independent.

A value of 2 means that the shader computes opacity in view-dependent manner. As such the renderer will avoid caching opacity for transmission rays. The opacity is still cached for the purpose of controlling continuations on diffuse and specular rays, but view-dependent shadows may be generated using areashadow() or transmission(). For mode 2, the opacity() method must only depend on view-dependent entities within a check for raytype == "transmission"..

And quoting Brian from Pixar:

Set it to 2 to do what you want. What you're seeing is the render runs opacity once with the domes' I, and caches that.