コード例 #1
0
ファイル: Renderer.cs プロジェクト: liangjuntu/SoftRenderer
        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);
        }
コード例 #2
0
        public static VSOutput PerspectiveDivide(VSOutput vClip)
        {
            const float FLT_EPSILON = 1.192092896e-07F; // smallest such that 1.0+FLT_EPSILON != 1.0

            if (vClip.position.W <= FLT_EPSILON)
            {
                return(null);
            }

            VSOutput vNDC = new VSOutput();

            Vector4 position = vClip.position;

            float fInvW = 1 / position.W;

            position = new Vector4(position.X * fInvW, position.Y * fInvW, position.Z * fInvW, fInvW);

            vNDC.position = position;

            vNDC.color       = vClip.color * fInvW;
            vNDC.texcoord    = vClip.texcoord * fInvW;
            vNDC.normalWorld = vClip.normalWorld * fInvW;

            return(vNDC);
        }
コード例 #3
0
ファイル: Renderer.cs プロジェクト: liangjuntu/SoftRenderer
        public void DrawFace(WavefrontObject meshObj, WavefrontFace face, Shader shader)
        {
            //WavefontFace是一个triangle fan
            //可能会有多个三角形;这些三角形共用第一个顶点做v0
            if (face.Vertices.Count < 3)
            {
                Debug.Assert(false);
                return;
            }
            Vertex   vertex0 = Vertex.FromWavefrontVertex(meshObj, face.Vertices[0]);
            VSOutput vClip0  = shader.VertShader(vertex0);

            context.statics.vertexCount += 1;

            for (int i = 1; i + 1 < face.Vertices.Count; i += 1)
            {
                Vertex vertex1 = Vertex.FromWavefrontVertex(meshObj, face.Vertices[i]);
                Vertex vertex2 = Vertex.FromWavefrontVertex(meshObj, face.Vertices[i + 1]);
                //顶点着色器
                VSOutput vClip1 = shader.VertShader(vertex1);
                VSOutput vClip2 = shader.VertShader(vertex2);
                context.statics.vertexCount += 2;
                DrawTriangle(vClip0, vClip1, vClip2);
            }
        }
コード例 #4
0
ファイル: Clipping.cs プロジェクト: liangjuntu/SoftRenderer
        static VSOutput ComputeIntersection(VSOutput S, VSOutput E, float ds, float de)
        {
            float    amount = ds / (ds - de);
            VSOutput v      = VSOutput.Lerp(S, E, amount);

            return(v);
        }
コード例 #5
0
ファイル: Clipping.cs プロジェクト: liangjuntu/SoftRenderer
        static List <VSOutput> ClipToPlane(List <VSOutput> inputs, Vector4 plane)
        {
            List <VSOutput> outputs = new List <VSOutput>();
            VSOutput        S       = inputs.Last();
            float           ds      = Vector4.Dot(plane, S.position);
            bool            sInside = ds >= 0;

            foreach (var E in inputs)
            {
                float de      = Vector4.Dot(plane, E.position);
                bool  eInside = de >= 0;
                if (eInside)
                {
                    if (!sInside)
                    {
                        VSOutput C = ComputeIntersection(S, E, ds, de);
                        outputs.Add(C);
                    }
                    outputs.Add(E);
                }
                else if (sInside)
                {
                    VSOutput C = ComputeIntersection(S, E, ds, de);
                    outputs.Add(C);
                }

                //记录为上一个
                S       = E;
                ds      = de;
                sInside = eInside;
            }
            return(outputs);
        }
コード例 #6
0
ファイル: Vertex.cs プロジェクト: liangjuntu/SoftRenderer
        }                                      //viewport坐标

        //Other Attributes
        public void Clone(VSOutput other)
        {
            this.position    = other.position;
            this.normalWorld = other.normalWorld;
            this.texcoord    = other.texcoord;
            this.color       = other.color;
            this.posScreen   = other.posScreen;
        }
コード例 #7
0
        void DrawWireframe(VSOutput v0, VSOutput v1, VSOutput v2)
        {
            Color col = context.wireframeColor;

            //col = Utils.NextWireframeColor();
            DrawLine(v0, v1, col);
            DrawLine(v1, v2, col);
            DrawLine(v2, v0, col);
        }
