Example #1
0
        //三角形扫描
        public void ScanLine_new(VertexTriangle vt, VertexTriangle orit, Scene scene)
        {
            Vertex A = vt.Vertices[0];
            Vertex B = vt.Vertices[1];
            Vertex C = vt.Vertices[2];

            DrawNormalTriangle(vt, orit, scene);
        }
Example #2
0
        //生成三角形数组
        private List <VertexTriangle> MakeTriangle(List <Vertex> input)
        {
            List <VertexTriangle> temp = new List <VertexTriangle>();

            for (int i = 0; i < input.Count - 2; i++)
            {
                VertexTriangle vt = new VertexTriangle(input[0], input[i + 1], input[i + 2]);
                temp.Add(vt);
            }
            return(temp);
        }
Example #3
0
        //消隐
        private bool ShouldBackFaceCull(VertexTriangle oriVt)
        {
            Vector4 a = new Vector4(oriVt.Vertices[0].ScreenSpacePosition);
            Vector4 b = new Vector4(oriVt.Vertices[1].ScreenSpacePosition);
            Vector4 c = new Vector4(oriVt.Vertices[2].ScreenSpacePosition);

            a.Z = b.Z = c.Z = 0;
            Vector4 ab = b - a;
            Vector4 ac = c - a;

            return(Vector4.Cross(ab, ac).Z > 0);
        }
Example #4
0
        private void DrawTriangle(VertexTriangle vt, VertexTriangle oriVt, Scene scene, bool isWorld)
        {
            if (!ShouldBackFaceCull(vt))
            {
                //this.scanLine.ProcessScanLine(vt, oriVt, scene);
                if (scene.renderState == Scene.RenderState.WireFrame)
                {
                    this.scanLine.ProcessScanLine(vt, oriVt, scene, isWorld);
                }
                else
                {
                    this.scanLine.ScanLine_new(vt, oriVt, scene);
                }

                //this.scanLine.StartScanLine(vt,oriVt,scene);
                //this.scanLine.StartScanTriangle(vt,oriVt,scene);
            }
        }
Example #5
0
        public static void GouraudColor(Scene scene, Device device, int i, Edge a1, Edge a2, VertexTriangle orivt, VertexTriangle vt, bool isworld)
        {
            Color4 final = new Color4();

            /*
             * 记过排序后的边传入连续两条边 相交的情况只有两种钝角三角形 和锐角三角形
             * x 从小到大
             *
             *        /\    /\
             *       /  \  /  \
             *      /    \/    \_________
             *     x1    x3 x4
             * 1. x左右分开
             * 2. x相同 以斜率排序
             *
             */

            /* 双线性插值算法
             *
             *
             */
            Vector4 screenA1V1 = a1.v1.ScreenSpacePosition;
            Vector4 screenA1V2 = a1.v2.ScreenSpacePosition;
            Vector4 screenA2V1 = a2.v1.ScreenSpacePosition;
            Vector4 screenA2V2 = a2.v2.ScreenSpacePosition;

            // 双线性插值系数

            // 第一次插值算出交点的颜色系数
            float r1 = ((float)i - screenA1V1.Y) / (float)(screenA1V2.Y - screenA1V1.Y);
            float r2 = ((float)i - screenA2V1.Y) / (float)(screenA2V2.Y - screenA2V1.Y);

            r1 = MathUtil.Clamp01(r1);
            r2 = MathUtil.Clamp01(r2);

            // 像素点深度插值
            float z1 = MathUtil.Interp(screenA1V1.Z, screenA1V2.Z, r1);
            float z2 = MathUtil.Interp(screenA2V1.Z, screenA2V2.Z, r2);
            //float z3 = 0;
            float r3 = MathUtil.Clamp01(((float)x - a1.x) / (a2.x - a1.x));
            //float r3 = (float)(x - Math.Floor(a1.x)) / (a2.x - a1.x);
            float z = MathUtil.Interp(z1, z2, r3);
            //float z = vt.GetInterValue(z1, z2, z3);
            float nDotL1 = 0, nDotL2 = 0;

            switch (scene.renderState)
            {
            case Scene.RenderState.WireFrame: { }
            break;

            case Scene.RenderState.GouraduShading:
            { }
            break;

            case Scene.RenderState.TextureMapping:
            {
                orivt.CalWeight(new Vector4(x, i, 0, 0));
                Vector4 uv = orivt.GetInterUV();
                if (isworld)
                {
                    //final = device.Tex2D(uv.X, uv.Y, scene.worldMap.texture);
                }
                else
                {
                    if (DirectionLight.IsEnable)
                    {
                        float nDotLA1V1 = DirectionLight.ComputeNDotL(a1.v1.nowPos, a1.v1.nowNormal);
                        float nDotLA1V2 = DirectionLight.ComputeNDotL(a1.v2.nowPos, a1.v2.nowNormal);
                        float nDotLA2V1 = DirectionLight.ComputeNDotL(a2.v1.nowPos, a2.v1.nowNormal);
                        float nDotLA2V2 = DirectionLight.ComputeNDotL(a2.v2.nowPos, a2.v2.nowNormal);

                        nDotL1 = MathUtil.Interp(nDotLA1V1, nDotLA1V2, r1);
                        nDotL2 = MathUtil.Interp(nDotLA2V1, nDotLA2V2, r2);

                        float nDotL = MathUtil.Interp(nDotL1, nDotL2, r3);
                        //Console.WriteLine(nDotL1+" "+ nDotL2+" " + nDotL);
                        final = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                        final = final * DirectionLight.GetFinalLightColor(nDotL);
                    }
                    else
                    {
                        final = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                    }
                }
            }
            break;
            }
            device.DrawPoint(new Vector4(x, i, z, 0), final);
        }
