Skip to content

cc in Chinese

agedboy edited this page Apr 14, 2016 · 1 revision

#多边形剪裁 & 背面剔除
遗憾的是,Puresoft3D目前没有多边形剪裁程序。

我一直没有意识到多边形剪裁的重要性,直到几天前我给DEMO程序增加了移动摄像机的功能。当摄像机距离一个小球非常近时,那该死的小球突然变形成了怪物。我花了很长时间调查问题,最后发现当一个三角形,有些顶点在视锥的内部,有些落在视锥尖端的“后面”的时候,透视投影矩阵和透视除法会制造出完全错误的投影形状。而这种错误的投影形状的一部分是落在投影平面里面的,xyz都拥有合法的值,所以没有别的方法拯救这种状况,必须先剪裁再投影。

我意识到的太晚了。为了按计划时间在这里公布这个项目,我只得暂时舍弃多边形剪裁,用一个临时的workaround来解决这个问题:投影变换和透视除法之后,只要一个三角形有一个顶点不在合法范围内,就舍弃该三角形。这样当摄像机接近物体时,物体可能会一块一块的过早的消失,但总好过变成怪物充满整个画面。

所以目前的“剪裁”代码如下:

// 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;

我知道检测透视除法之后的坐标是否在(-1,1)区间的做法使上面代码看起来更加“水”,你可能会觉得至少在剪裁空间里检查(-w,w)区间会更好一点。我觉得都差不多愚蠢,还是等将来有时间完成真正的剪裁程序吧。

好了,下面我的质朴的背面剔除代码。人们说用“有符号面积”法会更快一点,以后有空试试。

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);
}

(我还没有解释过那些以“mcemaths_”开头的函数,其作用请你照字面意思猜猜看吧)

返回“我们的图形管线”

返回“我们开始吧”
返回总目录

Clone this wiki locally