コード例 #8
0
ファイル: Renderer.cs プロジェクト: liangjuntu/SoftRenderer
        //裁剪前
        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);
            }
        }
コード例 #9
0
ファイル: Vertex.cs プロジェクト: liangjuntu/SoftRenderer
        public static VSOutput Lerp(VSOutput A, VSOutput B, float amount)
        {
            VSOutput C = new VSOutput();

            C.position    = Vector4.Lerp(A.position, B.position, amount);
            C.normalWorld = Vector3.Lerp(A.normalWorld, B.normalWorld, amount);
            C.texcoord    = Vector2.Lerp(A.texcoord, B.texcoord, amount);
            C.color       = Vector4.Lerp(A.color, B.color, amount);
            C.posScreen   = Vector3.Lerp(A.posScreen, B.posScreen, amount);
            return(C);
        }
コード例 #10
0
ファイル: Renderer.cs プロジェクト: liangjuntu/SoftRenderer
        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);
        }
コード例 #11
0
        public void DrawLine(VSOutput v0, VSOutput v1, Color color)
        {
            Vector2 p0     = new Vector2(v0.posScreen.X, v0.posScreen.Y);
            Vector2 p1     = new Vector2(v1.posScreen.X, v1.posScreen.Y);
            bool    accept = CohenSutherlandLineClip(ref p0, ref p1);

            if (!accept)
            {
                return;
            }
            BresenhamDrawLine(p0, p1, color);
        }
コード例 #12
0
        public VSOutput VertShader(Vertex v)
        {
            VSOutput OUT = new VSOutput();

            OUT.position = Vector4.Transform(v.position, MVP);
            Vector4 normalWorld = Vector4.Transform(v.normal, Matrix4x4.Transpose(worldToModel));

            OUT.normalWorld = new Vector3(normalWorld.X, normalWorld.Y, normalWorld.Z);
            OUT.texcoord    = v.texcoord;
            OUT.color       = v.color;
            return(OUT);
        }
コード例 #13
0
        public void RasterizeTriangle(VSOutput vScreen0, VSOutput vScreen1, VSOutput vScreen2)
        {
            switch (context.drawMode)
            {
            case DrawMode.Normal:
            case DrawMode.Depth:
                BarycentricRasterizeTriangle(vScreen0, vScreen1, vScreen2);
                break;

            case DrawMode.Wireframe:
                DrawWireframe(vScreen0, vScreen1, vScreen2);
                break;
            }
        }
コード例 #14
0
        public VSOutput ViewportTransform(VSOutput vNDC)
        {
            VSOutput vScreen = new VSOutput();

            vScreen.Clone(vNDC);

            int   width  = context.frameBuffer.Width;
            int   height = context.frameBuffer.Height;
            float x      = (vNDC.position.X + 1) * 0.5f;
            float y      = (1 - vNDC.position.Y) * 0.5f;
            //把z从[-1,1]转到[0,1]
            float z = (vNDC.position.Z + 1) * 0.5f;

            vScreen.posScreen = new Vector3(x * width, y * height, z);
            return(vScreen);
        }
コード例 #15
0
ファイル: Renderer.cs プロジェクト: liangjuntu/SoftRenderer
        public void TestClipping()
        {
            Clear();
            context.clippingMode = ClippingMode.SixPlane;
            //context.clippingMode = ClippingMode.Off;
            context.drawMode     = DrawMode.Wireframe;
            context.cullMode     = CullMode.Back;
            context.frontEndCull = FrontEndCull.Off;
            VSOutput v0 = new VSOutput();
            VSOutput v1 = new VSOutput();
            VSOutput v2 = new VSOutput();

            List <VSOutput> inputs = new List <VSOutput>()
            {
                v0, v1, v2
            };

            //第一个三角形,右裁剪平面,一个顶点在外=>生成两个三角形
            v0.position = new Vector4(0.5f, 0.5f, 0, 1);
            v1.position = new Vector4(0, -0.5f, 0, 1);
            v2.position = new Vector4(2, 0, 0, 1);//在外面
            DrawTriangle(v0, v1, v2);


            //第二个三角形,上裁剪平面,两个顶点在外=>生成一个三角形
            v0.position = new Vector4(-0.5f, 4f, 0, 1);
            v1.position = new Vector4(0.5f, 0f, 0, 1); //在外面
            v2.position = new Vector4(0.6f, 2f, 0, 1); //在外面
            DrawTriangle(v0, v1, v2);

            //第三个,三个顶点都在外
            v0.position = new Vector4(0.6f, 1.5f, 0, 1);
            v1.position = new Vector4(-1.5f, -0.3f, 0, 1);
            v2.position = new Vector4(0.8f, -1.2f, 0, 1);
            DrawTriangle(v0, v1, v2);


            //顺别测下Back face Culling;对换了v1和v2,应该不画
            v0.position = new Vector4(0.6f, 1.5f, 0, 1);
            v2.position = new Vector4(-1.5f, -0.3f, 0, 1);
            v1.position = new Vector4(0.8f, -1.2f, 0, 1);
            //DrawTriangle(v0, v1, v2);


            Present();
        }