Example #6
0
        /* gouraud 着色
         *
         * Ia = (ya - y2)*I1/(y1-y2) + (y1-ya)*I2/(y1 -y2)
         *
         */
        public static void GouraudColor(Scene scene, Device device, float x, float y, float z, VertexTriangle vt, VertexTriangle orivt)
        {
            Color4 final = new Color4();
            Vertex A     = vt.Vertices[0];
            Vertex B     = vt.Vertices[1];
            Vertex C     = vt.Vertices[2];

            float nDotLA1V1 = DirectionLight.ComputeNDotL(A.nowPos, A.nowNormal);

            A.lightColor = A.Color * DirectionLight.GetFinalLightColor(nDotLA1V1);

            float nDotLA1V2 = DirectionLight.ComputeNDotL(B.nowPos, B.nowNormal);

            B.lightColor = B.Color * DirectionLight.GetFinalLightColor(nDotLA1V2);

            float nDotLA2V1 = DirectionLight.ComputeNDotL(C.nowPos, C.nowNormal);

            C.lightColor = C.Color * DirectionLight.GetFinalLightColor(nDotLA2V1);


            float ay = A.ScreenSpacePosition.Y;
            float by = B.ScreenSpacePosition.Y;
            float cy = C.ScreenSpacePosition.Y;
            float ax = A.ScreenSpacePosition.X;
            float bx = B.ScreenSpacePosition.X;
            float cx = C.ScreenSpacePosition.X;

            bool isIn = vt.CalculateWeight(new Vector4(x, y, 0, 0));

            if (isIn)
            {
                final = vt.GetInterColor();
                device.DrawPoint(new Vector4(x, y, z, 0), final);
            }
            else
            {
            }
        }
Example #7
0
        public void renderTriangle(Vertex vertexA, Vertex vertexB, Vertex vertexC, Matrix4x4 matrixMVP, bool isWorld)
        {
            List <Vertex> pIn = new List <Vertex>();

            vertexA.ClipSpacePosition   = this.ClipSpace(vertexA.nowPos, matrixMVP);
            vertexB.ClipSpacePosition   = this.ClipSpace(vertexB.nowPos, matrixMVP);
            vertexC.ClipSpacePosition   = this.ClipSpace(vertexC.nowPos, matrixMVP);
            vertexA.ScreenSpacePosition = this.ViewPort(vertexA.ClipSpacePosition);
            vertexB.ScreenSpacePosition = this.ViewPort(vertexB.ClipSpacePosition);
            vertexC.ScreenSpacePosition = this.ViewPort(vertexC.ClipSpacePosition);

            pIn.Add(vertexA);
            pIn.Add(vertexB);
            pIn.Add(vertexC);

            for (int i = 0; i < 6; i++)
            {
                if (pIn.Count == 0)
                {
                    break;
                }
                clip = new HodgmanClip(this);
                clip.HodgmanPolygonClip((HodgmanClip.Boundary)i, clipMin, clipMax, pIn.ToArray());
                pIn = clip.GetOutputList();
            }
            List <VertexTriangle> vtList = this.MakeTriangle(pIn);
            VertexTriangle        oriVt  = new VertexTriangle(vertexA, vertexB, vertexC);

            if (scene.renderState == Scene.RenderState.WireFrame)
            {
                // 画线框, 需要vertex的normal,pos,color
                //DrawLine(vertexA, vertexB, pixelA, pixelB, scene);
                //DrawLine(vertexB, vertexC, pixelB, pixelC, scene);
                for (int i = 0; i < vtList.Count; i++)
                {
                    if (!ShouldBackFaceCull(vtList[i]))
                    {
                        int    length = vtList[i].Vertices.Length;
                        Vertex start  = vtList[i].Vertices[length - 1];
                        for (int j = 0; j < length; j++)
                        {
                            Vector4 viewPortA = this.ViewPort(start.ClipSpacePosition);
                            Vector4 viewPortB = this.ViewPort(vtList[i].Vertices[j].ClipSpacePosition);
                            // DrawLine(start, vtList[i].Vertices[j], viewPortA, viewPortB, scene);
                            DrawDDALine(start, vtList[i].Vertices[j]);
                            start = vtList[i].Vertices[j];
                        }
                    }
                }
            }
            else
            {
                // 填充三角形                   bv gf
                for (int i = 0; i < vtList.Count; i++)
                {
                    //Console.WriteLine(vtList.Count);
                    DrawTriangle(vtList[i], oriVt, scene, isWorld);
                    //DrawTriangle(vtList[i]);
                }
            }
        }
