Sign in to follow this  

Rendered image gets inverted on my software renderer

Recommended Posts

I recently coded a wireframe renderer which use GDI calls and a little help from MESA project.
The code is here.
 
It has a bug: 
When the camera comes close to the mesh the application gets non responsive.
and the rendered image gets inverted when the camera move past the mesh.
When i turn on z buffering it doesn't happen.
 
Hints for testing:
To move camera:
(UP arrow key)
To turn on z buffering:
(search for "vp.scr->EnableDepthCheck(false);" and make 'false' to 'true' )
 
I am facing this bad bug for a month. 
I have no clue how to solve it. 
 
This project aims undergraduate students for teaching them the fundamentals of 3D graphics.
So your help is greatly appreciated.
 
Thanks in advance.
 

Share this post


Link to post
Share on other sites

I'd say this sounds about right.
When you get close to the mesh there are more GDI (SetPixel?) calls. (Very slow design with limited fill rate)
And the inverted image would be expected when moving the camera past the object. (Nature of matrix math)

I would suggest dropping GDI at least for frame buffer actions.
An alternative is presented in week one of this series link: HandMadeHero Episodes

 

Teaching 3D with GDI is a disservice, in my opinion.

Share this post


Link to post
Share on other sites

Sounds like you are projecting triangles that are behind the camera. Are you clipping them at the near plane? The slow down could be because the reverse projection is generating a lot of triangles that turn fullscreen. And or invalid floating point numbers due to divide by zero?

Share this post


Link to post
Share on other sites

You need to do frustum clipping as well, otherwise the triangle may go out of the screen and written pixels end up in random memory.

Usually you clip against far and near plane, and the 4 frustum planes defining the screen edges (be careful with this - a single off screen pixel can cause memory corruption, and checkeng each pixel is not cool :)

So what you need first is a function to clip a triangle with a plane and the math to calculate the proper planes.

Share this post


Link to post
Share on other sites
@Goliath Forge
Thanks for clarifying that camera math is right.
GDI is slow. I used GDI because other alternatives like SDL, Direct2D etc. comes with a lot of boiler plate codes and extra libraries and DLLs. The students will have trouble downloading them and setting them.And the aim of this project is to teach implementing math behind modelling viewing and projection. I am not going to implement lighting, shading, texture mapping, etc. And for me the project is finished when I implement frustum culling.
 
 
@JoeJ
I had thought about frustum culling. But the thing holding me back was how to deal with triangles which are partially inside the view frustum. The readings on rendering pipeline say triangles are divided and new triangles are generated in that case. I don't know the algorithm for that. If I reject those triangles which are partially inside viewing frustum I think the rendered image might appear with holes.

Share this post


Link to post
Share on other sites
I had thought about frustum culling. But the thing holding me back was how to deal with triangles which are partially inside the view frustum. The readings on rendering pipeline say triangles are divided and new triangles are generated in that case. I don't know the algorithm for that. If I reject those triangles which are partially inside viewing frustum I think the rendered image might appear with holes.

 

Here is some example code to clip a polygon by a plane.

Basically it loops over the vertices, adds a new one for intersections and rejects outside vertices

int32_t ClipPolygon
(
const Polygon *pin, // initial polygon
const vec &plane, // clipping plane (4D vector: x, y, z, distance from origin)
Polygon *pout // resulting clipped polygon
)
    {
        if (pout->numAvailableVertices < pin->numVertices + 1)
            pout->Resize (pin->numVertices + 1); // clipping by plane can add only ONE vertex at maximum, so you should use a preallocated buffer with enough memory instead of dynamic allocation for realtime purposes

        int32_t i, curin, nextin;
        float curdot, nextdot, scale;
        Polygon::Vertex *pinvert, *poutvert, *nextvert;

        pinvert = pin->vertices;
        poutvert = pout->vertices;
        curdot = pinvert->pos.Dot (plane);
        curin = (curdot >= plane[3]);
    
        int32_t ret = -1; // assume inside

        for (i=0; i<pin->numVertices; i++)
        {
            nextvert = &pin->vertices[(i+1) % pin->numVertices];
            // keep if inside    
            if (curin)
            {
                *poutvert++ = *pinvert;
            }
        
            nextdot = nextvert->pos.Dot (plane); // test on what side of the plane the vertex is
            nextin = (nextdot >= plane[3]);
            
            if (curin!=nextin) // add clipped vertex if plane splits edge
            {
                assert (fabs(nextdot - curdot) > FP_EPSILON);
                ret = 1; // clipped or outside
                scale = (plane[3] - curdot) / (nextdot - curdot); // determinate where at the edge the new vertex is

                poutvert->pos = pinvert->pos + (nextvert->pos - pinvert->pos) * scale; // create new vertex

                poutvert++;
            }

            curdot = nextdot;
            curin = nextin;
            pinvert++;
        }

        pout->numVertices = int32_t(poutvert - pout->vertices);
        if (pout->numVertices < 3) return 0; // outside
    
        return ret;
    }

The code to clip against 6 frustum planes would like like this for instance:

Polygon temp[2];
temp[0]->Resize(9+8); // triangle against 6 planes, so max 9 vertices. But i add extra space due to paranoia (what if vertex is exactly on frustum edge or corner, would it generate 2 verts at the same spot?)
temp[1]->Resize(9+8);
 
foreach(scene triangle)
{
temp[0].FromSceneTrinagle(triangle);
 
if (!ClipPolygon (temp[0], clipPlane[0], temp[1])) continue; // skip if the cliped polygon is completely outside any plane
if (!ClipPolygon (temp[1], clipPlane[1], temp[0])) continue;
if (!ClipPolygon (temp[0], clipPlane[2], temp[1])) continue;
if (!ClipPolygon (temp[1], clipPlane[3], temp[0])) continue;
if (!ClipPolygon (temp[0], clipPlane[4], temp[1])) continue;
if (!ClipPolygon (temp[1], clipPlane[5], temp[0])) continue;
 
RenderPolygon(temp[0]);
}

Using polygons instead triangles avoids a lot of unnecessary edges, so they are faster for both clipping and rasterisation. Note that any polygon will be convex.

Edited by JoeJ

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this