Re: negative z coordinates



On Aug 3, 7:06 pm, Andy V <Nob...@xxxxxxxxxxx> wrote:
b...@xxxxxxxxxxxxxx wrote:
BTW, is this a decent prototype for a near-clip function?

vector<Triangle> NearClip(const Triangle& tri);

I would generate a triangle fan (polygon) rather than a vector of triangles.
Triangle fans (and strips) are important to handle efficiently.

If it's a software rasterizer, it doesn't optimize much. If he works
with vertices, he could do something like this:

int clip(vertex* out, vertex* in);

return value is number of vertices after clipping. "in" always has
three vertices (or more, then add argument for the count). This way he
can easily use the result in many different ways.

If he does software rendering, he might want to transform the whole
vertex array in one pass, computing outcodes and what not (what ever
approach he uses). The primitives could be indexed, it's the most
effective way anyhow. Then he would clip indexed primitives and write
back the clipped vertices at end of the vertex array (he must make
sure there is spare space at the end, and use these indices later in
the pipe).

Then, after clipping project and map the vertices that contribute to
visible triangles (eg. "visible" vertices), that would save some
processing cycles.

Cons of that approach is multiple read-modify-write passes over the
same data --> not so good with the cache. The Pro would be that shared
vertex indices would be processed only once.

Sharing the clipping workload is more difficult because you would
require edge connectivity information, plus it would be complicated to
track the new clipped vertices; the ones that cross only one boundary
are easy but corners and vertices resulting from *new* edges created
from clipping would be more difficult to handle. Not worth the effort
often enough, profiling with typical datasets that go through the pipe
usually tell that very small amount of primitives are clipped (lots of
screenspace-small primitives).

If the primitives are large and there is small number of then, the
fragment innerloop dominates runtime anyway.

Clipping is bottleneck only if you got large # of primitives and
rasterizer is very fast. That's not problem too often with software
rendering. :) :)

The triangle setup code might even overshadow the transform-clip-
project-etc. already all on itself, it depends a lot on the techniques
being deployed doesn't it? :)

Of course, the clipper can be inefficient/slow.. that's another story,
then the argument passing method isn't as relevant anyway. IMHO; all
things considered, treating the primitive as array-of-vertices is
straightforward and efficient. If you got N-vertex primitive coming
out of the clipper, it's planar, that we know for a fact, so we can do
a lot of neat stuff with that information: we can do the triangle
gradient computation for the unclipped triangle (remember,
barycentrics are clipped and they refer to the *original* triangle's
vertices!!!) so we can just scanconvert N-vertex polygon and treat it
as-if it were a triangle, so we don't even have to split the primitive
into lots of triangles and feed them separately to our rasterizer.

Rasterizer can handle the polygon (if it's result from clipped
triangle) quite nicely with that approach. Scanconversion with
polygons is slightly more complicated than for triangles, but it's
simple enough if you find the minimum-y vertex, and start scanning
from that one. If you have specific CW/CCW order for the vertices
(which you do, remember original input was a triangle) if you walk to
one direction in the array, you going left side of the polygon and
other direction in the array is the right side. Makes scanconverter
for polygons simple enough. Triangle is *much* simpler, but not so
much that you shouldn't have separate scanconverter.

Then if you do the gradient setup same way for triangle and polygon
(from clipped triangle), the outline should be something like this:

void polygon(const vertex* in, int count)
{
trisetup(in);
int y = compute_min_y(in,3);
edge left = ...;
edge right = ...;
for ( ;; ++y )
{
scan(left, right, y);
left.update(y);
right.update(y);
if ( left.y == right.y ) break; // i put this here for
illustration, there is nicer place.. spot it! :)
}
}

void triangle(const vertex* in)
{
trisetup(in);
int y = compute_min_y(in,3);
...
}

The big difference comes from trisetup(), I'm already too lazy to go
back and edit this post, but the idea is that for "polygon" you feed
the original vertices.. so they come in as separate array, and pass
that to the setup instead.

If you want the setup to do backface cull (like you haven't already?),
it can return bool and you go out based on that, or you do the setup
*before* calling the triangle() or polygon() rendering code; that's
quite simpler as you can then see the original vertices much better w/
o passing them around as function arguments, plus then the rendering
code is more uniform too.

There's lot of design choises going around and can't really recommend
one-fits-all solution, you have different parts of the code and how
you want input to be arranged and so on. Usually it's a good rule-of-
thumb to try to arrange the input so that it's efficient to use w/o
moving it around any extra cycles around the block so to speak. But
that should just be a one of many considerations not the primary
design factor, of course.

Indexed primitives. Well. Yeah. I wouldn't get too hung up on those
with software rasterizer. The primary reason is that we can share
vertices w/o kludges like strips (fans are a joke for generic meshes),
so it should be mostly transformation (or vertex shading) related
issue. In hardware terms this means that usually vertex caches work
with indices; they basically do index-lookup and that's it. For SW
transformation we don't have custom silicon for the lookup, it's
actually executing instructions serially with the ALU so that's not
practical, so doing the transform-array-range-at-one-pass is pretty
nice workaround as it's also SIMD friendly to process more elements
simultaneously (if possible).

....

I'm kind of thinking that I'm sort of ranting for no good reason here,
Andy V + fungus already know all this and the OP propably just ignores
everything I type since there's too fucking much of it. *sigh*

.