Ejemplo n.º 1
0
 public Renderer(int width, int height)
 {
     _width            = width;
     _height           = height;
     _faceDrawer       = new FaceDrawer(width, height);
     _firstPhaseScreen = new WritableTexture(new Bitmap(width, height, PixelFormat.Format32bppRgb), true);
 }
Ejemplo n.º 2
0
        private static void Draw(WritableTexture screen, Func <Shader> shaderFactory, FaceDrawer faceDrawer, int startY, int endY, World world)
        {
            var shaderState = new ShaderState(30, world);
            var shader      = shaderFactory();

            shader.World(world);

            for (var i = 0; i < world.WorldObject.Model.Geometry.Faces.Count; i++)
            {
                faceDrawer.Draw(i, screen, shader, shaderState, startY, endY);
            }
        }
Ejemplo n.º 3
0
        private async Task TwoPhaseDraw(World world, Tuple <int, int>[] regions, WritableTexture screen)
        {
            _firstPhaseScreen.Clear();
            _faceDrawer.Init(RenderMode.Fill);

            var firstPhaseTasks = regions.Select(
                region =>
                new Task(
                    () =>
                    Draw(_firstPhaseScreen, world.WorldObject.FirstPhaseShaderFactory, _faceDrawer, region.Item1,
                         region.Item2, world)))
                                  .ToArray();

            foreach (var task in firstPhaseTasks)
            {
                task.Start();
            }
            await Task.WhenAll(firstPhaseTasks).ConfigureAwait(false);

            _faceDrawer.Init(world.RenderMode);

            var secondPhaseTasks = regions.Select(
                region =>
                new Task(() =>
            {
                var shaderState = new ShaderState(30, world);
                var shader      = world.WorldObject.ShaderFactory();
                shader.World(world, _firstPhaseScreen);

                for (var i = 0; i < world.WorldObject.Model.Geometry.Faces.Count; i++)
                {
                    _faceDrawer.Draw(i, screen, shader, shaderState, region.Item1, region.Item2);
                }
            }))
                                   .ToArray();

            foreach (var task in secondPhaseTasks)
            {
                task.Start();
            }

            await Task.WhenAll(secondPhaseTasks).ConfigureAwait(false);
        }
Ejemplo n.º 4
0
        public void Draw(int faceIndex, WritableTexture screen, Shader shader, ShaderState shaderState, int startY, int endY)
        {
            var faceState     = shaderState.Face;
            var vertexState   = shaderState.Vertex;
            var fragmentState = shaderState.Fragment;

            faceState.Clear();
            vertexState.Clear();

            shader.Face(faceState, faceIndex);
            var v04 = shader.Vertex(vertexState, faceIndex, 0);
            var v14 = shader.Vertex(vertexState, faceIndex, 1);
            var v24 = shader.Vertex(vertexState, faceIndex, 2);

            var v0 = new Vector3(v04.X / v04.W, v04.Y / v04.W, v04.Z / v04.W);
            var v1 = new Vector3(v14.X / v14.W, v14.Y / v14.W, v14.Z / v14.W);
            var v2 = new Vector3(v24.X / v24.W, v24.Y / v24.W, v24.Z / v24.W);

            var diff1 = Vector3.Subtract(v1, v0);
            var diff2 = Vector3.Subtract(v2, v1);

            var normal = Vector3.Cross(diff1, diff2);

            normal = Vector3.Normalize(normal);

            var directionCulling = Vector3.Dot(normal, new Vector3(0, 0, 1));

            if (directionCulling <= 0)
            {
                return;
            }

            if (_useFill)
            {
                DrawFilling(screen, startY, endY, v0, v1, v2, fragmentState, faceState, vertexState, shader);
            }

            if (_useBorders)
            {
                DrawBorders(faceIndex, screen, shader, shaderState, startY, endY);
            }
        }
Ejemplo n.º 5
0
        private void DrawBorders(int faceIndex, WritableTexture screen, Shader shader, ShaderState shaderState, int startY, int endY)
        {
            shaderState.Vertex.Clear();
            var v0 = shader.Vertex(shaderState.Vertex, faceIndex, 0);
            var v1 = shader.Vertex(shaderState.Vertex, faceIndex, 1);
            var v2 = shader.Vertex(shaderState.Vertex, faceIndex, 2);

            var screenCoords = new[]
            {
                new Vector3(v0.X / v0.W, v0.Y / v0.W, v0.Z / v0.W),
                new Vector3(v1.X / v1.W, v1.Y / v1.W, v1.Z / v1.W),
                new Vector3(v2.X / v2.W, v2.Y / v2.W, v2.Z / v2.W)
            };

            DrawSolidLine((int)screenCoords[0].X, (int)screenCoords[0].Y, (int)screenCoords[1].X, (int)screenCoords[1].Y,
                          screen, _borderColor, startY, endY);
            DrawSolidLine((int)screenCoords[1].X, (int)screenCoords[1].Y, (int)screenCoords[2].X, (int)screenCoords[2].Y,
                          screen, _borderColor, startY, endY);
            DrawSolidLine((int)screenCoords[2].X, (int)screenCoords[2].Y, (int)screenCoords[0].X, (int)screenCoords[0].Y,
                          screen, _borderColor, startY, endY);
        }
