之前用包围盒和重心坐标法做过光栅化实现,但是那个方法存在问题,这次要实现一个更高效的光栅化方法.
之前使用的包围盒方法确定光栅化范围,但是包围盒确定的范围是矩形,要光栅化的是三角形,那么每次都会有不需要的像素参加运算,一个面当然没啥问题,但是如果是100个面问题就大了.
if(scrAY==scrBY&&scrAY==scrCY) //屏幕坐标所有y都相等,直线不进行光栅化
return;
int minY=max(0,min(scrAY,min(scrBY,scrCY))); //顶上的y0
int maxY=min(fb->height-1,max(scrAY,max(scrBY,scrCY))); //底部的y1
for(int scrY=minY;scrY<=maxY;scrY++) {
float x1,x2;
if(scrAY==scrBY) { //平顶平底情况
float paramAC=((float)scrY-scrAY)/(scrCY-scrAY);
float paramBC=((float)scrY-scrBY)/(scrCY-scrBY);
x1=(scrCX-scrAX)*paramAC+scrAX;
x2=(scrCX-scrBX)*paramBC+scrBX;
} else if(scrAY==scrCY) { //平顶平底情况
float paramAB=((float)scrY-scrAY)/(scrBY-scrAY);
float paramBC=((float)scrY-scrBY)/(scrCY-scrBY);
x1=(scrBX-scrAX)*paramAB+scrAX;
x2=(scrCX-scrBX)*paramBC+scrBX;
} else if(scrBY==scrCY) { //平顶平底情况
float paramAB=((float)scrY-scrAY)/(scrBY-scrAY);
float paramAC=((float)scrY-scrAY)/(scrCY-scrAY);
x1=(scrBX-scrAX)*paramAB+scrAX;
x2=(scrCX-scrAX)*paramAC+scrAX;
} else { //正常情况
float paramAB=((float)scrY-scrAY)/(scrBY-scrAY);
float paramAC=((float)scrY-scrAY)/(scrCY-scrAY);
float paramBC=((float)scrY-scrBY)/(scrCY-scrBY);
bool ab=(paramAB<=1.0&¶mAB>=0.0)?true:false;
bool ac=(paramAC<=1.0&¶mAC>=0.0)?true:false;
bool bc=(paramBC<=1.0&¶mBC>=0.0)?true:false;
float xAB=(scrBX-scrAX)*paramAB+scrAX;
float xAC=(scrCX-scrAX)*paramAC+scrAX;
float xBC=(scrCX-scrBX)*paramBC+scrBX;
if(!ab) {
x1=xAC;
x2=xBC;
} else if(!ac) {
x1=xAB;
x2=xBC;
} else if(!bc) {
x1=xAB;
x2=xAC;
} else {
x1=xAC;
x2=xBC;
if(x1==x2) //排除两线交点的情况
x2=xAB;
}
}
int minX=max(0,min(x1,x2)-0.5); //扫描线左边的x值
int maxX=min(fb->width-1,max(x1,x2)+0.5); //扫描线右边的x值 for(int scrX=minX;scrX<=maxX;scrX++) {
invViewPortTransform(scrX,scrY,fb->width,fb->height,ndcX,ndcY);
VECTOR4D ndcPixel(ndcX,ndcY,1,0);
VECTOR4D proportion4D=face->clipMatrixInv*ndcPixel;
VECTOR3D proportionFragment(proportion4D.x,proportion4D.y,proportion4D.z);
float pa=proportionFragment.x;
float pb=proportionFragment.y;
float pc=proportionFragment.z;
if(pa<0||pb<0||pc<0)
continue;
float sum=pa+pb+pc;
pa/=sum; pb/=sum; pc/=sum;
Fragment frag;
interpolate3f(pa,pb,pc,face->clipA.w,face->clipB.w,face->clipC.w,clipW);
interpolate3f(pa,pb,pc,face->clipA.z,face->clipB.z,face->clipC.z,frag.ndcZ);
frag.ndcZ/=clipW;
if(frag.ndcZ<-1||frag.ndcZ>1)
continue;
if(db!=NULL) {
float storeZ=readDepth(db,scrX,scrY);
if(storeZ<frag.ndcZ)
continue;
writeDepth(db,scrX,scrY,frag.ndcZ);
}
interpolate3f(pa,pb,pc,face->clipA.x,face->clipB.x,face->clipC.x,frag.ndcX);
frag.ndcX/=clipW;
interpolate3f(pa,pb,pc,face->clipA.y,face->clipB.y,face->clipC.y,frag.ndcY);
frag.ndcY/=clipW;
interpolate3f(pa,pb,pc,face->clipA.wx,face->clipB.wx,face->clipC.wx,frag.wx);
interpolate3f(pa,pb,pc,face->clipA.wy,face->clipB.wy,face->clipC.wy,frag.wy);
interpolate3f(pa,pb,pc,face->clipA.wz,face->clipB.wz,face->clipC.wz,frag.wz);
interpolate3f(pa,pb,pc,face->clipA.ww,face->clipB.ww,face->clipC.ww,frag.ww);
interpolate3f(pa,pb,pc,face->clipA.nx,face->clipB.nx,face->clipC.nx,frag.nx);
interpolate3f(pa,pb,pc,face->clipA.ny,face->clipB.ny,face->clipC.ny,frag.ny);
interpolate3f(pa,pb,pc,face->clipA.nz,face->clipB.nz,face->clipC.nz,frag.nz);
interpolate3f(pa,pb,pc,face->clipA.s,face->clipB.s,face->clipC.s,frag.s);
interpolate3f(pa,pb,pc,face->clipA.t,face->clipB.t,face->clipC.t,frag.t);
FragmentOut outFrag;
fs(frag,outFrag);
drawPixel(fb,scrX,scrY,outFrag.r,outFrag.g,outFrag.b);
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/zxx43/article/details/47680629