Ejemplo n.º 1
0
        public override void CreateScene()
        {
            TexturePtr mTexture = TextureManager.Singleton.CreateManual("RenderArea",
                                      ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, TextureType.TEX_TYPE_2D,
                                      512, 512, 0, PixelFormat.PF_R8G8B8, (int)TextureUsage.TU_RENDERTARGET);
            rttTex = mTexture.GetBuffer().GetRenderTarget();
            rttTex.IsAutoUpdated = false;
            {
                // Create the camera
                Camera camera2 = sceneMgr.CreateCamera("PlayerCam2");

                camera2.Position = new Vector3(0, 0, 3);
                camera2.LookAt(new Vector3(0.0f, 0.0f, 0.0f));
                camera2.NearClipDistance = 1;

                Viewport v = rttTex.AddViewport(camera2);

                MaterialPtr mat = MaterialManager.Singleton.GetByName("CgTutorials/RenderToTexture_Material");
                mat.GetTechnique(0).GetPass(0).GetTextureUnitState(0).SetTextureName("RenderArea");
                v.BackgroundColour = new ColourValue(0.0f, 0.3f, 0.2f, 0.0f);
                //v.SetClearEveryFrame(false);
                //v.OverlaysEnabled = false;
                rttTex.PreRenderTargetUpdate += new RenderTargetListener.PreRenderTargetUpdateHandler(RenderArea_PreRenderTargetUpdate);
                rttTex.PostRenderTargetUpdate += new RenderTargetListener.PostRenderTargetUpdateHandler(RenderArea_PostRenderTargetUpdate);
            }

            node1 = base.sceneMgr.RootSceneNode.CreateChildSceneNode("TutorialRender2TexNode1");
            node2 = base.sceneMgr.RootSceneNode.CreateChildSceneNode("TutorialRender2TexNode2");

            manualObj1 = sceneMgr.CreateManualObject("TutorialRender2TexObject1");
            manualObj2 = sceneMgr.CreateManualObject("TutorialRender2TexObject2");

            node1.AttachObject(DrawTriangle1(manualObj1));
            node2.AttachObject(DrawTriangle2(manualObj2));
        }
Ejemplo n.º 2
0
        protected void RenderFrame()
        {
            if ((_camera != null) && (_viewport == null))
            {
                _viewport = _renTarget.AddViewport(_camera);
                _viewport.BackgroundColour = new ColourValue(0.0f, 0.0f, 0.0f, 0.0f);
            }

            if (PreRender != null)
            {
                PreRender(this, EventArgs.Empty);
            }

            _root.RenderOneFrame();

            if (PostRender != null)
            {
                PostRender(this, EventArgs.Empty);
            }
        }
Ejemplo n.º 3
0
        public override void CreateScene()
        {
            TexturePtr mTexture = TextureManager.Singleton.CreateManual("RenderArea",
                                                                        ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, TextureType.TEX_TYPE_2D,
                                                                        512, 512, 0, PixelFormat.PF_R8G8B8, (int)TextureUsage.TU_RENDERTARGET);

            rttTex = mTexture.GetBuffer().GetRenderTarget();
            rttTex.IsAutoUpdated = false;
            {
                // Create the camera
                Camera camera2 = sceneMgr.CreateCamera("PlayerCam2");

                camera2.Position = new Vector3(0, 0, 3);
                camera2.LookAt(new Vector3(0.0f, 0.0f, 0.0f));
                camera2.NearClipDistance = 1;

                Viewport v = rttTex.AddViewport(camera2);

                MaterialPtr mat = MaterialManager.Singleton.GetByName("CgTutorials/RenderToTexture_Material");
                mat.GetTechnique(0).GetPass(0).GetTextureUnitState(0).SetTextureName("RenderArea");
                v.BackgroundColour = new ColourValue(0.0f, 0.3f, 0.2f, 0.0f);
                //v.SetClearEveryFrame(false);
                //v.OverlaysEnabled = false;
                rttTex.PreRenderTargetUpdate  += new RenderTargetListener.PreRenderTargetUpdateHandler(RenderArea_PreRenderTargetUpdate);
                rttTex.PostRenderTargetUpdate += new RenderTargetListener.PostRenderTargetUpdateHandler(RenderArea_PostRenderTargetUpdate);
            }

            node1 = base.sceneMgr.RootSceneNode.CreateChildSceneNode("TutorialRender2TexNode1");
            node2 = base.sceneMgr.RootSceneNode.CreateChildSceneNode("TutorialRender2TexNode2");

            manualObj1 = sceneMgr.CreateManualObject("TutorialRender2TexObject1");
            manualObj2 = sceneMgr.CreateManualObject("TutorialRender2TexObject2");

            node1.AttachObject(DrawTriangle1(manualObj1));
            node2.AttachObject(DrawTriangle2(manualObj2));
        }