Ejemplo n.º 6
0
        public void Render(World world, Bitmap bitmap)
        {
            using (var screen = new WritableTexture(bitmap, false))
            {
                screen.Clear();

                var parCount = Environment.ProcessorCount;
                var vertStep = _height / parCount - 1;
                var start    = 0;
                var regions  = new Tuple <int, int> [parCount];
                for (var i = 0; i < parCount; i++)
                {
                    var end = start + vertStep;
                    regions[i] = Tuple.Create(start, end);

                    start = end + 1;
                }
                var last = parCount - 1;
                regions[last] = Tuple.Create(regions[last].Item1, _height - 1);
                if (world.TwoPhaseRendering)
                {
                    var task = TwoPhaseDraw(world, regions, screen);
                    task.Wait();
                }
                else
                {
                    _faceDrawer.Init(world.RenderMode);
                    var tasks = regions.Select(
                        region =>
                        new Task(() => Draw(screen, world.WorldObject.ShaderFactory, _faceDrawer, region.Item1, region.Item2, world)))
                                .ToArray();
                    foreach (var task in tasks)
                    {
                        task.Start();
                    }
                    Task.WaitAll(tasks);
                }
            }
        }
Ejemplo n.º 7
0
        private void DrawSolidLine(int x0, int y0, int x1, int y1, WritableTexture screen, int color, int startY, int endY)
        {
            var vertOrientation = Math.Abs(x1 - x0) < Math.Abs(y1 - y0);

            if (vertOrientation)
            {
                int buf;

                buf = x0;
                x0  = y0;
                y0  = buf;

                buf = x1;
                x1  = y1;
                y1  = buf;
            }
            if (x0 > x1)
            {
                int buf;

                buf = x0;
                x0  = x1;
                x1  = buf;

                buf = y0;
                y0  = y1;
                y1  = buf;
            }

            int errorMul = 0;

            int sign = Math.Sign(y1 - y0);

            int kMul    = 2 * (y1 - y0);
            int halfMul = x1 - x0;
            int oneMul  = 2 * halfMul;

            int y = y0;

            for (var x = x0; x <= x1; x++)
            {
                errorMul += kMul;
                if (Math.Abs(errorMul) > halfMul)
                {
                    y        += sign;
                    errorMul -= sign * oneMul;
                }

                if (vertOrientation)
                {
                    if (y >= 0 && y < _width && x >= startY && x <= endY)
                    {
                        screen.Write(y, x, color);
                    }
                }
                else
                {
                    if (x >= 0 && x < _width && y >= startY && y <= endY)
                    {
                        screen.Write(x, y, color);
                    }
                }
            }
        }
Ejemplo n.º 8
0
        private void DrawFilling(WritableTexture screen, int startY, int endY, Vector3 v0, Vector3 v1, Vector3 v2,
                                 FragmentShaderState fragmentState, FaceShaderState faceState, VertexShaderState vertexState, Shader shader)
        {
            var x0 = (int)Math.Round(v0.X);
            var y0 = (int)Math.Round(v0.Y);
            var x1 = (int)Math.Round(v1.X);
            var y1 = (int)Math.Round(v1.Y);
            var x2 = (int)Math.Round(v2.X);
            var y2 = (int)Math.Round(v2.Y);

            int minX = ClipX(Math3(x0, x1, x2, Math.Min));
            int minY = ClipY(Math3(y0, y1, y2, Math.Min), startY, endY);
            int maxX = ClipX(Math3(x0, x1, x2, Math.Max));
            int maxY = ClipY(Math3(y0, y1, y2, Math.Max), startY, endY);

            float midX = (v0.X + v1.X + v2.X) / 3;
            float midY = (v0.Y + v1.Y + v2.Y) / 3;

            var dirV0 = new Vector3(v0.X - midX, v0.Y - midY, 0);
            var dirV1 = new Vector3(v1.X - midX, v1.Y - midY, 0);

            var direction = Vector3.Cross(dirV0, dirV1).Z;

            if (direction < 0)
            {
                Vector3 tbuf;
                tbuf = v1;
                v1   = v2;
                v2   = tbuf;
            }

            var line1 = new Line(v0.X, v0.Y, v1.X, v1.Y, minX, minY);
            var line2 = new Line(v1.X, v1.Y, v2.X, v2.Y, minX, minY);
            var line3 = new Line(v2.X, v2.Y, v0.X, v0.Y, minX, minY);

            var converter = new BarycentricCoordinatesConverter(v0.X, v0.Y, v1.X, v1.Y, v2.X, v2.Y);

            var writer = screen.GetWriter(minY);

            for (int y = minY; y <= maxY; y++)
            {
                for (int x = minX; x <= maxX; x++)
                {
                    var curr1 = line1.Value;
                    var curr2 = line2.Value;
                    var curr3 = line3.Value;

                    if (curr1 >= 0 && curr2 >= 0 && curr3 >= 0)
                    {
                        var p = converter.Convert(x, y);

                        if (p.A < 0 || p.B < 0 || p.C < 0)
                        {
                            continue;
                        }

                        var z = v0.Z * p.A + v1.Z * p.B + v2.Z * p.C;

                        if (z < _zBuffer[x, y])
                        {
                            continue;
                        }

                        fragmentState.Clear();
                        fragmentState.Intensity = faceState.Intensity;
                        for (var i = 0; i < vertexState.Varying[0].Count; i++)
                        {
                            var fragmentValue = vertexState.Varying[0][i] * p.A + vertexState.Varying[1][i] * p.B +
                                                vertexState.Varying[2][i] * p.C;
                            fragmentState.Varying.Add(fragmentValue);
                        }

                        var resColor = shader.Fragment(fragmentState);

                        if (resColor != null)
                        {
                            _zBuffer[x, y] = z;
                            writer.Write(x, resColor.Value);
                        }
                    }
                    line1.StepX();
                    line2.StepX();
                    line3.StepX();
                }
                line1.StepY();
                line2.StepY();
                line3.StepY();
                writer.NextLine();
            }
        }