コード例 #16
0
        public PSOutput FragShader(VSOutput v)
        {
            //invert uv
            if (shaderContext.invertTexture)
            {
                //v.texcoord = new Vector2(1 - v.texcoord.X, 1 - v.texcoord.Y);
                v.texcoord = new Vector2(v.texcoord.X, 1 - v.texcoord.Y);
                //v.texcoord = new Vector2(1 - v.texcoord.X, v.texcoord.Y);
            }

            PSOutput OUT = new PSOutput();
            Vector4  col = v.color;

            if ((shaderContext.shadeMode == ShadeMode.Lighting ||
                 shaderContext.shadeMode == ShadeMode.NDotL) &&
                shaderContext.light != null)
            {
                Vector3 normalWorld = v.normalWorld;
                normalWorld = Vector3.Normalize(normalWorld);
                Vector3 lightDir = shaderContext.light.lightDirForShader;

                //Lambert Lighting
                float NDotL = Vector3.Dot(normalWorld, lightDir);
                NDotL = Utils.Clamp(NDotL, 0, 1);
                if (shaderContext.shadeMode == ShadeMode.Lighting && texture != null)
                {
                    Vector4 tex = texture.Tex2D(v.texcoord, shaderContext.textureFilterMode);
                    col = tex * (NDotL * shaderContext.light.lightColor + shaderContext.ambient);
                }
                else
                {
                    col = new Vector4(NDotL, NDotL, NDotL, 1f);
                }
            }
            else if (shaderContext.shadeMode == ShadeMode.Texture && texture != null)
            {
                col = texture.Tex2D(v.texcoord, shaderContext.textureFilterMode);
            }
            //col = new Vector4(v.texcoord.X, v.texcoord.Y, 0, 1 );
            OUT.color = col;
            return(OUT);
        }
コード例 #17
0
ファイル: Renderer.cs プロジェクト: liangjuntu/SoftRenderer
        bool FrontEndCullingByAngle(VSOutput v0, VSOutput v1, VSOutput v2)
        {
            if (context.frontEndCull == FrontEndCull.Off)
            {
                return(true);
            }
            if (context.cullMode == CullMode.None)
            {
                return(true);
            }

            Vector3 pos0 = new Vector3(v0.position.X, v0.position.Y, v0.position.Z);
            Vector3 pos1 = new Vector3(v1.position.X, v1.position.Y, v1.position.Z);
            Vector3 pos2 = new Vector3(v2.position.X, v2.position.Y, v2.position.Z);
            //为什么把Z改成Eye Space的Z就是对的?
            //pos0.Z = v0.position.W;
            //pos1.Z = v1.position.W;
            //pos2.Z = v2.position.W;



            //Vector3 n = Vector3.Cross(pos1-pos0, pos2 - pos0);
            Vector3 n = Vector3.Cross(pos1 - pos0, pos2 - pos1);

            Vector3 p = pos0;

            Vector3 test = Vector3.Cross(new Vector3(1, 0, 0), new Vector3(0, 1, 0));

            //n = Vector3.Normalize(n);
            //p = Vector3.Normalize(p);

            float cos = Vector3.Dot(n, p);

            if (context.winding == Winding.Clockwise)
            {
                return(cos <= 0);
            }
            return(cos >= 0);
        }
