/// <summary>
 /// 屏幕空间插值生成新顶点,此时已近经过透视除法,z信息已经没有作用
 /// </summary>
 /// <param name="v1"></param>
 /// <param name="v2"></param>
 /// <param name="t"></param>
 /// <returns></returns>
 public static CVertex ScreenSpaceLerpVertex(CVertex v1, CVertex v2, float t)
 {
     CVertex v = new CVertex();
     float   u = MathUntil.Lerp(left.u, right.u, lerpFactor) * w * (_texture.Width - 1);
     float   v = MathUntil.Lerp(left.v, right.v, lerpFactor) * w * (_texture.Height - 1);
     float   r = MathUntil.Lerp(left.color.r, right.color.r, lerpFactor) * w * 255;
     float   g = MathUntil.Lerp(left.color.g, right.color.g, lerpFactor) * w * 255;
     float   b = MathUntil.Lerp(left.color.b, right.color.b, lerpFactor) * w * 255;
 }
 public CVertex(CVertex v)
 {
     point   = new CVector3D(v.point.x, v.point.y, v.point.z, 1);
     color.r = v.color.r;
     color.g = v.color.g;
     color.b = v.color.b;
     onePerZ = 1;
     this.u  = v.u;
     this.v  = v.v;
 }
 public CVertex(CVertex v)
 {
     point = new CVector3D(v.point.x, v.point.y, v.point.z, 1);
     color.r = v.color.r;
     color.g = v.color.g;
     color.b = v.color.b;
     onePerZ = 1;
     this.u = v.u;
     this.v = v.v;
 }
 /// <summary>
 /// 屏幕空间插值生成新顶点,此时已近经过透视除法,z信息已经没有作用
 /// </summary>
 /// <param name="v1"></param>
 /// <param name="v2"></param>
 /// <param name="t"></param>
 /// <returns></returns>
 public static void ScreenSpaceLerpVertex(ref CVertex v, CVertex v1, CVertex v2, float t)
 {
     v.onePerZ = MathUntil.Lerp(v1.onePerZ, v2.onePerZ, t);
     //
     v.u = MathUntil.Lerp(v1.u, v2.u, t);
     v.v = MathUntil.Lerp(v1.v, v2.v, t);
     //
     v.color.r = MathUntil.Lerp(v1.color.r, v2.color.r, t);
     v.color.g = MathUntil.Lerp(v1.color.g, v2.color.g, t);
     v.color.b = MathUntil.Lerp(v1.color.b, v2.color.b, t);
 }
 /// <summary>
 /// 屏幕空间插值生成新顶点,此时已近经过透视除法,z信息已经没有作用
 /// </summary>
 /// <param name="v1"></param>
 /// <param name="v2"></param>
 /// <param name="t"></param>
 /// <returns></returns>
 public static CVertex ScreenSpaceLerpVertex(CVertex v1, CVertex v2, float t)
 {
     CVertex v = new CVertex();
     float u = MathUntil.Lerp(left.u, right.u, lerpFactor) * w * (_texture.Width - 1);
     float v = MathUntil.Lerp(left.v, right.v, lerpFactor) * w * (_texture.Height - 1);
     float r = MathUntil.Lerp(left.color.r, right.color.r, lerpFactor) * w * 255;
     float g = MathUntil.Lerp(left.color.g, right.color.g, lerpFactor) * w * 255;
     float b = MathUntil.Lerp(left.color.b, right.color.b, lerpFactor) * w * 255;
 }
 /// <summary>
 /// 屏幕空间插值生成新顶点,此时已近经过透视除法,z信息已经没有作用
 /// </summary>
 /// <param name="v1"></param>
 /// <param name="v2"></param>
 /// <param name="t"></param>
 /// <returns></returns>
 public static void ScreenSpaceLerpVertex(ref CVertex v, CVertex v1, CVertex v2, float t)
 {
     v.onePerZ = MathUntil.Lerp(v1.onePerZ, v2.onePerZ, t);
     //
     v.u = MathUntil.Lerp(v1.u, v2.u, t);
     v.v = MathUntil.Lerp(v1.v, v2.v, t);
     //
     v.color.r = MathUntil.Lerp(v1.color.r, v2.color.r, t);
     v.color.g = MathUntil.Lerp(v1.color.g, v2.color.g, t);
     v.color.b = MathUntil.Lerp(v1.color.b, v2.color.b, t);
 }
        /// <summary>
        /// 光栅化三角形
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        private void TriangleRasterization(CVertex p1, CVertex p2, CVertex p3)
        {
            if(p1.point.y == p2.point.y)
            {
                if(p1.point.y < p3.point.y)
                {//平顶
                    DrawTriangleTop(p1, p2, p3);
                }
                else
                {//平底
                    DrawTriangleBottom(p3, p1, p2);
                }
            }
            else if (p1.point.y == p3.point.y)
            {
                if (p1.point.y < p2.point.y)
                {//平顶
                    DrawTriangleTop(p1, p3, p2);
                }
                else
                {//平底
                    DrawTriangleBottom(p2, p1, p1);
                }
            }
            else if (p2.point.y == p3.point.y)
            {
                if (p2.point.y < p1.point.y)
                {//平顶
                    DrawTriangleTop(p2, p3, p1);
                }
                else
                {//平底
                    DrawTriangleBottom(p1, p2, p3);
                }
            }
            else
            {//分割三角形
                CVertex top = null;

                CVertex bottom = null;
                CVertex middle = null;
                if(p1.point.y > p2.point.y && p2.point.y > p3.point.y)
                {
                    top = p3;
                    middle = p2;
                    bottom = p1;
                }
                else if (p3.point.y > p2.point.y && p2.point.y > p1.point.y)
                {
                    top = p1;
                    middle = p2;
                    bottom = p3;
                }
                else if (p2.point.y > p1.point.y && p1.point.y > p3.point.y)
                {
                    top = p3;
                    middle = p1;
                    bottom = p2;
                }
                else if (p3.point.y > p1.point.y && p1.point.y > p2.point.y)
                {
                    top = p2;
                    middle = p1;
                    bottom = p3;
                }
                else if(p1.point.y > p3.point.y && p3.point.y > p2.point.y)
                {
                    top = p2;
                    middle = p3;
                    bottom = p1;
                }
                else if (p2.point.y > p3.point.y && p3.point.y > p1.point.y)
                {
                    top = p1;
                    middle = p3;
                    bottom = p2;
                }
                //插值求中间点x
                float middlex = (middle.point.y - top.point.y) * (bottom.point.x - top.point.x) / (bottom.point.y - top.point.y) + top.point.x;
                float dy = middle.point.y - top.point.y;
                float t = dy / (bottom.point.y - top.point.y);
                //插值生成左右顶点
                CVertex newMiddle = new CVertex();
                newMiddle.point.x = middlex;
                newMiddle.point.y = middle.point.y;
                MathUntil.ScreenSpaceLerpVertex(ref newMiddle, top, bottom, t);

                //平底
                DrawTriangleBottom(top, newMiddle, middle);
                //平顶
                DrawTriangleTop(newMiddle, middle, bottom);
            }
        }
 /// <summary>
 /// 从齐次剪裁坐标系转到屏幕坐标
 /// </summary>
 private void TransformToScreen(CVertex v)
 {
     if(v.point.w != 0)
     {
         //先进行透视除法,转到cvv
         v.point.x *= 1 / v.point.w;
         v.point.y *= 1 / v.point.w;
         v.point.z *= 1 / v.point.w;
         v.point.w = 1;
         //cvv到屏幕坐标
         v.point.x = (v.point.x + 1) * 0.5f * this.MaximumSize.Width;
         v.point.y = (1 - v.point.y) * 0.5f * this.MaximumSize.Height;
     }
 }
        /// <summary>
        /// 进行mvp矩阵变换,将顶点变换到齐次裁剪空间
        /// </summary>
        private void SetMVPTransform(CMatrix4x4 m, CMatrix4x4 v, CMatrix4x4 p, CVertex vertex)
        {
            vertex.point = vertex.point * m;
            VectorMatrixTestCase.showVector3(vertex.point);
            vertex.point = vertex.point * v;
            VectorMatrixTestCase.showVector3(vertex.point);
            vertex.point = vertex.point * p;
            VectorMatrixTestCase.showVector3(vertex.point);

                //得到齐次裁剪空间的点 v.point.w 中保存着原来的z(具体是z还是-z要看使用的投影矩阵,我们使用投影矩阵是让w中保存着z)

                //onePerZ 保存1/z,方便之后对1/z关于x’、y’插值得到1/z’
            vertex.onePerZ = 1 / vertex.point.w;
                //校正的推论: s/z、t/z和x’、y’也是线性关系。而我们之前知道1/z和x’、y’是线性关系。则我们得出新的思路:对1/z关于x’、y’插值得到1/z’,然后对s/z、t/z关于x’、y’进行插值得到s’/z’、t’/z’,然后用s’/z’和t’/z’分别除以1/z’,就得到了插值s’和t’
                //这里将需要插值的信息都乘以1/z 得到 s/z和t/z等,方便光栅化阶段进行插值
            vertex.u *= vertex.onePerZ;
            vertex.v *= vertex.onePerZ;
                //
            vertex.color.r *= vertex.onePerZ;
            vertex.color.g *= vertex.onePerZ;
            vertex.color.b *= vertex.onePerZ;
        }
