2
$\begingroup$

How to check whether trace(ray,direction,...) collides the nearest face at front OR back side?

According to OSL: Anomalous normals returned by getmessage("trace"), these below codes won't work because it always return value as front-face (automatically flipped) from ray's perspective.

getmessage ("trace", "N", tN);
getmessage ("trace", "Ng", tNg);

The same link suggests that backfacing() is the solution.
However, it doesn't work. I will show a test case below.

I have 2 cubes.

enter image description here

Here is my OSL shader of CubeA.
For every point of CubeA, shoot +z ray, and check whether the ray touches CubeB at CubeB's back-face (return green) or front-face (return red).

#include "stdosl.h"
shader tN_anomaly
[[ string help = "" ]]
(      
    output vector hitBackfacing = vector(0,0,0)
){
    hitBackfacing=vector(0,0,0);  
    if (trace(P,vector(0,0,1))){
        string tObj;
        getmessage ("trace", "geom:name",tObj);
        if(tObj=="CubeB"){
            hitBackfacing=vector(1,0,0);
            if(backfacing()){
                hitBackfacing=vector(0,1,0); //: never reach
            };
            
        }
    }

}

The below image is the result. It suggests that backfacing() always return false.
It looks like to me that the backfacing() just cares about whether it is back-face from eye perspective, not from the most recent trace()'s perspective.

Left image = they are overlapping each other. (The correct result should be green.)
Right image = CubeB is above CubeA (not touching) enter image description here

Here is my blend file.

Here is another blend file. It is very similar, but I stretch Cube2 in x&y axis to cover the whole Cube1. It also prints log z which > 1.

$\endgroup$
6
  • 1
    $\begingroup$ I'm stumped. The information we need is backfacing, as determined by the clockwise / anticlockwise order of vertices around the polygon containing the shading point, from the ray's POV. The only way I can find of accessing this information is via the backfacing() function, but that can only be called on the shaded P, not on a P we hit ourselves, with a probing ray. I've tried vertex locations, dPdu,dPdv.. .... all sorts. $\endgroup$
    – Robin Betts
    Commented Jul 1, 2020 at 18:15
  • 1
    $\begingroup$ @Robin :: Thank. It gives me some idea. Perhaps "geom:trianglevertices" might be useful. I am investigating. docs.blender.org/manual/en/2.79/render/cycles/nodes/osl.html ... yea, look like it works. $\endgroup$ Commented Jul 2, 2020 at 1:43
  • 1
    $\begingroup$ @Robin I can use clockwise/counter-clockwise check (cross-product). In my simple test, it works. Thanks. $\endgroup$ Commented Jul 2, 2020 at 5:47
  • 1
    $\begingroup$ @Robin Here is the nutshell : point ps[3]; getmessage("trace","geom:trianglevertices",ps); vector trueNormal= cross(ps[1]-ps[0],ps[2]-ps[0]); I need to test more. $\endgroup$ Commented Jul 2, 2020 at 7:18
  • 1
    $\begingroup$ Fantastic. Example here $\endgroup$
    – Robin Betts
    Commented Jul 2, 2020 at 8:50

1 Answer 1

2
$\begingroup$

This is really @cppBeginner's answer to his own post.. (see commentary on OP).

The backfacing() function can be called on the implicit shading point in an OSL script, but is not available as an attribute returned in a message from a script-cast ray.

But many mesh and object attributes can be returned by OSL's trace(). See getmessage ("trace", ...) in the OSL specification.. this page of Blender source might help with types, etc.. (but that's only a grep, I don't strictly know how it ties in. Maybe someone can edit to flesh that out.)

These attributes include geom:trianglevertices, which is an array of three 3D points: the coordinates in World space of the corners of the render-triangle containing the shading point. They appear to be in order, so the cross-product of two edges can be taken to find the direction of the triangle's normal, as defined by the mesh.

#include "stdosl.h"
shader Hit_Backfacing
(    
    vector RayDir = vector(0.0),
    output int Hit = 0,
    output int Hit_Backfacing = 0
){
    if (trace(P,rayDir)){
    
        Hit = 1;  
        vector triNormal = vector(0.0);
        point  triVerts[3];
        
        getmessage("trace","geom:trianglevertices",triVerts);
        triNormal = cross(triVerts[1]-triVerts[0],triVerts[2]-triVerts[0]); 
        
        Hit_Backfacing = dot(triNormal,rayDir) > 0;    
    }
}

In this example, the sign of dot-product of that normal and the cast ray direction tells us whether the triangle we hit faces us, or not...

enter image description here

The large plane carries the illustrated material.

$\endgroup$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .