public static Tree OldTree(Random random, mat4 transform1, mat4 transform2, World world)
        {
            bool type0 = random.NextDouble() > 0.5;

            MeshRenderJob leavesOpaque = new MeshRenderJob(
                Renderer.Opaque.Mesh,
                Resources.UseMaterial("TreeLeaves01", UpvoidMiner.ModDomain),
                Resources.UseMesh(type0 ? "Vegetation/Tree01/Leaves_high" : "Vegetation/Tree03/Leaves_high", UpvoidMiner.ModDomain),
                transform2);

            MeshRenderJob leavesZPre = new MeshRenderJob(
                Renderer.zPre.Mesh,
                Resources.UseMaterial("TreeLeaves01.zPre", UpvoidMiner.ModDomain),
                Resources.UseMesh(type0 ? "Vegetation/Tree01/Leaves_high" : "Vegetation/Tree03/Leaves_high", UpvoidMiner.ModDomain),
                transform2);

            MeshRenderJob leavesShadow = new MeshRenderJob(
                Renderer.Shadow.Mesh,
                Resources.UseMaterial("TreeLeaves01.Shadow", UpvoidMiner.ModDomain),
                Resources.UseMesh(type0 ? "Vegetation/Tree01/Leaves_high" : "Vegetation/Tree03/Leaves_high", UpvoidMiner.ModDomain),
                transform2);

            MeshRenderJob trunkOpaque = new MeshRenderJob(
                Renderer.Opaque.Mesh,
                Resources.UseMaterial("TreeTrunk", UpvoidMiner.ModDomain),
                Resources.UseMesh(type0 ? "Vegetation/Tree01/Trunk" : "Vegetation/Tree03/Trunk", UpvoidMiner.ModDomain),
                transform2);

            MeshRenderJob trunkShadow = new MeshRenderJob(
                Renderer.Shadow.Mesh,
                Resources.UseMaterial("::Shadow", UpvoidMiner.ModDomain),
                Resources.UseMesh(type0 ? "Vegetation/Tree01/Trunk" : "Vegetation/Tree03/Trunk", UpvoidMiner.ModDomain),
                transform2);


            // Add some color variance to trees
            vec4 colorModulation = new vec4(0.7f + (float)random.NextDouble() * 0.5f, 0.7f + (float)random.NextDouble() * 0.5f, 1, 1);

            leavesOpaque.SetColor("uColorModulation", colorModulation);

            // Amount of wood depends on tree type (thicker/thinner trunk) and tree height scale factor.
            Tree t = new Tree((type0 ? 0.5f : 1.0f) * transform2.col1.y, Tree.TreeType.Birch);

            Tree.Log  l = new Tree.Log();
            RigidBody b = new RigidBody(0f, transform1 * mat4.Translate(new vec3(0, 5, 0)), new CylinderShape(.5f, 10));

            world.Physics.AddRigidBody(b);
            l.PhysicsComps.Add(new PhysicsComponent(b, mat4.Translate(new vec3(0, -5, 0))));

            t.RjLeaves0.Add(new RenderComponent(leavesOpaque, transform2));
            t.RjLeaves0.Add(new RenderComponent(leavesZPre, transform2));
            t.RjLeaves0.Add(new RenderComponent(leavesShadow, transform2));
            t.RjTrunk.Add(new RenderComponent(trunkOpaque, transform2));
            t.RjTrunk.Add(new RenderComponent(trunkShadow, transform2));

            t.Logs.Add(l);

            return(t);
        }
        public static Tree Cactus(Random random, mat4 transform1, mat4 transform2, World world)
        {
            // Compute random cactus type \in 0..5
            int type = (int)(random.NextDouble() * 6.0);

            // Circumvent the unlikely case of NextDouble() returning 1.0
            if (type > 5)
            {
                type = 5;
            }

            // 0..5 -> 1..6
            ++type;

            string meshString = "Vegetation/Cactus/Cactus" + type.ToString();

            MeshRenderJob cactus = new MeshRenderJob(
                Renderer.Opaque.Mesh,
                Resources.UseMaterial("Cactus", UpvoidMiner.ModDomain),
                Resources.UseMesh(meshString, UpvoidMiner.ModDomain),
                transform2);

            MeshRenderJob cactusShadow = new MeshRenderJob(
                Renderer.Shadow.Mesh,
                Resources.UseMaterial("Cactus.Shadow", UpvoidMiner.ModDomain),
                Resources.UseMesh(meshString, UpvoidMiner.ModDomain),
                transform2);

            // Add some color variance to cacti
            vec4 colorModulation = new vec4(0.7f + (float)random.NextDouble() * 0.6f, 0.9f + (float)random.NextDouble() * 0.2f, 1, 1);

            cactus.SetColor("uColorModulation", colorModulation);

            // Create new Tree of type Cactus with 0 wood to gather.
            Tree t = new Tree(0, Tree.TreeType.Cactus);

            Tree.Log  l = new Tree.Log();
            RigidBody b = new RigidBody(0f, transform1 * mat4.Translate(new vec3(0, 5, 0)), new CylinderShape(.5f, 10));

            world.Physics.AddRigidBody(b);
            l.PhysicsComps.Add(new PhysicsComponent(b, mat4.Translate(new vec3(0, -5, 0))));

            t.RjLeaves0.Add(new RenderComponent(cactus, transform2));
            t.RjLeaves0.Add(new RenderComponent(cactusShadow, transform2));

            t.Logs.Add(l);

            return(t);
        }
        /// <summary>
        /// Creates a log.
        /// </summary>
        private static Tree.Log CreateLog(Tree t,
                                          vec3 start, vec3 dir, vec3 front, float height, float radius,
                                          MaterialResource material, string meshName)
        {
            Tree.Log log = new Tree.Log();

            vec3 left      = vec3.cross(dir, front);
            mat4 transform = new mat4(left, dir, front, start) * mat4.Scale(new vec3(radius, height, radius));
            var  mesh      = Resources.UseMesh(meshName, UpvoidMiner.ModDomain);

            log.RenderComps.Add(new RenderComponent(new MeshRenderJob(Renderer.Opaque.Mesh, material, mesh, mat4.Identity), transform));
            log.RenderComps.Add(new RenderComponent(new MeshRenderJob(Renderer.Shadow.Mesh, Resources.UseMaterial("::Shadow", null), mesh, mat4.Identity), transform));
            log.RenderComps.Add(new RenderComponent(new MeshRenderJob(Renderer.zPre.Mesh, Resources.UseMaterial("::ZPre", null), mesh, mat4.Identity), transform));

            return(log);
        }