Ejemplo n.º 1
0
 public Fragment(Fragment v1, Fragment v2, float t)
 {
     this.RasterizedPosition = v1.RasterizedPosition + t * (v2.RasterizedPosition - v1.RasterizedPosition);
     this.Normal = v1.Normal + t * (v2.Normal - v1.Normal);
     this.U = v1.U + t * (v2.U - v1.U);
     this.V = v1.V + t * (v2.V - v1.V);
 }
        private void SetVertexColor(Fragment vertex)
        {
            Vector surfaceNormal = vertex.Normal;
            Vector lightDirection;
            Vector vertexColor = new Vector();

            Vector diffuse = new Vector();
            if (vertex.HasTexture)
            {
                diffuse = new Vector(1, 1, 1, 1);
            }
            else
            {
                diffuse = vertex.Material.Diffuse;
            }

            foreach (SceneLight light in scene.Lights)
            {
                Vector currentLightColor = new Vector();
                lightDirection = light.Position - vertex.WorldPosition;
                lightDirection.Normalize3();

                //Get cosine of angle between vectors
                float similarity = Vector.Dot3(surfaceNormal, lightDirection);
                Vector lambertColor = new Vector();
                lambertColor = Vector.ColorMultiplication(light.Color, diffuse) * Math.Max(0, similarity);

                //Get half vector between camera direction and light direction
                Vector eyeDirection = scene.Camera.Position - vertex.WorldPosition;
                eyeDirection.Normalize3();
                Vector halfVector = eyeDirection + lightDirection;
                halfVector.Normalize3();

                //Phong shading calculations
                float normalHalfSimilarity = Vector.Dot3(surfaceNormal, halfVector);
                Vector phongLightCoefficient = Vector.ColorMultiplication(light.Color, vertex.Material.Specular);
                float shininessComponent = (float)Math.Pow(Math.Max(0, normalHalfSimilarity), vertex.Material.Shininess);
                Vector phongColor = phongLightCoefficient * shininessComponent;

                //Add colors and ambient light
                currentLightColor = Vector.LightAdd(lambertColor, phongColor);
                vertexColor = Vector.LightAdd(vertexColor, currentLightColor);
            }

            vertex.BlinnPhongColor = vertexColor;
        }
        private List<SceneTriangle> ClipFrustrum()
        {
            List<SceneTriangle> clippedTriangles = new List<SceneTriangle>();
            foreach (SceneObject sceneObj in scene.Objects) clippedTriangles.Add(sceneObj as SceneTriangle);

            Vector w = CalculateW(scene.Camera.Position, scene.Camera.Target);
            Vector q = scene.Camera.Position - scene.Camera.NearClip * w;

            //Para efectos del clipping plane
               // float D = -Vector.Dot3(w, scene.Camera.Position) + scene.Camera.NearClip * Vector.Dot3(w, w);

            Console.WriteLine("Z: " + scene.Camera.Position.z);
            //Console.WriteLine("q: " + q);
            //Console.WriteLine("w: " + w);
            planeNormals.Clear();
            planePoints.Clear();
            planeNames.Clear();
            planeNormals.Add(-w);
            planePoints.Add(scene.Camera.Position - w * scene.Camera.NearClip);
            planeNormals.Add(w);
            planePoints.Add(scene.Camera.Position - w * scene.Camera.FarClip);
            planeNames.Add("Near");
            planeNames.Add("Far");
            Console.WriteLine("////////////////////////////////////////////////////////");
            Console.WriteLine("Num triangles: " + clippedTriangles.Count);
            Console.WriteLine("Num planes: " + planeNormals.Count);
            Console.WriteLine("Z: " + scene.Camera.Position.z);
            for (int current_plane = 0; current_plane < planeNormals.Count; current_plane++)
            {

                Console.WriteLine("Plane: " + planeNames[current_plane]);
               // Cons
                float D = -Vector.Dot3(planeNormals[current_plane], planePoints[current_plane]);
                List<SceneTriangle> newTriangles = new List<SceneTriangle>();
                foreach (SceneTriangle triangle in clippedTriangles)
                {
                    List<Fragment> outside = new List<Fragment>();
                    List<Fragment> inside = new List<Fragment>();

                    for (int i = 0; i < 3; ++i)
                    {
                        float x = triangle.Vertex[i].x, y = triangle.Vertex[i].y, z = triangle.Vertex[i].z;

                        float planeDistance = Vector.Dot3(planeNormals[current_plane], triangle.Vertex[i]) + D;
                        //Console.WriteLine("Vertex: " + triangle.Vertex[i]);
                        Console.WriteLine("Distance: " + planeDistance);
                        if (planeDistance < 0)
                        {
                            Fragment outsideVertex = new Fragment();

                            outsideVertex.U = triangle.U[i];
                            outsideVertex.V = triangle.V[i];
                            outsideVertex.Normal = triangle.Normal[i];
                            outsideVertex.Material = triangle.Materials[i];
                            outsideVertex.RasterizedPosition = triangle.Vertex[i];
                            outside.Add(outsideVertex);
                        }
                        else
                        {
                            Fragment insideVertex = new Fragment();

                            insideVertex.U = triangle.U[i];
                            insideVertex.RasterizedPosition = triangle.Vertex[i];
                            insideVertex.V = triangle.V[i];
                            insideVertex.Normal = triangle.Normal[i];
                            insideVertex.Material = triangle.Materials[i];

                            inside.Add(insideVertex);
                        }
                    }
                    if (outside.Count == 3)
                    {
                        Console.WriteLine("All vertex outside");
                        continue;
                    }
                    else if (outside.Count == 2)
                    {
                        Console.WriteLine("Two vertices outside, adding new triangle");

                        float t1 = (Vector.Dot3(planeNormals[current_plane], outside[0].RasterizedPosition) + D) / (Vector.Dot3(planeNormals[current_plane], outside[0].RasterizedPosition - inside[0].RasterizedPosition));
                        Fragment inter1 = new Fragment(outside[0], inside[0], t1);
                        Console.WriteLine("t1 = " + t1);
                        float t2 = (Vector.Dot3(planeNormals[current_plane], outside[1].RasterizedPosition) + D) / (Vector.Dot3(planeNormals[current_plane], outside[1].RasterizedPosition - inside[0].RasterizedPosition));
                        Fragment inter2 = new Fragment(outside[1], inside[0], t2);
                        Console.WriteLine("t2 = " + t2);

                        SceneTriangle clipped = new SceneTriangle();
                        clipped.Vertex = new List<Vector>();
                        clipped.Vertex.Add(inter1.RasterizedPosition);
                        clipped.Vertex.Add(inter2.RasterizedPosition);
                        clipped.Vertex.Add(inside[0].RasterizedPosition);

                        clipped.U = new List<float>();
                        clipped.U.Add(inter1.U);
                        clipped.U.Add(inter2.U);
                        clipped.U.Add(inside[0].U);

                        clipped.V = new List<float>();
                        clipped.V.Add(inter1.V);
                        clipped.V.Add(inter2.V);
                        clipped.V.Add(inside[0].V);

                        clipped.Normal = new List<Vector>();
                        clipped.Normal.Add(inter1.Normal);
                        clipped.Normal.Add(inter2.Normal);
                        clipped.Normal.Add(inside[0].Normal);

                        clipped.Materials = triangle.Materials;
                        clipped.Position = triangle.Position;
                        clipped.Rotation = triangle.Rotation;
                        clipped.Scale = triangle.Scale;
                        newTriangles.Add(clipped);

                        Console.WriteLine("New positions: ");
                        Console.WriteLine(clipped.Vertex[0]);
                        Console.WriteLine(clipped.Vertex[1]);
                        Console.WriteLine(clipped.Vertex[2]);
                    }
                    else if (outside.Count == 1)
                    {
                        Console.WriteLine("One vertex outside");
                        float t1 = (Vector.Dot3(planeNormals[current_plane], outside[0].RasterizedPosition) + D) / (Vector.Dot3(planeNormals[current_plane], outside[0].RasterizedPosition - inside[0].RasterizedPosition));
                        Fragment inter1 = new Fragment(outside[0], inside[0], t1);
                        Console.WriteLine("t1 = " + t1);
                        float t2 = (Vector.Dot3(planeNormals[current_plane], outside[0].RasterizedPosition) + D) / (Vector.Dot3(planeNormals[current_plane], outside[0].RasterizedPosition - inside[1].RasterizedPosition));
                        Fragment inter2 = new Fragment(outside[0], inside[1], t2);
                        Console.WriteLine("t2 = " + t2);

                        SceneTriangle clipped1 = new SceneTriangle();
                        clipped1.Vertex = new List<Vector>();
                        clipped1.Vertex.Add(inter1.RasterizedPosition);
                        clipped1.Vertex.Add(inter2.RasterizedPosition);
                        clipped1.Vertex.Add(inside[0].RasterizedPosition);

                        clipped1.U = new List<float>();
                        clipped1.U.Add(inter1.U);
                        clipped1.U.Add(inter2.U);
                        clipped1.U.Add(inside[0].U);

                        clipped1.V = new List<float>();
                        clipped1.V.Add(inter1.V);
                        clipped1.V.Add(inter2.V);
                        clipped1.V.Add(inside[0].V);

                        clipped1.Normal = new List<Vector>();
                        clipped1.Normal.Add(inter1.Normal);
                        clipped1.Normal.Add(inter2.Normal);
                        clipped1.Normal.Add(inside[0].Normal);

                        clipped1.Materials = triangle.Materials;
                        clipped1.Position = triangle.Position;
                        clipped1.Rotation = triangle.Rotation;
                        clipped1.Scale = triangle.Scale;
                        newTriangles.Add(clipped1);

                        SceneTriangle clipped2 = new SceneTriangle();
                        clipped2.Vertex = new List<Vector>();
                        clipped2.Vertex.Add(inter2.RasterizedPosition);
                        clipped2.Vertex.Add(inside[0].RasterizedPosition);
                        clipped2.Vertex.Add(inside[1].RasterizedPosition);

                        clipped2.U = new List<float>();
                        clipped2.U.Add(inter2.U);
                        clipped2.U.Add(inside[0].U);
                        clipped2.U.Add(inside[1].U);

                        clipped2.V = new List<float>();
                        clipped2.V.Add(inter2.V);
                        clipped2.V.Add(inside[0].V);
                        clipped2.V.Add(inside[1].V);

                        clipped2.Normal = new List<Vector>();
                        clipped2.Normal.Add(inter2.Normal);
                        clipped2.Normal.Add(inside[0].Normal);
                        clipped2.Normal.Add(inside[1].Normal);

                        SceneMaterial otherMat = scene.GetMaterial("Red");
                        clipped2.Materials.Add(otherMat);
                        clipped2.Materials.Add(otherMat);
                        clipped2.Materials.Add(otherMat);
                        clipped2.Materials = triangle.Materials;
                        clipped2.Position = triangle.Position;
                        clipped2.Rotation = triangle.Rotation;
                        clipped2.Scale = triangle.Scale;
                        newTriangles.Add(clipped2);

                        Console.WriteLine("New positions: ");
                        Console.WriteLine(clipped1.Vertex[0]);
                        Console.WriteLine(clipped1.Vertex[1]);
                        Console.WriteLine(clipped1.Vertex[2]);
                        Console.WriteLine(clipped2.Vertex[0]);
                        Console.WriteLine(clipped2.Vertex[1]);
                        Console.WriteLine(clipped2.Vertex[2]);
                    }
                    else
                    {
                        newTriangles.Add(triangle);
                    }
                }

                clippedTriangles = newTriangles;
            }
            Console.WriteLine("After clipping: " + clippedTriangles.Count + " triangles");
            return clippedTriangles;
        }
        /// <summary>
        /// Método que dibuja un triángulo 2D, pintando su superficie interpolando los colores de sus vértices.
        /// </summary>
        /// <param name="p1">Vertice 1</param>
        /// <param name="p2">Vertice 2</param>
        /// <param name="p3">Vertice 3</param>
        /// <param name="c1">Color asociado al vertice 1</param>
        /// <param name="c2">Color asociado al vertice 2</param>
        /// <param name="c3">Color asociado al vertice 3</param>
        /// <param name="antialias">Define con o sin antialias.</param>
        private void DrawTriangle(List<Fragment> rasterized)
        {
            //bool antiAlias = renderingParameters.EnableAntialias;
            //if (renderingParameters.WireFrame)
            //{
            //    DrawTriangleWire(rasterized);
            //    return;
            //}
            //if (renderingParameters.EnableAntialias)
            //{
            //    for (int i = 0; i < 3; i++)
            //    {
            //        DrawLineXiaolin(rasterized[i].Position, rasterized[(i + 1) % 3].Position, rasterized[i].BlinnPhongColor, rasterized[(i + 1) % 3].BlinnPhongColor);
            //    }
            //}

            float h0 = rasterized[0].RasterizedPosition.w;
            float h1 = rasterized[1].RasterizedPosition.w;
            float h2 = rasterized[2].RasterizedPosition.w;

            float x1 = rasterized[0].RasterizedPosition.x / rasterized[0].RasterizedPosition.w, x2 = rasterized[1].RasterizedPosition.x / rasterized[1].RasterizedPosition.w, x3 = rasterized[2].RasterizedPosition.x / rasterized[2].RasterizedPosition.w;
            float y1 = rasterized[0].RasterizedPosition.y / rasterized[0].RasterizedPosition.w, y2 = rasterized[1].RasterizedPosition.y / rasterized[1].RasterizedPosition.w, y3 = rasterized[2].RasterizedPosition.y / rasterized[2].RasterizedPosition.w;

            float y1y3 = y1 - y3, y1y2 = y1 - y2, y2y3 = y2 - y3;
            float x1x3 = x1 - x3, x1x2 = x1 - x2, x2x3 = x2 - x3;

            float leftmost = x1;
            if (x2 < leftmost) leftmost = x1;
            if (x3 < leftmost) leftmost = x3;

            float rightmost = x1;
            if (x2 > rightmost) rightmost = x2;
            if (x3 > rightmost) rightmost = x3;

            float topmost = y1;
            if (y2 > topmost) topmost = y2;
            if (y3 > topmost) topmost = y3;

            float bottommost = y1;
            if (y2 < bottommost) bottommost = y2;
            if (y3 < bottommost) bottommost = y3;

            float den1 = (y2y3 * x1x3 - x2x3 * y1y3);
            float den2 = (-y1y3 * x2x3 + x1x3 * y2y3);

                for (float x = leftmost; x <= rightmost && x < rendParams.Width; x++)
                {
                    if (x < 0)
                        continue;

                    for (float y = bottommost; y <= rendParams.Height; y++)
                    {
                        if (y < 0)
                            continue;

                        float alpha = (y2y3 * (x - x3) - x2x3 * (y - y3)) / den1;
                        if (alpha < 0 || alpha > 1) continue;

                        float betta = (-y1y3 * (x - x3) + x1x3 * (y - y3)) / den2;
                        if (betta < 0 || betta > 1) continue;

                        float gamma = 1 - alpha - betta;
                        if (gamma < 0 || gamma > 1) continue;

                        float z = alpha * rasterized[0].RasterizedPosition.z / rasterized[0].RasterizedPosition.w + betta * rasterized[1].RasterizedPosition.z / rasterized[1].RasterizedPosition.w + gamma * rasterized[2].RasterizedPosition.z / rasterized[2].RasterizedPosition.w;
                        float minZ = this.zBuffer[(int)x, (int)y];
                        //z es negativo, por eso el >
                        if (z > minZ)
                        {
                            minZ = z;
                            this.zBuffer[(int)x, (int)y] = z;
                            Fragment pixel = new Fragment();

                            float d = h1 * h2 + h2 * betta * (h0 - h1) + h1 * gamma * (h0 - h2);
                            betta = h0 * h2 * betta / d;
                            gamma = h0 * h1 * gamma / d;
                            alpha = (1 - betta - gamma);

                            float uCoord = 0, vCoord = 0;
                            Vector textureColor = new Vector();

                            if (rasterized[0].HasTexture)
                            {
                                uCoord = alpha * rasterized[0].U + betta * rasterized[1].U + gamma * rasterized[2].U;
                                vCoord = alpha * rasterized[0].V + betta * rasterized[1].V + gamma * rasterized[2].V;
                                textureColor = rasterized[0].Material.GetTexturePixelColor(uCoord, vCoord);
                            }

                            //Per pixel shading
                            if (rendParams.ShadeMode == ShadingMode.PixelPhong)
                            {
                                pixel.Material = rasterized[0].Material;
                                pixel.Normal = alpha * rasterized[0].Normal + betta * rasterized[1].Normal + gamma * rasterized[2].Normal;
                                pixel.RasterizedPosition = alpha * rasterized[0].RasterizedPosition + betta * rasterized[1].RasterizedPosition + gamma * rasterized[2].RasterizedPosition;
                                pixel.WorldPosition = alpha * rasterized[0].WorldPosition + betta * rasterized[1].WorldPosition + gamma * rasterized[2].WorldPosition;
                                SetVertexColor(pixel);

                                if (rasterized[0].HasTexture)
                                {
                                    this.buffer[(int)x, (int)y] = textureColor * pixel.BlinnPhongColor;
                                }
                                else
                                {
                                    this.buffer[(int)x, (int)y] = pixel.BlinnPhongColor;
                                }
                            }
                            //Per vertex shading
                            else
                            {
                                if (rasterized[0].HasTexture)
                                {
                                    this.buffer[(int)x, (int)y] = alpha * Vector.ColorMultiplication(rasterized[0].BlinnPhongColor, textureColor) +
                                        betta * Vector.ColorMultiplication(rasterized[1].BlinnPhongColor, textureColor) +
                                        gamma * Vector.ColorMultiplication(rasterized[2].BlinnPhongColor, textureColor);
                                }
                                else
                                {
                                    this.buffer[(int)x, (int)y] = alpha * rasterized[0].BlinnPhongColor + betta * rasterized[1].BlinnPhongColor + gamma * rasterized[2].BlinnPhongColor;
                                }
                            }
                        }

                    }
            }
        }
        public void TestRaster()
        {
            for (int i = 0; i < 16; i++)
            {
                Vector center = new Vector(200, 150);
                Vector pos = center + new Vector((float)(150 * Math.Cos(Math.PI / 16.0 + Math.PI * 2 * i / 16)), (float)(150 * Math.Sin(Math.PI / 16.0 + Math.PI * 2 * i / 16)));
                //Console.WriteLine(pos);
                DrawLine(new Vector(200, 150), pos, new Vector(1, 0, 0), new Vector(0, 1, 0), rendParams.EnableAntialias);

                Vector pos2 = center + new Vector((float)(150 * Math.Cos(Math.PI * 2 * i / 16)), (float)(150 * Math.Sin(Math.PI * 2 * i / 16)));
                //Console.WriteLine(pos);
                DrawLine(new Vector(200, 150), pos2, new Vector(1, 0, 0), new Vector(0, 0, 1), rendParams.EnableAntialias);
                //Glut.glutPostRedisplay();
            }

            List<Fragment> rasterized = new List<Fragment>();

            Fragment v1 = new Fragment();
            v1.BlinnPhongColor = new Vector(1, 0, 0);
            v1.RasterizedPosition = new Vector(80, 80);
            rasterized.Add(v1);

            Fragment v2 = new Fragment();
            v2.BlinnPhongColor = new Vector(0, 1, 0);
            v2.RasterizedPosition = new Vector(250, 270);
            rasterized.Add(v2);

            Fragment v3 = new Fragment();
            v3.BlinnPhongColor = new Vector(0, 0, 1);
            v3.RasterizedPosition = new Vector(260, 40);
            rasterized.Add(v3);

            DrawTriangle(rasterized);
        }