public Vertex(Vertex v)
 {
     point = v.point;
     normal = v.normal;
     this.vcolor = v.vcolor;
     onePerZ = 1;
     this.u = v.u;
     this.v = v.v;
     this.lightingColor = v.lightingColor;
 }
 /// <summary>
 /// 
 /// </summary>
 /// <param name="pointList">顶点位置列表</param>
 /// <param name="indexs">顶点索引列表</param>
 /// <param name="Uvs">uv坐标列表</param>
 /// <param name="vertColor">顶点色列表</param>
 public Mesh(Vector3D[] pointList, int[] indexs, Point2D[] Uvs, Vector3D[] vertColors, Vector3D[] normals, Material mat)
 {
     _verts = new Vertex[indexs.Length];
     //生成顶点列表
     for (int i = 0; i < indexs.Length; i++)
     {
         int pointIndex = indexs[i];
         Vector3D point = pointList[pointIndex];
         _verts[i] = new Vertex(point, normals[i], Uvs[i].x, Uvs[i].y, vertColors[i].x, vertColors[i].y, vertColors[i].z);
     }
     _mat = mat;
 }
        /// <summary>
        /// 光栅化三角形
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        private void TriangleRasterization(Vertex p1, Vertex p2, Vertex 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, p3);
                }
            }
            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
            {//分割三角形
                Vertex top;

                Vertex bottom;
                Vertex middle;
                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;
                }
                else
                {
                    //三点共线
                    return;
                }
                //插值求中间点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);
                //插值生成左右顶点
                Vertex newMiddle = new Vertex();
                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(ref Vertex 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>
        /// 投影变换,从相机空间到齐次剪裁空间
        /// </summary>
        /// <param name="p"></param>
        /// <param name="vertex"></param>
        private void SetProjectionTransform(Matrix4x4 p,ref Vertex vertex)
        {
            vertex.point = vertex.point * p;
            //得到齐次裁剪空间的点 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.vcolor *= vertex.onePerZ;
            //
            vertex.lightingColor *= vertex.onePerZ;
        }
 /// <summary>
 /// 进行mv矩阵变换,从本地模型空间到世界空间,再到相机空间
 /// </summary>
 private void SetMVTransform(Matrix4x4 m, Matrix4x4 v,ref Vertex vertex)
 {
     vertex.point = vertex.point * m * v;
 }
        /// <summary>
        /// 扫描线填充
        /// </summary>
        /// <param name="left">左端点,值已经经过插值</param>
        /// <param name="right">右端点,值已经经过插值</param>
        private void ScanlineFill(Vertex left, Vertex right, int yIndex)
        {
            float dx = right.point.x - left.point.x;
            float step = 1;
            if(dx != 0)
            {
                step = 1 / dx;
            }
            for (float x = left.point.x; x <= right.point.x; x += 0.5f)
            {
                int xIndex = (int)(x + 0.5f);
                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);
                        //纹理采样
                        SoftRenderer.RenderData.Color texColor = new RenderData.Color(1,1,1);
                        if(_textureFilterMode == TextureFilterMode.point)
                        {//点采样
                            int uIndex = (int)System.Math.Round(u , MidpointRounding.AwayFromZero);
                            int vIndex = (int)System.Math.Round(v , MidpointRounding.AwayFromZero);
                            uIndex = MathUntil.Range(uIndex, 0, _texture.Width - 1);
                            vIndex = MathUntil.Range(vIndex, 0, _texture.Height - 1);
                            //uv坐标系采用dx风格
                            texColor = new RenderData.Color(ReadTexture(uIndex, vIndex));//转到我们自定义的color进行计算
                        }
                        else if(_textureFilterMode == TextureFilterMode.Bilinear)
                        {//双线性采样
                            float uIndex = (float)System.Math.Floor(u);
                            float vIndex = (float)System.Math.Floor(v);
                            float du = u - uIndex;
                            float dv = v - vIndex;

                            SoftRenderer.RenderData.Color texcolor1 = new RenderData.Color(ReadTexture((int)uIndex, (int)vIndex)) * (1 - du) * (1 - dv);
                            SoftRenderer.RenderData.Color texcolor2 = new RenderData.Color(ReadTexture((int)uIndex + 1, (int)vIndex)) * du * (1 - dv);
                            SoftRenderer.RenderData.Color texcolor3 = new RenderData.Color(ReadTexture((int)uIndex, (int)vIndex + 1)) * (1 - du) * dv;
                            SoftRenderer.RenderData.Color texcolor4 = new RenderData.Color(ReadTexture((int)uIndex + 1, (int)vIndex + 1)) * du * dv;
                            texColor = texcolor1 + texcolor2 + texcolor3 + texcolor4;
                        }

                        //插值顶点颜色
                        SoftRenderer.RenderData.Color vertColor = MathUntil.Lerp(left.vcolor, right.vcolor, lerpFactor) * w;
                        //插值光照颜色
                        SoftRenderer.RenderData.Color lightColor = MathUntil.Lerp(left.lightingColor, right.lightingColor, lerpFactor) * w; ;

                        if(_lightMode == LightMode.On)
                        {//光照模式,需要混合光照的颜色
                            if (RenderMode.Textured == _currentMode)
                            {
                                SoftRenderer.RenderData.Color finalColor = texColor * lightColor;
                                _frameBuff.SetPixel(xIndex, yIndex, finalColor.TransFormToSystemColor());
                            }
                            else if (RenderMode.VertexColor == _currentMode)
                            {
                                SoftRenderer.RenderData.Color finalColor = vertColor * lightColor;
                                _frameBuff.SetPixel(xIndex, yIndex, finalColor.TransFormToSystemColor());
                            }
                        }
                        else
                        {
                            if (RenderMode.Textured == _currentMode)
                            {
                                _frameBuff.SetPixel(xIndex, yIndex, texColor.TransFormToSystemColor());
                            }
                            else if (RenderMode.VertexColor == _currentMode)
                            {
                                _frameBuff.SetPixel(xIndex, yIndex, vertColor.TransFormToSystemColor());
                            }
                        }
                    }
                }
            }
        }
        /// <summary>
        /// 实现了“基础光照模型”,在世界空间进行顶点光照处理
        /// </summary>
        /// <param name="v"></param>
        private void Lighting(Matrix4x4 m, Vector3D worldEyePositon ,ref Vertex v)
        {
            Vector3D worldPoint = v.point * m;//世界空间顶点位置
            Vector3D normal = v.normal * m.Inverse().Transpose();//模型空间法线乘以世界矩阵的逆转置得到世界空间法线
            normal = normal.Normalize();
            SoftRenderer.RenderData.Color emissiveColor = _mesh.material.emissive;//自发光
            SoftRenderer.RenderData.Color ambientColor = _ambientColor * _mesh.material.ka;//环境光

            Vector3D inLightDir = (_light.worldPosition - worldPoint).Normalize();
            float diffuse = Vector3D.Dot(normal, inLightDir);
            if(diffuse < 0)
            {
                diffuse = 0;
            }
            SoftRenderer.RenderData.Color diffuseColor = _mesh.material.diffuse * diffuse * _light.lightColor;//漫反射
            //
            Vector3D inViewDir = (worldEyePositon - worldPoint).Normalize();
            Vector3D h = (inViewDir + inLightDir).Normalize();
            float specular = 0;
            if(diffuse != 0)
            {//防止出现光源在物体背面产生高光的情况
                specular = (float)System.Math.Pow(MathUntil.Range(Vector3D.Dot(h, normal), 0, 1), _mesh.material.shininess);
            }
            SoftRenderer.RenderData.Color specularColor = _mesh.material.specular * specular * _light.lightColor;//镜面高光
            //
            v.lightingColor = emissiveColor + ambientColor + diffuseColor + specularColor;
        }
        //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(Vertex p1, Vertex p2, Vertex p3)
        {
            for (float y = p1.point.y; y <= p3.point.y; y+= 0.5f)
            {
                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);
                    //插值生成左右顶点
                    Vertex new1 = new Vertex();
                    new1.point.x = xl;
                    new1.point.y = y;
                    MathUntil.ScreenSpaceLerpVertex(ref new1, p1, p3, t);
                    //
                    Vertex new2 = new Vertex();
                    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);
                    }
                }
            }
        }