Esempio n. 10
0
        /// <summary>
        /// 扫描线填充
        /// </summary>
        /// <param name="left">左端点,值已经经过插值</param>
        /// <param name="right">右端点,值已经经过插值</param>
        private void ScanlineFill(CVertex left, CVertex right, int yIndex)
        {
            float dx = right.point.x - left.point.x;
            for (float x = left.point.x; x <= right.point.x; x++)
            {
                int xIndex = (int)(System.Math.Round(x, MidpointRounding.AwayFromZero));
                if (xIndex >= 0 && xIndex < this.MaximumSize.Width)
                {
                     float lerpFactor = 0;
                    if(dx != 0)
                    {
                        lerpFactor = (x - left.point.x) / dx;
                    }
                    //1/z’与x’和y'是线性关系的
                    float onePreZ = MathUntil.Lerp(left.onePerZ, right.onePerZ, lerpFactor);
                    if (onePreZ >= _zBuff[yIndex, xIndex])//使用1/z进行深度测试
                    {//通过测试
                        float w = 1 / onePreZ;
                        _zBuff[yIndex, xIndex] = onePreZ;
                        //uv 插值,求纹理颜色
                        float u = MathUntil.Lerp(left.u, right.u, lerpFactor) * w * (_texture.Width - 1);
                        float v = MathUntil.Lerp(left.v, right.v, lerpFactor) * w * (_texture.Height - 1);
                        int uIndex = (int)(u + 0.5f);
                        int vIndex = (int)(v + 0.5f);
                        uIndex = MathUntil.Range(uIndex, 0, _texture.Width - 1);
                        vIndex = MathUntil.Range(vIndex, 0, _texture.Height - 1);
                        //uv坐标系采用dx风格
                        System.Drawing.Color textrueColor = _texture.GetPixel(vIndex, uIndex);

                        //插值顶点颜色
                        float r = MathUntil.Lerp(left.color.r, right.color.r, lerpFactor) * w * 255;
                        float g = MathUntil.Lerp(left.color.g, right.color.g, lerpFactor) * w * 255;
                        float b = MathUntil.Lerp(left.color.b, right.color.b, lerpFactor) * w * 255;

                        //更新渲染模式渲染
                        if (RenderMode.Textured == _currentMode)
                        {
                            _frameBuff.SetPixel(xIndex, yIndex, textrueColor);
                        }
                        else if (RenderMode.VertexColor == _currentMode)
                        {
                            _frameBuff.SetPixel(xIndex, yIndex, System.Drawing.Color.FromArgb((int)r, (int)g, (int)b));
                        }
                    }
                }
            }
        }