Example #8
0
        public void DrawTopTriangle(Vertex v1, Vertex v2, Vertex v3, Scene scene, VertexTriangle vt, VertexTriangle oriVt)
        {
            Vector4 p1 = v1.ScreenSpacePosition;
            Vector4 p2 = v2.ScreenSpacePosition;
            Vector4 p3 = v3.ScreenSpacePosition;

            Color4 color1 = v1.Color;
            Color4 color2 = v2.Color;
            Color4 color3 = v3.Color;

            float ax = p1.X;
            float bx = p2.X;
            float cx = p3.X;
            float ay = p1.Y;
            float by = p2.Y;
            float cy = p3.Y;

            float az = p1.Z;
            float bz = p2.Z;
            float cz = p3.Z;

            Vector4 normal1 = v1.nowNormal;
            Vector4 normal2 = v2.nowNormal;
            Vector4 normal3 = v3.nowNormal;

            oriVt.PreCalWeight();

            if (bx == cx)
            {
                for (int y = (int)ay; y <= (int)cy; y++)
                {
                    float y1 = (float)(y - ay) / (float)(cy - ay);
                    float y2 = (float)(y - by) / (float)(cy - by);

                    y1 = MathUtil.Clamp01(y1);
                    y2 = MathUtil.Clamp01(y2);

                    int x0 = (int)MathUtil.Interp(ax, cx, y1);
                    int x1 = (int)bx;

                    float z1 = MathUtil.Interp(az, cz, y1);
                    float z2 = bz;

                    Color4 c1 = new Color4();
                    Color4 c2 = new Color4();

                    if (scene.renderState == Scene.RenderState.GouraduShading)
                    {
                        c1 = MathUtil.ColorInterp(color1, color3, y1);
                        c2 = MathUtil.ColorInterp(color2, color3, y2);
                    }

                    Vector4 n1 = new Vector4(0, 0, 0, 0);
                    Vector4 n2 = new Vector4(0, 0, 0, 0);

                    if (DirectionLight.IsEnable)
                    {
                        n1 = MathUtil.Vector4Interp(normal1, normal3, y1);
                        n2 = MathUtil.Vector4Interp(normal2, normal3, y2);
                    }

                    for (int x = x0; x <= x1; x++)
                    {
                        float r3 = (float)(x - x0) / (float)(x1 - x0);

                        r3 = MathUtil.Clamp01(r3);

                        float z = MathUtil.Interp(z1, z2, r3);

                        Vector4 pos = new Vector4(x, y, z, 0);

                        switch (scene.renderState)
                        {
                        case Scene.RenderState.WireFrame:
                        { }
                        break;

                        case Scene.RenderState.GouraduShading:
                        {
                            oriVt.CalWeight(pos);
                            Color4 c3 = MathUtil.ColorInterp(c1, c2, r3);

                            if (DirectionLight.IsEnable)
                            {
                                Vector4 n3 = MathUtil.Vector4Interp(n1, n2, r3);
                                n3    = oriVt.GetNormal();
                                final = DirectionLight.GetFinalLightColor(n3, c3);
                            }
                            else
                            {
                                final = c3;
                            }
                        }
                        break;

                        case Scene.RenderState.TextureMapping:
                        {
                            oriVt.CalWeight(pos);

                            Vector4 n3 = MathUtil.Vector4Interp(n1, n2, r3);

                            Vector4 uv = oriVt.GetInterUV();

                            if (DirectionLight.IsEnable)
                            {
                                Color4 c = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                                n3    = oriVt.GetNormal();
                                final = DirectionLight.GetFinalLightColor(n3, c);
                            }
                            else
                            {
                                final = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                            }
                        }
                        break;
                        }
                        device.DrawPoint(pos, final);
                    }
                }
            }
            else if (ax == cx)
            {
                for (int y = (int)ay; y <= (int)cy; y++)
                {
                    float y1 = (float)(y - ay) / (float)(cy - ay);
                    float y2 = (float)(y - by) / (float)(cy - by);
                    y1 = MathUtil.Clamp01(y1);
                    y2 = MathUtil.Clamp01(y2);

                    int x0 = (int)ax;
                    int x1 = (int)MathUtil.Interp(bx, cx, y2);

                    float z1 = MathUtil.Interp(az, cz, y1);
                    float z2 = MathUtil.Interp(bz, cz, y2);

                    Color4 c1 = new Color4();
                    Color4 c2 = new Color4();

                    if (scene.renderState == Scene.RenderState.GouraduShading)
                    {
                        c1 = MathUtil.ColorInterp(color1, color3, y1);
                        c2 = MathUtil.ColorInterp(color2, color3, y2);
                    }

                    Vector4 n1 = new Vector4(0, 0, 0, 0);
                    Vector4 n2 = new Vector4(0, 0, 0, 0);

                    if (DirectionLight.IsEnable)
                    {
                        n1 = MathUtil.Vector4Interp(normal1, normal3, y1);
                        n2 = MathUtil.Vector4Interp(normal2, normal3, y2);
                    }

                    for (int x = x0; x < x1; x++)
                    {
                        float r3 = (float)(x - x0) / (float)(x1 - x0);

                        r3 = MathUtil.Clamp01(r3);

                        float z = MathUtil.Interp(z1, z2, r3);

                        Vector4 pos = new Vector4(x, y, z, 0);

                        switch (scene.renderState)
                        {
                        case Scene.RenderState.WireFrame:
                        { }
                        break;

                        case Scene.RenderState.GouraduShading:
                        {
                            oriVt.CalWeight(pos);
                            Color4 c3 = MathUtil.ColorInterp(c1, c2, r3);

                            if (DirectionLight.IsEnable)
                            {
                                Vector4 n3 = MathUtil.Vector4Interp(n1, n2, r3);
                                n3    = oriVt.GetNormal();
                                final = DirectionLight.GetFinalLightColor(n3, c3);
                            }
                            else
                            {
                                final = c3;
                            }
                        }
                        break;

                        case Scene.RenderState.TextureMapping:
                        {
                            oriVt.CalWeight(pos);

                            Vector4 n3 = MathUtil.Vector4Interp(n1, n2, r3);

                            Vector4 uv = oriVt.GetInterUV();

                            if (DirectionLight.IsEnable)
                            {
                                Color4 c = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                                n3    = oriVt.GetNormal();
                                final = DirectionLight.GetFinalLightColor(n3, c);
                            }
                            else
                            {
                                final = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                            }
                        }
                        break;
                        }
                        device.DrawPoint(pos, final);
                    }
                }
            }
            else
            {
                for (int y = (int)ay; y <= cy; y++)
                {
                    float y1 = (float)(y - ay) / (float)(cy - ay);
                    y1 = MathUtil.Clamp01(y1);

                    float y2 = (y - by) / (cy - by);
                    y2 = MathUtil.Clamp01(y2);

                    float x0 = (int)MathUtil.Interp(ax, cx, y1);
                    float x1 = (int)MathUtil.Interp(bx, cx, y2);

                    float z1 = MathUtil.Interp(az, cz, y1);
                    float z2 = MathUtil.Interp(bz, cz, y2);

                    Color4 c1 = new Color4();
                    Color4 c2 = new Color4();

                    if (scene.renderState == Scene.RenderState.GouraduShading)
                    {
                        c1 = MathUtil.ColorInterp(color1, color3, y1);
                        c2 = MathUtil.ColorInterp(color2, color3, y2);
                    }
                    Vector4 n1 = new Vector4(0, 0, 0, 0);
                    Vector4 n2 = new Vector4(0, 0, 0, 0);

                    if (DirectionLight.IsEnable)
                    {
                        n1 = MathUtil.Vector4Interp(normal1, normal3, y1);
                        n2 = MathUtil.Vector4Interp(normal2, normal3, y2);
                    }

                    for (float x = x0; x < x1; x++)
                    {
                        float r3 = (float)(x - x0) / (float)(x1 - x0);

                        r3 = MathUtil.Clamp01(r3);

                        float z = MathUtil.Interp(z1, z2, r3);

                        //Color4 c3 = MathUtil.ColorInterp(c1, c2, r3);

                        Vector4 pos = new Vector4(x, y, z, 0);

                        switch (scene.renderState)
                        {
                        case Scene.RenderState.WireFrame:
                        { }
                        break;

                        case Scene.RenderState.GouraduShading:
                        {
                            Color4 c3 = MathUtil.ColorInterp(c1, c2, r3);
                            oriVt.CalWeight(pos);
                            if (DirectionLight.IsEnable)
                            {
                                Vector4 n3 = MathUtil.Vector4Interp(n1, n2, r3);
                                n3    = oriVt.GetNormal();
                                final = DirectionLight.GetFinalLightColor(n3, c3);
                            }
                            else
                            {
                                final = c3;
                            }
                        }
                        break;

                        case Scene.RenderState.TextureMapping:
                        {
                            oriVt.CalWeight(pos);

                            Vector4 n3 = MathUtil.Vector4Interp(n1, n2, r3);

                            Vector4 uv = oriVt.GetInterUV();

                            if (DirectionLight.IsEnable)
                            {
                                Color4 c = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                                n3    = oriVt.GetNormal();
                                final = DirectionLight.GetFinalLightColor(n3, c);
                            }
                            else
                            {
                                final = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                            }
                        }
                        break;
                        }
                        device.DrawPoint(pos, final);
                    }
                }
            }
        }
