Manta Interactive Ray Tracer Development Mailing List

Text archives Help


[Manta] Re: RE: Re: Some observations


Chronological Thread 
  • From: Abe Stephens < >
  • To:
  • Subject: [Manta] Re: RE: Re: Some observations
  • Date: Thu, 9 Oct 2008 14:49:32 -0600


On Oct 9, 2008, at 1:20 PM, Bo Huang wrote:

1)
If working with SingleSampler, a ray packet corresponds nicely to an 8x8 pixel area on screen. Thus for any ray index A in the packet, I know its top, down, left, right neighbors: A+8, A-8, A-1, A+1, mindful of modulo math of course. (Being unfamiliar and lack of docs, I do not yet know if neighbors can be inferred with other cluster, jittered, and etc. samplers)

There are no conventions for the shape of packets. In some instances, especially when frustum techniques are employed, square or rectangular packets are used, in other cases the packets might be long and skinny (on one platform 32x2 packets were the most efficient).

Also the shape of packets for secondary effects (reflections, shadows, etc.) is determined by code in the individual shaders.  Some of it is modular, for example there is a single ShadowAlgorithm which traces rays, but individual materials don't share a standard hemispherical sampler, etc.

In my own work I've gotten around this by either writing my own shaders (by modifying the existing ones), or only using a small number of difference configurations where I know how primary rays will be mapped to the image.

 Let’s say the first 32 rays in the packet intersect a plastic geometry and are each assigned the plastic material, and the latter 32 rays intersects nothing (the background). Because the Background is not a Material, the latter 32 rays do not get any assignment and their hitMatl remain the un-initialized 0xcccccccc.

The material pointers for active rays in a packet (between rayBegin and rayEnd) should be initialized to zero by a call to resetHits() for example the call on line 52 of Renderers/Raytracer.cc.... (see below)

Hence calling wasHit( 31 + 8) returns true, which is erroneous. resetHits() would be of limited use since it does not initialize the rays outside the packet’s begin and end indices. And resetting all 64 rays would wipe out calculated data.

The issue here is that, by design, the API doesn't provide information about rays outside of a ray packet.

In the code, the RayPacket is a set of flags and a rayBegin and rayEnd interval, while the RayPacketData structure contains the actual ray information.  Rays outside of this range might be uninitialized or belong to other ray packets.  Each thread allocates RayPacketData structures on the stack and passes the light weight RayPacket structures throughout the interface.

Consider how the material shader is invoked in Raytracer.cc, the code finds runs of ray that intersect the same material, and creates subpackets containing these rays. In the example you gave above, the plastic shader would get a subpacket containing rays 0-31, but if you access memory outside the packet, there's no way to know what it will contain.

I guess there are two options (if I understand what you're trying to do): only operate with neighboring rays inside the active [sub]packet, or perform any operations that require a greater neighborhood of rays, after all of the packets/fragments/tiles that you need have been traced. Depending on what you're trying to do, the first approach is probably easier.




2)
I reverted back to my first revision, in which I hijacked the for(;;) in void RTRT::internalRenderLoop(int proc, bool lateComerFlag), and stuffed this infinite loop into a WinMain(). Too bad the artifacts still appear for the scenes, default or not. Maybe this change is to blame.
 
Other than that, no change to where it is called or transactions. No addition or modification of modules in that revision.
 

It's difficult to suggest a solution if you're working with a modified version of the pipeline... Maybe start debugging by turning off different sections of the pipeline to try and isolate where the artifact occurs (e.g. -renderer null, -imagetraverser null, etc.).



 
3)
Understood.
 
For the memory layout, we have a Vector class in Manta that handles x0y0z0, x1y1z1, … xNyNzN.
 
Similarly, I wonder if an imagined Vector_grouped_by_component class catered to handle x0x1x2…xN, y0y1y2…yN, z0z1z3…zN would make the code more readable. Then again as you pointed out it is probably unnecessary.

I completely agree that the SSE code is unreadable... the best approach would probably be to program in something like RTSL and let a compiler worry about turning your scalar code into vector code....


Abe







 
Hi,
 
Comments inline:
 
On Oct 8, 2008, at 1:46 PM, Bo Huang wrote:


1)
The wasHit() function for RayPacket works by checking if the material corresponding to a ray is null.
 
When a RayPacketData is constructed, it does not set the hitMatl member array to null. Thus sometimes I receive erroneous hitMatl values when I call wasHit() for neighbor rays in the same packet.
 
Hence I explicitly added a memset to zero out hitMatl in RayPacketData’s constructor. It works for my purposes but perhaps there is a better way, knowing that under the current design perhaps one should not examine neighbor rays in the packet.
 
Call RayPacket::resetHits() first, see documentation in RayPacket.h.
 
I'm not sure what you mean by neighbor rays...?
 
2)
If I change
rtrt->changeNumWorkers(1);
to
rtrt->changeNumWorkers(2); //or more than 2
I get faster speed but the rendering becomes quite unstable. For example, some or most 64x64 tiles would be black periodically, even if the view is not changing. Or the tiles would overlap each other for some frames.
 
Does this occur for the default scene? If not which modules have you altered?
 
Also, are you using a transaction to call the method?
 


3)
I noticed at many places, vector math calculations are done like this:
 
// This is a vector multiplication
Real scale = 1/Sqrt(sum);
for(int j=0;j<3;++j)
data->normal[j][s] *= scale;
 
Why not expand this out to
            data->normal [0][s] *= scale;
            data->normal [1][s] *= scale;
            data->normal [2][s] *= scale;
 
The compiler is expected to unroll the loop.  Also, most fast code paths are implemented in SSE so this is probably a slow code path.
 
 
 
Or even wrap this around a vector library function vector_scale(float** normal, int idx, float scale) designed for data stored as
 
x0x1x2…xN, y0y1y2…yN, z0z1z3…zN
rather than
 
x0y0z0, x1y1z1, … xNyNzN
format?
 
The memory layout of normal[3][MaxSize] is the former. 
 
Abe
 




Archive powered by MHonArc 2.6.16.

Top of page