-
Notifications
You must be signed in to change notification settings - Fork 50
####POLYGON CLIPPING AND BACK FACE CULLING
It is a shame. Puresoft3D does not have a polygon clipper. I did not realize I do need a polygon clipper until, days ago, I implemented camera-moving in a demo programme. When camera got very close to a silly small sphere, the damn ball suddenly became a huge monster like a transformer. I spent quite a lot of time on investigating the issue, finally I figured out that, when one or more vertices moves to ‘the back’ of the top point of the projection frustum, the projection matrix, together with the perspective division, would probably make wrong calculation result. If a triangle stands across that top point, after projection, parts of it would still be inside the frustum. But due to the wrong projection position(s) of its out-side-of-frustum vertex(ices), the triangle part standing inside the frustum would be in wrong shape. So only the depth removal mechanism cannot save me from such case, I do need a polygon clipper.
It is too late for me to implement it prior to the planned publish date of this project, so I have to put this function in the wish list. In the current code, I just simply throw a triangle away as long as one of its three vertices is found outside the frustum. In most scene where triangles are usually tiny, this approach seems suffice. Yet I know that if I move camera towards a giant triangle, the triangle will disappear at wrong time.
The poor ‘clipping’ code currently used is like below.
// vertex transformation
if(!processVertices(vaoObj->getVBOs(), m_vertOutput, . . .))
{
// done with all vertices
break;
}
// cull back-face
if((m_behavior & BEHAVIOR_FACE_CULLING)
&& isBackFace(m_vertOutput[0].position, m_vertOutput[1].position, m_vertOutput[2].position))
{
continue;
}
// an arbitrary polygon clipper
if(m_vertOutput[0].position[2] < -1.0f || m_vertOutput[0].position[2] > 1.0f)
continue;
if(m_vertOutput[1].position[2] < -1.0f || m_vertOutput[1].position[2] > 1.0f)
continue;
if(m_vertOutput[2].position[2] < -1.0f || m_vertOutput[2].position[2] > 1.0f)
continue;
I know checking z toward (-1, 1) makes it even more silly, because the check should better happen before perspective division, right? But just leave it here until I implement real clipper some day. Checking z towards (-w, w) prior to perspective division will not make it less silly I guess.
Well, the following is my back face detection code. Not optimised but intuitive.
bool PuresoftPipeline::isBackFace(float* vert0, float* vert1, float* vert2)
{
// determine back face in naive way :-(
__declspec(align(16)) float vec0[4], vec1[4], cross[4], test[4] = {0, 0, 1.0f, 0};
mcemaths_sub_3_4(vec0, vert1, vert0);
mcemaths_sub_3_4(vec1, vert2, vert1);
mcemaths_cross_3(cross, vec0, vec1);
mcemaths_norm_3_4(cross);
return (mcemaths_dot_3_4(test, cross) < 0);
}
(I have not yet explained the mcemath_XXX functions, please guess their purpose by the names)