Esempio n. 11
0
        //x = (y-y1) * (x2-x1) / (y2-y1) + x1
        /// <summary>
        /// 平顶,p1,p2,p3为下顶点
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        private void DrawTriangleTop(CVertex p1, CVertex p2, CVertex p3)
        {
            for (float y = p1.point.y; y <= p3.point.y; y++)
            {
                int yIndex = (int)(System.Math.Round(y, MidpointRounding.AwayFromZero));
                if (yIndex >= 0 && yIndex < this.MaximumSize.Height)
                {
                    float xl = (y - p1.point.y) * (p3.point.x - p1.point.x) / (p3.point.y - p1.point.y) + p1.point.x;
                    float xr = (y - p2.point.y) * (p3.point.x - p2.point.x) / (p3.point.y - p2.point.y) + p2.point.x;

                    float dy = y - p1.point.y;
                    float t = dy / (p3.point.y - p1.point.y);
                    //插值生成左右顶点
                    CVertex new1 = new CVertex();
                    new1.point.x = xl;
                    new1.point.y = y;
                    MathUntil.ScreenSpaceLerpVertex(ref new1, p1, p3, t);
                    //
                    CVertex new2 = new CVertex();
                    new2.point.x = xr;
                    new2.point.y = y;
                    MathUntil.ScreenSpaceLerpVertex(ref new2, p2, p3, t);
                    //扫描线填充
                    if (new1.point.x < new2.point.x)
                    {
                        ScanlineFill(new1, new2, yIndex);
                    }
                    else
                    {
                        ScanlineFill(new2, new1, yIndex);
                    }
                }
            }
        }