Example #9
0
        /* 三角形扫描
         * 搜索三角形光栅化
         * __________  top
         * \            /
         *   \        /
         *     \    /
         *       \/
         *          bottom
         *       /\
         *     /    \
         *   /        \
         *  ---------
         */
        public void DrawNormalTriangle(VertexTriangle vt, VertexTriangle orit, Scene scene)
        {
            Vertex[] vv = GetList(vt.Vertices);

            Vertex v1 = vv[0];
            Vertex v2 = vv[1];
            Vertex v3 = vv[2];

            if (v1 == null)
            {
                return;
            }
            Vector4 p1 = v1.ScreenSpacePosition;
            Vector4 p2 = v2.ScreenSpacePosition;
            Vector4 p3 = v3.ScreenSpacePosition;

            float ax = p1.X;
            float bx = p2.X;
            float cx = p3.X;
            float ay = p1.Y;
            float by = p2.Y;
            float cy = p3.Y;

            float az = p1.Z;
            float bz = p2.Z;
            float cz = p3.Z;

            Color4 color1 = v1.Color;
            Color4 color2 = v2.Color;
            Color4 color3 = v3.Color;

            Vector4 normal1 = v1.nowNormal;
            Vector4 normal2 = v2.nowNormal;
            Vector4 normal3 = v3.nowNormal;

            if (ay == by)
            {
                DrawTopTriangle(v1, v2, v3, scene, vt, orit);
            }
            else if (by == cy)
            {
                DrawBottomTriangle(v1, v2, v3, scene, vt, orit);
            }
            else
            {
                if (ax == cx)
                {
                    Vertex newVt = new Vertex();

                    float y1 = (by - ay) / (cy - ay);

                    y1 = MathUtil.Clamp01(y1);

                    float x = MathUtil.Interp(ax, cx, y1);

                    float z = MathUtil.Interp(az, cz, y1);

                    Color4 c = MathUtil.ColorInterp(color1, color3, y1);

                    newVt.ScreenSpacePosition = new Vector4(x, by, z, 0);

                    newVt.lightColor = c;

                    newVt.Color = c;

                    newVt.nowNormal = MathUtil.Vector4Interp(normal1, normal3, y1);

                    newVt.UV = MathUtil.Vector4Interp(v1.UV, v3.UV, y1);

                    if ((int)bx > (int)cx)
                    {
                        DrawBottomTriangle(v1, newVt, v2, scene, vt, orit);

                        DrawTopTriangle(newVt, v2, v3, scene, vt, orit);
                    }
                    else
                    {
                        DrawBottomTriangle(v1, v2, newVt, scene, vt, orit);

                        DrawTopTriangle(v2, newVt, v3, scene, vt, orit);
                    }
                }
                else if (ax == bx)
                {
                    Vertex newVt = new Vertex();

                    float y1 = (by - ay) / (cy - ay);

                    y1 = MathUtil.Clamp01(y1);

                    float x = MathUtil.Interp(ax, cx, y1);

                    float z = MathUtil.Interp(az, cz, y1);

                    Color4 c = MathUtil.ColorInterp(color1, color3, y1);

                    newVt.ScreenSpacePosition = new Vector4(x, by, z, 0);

                    newVt.lightColor = c;

                    newVt.Color = c;

                    newVt.nowNormal = MathUtil.Vector4Interp(normal1, normal3, y1);

                    newVt.UV = MathUtil.Vector4Interp(v1.UV, v3.UV, y1);

                    if (cx < bx)
                    {
                        DrawBottomTriangle(v1, newVt, v2, scene, vt, orit);

                        DrawTopTriangle(newVt, v2, v3, scene, vt, orit);
                    }
                    else
                    {
                        DrawBottomTriangle(v1, v2, newVt, scene, vt, orit);

                        DrawTopTriangle(v2, newVt, v3, scene, vt, orit);
                    }
                }
                else if (bx == cx)
                {
                    Vertex newVt = new Vertex();

                    float y1 = (by - ay) / (cy - ay);

                    y1 = MathUtil.Clamp01(y1);

                    float x = MathUtil.Interp(ax, cx, y1);

                    float z = MathUtil.Interp(az, cz, y1);

                    Color4 c = MathUtil.ColorInterp(color1, color3, y1);

                    newVt.ScreenSpacePosition = new Vector4(x, by, z, 0);

                    newVt.lightColor = c;

                    newVt.Color = c;

                    newVt.nowNormal = MathUtil.Vector4Interp(normal1, normal3, y1);

                    newVt.UV = MathUtil.Vector4Interp(v1.UV, v3.UV, y1);

                    if (ax < bx)
                    {
                        DrawBottomTriangle(v1, newVt, v2, scene, vt, orit);

                        DrawTopTriangle(newVt, v2, v3, scene, vt, orit);
                    }
                    else
                    {
                        DrawBottomTriangle(v1, v2, newVt, scene, vt, orit);

                        DrawTopTriangle(v2, newVt, v3, scene, vt, orit);
                    }
                }
                else
                {
                    Vertex newVt = new Vertex();

                    float y1 = (float)(by - ay) / (float)(cy - ay);

                    y1 = MathUtil.Clamp01(y1);

                    float x = MathUtil.Interp(ax, cx, y1);

                    float z = MathUtil.Interp(az, cz, y1);

                    Color4 c = MathUtil.ColorInterp(color1, color3, y1);

                    newVt.ScreenSpacePosition = new Vector4(x, by, z, 0);

                    newVt.lightColor = c;

                    newVt.Color = c;

                    newVt.nowNormal = MathUtil.Vector4Interp(normal1, normal3, y1);

                    newVt.UV = MathUtil.Vector4Interp(v1.UV, v3.UV, y1);

                    // 计算线条的方向
                    float dP1P2, dP1P3;

                    // http://en.wikipedia.org/wiki/Slope
                    // 计算斜率
                    if (p2.Y - p1.Y > 0)
                    {
                        dP1P2 = (p2.X - p1.X) / (p2.Y - p1.Y);
                    }
                    else
                    {
                        dP1P2 = 0;
                    }

                    if (p3.Y - p1.Y > 0)
                    {
                        dP1P3 = (p3.X - p1.X) / (p3.Y - p1.Y);
                    }
                    else
                    {
                        dP1P3 = 0;
                    }

                    if (dP1P2 > dP1P3)
                    {
                        DrawBottomTriangle(v1, newVt, v2, scene, vt, orit);

                        DrawTopTriangle(newVt, v2, v3, scene, vt, orit);
                    }
                    else
                    {
                        DrawBottomTriangle(v1, v2, newVt, scene, vt, orit);

                        DrawTopTriangle(v2, newVt, v3, scene, vt, orit);
                    }
                }
            }
        }
