标签:技术 错误 cli 通过 frame shader 应该 delete article
近期在写软渲染的时候碰到了一个问题. 假设视图空间里顶点在视点之后直接乘以投影矩阵会错误发生. 如图中绿色的点直接乘以投影矩阵会被投影到紫黑色的点上明显就不正确了:
所以须要又一次想个办法修补这个bug,因为近裁剪面后面的点都是看不到的,能够将这些点裁剪掉,而且生成新的顶点,就例如以下图这样:
另一种两个点在近裁剪面后面的情况:
紫色的两个点就是须要又一次生成的新顶点,然后将红色的顶点和紫色的顶点组成新面參与之后的光栅化步骤. 新顶点在视图坐标系的位置能够求解两条直线和z=-clipNear平面的交点得到,顶点的属性值能够通过和直线的头尾顶点进行插值得到. 一个面中的一个顶点在近裁剪面后将生成两个新面,两个顶点在近裁剪面后将生成一个新面,抛弃老的面,把新面提交给管线.
因为已知最多会生成两个面,预先分配两个面的空间,这样就不必频繁的操作内存了:
void initFixFace() { nFace1=new Face(); nFace2=new Face(); } void releaseFixFace() { delete nFace1; delete nFace2; }
int checkFace(Face* face) { bool failA=false,failB=false,failC=false; int nFail=0; if(face->clipA.vz/face->clipA.vw>-clipNear) { failA=true; nFail++; } if(face->clipB.vz/face->clipB.vw>-clipNear) { failB=true; nFail++; } if(face->clipC.vz/face->clipC.vw>-clipNear) { failC=true; nFail++; } if(nFail==3) return 000; else if(nFail==0) return 111; else if(nFail==2) { if(failA&&failB) return 001; else if(failA&&failC) return 010; else if(failB&&failC) return 100; } else if(nFail==1) { if(failA) return 011; else if(failB) return 101; else if(failC) return 110; } return 000; }
因为有两种情况,这边能够定义两个修补函数:
void fix1FailFace(VertexOut fail,VertexOut succ1,VertexOut succ2); void fix2FailFace(VertexOut fail1,VertexOut fail2,VertexOut succ);
然后依据之前的检測情况分别调用不同的修补函数:
void fixFaces(Face* face,int fixFlag) { switch(fixFlag) { case 011: fix1FailFace(face->clipA,face->clipB,face->clipC); break; case 101: fix1FailFace(face->clipB,face->clipA,face->clipC); break; case 110: fix1FailFace(face->clipC,face->clipA,face->clipB); break; case 001: fix2FailFace(face->clipA,face->clipB,face->clipC); break; case 010: fix2FailFace(face->clipA,face->clipC,face->clipB); break; case 100: fix2FailFace(face->clipB,face->clipC,face->clipA); break; } }
首先利用直线的參数方程和平面方程求出交点:
float z=-clipNear; VECTOR3D pFail(fail.vx/fail.vw,fail.vy/fail.vw,fail.vz/fail.vw); VECTOR3D pSucc1(succ1.vx/succ1.vw,succ1.vy/succ1.vw,succ1.vz/succ1.vw); VECTOR3D pSucc2(succ2.vx/succ2.vw,succ2.vy/succ2.vw,succ2.vz/succ2.vw); float param1=calcZPara(pFail.z,pSucc1.z,z); VECTOR3D interPoint1=calcParaEqu(pFail,pSucc1,param1);
float calcZPara(float v1z,float v2z,float z) { return (z-v2z)/(v1z-v2z); } VECTOR3D calcParaEqu(VECTOR3D vect1,VECTOR3D vect2,float param) { VECTOR3D result; result=param*(vect1-vect2)+vect2; return result; }
float sp=(pFail-interPoint1).GetLength(); float fp=(pSucc1-interPoint1).GetLength(); float sum=sp+fp; sp/=sum; fp/=sum;
VertexOut inter1; interpolate2v(sp,fp,succ1,fail,inter1);
void interpolate2f(float pa,float pb, float a,float b, float& result) { result=pa*a+pb*b; } void interpolate2v(float pa,float pb, VertexOut a,VertexOut b, VertexOut& result) { interpolate2f(pa,pb,a.x,b.x,result.x); interpolate2f(pa,pb,a.y,b.y,result.y); interpolate2f(pa,pb,a.z,b.z,result.z); interpolate2f(pa,pb,a.w,b.w,result.w); interpolate2f(pa,pb,a.wx,b.wx,result.wx); interpolate2f(pa,pb,a.wy,b.wy,result.wy); interpolate2f(pa,pb,a.wz,b.wz,result.wz); interpolate2f(pa,pb,a.ww,b.ww,result.ww); interpolate2f(pa,pb,a.vx,b.vx,result.vx); interpolate2f(pa,pb,a.vy,b.vy,result.vy); interpolate2f(pa,pb,a.vz,b.vz,result.vz); interpolate2f(pa,pb,a.vw,b.vw,result.vw); interpolate2f(pa,pb,a.nx,b.nx,result.nx); interpolate2f(pa,pb,a.ny,b.ny,result.ny); interpolate2f(pa,pb,a.nz,b.nz,result.nz); interpolate2f(pa,pb,a.s,b.s,result.s); interpolate2f(pa,pb,a.t,b.t,result.t); }
完整修补方法实现例如以下:
void fix1FailFace(VertexOut fail,VertexOut succ1,VertexOut succ2) { float z=-clipNear; VECTOR3D pFail(fail.vx/fail.vw,fail.vy/fail.vw,fail.vz/fail.vw); VECTOR3D pSucc1(succ1.vx/succ1.vw,succ1.vy/succ1.vw,succ1.vz/succ1.vw); VECTOR3D pSucc2(succ2.vx/succ2.vw,succ2.vy/succ2.vw,succ2.vz/succ2.vw); float param1=calcZPara(pFail.z,pSucc1.z,z); VECTOR3D interPoint1=calcParaEqu(pFail,pSucc1,param1); float sp=(pFail-interPoint1).GetLength(); float fp=(pSucc1-interPoint1).GetLength(); float sum=sp+fp; sp/=sum; fp/=sum; VertexOut inter1; interpolate2v(sp,fp,succ1,fail,inter1); float param2=calcZPara(pFail.z,pSucc2.z,z); VECTOR3D interPoint2=calcParaEqu(pFail,pSucc2,param2); sp=(pFail-interPoint2).GetLength(); fp=(pSucc2-interPoint2).GetLength(); sum=sp+fp; sp/=sum; fp/=sum; VertexOut inter2; interpolate2v(sp,fp,succ2,fail,inter2); nFace1->copy2FaceOut(succ1,inter1,inter2); nFace2->copy2FaceOut(succ2,succ1,inter2); } void fix2FailFace(VertexOut fail1,VertexOut fail2,VertexOut succ) { float z=-clipNear; VECTOR3D pFail1(fail1.vx/fail1.vw,fail1.vy/fail1.vw,fail1.vz/fail1.vw); VECTOR3D pFail2(fail2.vx/fail2.vw,fail2.vy/fail2.vw,fail2.vz/fail2.vw); VECTOR3D pSucc(succ.vx/succ.vw,succ.vy/succ.vw,succ.vz/succ.vw); float param1=calcZPara(pFail1.z,pSucc.z,z); VECTOR3D interPoint1=calcParaEqu(pFail1,pSucc,param1); float sp=(pFail1-interPoint1).GetLength(); float fp=(pSucc-interPoint1).GetLength(); float sum=sp+fp; sp/=sum; fp/=sum; VertexOut inter1; interpolate2v(sp,fp,succ,fail1,inter1); float param2=calcZPara(pFail2.z,pSucc.z,z); VECTOR3D interPoint2=calcParaEqu(pFail2,pSucc,param2); sp=(pFail2-interPoint2).GetLength(); fp=(pSucc-interPoint2).GetLength(); sum=sp+fp; sp/=sum; fp/=sum; VertexOut inter2; interpolate2v(sp,fp,succ,fail2,inter2); nFace1->copy2FaceOut(succ,inter1,inter2); }
void drawFace(FrameBuffer* fb,DepthBuffer* db,VertexShader vs,FragmentShader fs,int cullFlag,Face* face) { vs(face->modelA,face->clipA); vs(face->modelB,face->clipB); vs(face->modelC,face->clipC); if(cullFace(face,cullFlag)) return; int clipFlag=checkFace(face); if(clipFlag!=111) { if(clipFlag==000) return; fixFaces(face,clipFlag); if(!cullFace(nFace1,cullFlag)) { nFace1->calculateClipMatrixInv(); nFace1->calculateNDCVertex(); rasterize(fb,db,fs,nFace1); } if(clipFlag==011||clipFlag==101||clipFlag==110) { if(!cullFace(nFace2,cullFlag)) { nFace2->calculateClipMatrixInv(); nFace2->calculateNDCVertex(); rasterize(fb,db,fs,nFace2); } } } else if(clipFlag==111) { face->calculateClipMatrixInv(); face->calculateNDCVertex(); rasterize(fb,db,fs,face); } }
正确裁剪,看来是成功了.
标签:技术 错误 cli 通过 frame shader 应该 delete article
原文地址:http://www.cnblogs.com/yfceshi/p/6791688.html