Example #1
0
        private void Render(ref ShaderVariables shader, IEnumerable <Triangle> tris, IUvMap?uvs, Material material)
        {
            var backwards = this.Backward;

            foreach (var tri in tris)
            {
                var worldTri = tri.Transform(shader.ModelToWorld); // Convert to world space
                shader.WorldNormal = worldTri.Normal;

                // Backface culling
                if (!material.TwoSided)
                {
                    var normal = worldTri.Normal;
                    if (Vec3.Dot(backwards, normal) < -0.1)
                    {
                        continue;
                    }
                }

                // Get triangles
                var v1 = WorldToScreenPoint(worldTri.Item1);
                var v2 = WorldToScreenPoint(worldTri.Item2);
                var v3 = WorldToScreenPoint(worldTri.Item3);

                // Get the UV coordinates
                Vec2 uv1 = (uvs != null) ? uvs[tri.Item1] : Vec2.Zero;
                Vec2 uv2 = (uvs != null) ? uvs[tri.Item2] : Vec2.Zero;
                Vec2 uv3 = (uvs != null) ? uvs[tri.Item3] : Vec2.Zero;

                Rasterize(ref shader, worldTri, v1, v2, v3, uv1, uv2, uv3, material);
            }
        }
Example #2
0
        private void DrawVertex(Vec3 world, Vec3 screen, Vec2 uv, Material material, ref ShaderVariables vars)
        {
            vars.WorldPosition = world;
            vars.ScreenPixel   = screen;
            vars.UVCoordinates = uv;

            var colour = material.Vert(vars);

            SetPixel(screen, colour);
        }
Example #3
0
        /// <summary>
        /// Shader to apply to each face's surface
        /// </summary>
        /// <param name="variables">shading variables</param>
        /// <returns>color of point on face</returns>
        public override Color Fragment(ShaderVariables variables)
        {
            var  surfColour = ColourSample(variables.UVCoordinates);
            Vec3 N          = variables.WorldNormal;
            var  tint       = variables.LightSources.Select((light) => {
                var lightColour              = light.Tint;
                Vec3 L                       = light.Direction(variables.WorldPosition, variables.WorldNormal);
                double Lintensity            = light.Intensity(variables.WorldPosition, variables.WorldNormal);
                double diffuse_surface_shade = (Albedo / Math.PI) * Lintensity * Math.Max(Vec3.Dot(L, N), 0);

                return(Darken(lightColour, diffuse_surface_shade));
            }).Aggregate((a, b) => Mix(a, b));

            return(Mix(surfColour, tint));
        }
Example #4
0
        /// <summary>
        /// Render the given scene to the pixel buffer
        /// </summary>
        /// <param name="scene">scene to render</param>
        public void Render(Scene scene)
        {
            // Clean data
            ClearPixels();
            ClearDepth();

            // Set constant shader properties
            var vars = new ShaderVariables();

            vars.WorldCameraPosition = this.Position;
            vars.LightSources        = scene.OfType <LightSource>().ToList().AsReadOnly();

            // Loop over all models
            foreach (var renderable in scene.OfType <IRenderable>())
            {
                vars.ModelToWorld = renderable.LocalToWorldMatrix;
                if (renderable.Mesh != null && renderable.Material != null)
                {
                    Render(ref vars, renderable.Mesh, renderable.UVs, (Material)renderable.Material);
                }
            }
        }
Example #5
0
 /// <summary>
 /// Shader to apply to each face's edges
 /// </summary>
 /// <param name="variables">shading variables</param>
 /// <returns>edge colour</returns>
 public override Color Edge(ShaderVariables variables)
 {
     return(Colour);
 }
Example #6
0
 /// <summary>
 /// Shader to apply to each face's surface
 /// </summary>
 /// <param name="variables">shading variables</param>
 /// <returns>color of point on face</returns>
 public virtual Color Fragment(ShaderVariables variables)
 {
     return(Color.Transparent);
 }
