bool FrontEndCullingByArea(VSOutput v0, VSOutput v1, VSOutput v2) { if (context.frontEndCull == FrontEndCull.Off) { return(true); } if (context.cullMode == CullMode.None) { return(true); } //cull back Vector2 p0 = new Vector2(v0.position.X, v0.position.Y); Vector2 p1 = new Vector2(v1.position.X, v1.position.Y); Vector2 p2 = new Vector2(v2.position.X, v2.position.Y); //做了透射除法,Culling准确点 p0 *= 1 / v0.position.W; p1 *= 1 / v1.position.W; p2 *= 1 / v2.position.W; float area = Rasterizer.EdgeFunction(p0, p1, p2); //在Clip Space, area >= 0表示顺时针 if (context.winding == Winding.Clockwise) { return(area > 0); } return(area < 0); }
//裁剪前 public void DrawTriangle(VSOutput vClip0, VSOutput vClip1, VSOutput vClip2) { //Backface Culling if (!FrontEndCulling(vClip0, vClip1, vClip2)) { return; } context.statics.triangleCount += 1; //Clipping List <VSOutput> inputs = new List <VSOutput> { vClip0, vClip1, vClip2 }; List <VSOutput> outputs = Clipping.Clip(inputs, context); //输出结果是trianglefan if (outputs.Count < 3) { //全裁剪掉了 return; } //画Triangle Fan VSOutput v0 = outputs[0]; VSOutput vNDC0 = Rasterizer.PerspectiveDivide(v0); if (vNDC0 == null) { return; } VSOutput vScreen0 = rasterizer.ViewportTransform(vNDC0); for (int i = 1; i + 1 < outputs.Count; i += 1) { VSOutput v1 = outputs[i]; VSOutput v2 = outputs[i + 1]; VSOutput vNDC1 = Rasterizer.PerspectiveDivide(v1); VSOutput vNDC2 = Rasterizer.PerspectiveDivide(v2); if (vNDC1 == null || vNDC2 == null) { continue; } VSOutput vScreen1 = rasterizer.ViewportTransform(vNDC1); VSOutput vScreen2 = rasterizer.ViewportTransform(vNDC2); //检查Backface if (i == 1) { //由于裁剪前后的三角形都在同一个平面上,所以只要检查第一个就够了 if (!BackfaceCulling(vScreen0, vScreen1, vScreen2)) { return; } } context.statics.rasterTriCount += 1; rasterizer.RasterizeTriangle(vScreen0, vScreen1, vScreen2); } }
//初始化 void Init(Graphics g) { InitByGraphics(g); //初始化Frame Buffer RectangleF rect = graphics.VisibleClipBounds; Size frameSize = new Size((int)rect.Width, (int)rect.Height); context = new Context(frameSize); rasterizer = new Rasterizer(context); camera = new Camera(); }
public void Test_BarycentricRasterizeTriangle() { context.clearColor = Color.White; Clear(); //假设n = 1, far = 2 //测试光栅化和插值 //第一个三角形,v0红色在中上,v1绿和v2蓝在中间的左右,v0在far plane, v1,v2在near plane VSOutput v0 = new VSOutput(); v0.position = new Vector4(0f, 1f, 1f, 2f); v0.color = new Vector4(1f, 0f, 0f, 1f); VSOutput v1 = new VSOutput(); v1.position = new Vector4(-0.5f, -0.5f, -1f, 1f); v1.color = new Vector4(0f, 1f, 0f, 1f); VSOutput v2 = new VSOutput(); v2.position = new Vector4(0.5f, -0.5f, -1f, 1f); v2.color = new Vector4(0f, 0f, 1f, 1f); v0 = Rasterizer.PerspectiveDivide(v0); v0 = rasterizer.ViewportTransform(v0); v1 = Rasterizer.PerspectiveDivide(v1); v1 = rasterizer.ViewportTransform(v1); v2 = Rasterizer.PerspectiveDivide(v2); v2 = rasterizer.ViewportTransform(v2); rasterizer.BarycentricRasterizeTriangle(v0, v1, v2); //测试depth test //第二个三角形,v0红在近平面,v1,v2在远 v0.position = new Vector4(-0.5f, 0.5f, -1f, 1f); v1.position = new Vector4(-2f, -1f, 1f, 2f); v2.position = new Vector4(0f, -2f, 1f, 2f); v0 = Rasterizer.PerspectiveDivide(v0); v0 = rasterizer.ViewportTransform(v0); v1 = Rasterizer.PerspectiveDivide(v1); v1 = rasterizer.ViewportTransform(v1); v2 = Rasterizer.PerspectiveDivide(v2); v2 = rasterizer.ViewportTransform(v2); rasterizer.BarycentricRasterizeTriangle(v0, v1, v2); //第三个三角形,v1绿在近,其他在远平面 v0.position = new Vector4(-2f, 0f, 1f, 2f); v1.position = new Vector4(-0.5f, -1f, -1f, 1f); v2.position = new Vector4(0f, -1f, 1f, 2f); v0 = Rasterizer.PerspectiveDivide(v0); v0 = rasterizer.ViewportTransform(v0); v1 = Rasterizer.PerspectiveDivide(v1); v1 = rasterizer.ViewportTransform(v1); v2 = Rasterizer.PerspectiveDivide(v2); v2 = rasterizer.ViewportTransform(v2); rasterizer.BarycentricRasterizeTriangle(v0, v1, v2); }
bool BackfaceCulling(VSOutput vScreen0, VSOutput vScreen1, VSOutput vScreen2) { if (context.cullMode == CullMode.None) { return(true); } if (context.frontEndCull == FrontEndCull.On) { return(true); } Vector2 p0 = new Vector2(vScreen0.posScreen.X, vScreen0.posScreen.Y); Vector2 p1 = new Vector2(vScreen1.posScreen.X, vScreen1.posScreen.Y); Vector2 p2 = new Vector2(vScreen2.posScreen.X, vScreen2.posScreen.Y); float area = Rasterizer.EdgeFunction(p0, p1, p2); if (context.winding == Winding.Clockwise) { return(area < 0); } //在Viewport Space, 由于Y轴向下, area > 0表示逆时针 return(area > 0); }