Example #1
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 #2
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 #3
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);
            }
        }