示例#10
0
        /// <summary>
        /// 绘制三角形
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        /// <param name="p3"></param>
        /// <param name="mvp"></param>
        private void DrawTriangle(Vertex p1, Vertex p2, Vertex p3, Matrix4x4 m, Matrix4x4 v, Matrix4x4 p)
        {
            //--------------------几何阶段---------------------------
            if (_lightMode == LightMode.On)
            {//进行顶点光照
                Lighting(m, _camera.pos, ref p1);
                Lighting(m, _camera.pos, ref p2);
                Lighting(m, _camera.pos, ref p3);
            }

            //变换到相机空间
            SetMVTransform(m, v,ref p1);
            SetMVTransform(m, v, ref p2);
            SetMVTransform(m, v, ref p3);

            //在相机空间进行背面消隐
            if (BackFaceCulling(p1, p2, p3) == false)
            {
                return;
            }

            //变换到齐次剪裁空间
            SetProjectionTransform(p, ref p1);
            SetProjectionTransform(p, ref p2);
            SetProjectionTransform(p, ref p3);

            //裁剪
            if (Clip(p1) == false || Clip(p2) == false || Clip(p3) == false)
            {
                return;
            }

            //变换到屏幕坐标
            TransformToScreen(ref p1);
            TransformToScreen(ref p2);
            TransformToScreen(ref p3);

            //--------------------光栅化阶段---------------------------

            if(_currentMode == RenderMode.Wireframe)
            {//线框模式
                BresenhamDrawLine(p1, p2);
                BresenhamDrawLine(p2, p3);
                BresenhamDrawLine(p3, p1);
            }
            else
            {
                TriangleRasterization(p1, p2, p3);
            }
        }