Example #10
0
        /* 边表法填充
         * 优点 扫描效率高,结构清晰
         * 缺点 光栅化时三角形斜边在水平情况下差值不均匀造成颜色区块
         * vt是裁剪后的三角形,
         * orivt是原始三角形,目的是在纹理映射的时候计算权重
         *
         */
        public void ProcessScanLine(VertexTriangle vt, VertexTriangle oriVt, Scene scene, bool isworld)
        {
            int yMin = this.height;
            int yMax = 0;

            Vertex A = vt.Vertices[0];
            Vertex B = vt.Vertices[1];
            Vertex C = vt.Vertices[2];

            /* 扫描线原理
             *
             * 1. 求扫描线与多边形的交点
             * 2. 对所求得的交点按 x 从小到大排序
             * 3. 将交点两两配对,并填充每一区段
             *
             */
            // ET AEL 扫描算法见 72 页 4.2.2

            /* 1. 找到三角形 y 的最大值和最小值
             * 并将三角形的边以顶点坐标X的值从左往右(x 从小到大)填充
             * 在边表 ET[] 中对应三角形的Ymin处
             */

            Vertex[] vertices = vt.Vertices;

            for (int i = 0; i < vertices.Length; i++)
            {
                for (int j = i + 1; j < vertices.Length; j++)
                {
                    Vector4 screen1 = vertices[i].ScreenSpacePosition;
                    Vector4 screen2 = vertices[j].ScreenSpacePosition;

                    if ((int)screen1.Y != (int)screen2.Y)
                    {
                        if (screen1.Y > yMax)
                        {
                            yMax = (int)screen1.Y;
                        }
                        if (screen2.Y > yMax)
                        {
                            yMax = (int)screen2.Y;
                        }
                        if (screen1.Y < yMin)
                        {
                            yMin = (int)screen1.Y;
                        }
                        if (screen2.Y < yMin)
                        {
                            yMin = (int)screen2.Y;
                        }
                        if (yMax > this.height)
                        {
                            yMax = this.height;
                        }
                        if (yMin < 0)
                        {
                            yMin = 0;
                        }

                        int x1   = (int)screen1.X;
                        int y1   = (int)screen1.Y;
                        int x2   = (int)screen2.X;
                        int y2   = (int)screen2.Y;
                        int ymin = y1 > y2 ? y2 : y1;
                        if (ymin < 0)
                        {
                            ymin = 0;
                        }
                        int ymax = y1 > y2 ? y1 : y2;
                        if (ymax > this.height)
                        {
                            ymax = this.height;
                        }

                        // 保存的边的上端点x坐标
                        float x = y1 > y2 ? x2 : x1;

                        //边的斜率的倒数
                        float dx = (float)(x1 - x2) * 1.0f / (float)(y1 - y2);

                        Edge e = new Edge();
                        e.yMax = ymax;

                        // 保存x的目的是为了插入时保证边的顺序是按照x从小到大插入
                        // 在AEL中表示当前扫描线与边的交点x坐标,初值(在ET中的值)为边的下端点的x坐标
                        e.x = x;
                        // 斜率是保证在插入时,如果 x相同,以斜率大小比较
                        e.deltaX = dx;
                        // 保存边的上端点
                        e.v1 = y1 > y2 ? vertices[j] : vertices[i];
                        // 保存边的下端点
                        e.v2 = y1 > y2 ? vertices[i] : vertices[j];

                        EdgeTable.InsertEdge(ref ET[ymin].nextEdge, e);
                    }
                }
            }

            /* 2. 置空活动边表 AEL
             * AEL 存储的是 ET表在 扫描线 y = i 有交点的三角形的边
             */
            AEL = new Edge();

            oriVt.PreCalWeight();

            for (int i = yMin; i < yMax; i++)
            {
                // 将边表中在 y = i 的边 插入活动边表AEL中,并删除边表里的边
                EdgeTable.SearchTable(i, ET, AEL);

                if (AEL.nextEdge == null)
                {
                    continue;
                }

                // 获取连续的两条边
                Edge a1 = (Edge)AEL.nextEdge.Clone();
                Edge a2 = (Edge)AEL.nextEdge.nextEdge.Clone();

                // 从ymin开始扫描填充

                /*
                 * 记过排序后的边传入连续两条边 相交的情况只有两种钝角三角形 和锐角三角形
                 * x 从小到大
                 *
                 *        /\    /\
                 *       /  \  /  \
                 *      /    \/    \_________
                 *     x1    x3 x4
                 * 1. x左右分开
                 * 2. x相同 以斜率排序
                 *
                 */

                /* 双线性插值算法
                 * 斜边一次差值找出交点
                 * 水平扫描差值找出当前点
                 */
                Vector4 screenA1V1 = a1.v1.ScreenSpacePosition;
                Vector4 screenA1V2 = a1.v2.ScreenSpacePosition;
                Vector4 screenA2V1 = a2.v1.ScreenSpacePosition;
                Vector4 screenA2V2 = a2.v2.ScreenSpacePosition;

                // 第一次插值算出交点的颜色系数
                float r1 = ((float)i - screenA1V1.Y) / (float)(screenA1V2.Y - screenA1V1.Y);
                float r2 = ((float)i - screenA2V1.Y) / (float)(screenA2V2.Y - screenA2V1.Y);

                r1 = MathUtil.Clamp01(r1);
                r2 = MathUtil.Clamp01(r2);

                // 像素点深度插值
                float z1 = MathUtil.Interp(screenA1V1.Z, screenA1V2.Z, r1);
                float z2 = MathUtil.Interp(screenA2V1.Z, screenA2V2.Z, r2);

                float nDotLA1V1 = 0, nDotLA1V2 = 0, nDotLA2V1 = 0, nDotLA2V2 = 0, nDotL1 = 0, nDotL2 = 0;
                if (DirectionLight.IsEnable)
                {
                    nDotLA1V1 = DirectionLight.ComputeNDotL(a1.v1.nowPos, a1.v1.nowNormal);
                    nDotLA1V2 = DirectionLight.ComputeNDotL(a1.v2.nowPos, a1.v2.nowNormal);
                    nDotLA2V1 = DirectionLight.ComputeNDotL(a2.v1.nowPos, a2.v1.nowNormal);
                    nDotLA2V2 = DirectionLight.ComputeNDotL(a2.v2.nowPos, a2.v2.nowNormal);
                    // 双线性插值系数

                    nDotL1 = MathUtil.Interp(nDotLA1V1, nDotLA1V2, r1);
                    nDotL2 = MathUtil.Interp(nDotLA2V1, nDotLA2V2, r2);
                }

                // 横向填充
                while (a1 != null && a2 != null)
                {
                    for (int x = (int)AEL.nextEdge.x; x < (int)AEL.nextEdge.nextEdge.x; x++)
                    {
                        float r3 = MathUtil.Clamp01(((float)x - a1.x) / (a2.x - a1.x));
                        float z  = MathUtil.Interp(z1, z2, r3);

                        switch (scene.renderState)
                        {
                        case Scene.RenderState.WireFrame:
                        {
                        }
                        break;

                        case Scene.RenderState.GouraduShading:
                        {
                            //Padding.x = x;
                            //Padding.GouraudColor(scene,device,x,i,z,vt,oriVt);
                        }
                        break;

                        case Scene.RenderState.TextureMapping:
                        {
                            oriVt.CalWeight(new Vector4(x, i, 0, 0));
                            Vector4 uv = oriVt.GetInterUV();
                            if (isworld)
                            {
                                final = device.Tex2D(uv.X, uv.Y, scene.worldMap.texture);
                            }
                            else
                            {
                                if (DirectionLight.IsEnable)
                                {
                                    float nDotL = MathUtil.Interp(nDotL1, nDotL2, r3);
                                    final = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                                    final = final * DirectionLight.GetFinalLightColor(nDotL);
                                }
                                else
                                {
                                    final = device.Tex2D(uv.X, uv.Y, scene.mesh.texture);
                                }
                            }
                        }
                        break;
                        }
                        device.DrawPoint(new Vector4(x, i, z, 0), final);
                    }

                    if (a2.nextEdge != null)
                    {
                        a1 = (Edge)a2.nextEdge.Clone();
                        a2 = (Edge)a1.nextEdge.Clone();
                    }
                    else
                    {
                        break;
                    }
                }

                // 删除y=yMax-1的边 , 边的特性是上开下闭, 所以 当扫描到y = yamx后,ymax以前的边和扫描线不会再有交点
                // 所以要删除,避免盲目求交
                // 同时算出 x 的下一个坐标 并保存在 AEL的第一个边中 p.nextEdge.x += p.nextEdge.deltaX;
                EdgeTable.DeleteEdge(AEL, i);
            }
        }
