3
$\begingroup$

I'm writing an OpenGL application that runs on a Raspberry Pi, i.e., a quite resource-limited system. Essentially, a few quads with RGBA textures are overlayed/alpha blended on top of each other with individual translation/rotation applied. They are clipped against an unrotated rectangle.

For this purpose, I currently use the stencil buffer. I.e., when drawing a texture which requires clipping, I clear the stencil buffer, render the clipping quad to the stencil buffer and enable the stencil testing before rendering the translated/rotated object.

On a Pi, clearing the stencil buffer is a painfully slow process in the order of 20ms, completely ruining performace. I thought about pre-rending the clipping rects to different bits of the stencil buffer, but that would lead to a maximum of 8 clipping regions (I need more).

Therefore, is there a different way of achieving clipping against a simple rectangle that does not require an expensive operation such as flushing the stencil buffer?

$\endgroup$
1
$\begingroup$

It sounds like what you need is a scissor test. It's specifically designed for clipping against an unrotated rectangle, and should be faster than messing about with the stencil buffer.

$\endgroup$
  • $\begingroup$ This works perfectly and is extremely fast, even though the GL driver of my Pi does not advertise ARB_viewport_array. Thank you! $\endgroup$ – Jonas Mechtheim Dec 18 '17 at 10:12
0
$\begingroup$

You could try clipping the polygons in code before you send them off to the renderer. Then you could avoid the stencil buffer entirely. To do this you could clip against all sides of the rectangle one at a time. I can't say for sure if this is faster than what you were doing before but here goes:

For this algorithm you need to represent a polygon as a list of points

How to clip against one side:

# careful of array out of bounds access
k = -1
# find first instance where a vertex is outside followed by one that is inside
for(i = 0; i < verts.length; ++i)
    if(isOutside(verts[i]) && !isOutside(verts[i + 1]))
        k = i
# if no such instance found
if(k == -1)
    if(isOutside(verts[0])) # entire thing outside
        return empty array
    else # entire thing inside
        return verts # return unchanged
# if instance was found
else
    newVerts = empty array
    # add first vertex in new shape
    newVerts.add(intersect(verts[k], verts[k + 1]))
    # walk the part of the polygon that is inside
    while(!isOutside(verts[++k]))
        newVerts.add(verts[k])
    # add last vertex in new shape
    newVerts.add(intersect(verts[k - 1], verts[k]))
    return newVerts

Then you could do something like:

poly = clipLeftEdge(poly)
poly = clipRightEdge(poly)
poly = clipTopEdge(poly)
poly = clipBottomEdge(poly)

If the the original polygon was convex then the new one should be as well which means you could triangulate it or whatever you need before you draw.

A line which forms an edge of the clipping rectangle (if you extend it to be infinitely long) splits the entire space into 2 half spaces. You will need to provide a function to check whether a vertex is in the "inside" half space or the "outside" half space. Ex: left edge of rectangle is at x = -15. To check if the point is outside, do (point.x < -15).

You will also need to provide a function to intersect 2 vertices. You have one vertex on the outside and one on the inside and somewhere in between there is a line that you want to clip against. For example if the left edge of the rectangle is at x = -15:

factor = (-15 - p1.x)/(p2.x - p1.x)
newVertex.x = -15
newVertex.y = (p2.y - p1.y)*factor + p1.y

You will also need to linearly interpolate all other attributes you care about (like texture coordinates).

If you want to be really slick, you can write the clipping algorithm once and provide an appropriate isOutside and intersect function for each run.

$\endgroup$
0
$\begingroup$

As per Russ's answer, I'd also suggest using scissor rectangles but, on the off-chance that is also slow, is it possible to use the Z buffer to set the Z to "near" in the regions you don't want drawn?

BTW, it would be useful to have an example image.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.