Example #7
0
 /// <summary>
 /// Shader to apply to each face's edges
 /// </summary>
 /// <param name="variables">shading variables</param>
 /// <returns>edge colour</returns>
 public virtual Color Edge(ShaderVariables variables)
 {
     return(Fragment(variables));
 }
Example #8
0
 /// <summary>
 /// Shader to apply to each face's surface
 /// </summary>
 /// <param name="variables">shading variables</param>
 /// <returns>color of point on face</returns>
 public override Color Fragment(ShaderVariables variables)
 {
     return(ColourSample(variables.UVCoordinates));
 }
Example #9
0
 /// <summary>
 /// Shader to apply to each face's edges
 /// </summary>
 /// <param name="variables">shading variables</param>
 /// <returns>edge colour</returns>
 public override Color Edge(ShaderVariables variables)
 {
     return(Fragment(variables));
 }
Example #10
0
 /// <summary>
 /// Shader to apply to each face's surface
 /// </summary>
 /// <param name="variables">shading variables</param>
 /// <returns>color of point on face</returns>
 public override Color Fragment(ShaderVariables variables)
 {
     return(Colour);
 }
Example #11
0
        private void DrawFlatTopTriangle(Vec3 worldV1, Vec3 worldV2, Vec3 worldV3, Vec3 a, Vec3 b, Vec3 c, Vec2 uva, Vec2 uvb, Vec2 uvc, Material img, ref ShaderVariables shader)
        {
            double invslope1 = (c.X - a.X) / (c.Y - a.Y);
            double invslope2 = (c.X - b.X) / (c.Y - b.Y);

            double leftX  = Math.Floor(c.X);
            double rightX = Math.Floor(c.X);

            int startH = (int)Math.Floor(c.Y);
            int endH   = (int)Math.Floor(a.Y);

            for (int scan = startH; scan > endH; scan--)
            {
                double t = (scan - startH) / (endH - startH);

                Vec2 left       = Vec2.Lerp(uvc, uva, t);
                Vec2 right      = Vec2.Lerp(uvc, uvb, t);
                Vec3 worldLeft  = Vec3.Lerp(worldV3, worldV1, t);
                Vec3 worldRight = Vec3.Lerp(worldV3, worldV2, t);

                double zL = Lerp(c.Z, a.Z, t);
                double zR = Lerp(c.Z, b.Z, t);
                DrawLine(worldLeft, worldRight, new Vec3(leftX, scan, zL), new Vec3(rightX, scan, zR), left, right, img, ref shader, surface: true);

                leftX  -= invslope1;
                rightX -= invslope2;
            }
        }
Example #12
0
        private void DrawLine(Vec3 worldV1, Vec3 worldV2, Vec3 v1, Vec3 v2, Vec2 uv1, Vec2 uv2, Material material, ref ShaderVariables shader, bool surface)
        {
            double dist2d = Math.Sqrt((v2.X - v1.X) * (v2.X - v1.X) + (v2.Y - v1.Y) * (v2.Y - v1.Y));

            if (dist2d != 0)
            {
                double invdist = 1 / dist2d;
                for (double i = 0; i < 1; i += invdist)
                {
                    Vec3 world = Vec3.Lerp(worldV1, worldV2, i);
                    Vec3 pixel = Vec3.Lerp(v1, v2, i);
                    Vec2 uv    = Vec2.Lerp(uv1, uv2, i);

                    shader.WorldPosition = world;
                    shader.ScreenPixel   = pixel;
                    shader.UVCoordinates = uv;

                    var colour = surface ? material.Fragment(shader) : material.Edge(shader);
                    SetPixel(pixel, colour);
                }
            }
        }