示例#11
0
 /// <summary>
 /// 检查是否裁剪这个顶点,简单的cvv裁剪,在透视除法之前
 /// </summary>
 /// <returns>是否通关剪裁</returns>
 private bool Clip(Vertex 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;
 }
示例#12
0
        /// <summary>
        /// 绘制直线,使用bresenham算法
        /// </summary>
        /// <param name="p1"></param>
        /// <param name="p2"></param>
        private void BresenhamDrawLine(Vertex p1, Vertex p2)
        {
            int x = (int)(System.Math.Round(p1.point.x, MidpointRounding.AwayFromZero));
            int y = (int)(System.Math.Round(p1.point.y, MidpointRounding.AwayFromZero));
            int dx = (int)(System.Math.Round(p2.point.x - p1.point.x, MidpointRounding.AwayFromZero));
            int dy = (int)(System.Math.Round(p2.point.y - p1.point.y, MidpointRounding.AwayFromZero));
            int stepx = 1;
            int stepy = 1;

            if(dx >= 0)
            {
                stepx = 1;
            }
            else
            {
                stepx = -1;
                dx = System.Math.Abs(dx);
            }

            if(dy >= 0)
            {
                stepy = 1;
            }
            else
            {
                stepy = -1;
                dy = System.Math.Abs(dy);
            }

            int dx2 = 2 * dx;
            int dy2 = 2 * dy;

            if(dx > dy)
            {
                int error = dy2 - dx;
                for (int i = 0; i <= dx; i++)
                {
                    _frameBuff.SetPixel(x, y, System.Drawing.Color.White);
                    if(error >= 0)
                    {
                        error -= dx2;
                        y += stepy;
                    }
                    error += dy2;
                    x += stepx;

                }
            }
            else
            {
                int error = dx2 - dy;
                for (int i = 0; i <= dy; i++)
                {
                    _frameBuff.SetPixel(x, y, System.Drawing.Color.White);
                    if (error >= 0)
                    {
                        error -= dy2;
                        x += stepx;
                    }
                    error += dx2;
                    y += stepy;

                }
            }
        }
示例#13
0
 /// <summary>
 /// 背面消隐
 /// </summary>
 /// <returns>是否通关背面消隐测试</returns>
 private bool BackFaceCulling(Vertex p1, Vertex p2, Vertex p3)
 {
     if(_currentMode == RenderMode.Wireframe)
     {//线框模式不进行背面消隐
         return true;
     }
     else
     {
         Vector3D v1 = p2.point - p1.point;
         Vector3D v2 = p3.point - p2.point;
         Vector3D normal = Vector3D.Cross(v1, v2);
         //由于在视空间中,所以相机点就是(0,0,0)
         Vector3D viewDir = p1.point - new Vector3D(0, 0, 0);
         if (Vector3D.Dot(normal, viewDir) > 0)
         {
             _showTrisCount++;
             return true;
         }
         return false;
     }
 }