コード例 #18
0
ファイル: Renderer.cs プロジェクト: liangjuntu/SoftRenderer
        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);
        }
コード例 #19
0
        public void BarycentricRasterizeTriangle(VSOutput v0, VSOutput v1, VSOutput v2)
        {
            int     width  = context.frameSize.Width;
            int     height = context.frameSize.Height;
            Vector2 xy0    = new Vector2(v0.posScreen.X, v0.posScreen.Y);
            Vector2 xy1    = new Vector2(v1.posScreen.X, v1.posScreen.Y);
            Vector2 xy2    = new Vector2(v2.posScreen.X, v2.posScreen.Y);
            float   z0     = v0.posScreen.Z;
            float   z1     = v1.posScreen.Z;
            float   z2     = v2.posScreen.Z;

            //求包围盒
            float xmin = Math.Min(Math.Min(xy0.X, xy1.X), xy2.X);
            float xmax = Math.Max(Math.Max(xy0.X, xy1.X), xy2.X);
            float ymin = Math.Min(Math.Min(xy0.Y, xy1.Y), xy2.Y);
            float ymax = Math.Max(Math.Max(xy0.Y, xy1.Y), xy2.Y);
            //像素坐标包围盒
            int x0 = Utils.Clamp((int)xmin, 0, width - 1);
            int y0 = Utils.Clamp((int)ymin, 0, height - 1);
            int x1 = Utils.Clamp((int)xmax, 0, width - 1);
            int y1 = Utils.Clamp((int)ymax, 0, height - 1);



            for (int y = y0; y <= y1; ++y)
            {
                for (int x = x0; x <= x1; ++x)
                {
                    //加0.5取像素的中间位置的坐标
                    Vector2 pixel = new Vector2(x + 0.5f, y + 0.5f);
                    Vector3 w = BarycentricCoordinates(pixel, xy0, xy1, xy2);
                    float   w0 = w.X; float w1 = w.Y; float w2 = w.Z;
                    if (!(w0 >= 0 && w1 >= 0 && w2 >= 0))
                    {
                        //像素点不在三角形内
                        continue;
                    }

                    context.statics.fragmentCount += 1;


                    //深度测试
                    float depth = w0 * z0 + w1 * z1 + w2 * z2;
                    if (context.depthBuffer[x, y] < depth)
                    {
                        continue;
                    }

                    Color col;
                    if (context.drawMode == DrawMode.Depth)
                    {
                        Vector4 depthColor = new Vector4(depth, depth, depth, 1);
                        col = Utils.VectorToColor(depthColor);
                    }
                    else
                    {
                        //正常渲染

                        //插值UV等顶点属性
                        float fInvW = w0 * v0.position.W + w1 * v1.position.W + w2 * v2.position.W;
                        //由于position.W是1/W = 1/-Z_Eye
                        float   Z_Eye = 1f / fInvW;
                        Vector2 uv    = w0 * v0.texcoord + w1 * v1.texcoord + w2 * v2.texcoord;
                        uv *= Z_Eye;

                        Vector4 color = w0 * v0.color + w1 * v1.color + w2 * v2.color;
                        color *= Z_Eye;

                        Vector3 normalWorld = w0 * v0.normalWorld + w1 * v1.normalWorld + w2 * v2.normalWorld;

                        if (shader != null)
                        {
                            VSOutput fragment = new VSOutput();
                            //v.position =
                            fragment.normalWorld = normalWorld;
                            fragment.texcoord    = uv;
                            fragment.color       = color;

                            PSOutput OUT = shader.FragShader(fragment);
                            if (OUT.isDiscard)
                            {
                                continue;
                            }
                            col = Utils.VectorToColor(OUT.color);
                        }
                        else
                        {
                            col = Utils.VectorToColor(color);
                        }
                    }

                    context.depthBuffer[x, y] = depth;
                    DrawPixel(x, y, col);
                }
            }
        }
コード例 #20
0
ファイル: Renderer.cs プロジェクト: liangjuntu/SoftRenderer
 bool FrontEndCulling(VSOutput v0, VSOutput v1, VSOutput v2)
 {
     return(FrontEndCullingByArea(v0, v1, v2));
     //return FrontEndCullingByAngle(v0, v1, v2);
 }