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); }