Esempio n. 12
0
        /// <summary>
        /// 绘制三角形
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        /// <param name="mvp"></param>
        private void DrawTriangle(CVertex p1, CVertex p2, CVertex p3, CMatrix4x4 m, CMatrix4x4 v, CMatrix4x4 p)
        {
            //--------------------几何阶段---------------------------
            //变换到齐次裁剪空
            SetMVPTransform(m, v, p, p1);
            SetMVPTransform(m, v, p, p2);
            SetMVPTransform(m, v, p, p3);

            ////裁剪
            if (Clip(p1) == false || Clip(p2) == false || Clip(p3) == false)
            {
                return;
            }
            //背面消隐
            //if (BackFaceCulling(p1, p2, p3) == false)
            //{
            //    return;
            //}
            //变换到屏幕坐标
            TransformToScreen(p1);
            VectorMatrixTestCase.showVector3(p1.point);
            TransformToScreen(p2);
            VectorMatrixTestCase.showVector3(p2.point);
            TransformToScreen(p3);
            VectorMatrixTestCase.showVector3(p3.point);

            //--------------------光栅化阶段---------------------------
            //todo test
            //_frameBuff.SetPixel((int)p1.point.x, (int)p1.point.y, System.Drawing.Color.White);
            //_frameBuff.SetPixel((int)p2.point.x, (int)p2.point.y, System.Drawing.Color.White);
            //_frameBuff.SetPixel((int)p3.point.x, (int)p3.point.y, System.Drawing.Color.White);

            TriangleRasterization(p1, p2, p3);
        }
Esempio n. 13
0
        /// <summary>
        /// 绘制平面
        /// </summary>
        /// <param name="vIndex1">顶点索引</param>
        /// <param name="vIndex2">顶点索引</param>
        /// <param name="vIndex3">顶点索引</param>
        /// <param name="vIndex4">顶点索引</param>
        /// <param name="mvp">mvp矩阵</param>
        private void DrawPanel(int vIndex1, int vIndex2, int vIndex3, int vIndex4, CMatrix4x4 m, CMatrix4x4 v, CMatrix4x4 p)
        {
            CVertex p1 = new CVertex(mesh[vIndex1]);
            CVertex p2 = new CVertex(mesh[vIndex2]);
            CVertex p3 = new CVertex(mesh[vIndex3]);
            //
            DrawTriangle(p1, p2, p3, m, v, p);
            p1 = new CVertex(mesh[vIndex1]);
            p3 = new CVertex(mesh[vIndex3]);
            CVertex p4 = new CVertex(mesh[vIndex4]);

            DrawTriangle(p3, p4, p1, m, v, p);
        }
Esempio n. 14
0
 /// <summary>
 /// 检查是否裁剪这个顶点,简单的cvv裁剪,在透视除法之前
 /// </summary>
 /// <returns>是否通关剪裁</returns>
 private bool Clip(CVertex v)
 {
     //cvv为 x-1,1  y-1,1  z0,1
     if(v.point.x >= -v.point.w && v.point.x <= v.point.w &&
         v.point.y >= -v.point.w && v.point.y <= v.point.w &&
         v.point.z >= 0f && v.point.z <= v.point.w)
     {
         return true;
     }
     return false;
 }
Esempio n. 15
0
 /// <summary>
 /// 背面消隐
 /// </summary>
 /// <returns>是否通关背面消隐测试</returns>
 private bool BackFaceCulling(CVertex p1, CVertex p2, CVertex p3)
 {
     CVector3D v1 = p2.point - p1.point;
     CVector3D v2 = p3.point - p2.point;
     CVector3D normal = CVector3D.Cross(v1, v2);
     CVector3D viewDir = new CVector3D(0,0,1);//由于在剪裁空间,视线一点是这个方向
     if (CVector3D.Dot(normal,viewDir) > 0)
     {
         return true;
     }
     return false;
 }