Example #11
0
        /* 重心坐标填充
         * 填充效果明显,但基于精度问题,会有漏点
         * 切效率低,不建议使用
         */
        public void StartScanLine(VertexTriangle vt, VertexTriangle oriVt, Scene scene)
        {
            float yMin = this.height;
            float yMax = 0;

            Vertex[] vv = GetList(vt.Vertices);
            Vertex   A  = vv[0];
            Vertex   B  = vv[1];
            Vertex   C  = vv[2];

            float nDotLA1V1 = DirectionLight.ComputeNDotL(A.nowPos, A.nowNormal);

            A.lightColor = A.Color * DirectionLight.GetFinalLightColor(nDotLA1V1);

            float nDotLA1V2 = DirectionLight.ComputeNDotL(B.nowPos, B.nowNormal);

            B.lightColor = B.Color * DirectionLight.GetFinalLightColor(nDotLA1V2);

            float nDotLA2V1 = DirectionLight.ComputeNDotL(C.nowPos, C.nowNormal);

            C.lightColor = C.Color * DirectionLight.GetFinalLightColor(nDotLA2V1);

            float ay = A.ScreenSpacePosition.Y;
            float by = B.ScreenSpacePosition.Y;
            float cy = C.ScreenSpacePosition.Y;

            float ax = A.ScreenSpacePosition.X;
            float bx = B.ScreenSpacePosition.X;
            float cx = C.ScreenSpacePosition.X;

            float az = A.ScreenSpacePosition.Z;
            float bz = B.ScreenSpacePosition.Z;
            float cz = C.ScreenSpacePosition.Z;

            yMin = Math.Min(Math.Min(ay, by), Math.Min(by, cy));
            yMax = Math.Max(Math.Max(ay, by), Math.Max(by, cy));
            float xMin = (int)Math.Min(Math.Min(ax, bx), Math.Min(bx, cx));
            float xMax = (int)Math.Max(Math.Max(ax, bx), Math.Max(bx, cx));

            vt.Preproccess();

            float dtx = 0;
            float dty = 0;

            if (yMax - yMin > xMax - xMin)
            {
                dtx = (xMax - xMin) / (yMax - yMin);
                dty = 1;
            }
            else
            {
                dtx = 1;
                dty = (yMax - yMin) / (xMax - xMin);
            }

            for (int y = (int)yMin; y < yMax; y++)
            {
                for (int x = (int)xMin; x < xMax; x++)
                {
                    float z = vt.GetInterValue(az, bz, cz);

                    Padding.GouraudColor(scene, device, x, y, z, vt, oriVt);
                }
            }
        }