Example #13
0
        private void Rasterize(ref ShaderVariables shader, Triangle worldTri, Vec3 v1, Vec3 v2, Vec3 v3, Vec2 uv1, Vec2 uv2, Vec2 uv3, Material material)
        {
            // Sort vertices into ascending order of y
            var worldV1 = worldTri.Item1;
            var worldV2 = worldTri.Item2;
            var worldV3 = worldTri.Item3;

            if (v1.Y > v2.Y)
            {
                (v1, v2)           = (v2, v1);
                (uv1, uv2)         = (uv2, uv1);
                (worldV1, worldV2) = (worldV2, worldV1);
            }
            if (v2.Y > v3.Y)
            {
                (v2, v3)           = (v3, v2);
                (uv2, uv3)         = (uv3, uv2);
                (worldV2, worldV3) = (worldV3, worldV2);
            }
            if (v1.Y > v2.Y)
            {
                (v1, v2)           = (v2, v1);
                (uv1, uv2)         = (uv2, uv1);
                (worldV1, worldV2) = (worldV2, worldV1);
            }

            // Rasterize
            if (v2.Y == v3.Y)
            {
                // Flat Bottom Triangle
                DrawFlatBottomTriangle(worldV1, worldV2, worldV3, v1, v2, v3, uv1, uv2, uv3, material, ref shader);

                DrawLine(worldV1, worldV2, v1, v2, uv1, uv2, material, ref shader, surface: false);
                DrawLine(worldV2, worldV3, v2, v3, uv2, uv3, material, ref shader, surface: false);
                DrawLine(worldV1, worldV3, v1, v3, uv1, uv3, material, ref shader, surface: false);

                DrawVertex(worldV1, v1, uv1, material, ref shader);
                DrawVertex(worldV2, v2, uv2, material, ref shader);
                DrawVertex(worldV3, v3, uv3, material, ref shader);
            }
            else if (v1.Y == v2.Y)
            {
                // Flat Top Triangle
                DrawFlatTopTriangle(worldV1, worldV2, worldV3, v1, v2, v3, uv1, uv2, uv3, material, ref shader);

                DrawLine(worldV1, worldV2, v1, v2, uv1, uv2, material, ref shader, surface: false);
                DrawLine(worldV2, worldV3, v2, v3, uv2, uv3, material, ref shader, surface: false);
                DrawLine(worldV1, worldV3, v1, v3, uv1, uv3, material, ref shader, surface: false);

                DrawVertex(worldV1, v1, uv1, material, ref shader);
                DrawVertex(worldV2, v2, uv2, material, ref shader);
                DrawVertex(worldV3, v3, uv3, material, ref shader);
            }
            else
            {
                // General Triangle
                double t = (v2.Y - v3.Y) / (v1.Y - v3.Y);
                Vec3   d = new Vec3(
                    (v1.X) + ((v2.Y - v1.Y) / (v3.Y - v1.Y)) * (v3.X - v1.X),
                    v2.Y,
                    Lerp(v3.Z, v1.Z, t)
                    );
                Vec3 worldD = Vec3.Lerp(worldV3, worldV1, t);
                Vec2 uvd    = new Vec2(
                    Lerp(uv3.X, uv1.X, t),
                    Lerp(uv3.Y, uv1.Y, t)
                    );

                DrawFlatBottomTriangle(worldV1, worldV2, worldD, v1, v2, d, uv1, uv2, uvd, material, ref shader);
                DrawFlatTopTriangle(worldV2, worldD, worldV3, v2, d, v3, uv2, uvd, uv3, material, ref shader);

                DrawLine(worldV1, worldV2, v1, v2, uv1, uv2, material, ref shader, surface: false);
                DrawLine(worldV2, worldV3, v2, v3, uv2, uv3, material, ref shader, surface: false);
                DrawLine(worldV1, worldV3, v1, v3, uv1, uv3, material, ref shader, surface: false);

                DrawVertex(worldV1, v1, uv1, material, ref shader);
                DrawVertex(worldV2, v2, uv2, material, ref shader);
                DrawVertex(worldV3, v3, uv3, material, ref shader);
            }
        }