Ejemplo n.º 4
0
        /// <summary>
        /// Helper method to render a composite map.
        /// </summary>
        /// <param name="size"> The requested composite map size</param>
        /// <param name="rect"> The region of the composite map to update, in image space</param>
        /// <param name="mat">The material to use to render the map</param>
        /// <param name="destCompositeMap"></param>
        public virtual void RenderCompositeMap(int size, Rectangle rect, Material mat, Texture destCompositeMap)
        {
            //return;
            if (this.mCompositeMapSM == null)
            {
                //dedicated SceneManager

                this.mCompositeMapSM = Root.Instance.CreateSceneManager(SceneType.ExteriorClose,
                                                                        "TerrainMaterialGenerator_SceneManager");
                float camDist     = 100;
                float halfCamDist = camDist * 0.5f;
                this.mCompositeMapCam          = this.mCompositeMapSM.CreateCamera("TerrainMaterialGenerator_Camera");
                this.mCompositeMapCam.Position = new Vector3(0, 0, camDist);
                //mCompositeMapCam.LookAt(Vector3.Zero);
                this.mCompositeMapCam.ProjectionType = Projection.Orthographic;
                this.mCompositeMapCam.Near           = 10;
                this.mCompositeMapCam.Far            = 999999 * 3;
                //mCompositeMapCam.AspectRatio = camDist / camDist;
                this.mCompositeMapCam.SetOrthoWindow(camDist, camDist);
                // Just in case material relies on light auto params
                this.mCompositeMapLight      = this.mCompositeMapSM.CreateLight("TerrainMaterialGenerator_Light");
                this.mCompositeMapLight.Type = LightType.Directional;

                RenderSystem rSys    = Root.Instance.RenderSystem;
                float        hOffset = rSys.HorizontalTexelOffset / (float)size;
                float        vOffset = rSys.VerticalTexelOffset / (float)size;

                //setup scene
                this.mCompositeMapPlane = this.mCompositeMapSM.CreateManualObject("TerrainMaterialGenerator_ManualObject");
                this.mCompositeMapPlane.Begin(mat.Name, OperationType.TriangleList);
                this.mCompositeMapPlane.Position(-halfCamDist, halfCamDist, 0);
                this.mCompositeMapPlane.TextureCoord(0 - hOffset, 0 - vOffset);
                this.mCompositeMapPlane.Position(-halfCamDist, -halfCamDist, 0);
                this.mCompositeMapPlane.TextureCoord(0 - hOffset, 1 - vOffset);
                this.mCompositeMapPlane.Position(halfCamDist, -halfCamDist, 0);
                this.mCompositeMapPlane.TextureCoord(1 - hOffset, 1 - vOffset);
                this.mCompositeMapPlane.Position(halfCamDist, halfCamDist, 0);
                this.mCompositeMapPlane.TextureCoord(1 - hOffset, 0 - vOffset);
                this.mCompositeMapPlane.Quad(0, 1, 2, 3);
                this.mCompositeMapPlane.End();
                this.mCompositeMapSM.RootSceneNode.AttachObject(this.mCompositeMapPlane);
            }             //end if

            // update
            this.mCompositeMapPlane.SetMaterialName(0, mat.Name);
            this.mCompositeMapLight.Direction = TerrainGlobalOptions.LightMapDirection;
            this.mCompositeMapLight.Diffuse   = TerrainGlobalOptions.CompositeMapDiffuse;
            this.mCompositeMapSM.AmbientLight = TerrainGlobalOptions.CompositeMapAmbient;


            //check for size change (allow smaller to be reused)
            if (this.mCompositeMapRTT != null && size != this.mCompositeMapRTT.Width)
            {
                TextureManager.Instance.Remove(this.mCompositeMapRTT);
                this.mCompositeMapRTT = null;
            }
            if (this.mCompositeMapRTT == null)
            {
                this.mCompositeMapRTT = TextureManager.Instance.CreateManual(this.mCompositeMapSM.Name + "/compRTT",
                                                                             ResourceGroupManager.DefaultResourceGroupName,
                                                                             TextureType.TwoD, size, size, 0, PixelFormat.BYTE_RGBA,
                                                                             TextureUsage.RenderTarget);

                RenderTarget rtt = this.mCompositeMapRTT.GetBuffer().GetRenderTarget();
                // don't render all the time, only on demand
                rtt.IsAutoUpdated = false;
                Viewport vp = rtt.AddViewport(this.mCompositeMapCam);
                // don't render overlays
                vp.ShowOverlays = false;
            }

            // calculate the area we need to update
            float vpleft   = (float)rect.Left / (float)size;
            float vptop    = (float)rect.Top / (float)size;
            float vpright  = (float)rect.Right / (float)size;
            float vpbottom = (float)rect.Bottom / (float)size;
            float vpwidth  = (float)rect.Width / (float)size;
            float vpheight = (float)rect.Height / (float)size;

            RenderTarget rtt2 = this.mCompositeMapRTT.GetBuffer().GetRenderTarget();
            Viewport     vp2  = rtt2.GetViewport(0);

            this.mCompositeMapCam.SetWindow(vpleft, vptop, vpright, vpbottom);
            rtt2.Update();
            vp2.Update();
            // We have an RTT, we want to copy the results into a regular texture
            // That's because in non-update scenarios we don't want to keep an RTT
            // around. We use a single RTT to serve all terrain pages which is more
            // efficient.
            var box = new BasicBox((int)rect.Left, (int)rect.Top, (int)rect.Right, (int)rect.Bottom);

            destCompositeMap.GetBuffer().Blit(this.mCompositeMapRTT.GetBuffer(), box, box);
        }
            void CreateViewport()
            {
                int index = instance.views.IndexOf(this);

                DestroyViewport();

                Vec2I textureSize = GetNeededTextureSize();

                string textureName = TextureManager.Instance.GetUniqueName(
                    string.Format("MultiViewRendering{0}", index));
                PixelFormat format = PixelFormat.R8G8B8;

                int fsaa;

                if (!int.TryParse(RendererWorld.InitializationOptions.FullSceneAntialiasing, out fsaa))
                {
                    fsaa = 0;
                }

                texture = TextureManager.Instance.Create(textureName, Texture.Type.Type2D,
                                                         textureSize, 1, 0, format, Texture.Usage.RenderTarget, false, fsaa);
                if (texture == null)
                {
                    Log.Fatal("MultiViewRenderingManager: Unable to create texture.");
                    return;
                }

                RenderTarget renderTarget = texture.GetBuffer().GetRenderTarget();

                renderTarget.AutoUpdate          = true;
                renderTarget.AllowAdditionalMRTs = true;

                //create camera
                camera = SceneManager.Instance.CreateCamera(
                    SceneManager.Instance.GetUniqueCameraName(string.Format("MultiViewRendering{0}", index)));
                camera.Purpose = Camera.Purposes.MainCamera;

                //add viewport
                viewport = renderTarget.AddViewport(camera, 0);
                viewport.ShadowsEnabled = true;

                //Create compositor for HDR render technique
                bool hdrCompositor =
                    RendererWorld.Instance.DefaultViewport.GetCompositorInstance("HDR") != null;

                if (hdrCompositor)
                {
                    viewport.AddCompositor("HDR");
                    viewport.SetCompositorEnabled("HDR", true);
                }

                //FXAA antialiasing post effect
                bool fxaaCompositor =
                    RendererWorld.Instance.DefaultViewport.GetCompositorInstance("FXAA") != null;

                if (fxaaCompositor)
                {
                    viewport.AddCompositor("FXAA");
                    viewport.SetCompositorEnabled("FXAA", true);
                }

                //add listener
                renderTargetListener = new ViewRenderTargetListener(this);
                renderTarget.AddListener(renderTargetListener);

                initializedTextureSize = textureSize;
            }
Ejemplo n.º 6
0
        public override void CreateScene()
        {
            //init spline array
            for (int i = 0; i < NUM_FISH; i++)
            {
                fishSplines[i] = new SimpleSpline();
            }


            // Check prerequisites first
            RenderSystemCapabilities caps = Root.Singleton.RenderSystem.Capabilities;

            if (!caps.HasCapability(Capabilities.RSC_VERTEX_PROGRAM) || !(caps.HasCapability(Capabilities.RSC_FRAGMENT_PROGRAM)))
            {
                throw new System.Exception("Your card does not support vertex and fragment programs, so cannot run this demo. Sorry!");
            }
            else
            {
                if (!GpuProgramManager.Singleton.IsSyntaxSupported("arbfp1") &&
                    !GpuProgramManager.Singleton.IsSyntaxSupported("ps_2_0") &&
                    !GpuProgramManager.Singleton.IsSyntaxSupported("ps_1_4")
                    )
                {
                    throw new System.Exception("Your card does not support advanced fragment programs, so cannot run this demo. Sorry!");
                }
            }

            camera.SetPosition(-50, 125, 760);
            camera.SetDirection(0, 0, -1);
            // Set ambient light
            sceneMgr.AmbientLight = new ColourValue(0.5f, 0.5f, 0.5f);

            // Create a point light
            Light l = sceneMgr.CreateLight("MainLight");

            l.Type      = Light.LightTypes.LT_DIRECTIONAL;
            l.Direction = -Vector3.UNIT_Y;

            Entity pEnt;

            TexturePtr mTexture = TextureManager.Singleton.CreateManual("Refraction",
                                                                        ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, TextureType.TEX_TYPE_2D,
                                                                        512, 512, 0, PixelFormat.PF_R8G8B8, (int)TextureUsage.TU_RENDERTARGET);
            //RenderTexture* rttTex = mRoot.getRenderSystem().createRenderTexture( "Refraction", 512, 512 );
            RenderTarget rttTex = mTexture.GetBuffer().GetRenderTarget();

            {
                Viewport    v   = rttTex.AddViewport(camera);
                MaterialPtr mat = MaterialManager.Singleton.GetByName("Examples/FresnelReflectionRefraction");
                mat.GetTechnique(0).GetPass(0).GetTextureUnitState(2).SetTextureName("Refraction");
                v.OverlaysEnabled              = false;
                rttTex.PreRenderTargetUpdate  += new RenderTargetListener.PreRenderTargetUpdateHandler(Refraction_PreRenderTargetUpdate);
                rttTex.PostRenderTargetUpdate += new RenderTargetListener.PostRenderTargetUpdateHandler(Refraction_PostRenderTargetUpdate);
            }

            mTexture = TextureManager.Singleton.CreateManual("Reflection",
                                                             ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME, TextureType.TEX_TYPE_2D,
                                                             512, 512, 0, PixelFormat.PF_R8G8B8, (int)TextureUsage.TU_RENDERTARGET);
            //rttTex = mRoot.getRenderSystem().createRenderTexture( "Reflection", 512, 512 );
            rttTex = mTexture.GetBuffer().GetRenderTarget();
            {
                Viewport    v   = rttTex.AddViewport(camera);
                MaterialPtr mat = MaterialManager.Singleton.GetByName("Examples/FresnelReflectionRefraction");
                mat.GetTechnique(0).GetPass(0).GetTextureUnitState(1).SetTextureName("Reflection");
                v.OverlaysEnabled              = false;
                rttTex.PreRenderTargetUpdate  += new RenderTargetListener.PreRenderTargetUpdateHandler(Reflection_PreRenderTargetUpdate);
                rttTex.PostRenderTargetUpdate += new RenderTargetListener.PostRenderTargetUpdateHandler(Reflection_PostRenderTargetUpdate);
            }


            // Define a floor plane mesh
            reflectionPlane.normal = Vector3.UNIT_Y;
            reflectionPlane.d      = 0;
            MeshManager.Singleton.CreatePlane("ReflectPlane",
                                              ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
                                              reflectionPlane,
                                              1500, 1500, 10, 10, true, 1, 5, 5, Vector3.UNIT_Z);
            pPlaneEnt = sceneMgr.CreateEntity("plane", "ReflectPlane");
            pPlaneEnt.SetMaterialName("Examples/FresnelReflectionRefraction");
            sceneMgr.RootSceneNode.CreateChildSceneNode().AttachObject(pPlaneEnt);


            sceneMgr.SetSkyBox(true, "Examples/CloudyNoonSkyBox");

            // My node to which all objects will be attached
            SceneNode myRootNode = sceneMgr.RootSceneNode.CreateChildSceneNode();

            // above water entities
            pEnt = sceneMgr.CreateEntity("RomanBathUpper", "RomanBathUpper.mesh");
            myRootNode.AttachObject(pEnt);
            aboveWaterEnts.Add(pEnt);

            pEnt = sceneMgr.CreateEntity("Columns", "Columns.mesh");
            myRootNode.AttachObject(pEnt);
            aboveWaterEnts.Add(pEnt);

            SceneNode headNode = myRootNode.CreateChildSceneNode();

            pEnt = sceneMgr.CreateEntity("OgreHead", "ogrehead.mesh");
            pEnt.SetMaterialName("RomanBath/OgreStone");
            headNode.AttachObject(pEnt);
            headNode.SetPosition(-350, 55, 130);
            headNode.Rotate(Vector3.UNIT_Y, new Degree(90));
            aboveWaterEnts.Add(pEnt);

            // below water entities
            pEnt = sceneMgr.CreateEntity("RomanBathLower", "RomanBathLower.mesh");
            myRootNode.AttachObject(pEnt);
            belowWaterEnts.Add(pEnt);

            for (int fishNo = 0; fishNo < NUM_FISH; ++fishNo)
            {
                pEnt = sceneMgr.CreateEntity("fish" + fishNo, "fish.mesh");
                fishNodes[fishNo]              = myRootNode.CreateChildSceneNode();
                fishAnimations[fishNo]         = pEnt.GetAnimationState("swim");
                fishAnimations[fishNo].Enabled = true;
                fishNodes[fishNo].AttachObject(pEnt);
                belowWaterEnts.Add(pEnt);


                // Generate a random selection of points for the fish to swim to
                fishSplines[fishNo].SetAutoCalculate(false);
                Vector3 lastPos = new Vector3();
                for (int waypoint = 0; waypoint < NUM_FISH_WAYPOINTS; ++waypoint)
                {
                    Vector3 pos = new Vector3(
                        Mogre.Math.SymmetricRandom() * 270, -10, Mogre.Math.SymmetricRandom() * 700);
                    if (waypoint > 0)
                    {
                        // check this waypoint isn't too far, we don't want turbo-fish ;)
                        // since the waypoints are achieved every 5 seconds, half the length
                        // of the pond is ok
                        while ((lastPos - pos).Length > 750)
                        {
                            pos = new Vector3(
                                Mogre.Math.SymmetricRandom() * 270, -10, Mogre.Math.SymmetricRandom() * 700);
                        }
                    }
                    fishSplines[fishNo].AddPoint(pos);
                    lastPos = pos;
                }
                // close the spline
                fishSplines[fishNo].AddPoint(fishSplines[fishNo].GetPoint(0));
                // recalc
                fishSplines[fishNo].RecalcTangents();
            }
        }
Ejemplo n.º 7
0
        // Just override the mandatory create scene method
        public override void CreateScene()
        {
            // Set ambient light
            sceneMgr.AmbientLight = new ColourValue(0.2f, 0.2f, 0.2f);
            // Skybox
            sceneMgr.SetSkyBox(true, "Examples/MorningSkyBox");

            // Create a light
            Light l = sceneMgr.CreateLight("MainLight");

            l.Type = Light.LightTypes.LT_DIRECTIONAL;
            Vector3 dir = new Vector3(0.5f, -1, 0);

            dir.Normalise();
            l.Direction      = dir;
            l.DiffuseColour  = new ColourValue(1.0f, 1.0f, 0.8f);
            l.SpecularColour = new ColourValue(1.0f, 1.0f, 1.0f);

            // Create a prefab plane
            mPlane = new MovablePlane(Vector3.UNIT_Y, 0);

            MeshManager.Singleton.CreatePlane("ReflectionPlane",
                                              ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
                                              mPlane._getDerivedPlane(), 2000, 2000,
                                              1, 1, true, 1, 1, 1, Vector3.UNIT_Z);
            mPlaneEnt = sceneMgr.CreateEntity("Plane", "ReflectionPlane");

            // Create an entity from a model (will be loaded automatically)
            Entity knotEnt = sceneMgr.CreateEntity("Knot", "knot.mesh");

            // Create an entity from a model (will be loaded automatically)
            Entity ogreHead = sceneMgr.CreateEntity("Head", "ogrehead.mesh");

            knotEnt.SetMaterialName("Examples/TextureEffect2");

            // Attach the rtt entity to the root of the scene
            SceneNode rootNode = sceneMgr.RootSceneNode;

            mPlaneNode = rootNode.CreateChildSceneNode();

            // Attach both the plane entity, and the plane definition
            mPlaneNode.AttachObject(mPlaneEnt);
            mPlaneNode.AttachObject(mPlane);
            mPlaneNode.Translate(0, -10, 0);
            // Tilt it a little to make it interesting
            mPlaneNode.Roll(new Degree(5));

            rootNode.CreateChildSceneNode("Head").AttachObject(ogreHead);

            TexturePtr texture = TextureManager.Singleton.CreateManual("RttTex",
                                                                       ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME,
                                                                       TextureType.TEX_TYPE_2D,
                                                                       512, 512, 0,
                                                                       PixelFormat.PF_R8G8B8,
                                                                       (int)TextureUsage.TU_RENDERTARGET);
            RenderTarget rttTex = texture.GetBuffer().GetRenderTarget();

            mReflectCam = sceneMgr.CreateCamera("ReflectCam");
            mReflectCam.NearClipDistance = camera.NearClipDistance;
            mReflectCam.FarClipDistance  = camera.FarClipDistance;
            mReflectCam.AspectRatio      =
                (float)window.GetViewport(0).ActualWidth /
                (float)window.GetViewport(0).ActualHeight;
            mReflectCam.FOVy = camera.FOVy;

            Viewport v = rttTex.AddViewport(mReflectCam);

            v.SetClearEveryFrame(true);
            v.BackgroundColour = ColourValue.Black;

            MaterialPtr mat = MaterialManager.Singleton.Create("RttMat",
                                                               ResourceGroupManager.DEFAULT_RESOURCE_GROUP_NAME);
            TextureUnitState t = mat.GetTechnique(0).GetPass(0).CreateTextureUnitState("RustedMetal.jpg");

            t = mat.GetTechnique(0).GetPass(0).CreateTextureUnitState("RttTex");
            // Blend with base texture
            t.SetColourOperationEx(LayerBlendOperationEx.LBX_BLEND_MANUAL,
                                   LayerBlendSource.LBS_TEXTURE,
                                   LayerBlendSource.LBS_CURRENT,
                                   ColourValue.White,
                                   ColourValue.White, 0.25f);
            t.SetTextureAddressingMode(TextureUnitState.TextureAddressingMode.TAM_CLAMP);
            t.SetProjectiveTexturing(true, mReflectCam);
            rttTex.PostRenderTargetUpdate += postRenderTargetUpdate;
            rttTex.PreRenderTargetUpdate  += preRenderTargetUpdate;

            // set up linked reflection
            mReflectCam.EnableReflection(mPlane);
            // Also clip
            mReflectCam.EnableCustomNearClipPlane(mPlane);


            // Give the plane a texture
            mPlaneEnt.SetMaterialName("RttMat");

            // Add a whole bunch of extra transparent entities
            Entity cloneEnt;

            for (int n = 0; n < 10; ++n)
            {
                // Create a new node under the root
                SceneNode node = sceneMgr.CreateSceneNode();
                // Random translate
                Vector3 nodePos;
                nodePos.x     = Mogre.Math.SymmetricRandom() * 750.0f;
                nodePos.y     = Mogre.Math.SymmetricRandom() * 100.0f + 25;
                nodePos.z     = Mogre.Math.SymmetricRandom() * 750.0f;
                node.Position = nodePos;
                rootNode.AddChild(node);
                // Clone knot
                string cloneName = "Knot" + n;
                cloneEnt = knotEnt.Clone(cloneName);
                // Attach to new node
                node.AttachObject(cloneEnt);
            }

            camera.Position = new Vector3(-50, 100, 500);
            camera.LookAt(0, 0, 0);
        }